Skip to content

Commit

Permalink
[WIP] solaris/illumos support.
Browse files Browse the repository at this point in the history
  • Loading branch information
devnexen committed May 4, 2024
1 parent 5c32d0a commit 9e147d0
Show file tree
Hide file tree
Showing 9 changed files with 114 additions and 24 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down
1 change: 1 addition & 0 deletions ci/ci.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
14 changes: 14 additions & 0 deletions src/concurrency/thread.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,13 @@ impl TryFrom<u64> for ThreadId {
}
}

impl TryFrom<i128> for ThreadId {
type Error = TryFromIntError;
fn try_from(id: i128) -> Result<Self, Self::Error> {
u32::try_from(id).map(Self)
}
}

impl From<u32> for ThreadId {
fn from(id: u32) -> Self {
Self(id)
Expand All @@ -90,6 +97,13 @@ impl From<ThreadId> for u64 {
}
}

impl From<ThreadId> 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 {
Expand Down
8 changes: 6 additions & 2 deletions src/shims/unix/foreign_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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,
},
}
Expand Down Expand Up @@ -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
Expand All @@ -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)?;
Expand Down Expand Up @@ -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),
};
}
Expand Down
1 change: 1 addition & 0 deletions src/shims/unix/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ mod thread;
mod freebsd;
mod linux;
mod macos;
mod solarish;

pub use env::UnixEnvVars;
pub use fd::{FdTable, FileDescription};
Expand Down
48 changes: 48 additions & 0 deletions src/shims/unix/solarish/foreign_items.rs
Original file line number Diff line number Diff line change
@@ -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)
}
}
1 change: 1 addition & 0 deletions src/shims/unix/solarish/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub mod foreign_items;
62 changes: 41 additions & 21 deletions src/shims/unix/sync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>(
Expand All @@ -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,
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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>(
Expand All @@ -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,
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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
);
}
Expand All @@ -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
);
}
Expand Down Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion src/shims/unix/thread.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down

0 comments on commit 9e147d0

Please sign in to comment.