From 9e147d0b8fc119ce2dad69c1ab565db6f7b1759d Mon Sep 17 00:00:00 2001 From: David Carlier Date: Fri, 1 Dec 2023 23:41:07 +0000 Subject: [PATCH] [WIP] solaris/illumos support. --- README.md | 1 + ci/ci.sh | 1 + src/concurrency/thread.rs | 14 ++++++ src/shims/unix/foreign_items.rs | 8 ++- src/shims/unix/mod.rs | 1 + src/shims/unix/solarish/foreign_items.rs | 48 ++++++++++++++++++ src/shims/unix/solarish/mod.rs | 1 + src/shims/unix/sync.rs | 62 ++++++++++++++++-------- src/shims/unix/thread.rs | 2 +- 9 files changed, 114 insertions(+), 24 deletions(-) create mode 100644 src/shims/unix/solarish/foreign_items.rs create mode 100644 src/shims/unix/solarish/mod.rs diff --git a/README.md b/README.md index f92cc088e0..33485c3785 100644 --- a/README.md +++ b/README.md @@ -227,6 +227,7 @@ degree documented below): - We have unofficial support (not maintained by the Miri team itself) for some further operating systems. - `freebsd`: **maintainer wanted**. Supports `std::env` and parts of `std::{thread, fs}`, but not `std::sync`. - `android`: **maintainer wanted**. Support very incomplete, but a basic "hello world" works. + - `solaris/illumos`: maintained by @devnexen. Support very incomplete, but a basic "hello world" works. - `wasm`: **maintainer wanted**. Support very incomplete, not even standard output works, but an empty `main` function works. - For targets on other operating systems, Miri might fail before even reaching the `main` function. diff --git a/ci/ci.sh b/ci/ci.sh index d3dee0de61..98dc3f7920 100755 --- a/ci/ci.sh +++ b/ci/ci.sh @@ -146,6 +146,7 @@ case $HOST_TARGET in MIRI_TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal $BASIC panic/panic concurrency/simple atomic threadname libc-getentropy libc-getrandom libc-misc fs env num_cpus MIRI_TEST_TARGET=i686-unknown-freebsd run_tests_minimal $BASIC panic/panic concurrency/simple atomic threadname libc-getentropy libc-getrandom libc-misc fs env num_cpus MIRI_TEST_TARGET=aarch64-linux-android run_tests_minimal $VERY_BASIC hello panic/panic + MIRI_TEST_TARGET=x86_64-unknown-illumos run_tests_minimal $VERY_BASIC hello panic/panic pthread-sync MIRI_TEST_TARGET=wasm32-wasi run_tests_minimal $VERY_BASIC wasm MIRI_TEST_TARGET=wasm32-unknown-unknown run_tests_minimal $VERY_BASIC wasm MIRI_TEST_TARGET=thumbv7em-none-eabihf run_tests_minimal no_std diff --git a/src/concurrency/thread.rs b/src/concurrency/thread.rs index 0116bd0281..c730aeb9ea 100644 --- a/src/concurrency/thread.rs +++ b/src/concurrency/thread.rs @@ -78,6 +78,13 @@ impl TryFrom for ThreadId { } } +impl TryFrom for ThreadId { + type Error = TryFromIntError; + fn try_from(id: i128) -> Result { + u32::try_from(id).map(Self) + } +} + impl From for ThreadId { fn from(id: u32) -> Self { Self(id) @@ -90,6 +97,13 @@ impl From for u64 { } } +impl From for i128 { + fn from(t: ThreadId) -> Self { + t.0.into() + } +} + + /// Keeps track of what the thread is blocked on. #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum BlockReason { diff --git a/src/shims/unix/foreign_items.rs b/src/shims/unix/foreign_items.rs index 90e0406f09..3d3a510c4a 100644 --- a/src/shims/unix/foreign_items.rs +++ b/src/shims/unix/foreign_items.rs @@ -13,6 +13,7 @@ use crate::*; use shims::unix::freebsd::foreign_items as freebsd; use shims::unix::linux::foreign_items as linux; use shims::unix::macos::foreign_items as macos; +use shims::unix::solarish::foreign_items as solarish; pub fn is_dyn_sym(name: &str, target_os: &str) -> bool { match name { @@ -29,6 +30,7 @@ pub fn is_dyn_sym(name: &str, target_os: &str) -> bool { "freebsd" => freebsd::is_dyn_sym(name), "linux" => linux::is_dyn_sym(name), "macos" => macos::is_dyn_sym(name), + "solaris" | "illumos" => solarish::is_dyn_sym(name), _ => false, }, } @@ -591,8 +593,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { } "getentropy" => { // This function is non-standard but exists with the same signature and behavior on - // Linux, macOS, and FreeBSD. - if !matches!(&*this.tcx.sess.target.os, "linux" | "macos" | "freebsd") { + // Linux, macOS, FreeBSD and Solaris/Illumos. + if !matches!(&*this.tcx.sess.target.os, "linux" | "macos" | "freebsd" | "illumos" | "solaris") { throw_unsup_format!( "`getentropy` is not supported on {}", this.tcx.sess.target.os @@ -608,6 +610,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { // FreeBSD: https://man.freebsd.org/cgi/man.cgi?query=getentropy&sektion=3&format=html // Linux: https://man7.org/linux/man-pages/man3/getentropy.3.html // macOS: https://keith.github.io/xcode-man-pages/getentropy.2.html + // Solaris/Illumos: https://illumos.org/man/3C/getentropy if bufsize > 256 { let err = this.eval_libc("EIO"); this.set_last_error(err)?; @@ -730,6 +733,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { "freebsd" => freebsd::EvalContextExt::emulate_foreign_item_inner(this, link_name, abi, args, dest), "linux" => linux::EvalContextExt::emulate_foreign_item_inner(this, link_name, abi, args, dest), "macos" => macos::EvalContextExt::emulate_foreign_item_inner(this, link_name, abi, args, dest), + "solaris" | "illumos" => solarish::EvalContextExt::emulate_foreign_item_inner(this, link_name, abi, args, dest), _ => Ok(EmulateItemResult::NotSupported), }; } diff --git a/src/shims/unix/mod.rs b/src/shims/unix/mod.rs index bede2fbd38..6dee30d895 100644 --- a/src/shims/unix/mod.rs +++ b/src/shims/unix/mod.rs @@ -11,6 +11,7 @@ mod thread; mod freebsd; mod linux; mod macos; +mod solarish; pub use env::UnixEnvVars; pub use fd::{FdTable, FileDescription}; diff --git a/src/shims/unix/solarish/foreign_items.rs b/src/shims/unix/solarish/foreign_items.rs new file mode 100644 index 0000000000..8169de4081 --- /dev/null +++ b/src/shims/unix/solarish/foreign_items.rs @@ -0,0 +1,48 @@ +use rustc_span::Symbol; +use rustc_target::spec::abi::Abi; + +use crate::shims::unix::*; +use crate::*; +use shims::EmulateItemResult; + +pub fn is_dyn_sym(_name: &str) -> bool { + false +} + +impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {} +pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { + fn emulate_foreign_item_inner( + &mut self, + link_name: Symbol, + abi: Abi, + args: &[OpTy<'tcx, Provenance>], + dest: &MPlaceTy<'tcx, Provenance>, + ) -> InterpResult<'tcx, EmulateItemResult> { + let this = self.eval_context_mut(); + match link_name.as_str() { + // errno + "__errno" => { + let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let errno_place = this.last_error_place()?; + this.write_scalar(errno_place.to_ref(this).to_scalar(), dest)?; + } + + // Threading + "pthread_condattr_setclock" => { + let [attr, clock_id] = + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let result = this.pthread_condattr_setclock(attr, clock_id)?; + this.write_scalar(result, dest)?; + } + "pthread_condattr_getclock" => { + let [attr, clock_id] = + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let result = this.pthread_condattr_getclock(attr, clock_id)?; + this.write_scalar(result, dest)?; + } + + _ => return Ok(EmulateItemResult::NotSupported), + } + Ok(EmulateItemResult::NeedsJumping) + } +} diff --git a/src/shims/unix/solarish/mod.rs b/src/shims/unix/solarish/mod.rs new file mode 100644 index 0000000000..09c6507b24 --- /dev/null +++ b/src/shims/unix/solarish/mod.rs @@ -0,0 +1 @@ +pub mod foreign_items; diff --git a/src/shims/unix/sync.rs b/src/shims/unix/sync.rs index 9c09676041..2c9208deb3 100644 --- a/src/shims/unix/sync.rs +++ b/src/shims/unix/sync.rs @@ -68,11 +68,20 @@ fn mutexattr_set_kind<'mir, 'tcx: 'mir>( // (the kind has to be at this particular offset for compatibility with Linux's static initializer // macros, e.g. PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP.) +#[inline] +fn mutex_id_offset<'mir, 'tcx: 'mir>(ecx: &MiriInterpCx<'mir, 'tcx>) -> u64 { + if matches!(&*ecx.tcx.sess.target.os, "macos") { 4 } else { 0 } +} + fn mutex_get_id<'mir, 'tcx: 'mir>( ecx: &mut MiriInterpCx<'mir, 'tcx>, mutex_op: &OpTy<'tcx, Provenance>, ) -> InterpResult<'tcx, MutexId> { - ecx.mutex_get_or_create_id(mutex_op, ecx.libc_ty_layout("pthread_mutex_t"), 4) + ecx.mutex_get_or_create_id( + mutex_op, + ecx.libc_ty_layout("pthread_mutex_t"), + mutex_id_offset(ecx), + ) } fn mutex_reset_id<'mir, 'tcx: 'mir>( @@ -81,7 +90,7 @@ fn mutex_reset_id<'mir, 'tcx: 'mir>( ) -> InterpResult<'tcx, ()> { ecx.deref_pointer_and_write( mutex_op, - 4, + mutex_id_offset(ecx), Scalar::from_i32(0), ecx.libc_ty_layout("pthread_mutex_t"), ecx.machine.layouts.u32, @@ -124,13 +133,20 @@ fn mutex_set_kind<'mir, 'tcx: 'mir>( // (need to avoid this because it is set by static initializer macros) // bytes 4-7: rwlock id as u32 or 0 if id is not assigned yet. -const RWLOCK_ID_OFFSET: u64 = 4; +#[inline] +fn rwlock_id_offset<'mir, 'tcx: 'mir>(ecx: &MiriInterpCx<'mir, 'tcx>) -> u64 { + if matches!(&*ecx.tcx.sess.target.os, "macos") { 4 } else { 0 } +} fn rwlock_get_id<'mir, 'tcx: 'mir>( ecx: &mut MiriInterpCx<'mir, 'tcx>, rwlock_op: &OpTy<'tcx, Provenance>, ) -> InterpResult<'tcx, RwLockId> { - ecx.rwlock_get_or_create_id(rwlock_op, ecx.libc_ty_layout("pthread_rwlock_t"), RWLOCK_ID_OFFSET) + ecx.rwlock_get_or_create_id( + rwlock_op, + ecx.libc_ty_layout("pthread_rwlock_t"), + rwlock_id_offset(ecx), + ) } // pthread_condattr_t @@ -177,14 +193,18 @@ fn condattr_set_clock_id<'mir, 'tcx: 'mir>( // bytes 4-7: the conditional variable id as u32 or 0 if id is not assigned yet. // bytes 8-11: the clock id constant as i32 -const CONDVAR_ID_OFFSET: u64 = 4; const CONDVAR_CLOCK_OFFSET: u64 = 8; +#[inline] +fn cond_id_offset<'mir, 'tcx: 'mir>(ecx: &MiriInterpCx<'mir, 'tcx>) -> u64 { + if matches!(&*ecx.tcx.sess.target.os, "macos") { 4 } else { 0 } +} + fn cond_get_id<'mir, 'tcx: 'mir>( ecx: &mut MiriInterpCx<'mir, 'tcx>, cond_op: &OpTy<'tcx, Provenance>, ) -> InterpResult<'tcx, CondvarId> { - ecx.condvar_get_or_create_id(cond_op, ecx.libc_ty_layout("pthread_cond_t"), CONDVAR_ID_OFFSET) + ecx.condvar_get_or_create_id(cond_op, ecx.libc_ty_layout("pthread_cond_t"), cond_id_offset(ecx)) } fn cond_reset_id<'mir, 'tcx: 'mir>( @@ -193,7 +213,7 @@ fn cond_reset_id<'mir, 'tcx: 'mir>( ) -> InterpResult<'tcx, ()> { ecx.deref_pointer_and_write( cond_op, - CONDVAR_ID_OFFSET, + cond_id_offset(ecx), Scalar::from_i32(0), ecx.libc_ty_layout("pthread_cond_t"), ecx.machine.layouts.u32, @@ -287,7 +307,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - if !matches!(&*this.tcx.sess.target.os, "linux" | "macos") { + if !matches!(&*this.tcx.sess.target.os, "linux" | "macos" | "solaris" | "illumos") { throw_unsup_format!( "`pthread_mutexattr_init` is not supported on {}", this.tcx.sess.target.os @@ -376,7 +396,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - if !matches!(&*this.tcx.sess.target.os, "linux" | "macos") { + if !matches!(&*this.tcx.sess.target.os, "linux" | "macos" | "solaris" | "illumos") { throw_unsup_format!( "`pthread_mutex_init` is not supported on {}", this.tcx.sess.target.os @@ -537,7 +557,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - if !matches!(&*this.tcx.sess.target.os, "linux" | "macos") { + if !matches!(&*this.tcx.sess.target.os, "linux" | "macos" | "solaris" | "illumos") { throw_unsup_format!( "`pthread_rwlock_rdlock` is not supported on {}", this.tcx.sess.target.os @@ -562,7 +582,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - if !matches!(&*this.tcx.sess.target.os, "linux" | "macos") { + if !matches!(&*this.tcx.sess.target.os, "linux" | "macos" | "solaris" | "illumos") { throw_unsup_format!( "`pthread_rwlock_tryrdlock` is not supported on {}", this.tcx.sess.target.os @@ -586,7 +606,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - if !matches!(&*this.tcx.sess.target.os, "linux" | "macos") { + if !matches!(&*this.tcx.sess.target.os, "linux" | "macos" | "solaris" | "illumos") { throw_unsup_format!( "`pthread_rwlock_wrlock` is not supported on {}", this.tcx.sess.target.os @@ -623,7 +643,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - if !matches!(&*this.tcx.sess.target.os, "linux" | "macos") { + if !matches!(&*this.tcx.sess.target.os, "linux" | "macos" | "solaris" | "illumos") { throw_unsup_format!( "`pthread_rwlock_trywrlock` is not supported on {}", this.tcx.sess.target.os @@ -647,7 +667,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - if !matches!(&*this.tcx.sess.target.os, "linux" | "macos") { + if !matches!(&*this.tcx.sess.target.os, "linux" | "macos" | "solaris" | "illumos") { throw_unsup_format!( "`pthread_rwlock_unlock` is not supported on {}", this.tcx.sess.target.os @@ -673,7 +693,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - if !matches!(&*this.tcx.sess.target.os, "linux" | "macos") { + if !matches!(&*this.tcx.sess.target.os, "linux" | "macos" | "solaris" | "illumos") { throw_unsup_format!( "`pthread_rwlock_destroy` is not supported on {}", this.tcx.sess.target.os @@ -704,7 +724,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - if !matches!(&*this.tcx.sess.target.os, "linux" | "macos") { + if !matches!(&*this.tcx.sess.target.os, "linux" | "macos" | "solaris" | "illumos") { throw_unsup_format!( "`pthread_condattr_init` is not supported on {}", this.tcx.sess.target.os @@ -728,9 +748,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let this = self.eval_context_mut(); // Does not exist on macOS! - if !matches!(&*this.tcx.sess.target.os, "linux") { + if !matches!(&*this.tcx.sess.target.os, "linux" | "solaris" | "illumos") { throw_unsup_format!( - "`pthread_condattr_init` is not supported on {}", + "`pthread_condattr_setclock` is not supported on {}", this.tcx.sess.target.os ); } @@ -756,9 +776,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let this = self.eval_context_mut(); // Does not exist on macOS! - if !matches!(&*this.tcx.sess.target.os, "linux") { + if !matches!(&*this.tcx.sess.target.os, "linux" | "solaris" | "illumos") { throw_unsup_format!( - "`pthread_condattr_init` is not supported on {}", + "`pthread_condattr_getclock` is not supported on {}", this.tcx.sess.target.os ); } @@ -793,7 +813,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - if !matches!(&*this.tcx.sess.target.os, "linux" | "macos") { + if !matches!(&*this.tcx.sess.target.os, "linux" | "macos" | "solaris" | "illumos") { throw_unsup_format!( "`pthread_cond_init` is not supported on {}", this.tcx.sess.target.os diff --git a/src/shims/unix/thread.rs b/src/shims/unix/thread.rs index 2a56cd35dc..7f814e080f 100644 --- a/src/shims/unix/thread.rs +++ b/src/shims/unix/thread.rs @@ -42,7 +42,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { throw_unsup_format!("Miri supports pthread_join only with retval==NULL"); } - let thread_id = this.read_target_usize(thread)?; + let thread_id = this.read_scalar(thread)?.to_int(this.libc_ty_layout("pthread_t").size)?; this.join_thread_exclusive(thread_id.try_into().expect("thread ID should fit in u32"))?; Ok(0)