diff --git a/ci.sh b/ci.sh index 01b86ff2f9..1fa67f5213 100755 --- a/ci.sh +++ b/ci.sh @@ -42,6 +42,16 @@ function run_tests { echo } +function run_tests_minimal { + if [ -n "${MIRI_TEST_TARGET+exists}" ]; then + echo "Testing MINIMAL foreign architecture $MIRI_TEST_TARGET: only testing $@" + else + echo "Testing MINIMAL host architecture: only testing $@" + fi + + ./miri test --locked -- "$@" +} + # host run_tests @@ -50,6 +60,7 @@ case $HOST_TARGET in MIRI_TEST_TARGET=i686-unknown-linux-gnu run_tests MIRI_TEST_TARGET=aarch64-apple-darwin run_tests MIRI_TEST_TARGET=i686-pc-windows-msvc run_tests + MIRI_TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal hello integer vec ;; x86_64-apple-darwin) MIRI_TEST_TARGET=mips64-unknown-linux-gnuabi64 run_tests # big-endian architecture diff --git a/src/helpers.rs b/src/helpers.rs index 134f556bf1..86823f2817 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -910,5 +910,5 @@ impl std::fmt::Display for HexRange { /// Helper function used inside the shims of foreign functions to check that /// `target_os` is a supported UNIX OS. pub fn target_os_is_unix(target_os: &str) -> bool { - matches!(target_os, "linux" | "macos") + matches!(target_os, "linux" | "macos" | "freebsd") } diff --git a/src/shims/unix/dlsym.rs b/src/shims/unix/dlsym.rs index 578ae488a9..e1f819fb85 100644 --- a/src/shims/unix/dlsym.rs +++ b/src/shims/unix/dlsym.rs @@ -2,6 +2,7 @@ use rustc_middle::mir; use rustc_target::spec::abi::Abi; use crate::*; +use shims::unix::freebsd::dlsym as freebsd; use shims::unix::linux::dlsym as linux; use shims::unix::macos::dlsym as macos; @@ -9,6 +10,7 @@ use shims::unix::macos::dlsym as macos; pub enum Dlsym { Linux(linux::Dlsym), MacOs(macos::Dlsym), + FreeBSD(freebsd::Dlsym), } impl Dlsym { @@ -18,6 +20,7 @@ impl Dlsym { Ok(match target_os { "linux" => linux::Dlsym::from_str(name)?.map(Dlsym::Linux), "macos" => macos::Dlsym::from_str(name)?.map(Dlsym::MacOs), + "freebsd" => freebsd::Dlsym::from_str(name)?.map(Dlsym::FreeBSD), _ => unreachable!(), }) } @@ -40,6 +43,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match dlsym { Dlsym::Linux(dlsym) => linux::EvalContextExt::call_dlsym(this, dlsym, args, dest, ret), Dlsym::MacOs(dlsym) => macos::EvalContextExt::call_dlsym(this, dlsym, args, dest, ret), + Dlsym::FreeBSD(dlsym) => + freebsd::EvalContextExt::call_dlsym(this, dlsym, args, dest, ret), } } } diff --git a/src/shims/unix/foreign_items.rs b/src/shims/unix/foreign_items.rs index d002ab75b9..d0c93ef4cd 100644 --- a/src/shims/unix/foreign_items.rs +++ b/src/shims/unix/foreign_items.rs @@ -461,6 +461,28 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } + // Querying system information + "pthread_attr_getstack" => { + // We don't support "pthread_attr_setstack", so we just pretend all stacks have the same values here. Hence we can mostly ignore the input `attr_place`. + let [attr_place, addr_place, size_place] = + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let _attr_place = this.deref_operand(attr_place)?; + let addr_place = this.deref_operand(addr_place)?; + let size_place = this.deref_operand(size_place)?; + + this.write_scalar( + Scalar::from_uint(STACK_ADDR, this.pointer_size()), + &addr_place.into(), + )?; + this.write_scalar( + Scalar::from_uint(STACK_SIZE, this.pointer_size()), + &size_place.into(), + )?; + + // Return success (`0`). + this.write_null(dest)?; + } + | "signal" | "sigaltstack" if this.frame_in_std() => { @@ -485,6 +507,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match this.tcx.sess.target.os.as_ref() { "linux" => return shims::unix::linux::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest, ret), "macos" => return shims::unix::macos::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest, ret), + "freebsd" => return shims::unix::freebsd::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest, ret), _ => unreachable!(), } } diff --git a/src/shims/unix/freebsd/dlsym.rs b/src/shims/unix/freebsd/dlsym.rs new file mode 100644 index 0000000000..18347d274e --- /dev/null +++ b/src/shims/unix/freebsd/dlsym.rs @@ -0,0 +1,32 @@ +use rustc_middle::mir; + +use crate::*; + +#[derive(Debug, Copy, Clone)] +#[allow(non_camel_case_types)] +pub enum Dlsym {} + +impl Dlsym { + // Returns an error for unsupported symbols, and None if this symbol + // should become a NULL pointer (pretend it does not exist). + pub fn from_str<'tcx>(name: &str) -> InterpResult<'tcx, Option> { + throw_unsup_format!("unsupported FreeBSD dlsym: {}", name) + } +} + +impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { + fn call_dlsym( + &mut self, + dlsym: Dlsym, + _args: &[OpTy<'tcx, Tag>], + _dest: &PlaceTy<'tcx, Tag>, + ret: Option, + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + let _ret = ret.expect("we don't support any diverging dlsym"); + assert!(this.tcx.sess.target.os == "freebsd"); + + match dlsym {} + } +} diff --git a/src/shims/unix/freebsd/foreign_items.rs b/src/shims/unix/freebsd/foreign_items.rs new file mode 100644 index 0000000000..cad1192337 --- /dev/null +++ b/src/shims/unix/freebsd/foreign_items.rs @@ -0,0 +1,31 @@ +use rustc_middle::mir; +use rustc_span::Symbol; +use rustc_target::spec::abi::Abi; + +use crate::*; +use shims::foreign_items::EmulateByNameResult; + +impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} + +pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { + fn emulate_foreign_item_by_name( + &mut self, + link_name: Symbol, + abi: Abi, + args: &[OpTy<'tcx, Tag>], + dest: &PlaceTy<'tcx, Tag>, + _ret: mir::BasicBlock, + ) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> { + let this = self.eval_context_mut(); + match link_name.as_str() { + // Linux's `pthread_getattr_np` equivalent + "pthread_attr_get_np" if this.frame_in_std() => { + let [_thread, _attr] = + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + this.write_null(dest)?; + } + _ => return Ok(EmulateByNameResult::NotSupported), + } + Ok(EmulateByNameResult::NeedsJumping) + } +} diff --git a/src/shims/unix/freebsd/mod.rs b/src/shims/unix/freebsd/mod.rs new file mode 100644 index 0000000000..434f5f30b5 --- /dev/null +++ b/src/shims/unix/freebsd/mod.rs @@ -0,0 +1,2 @@ +pub mod dlsym; +pub mod foreign_items; diff --git a/src/shims/unix/linux/foreign_items.rs b/src/shims/unix/linux/foreign_items.rs index ab3f39147c..48abe9bf08 100644 --- a/src/shims/unix/linux/foreign_items.rs +++ b/src/shims/unix/linux/foreign_items.rs @@ -80,28 +80,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_i32(result), dest)?; } - // Querying system information - "pthread_attr_getstack" => { - // We don't support "pthread_attr_setstack", so we just pretend all stacks have the same values here. - let [attr_place, addr_place, size_place] = - this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - this.deref_operand(attr_place)?; - let addr_place = this.deref_operand(addr_place)?; - let size_place = this.deref_operand(size_place)?; - - this.write_scalar( - Scalar::from_uint(STACK_ADDR, this.pointer_size()), - &addr_place.into(), - )?; - this.write_scalar( - Scalar::from_uint(STACK_SIZE, this.pointer_size()), - &size_place.into(), - )?; - - // Return success (`0`). - this.write_null(dest)?; - } - // Threading "prctl" => { // prctl is variadic. (It is not documented like that in the manpage, but defined like that in the libc crate.) diff --git a/src/shims/unix/mod.rs b/src/shims/unix/mod.rs index f40dfaefb9..8e8c70bbd0 100644 --- a/src/shims/unix/mod.rs +++ b/src/shims/unix/mod.rs @@ -5,6 +5,7 @@ mod fs; mod sync; mod thread; +mod freebsd; mod linux; mod macos; diff --git a/tests/pass/libc.rs b/tests/pass/libc.rs index f97b9dd2b9..e73e796449 100644 --- a/tests/pass/libc.rs +++ b/tests/pass/libc.rs @@ -5,14 +5,14 @@ extern crate libc; -#[cfg(target_os = "linux")] +#[cfg(any(target_os = "linux", target_os = "freebsd"))] fn tmp() -> std::path::PathBuf { std::env::var("MIRI_TEMP") .map(std::path::PathBuf::from) .unwrap_or_else(|_| std::env::temp_dir()) } -#[cfg(target_os = "linux")] +#[cfg(any(target_os = "linux", target_os = "freebsd"))] fn test_posix_fadvise() { use std::convert::TryInto; use std::fs::{remove_file, File}; @@ -42,7 +42,7 @@ fn test_posix_fadvise() { assert_eq!(result, 0); } -#[cfg(target_os = "linux")] +#[cfg(any(target_os = "linux", target_os = "freebsd"))] fn test_sync_file_range() { use std::fs::{remove_file, File}; use std::io::Write; @@ -208,7 +208,7 @@ fn test_rwlock_libc_static_initializer() { /// Test whether the `prctl` shim correctly sets the thread name. /// /// Note: `prctl` exists only on Linux. -#[cfg(target_os = "linux")] +#[cfg(any(target_os = "linux", target_os = "freebsd"))] fn test_prctl_thread_name() { use libc::c_long; use std::ffi::CString; @@ -277,7 +277,7 @@ fn test_thread_local_errno() { } /// Tests whether clock support exists at all -#[cfg(target_os = "linux")] +#[cfg(any(target_os = "linux", target_os = "freebsd"))] fn test_clocks() { let mut tp = std::mem::MaybeUninit::::uninit(); let is_error = unsafe { libc::clock_gettime(libc::CLOCK_REALTIME, tp.as_mut_ptr()) }; @@ -291,10 +291,10 @@ fn test_clocks() { } fn main() { - #[cfg(target_os = "linux")] + #[cfg(any(target_os = "linux", target_os = "freebsd"))] test_posix_fadvise(); - #[cfg(target_os = "linux")] + #[cfg(any(target_os = "linux", target_os = "freebsd"))] test_sync_file_range(); test_mutex_libc_init_recursive(); @@ -302,14 +302,14 @@ fn main() { test_mutex_libc_init_errorcheck(); test_rwlock_libc_static_initializer(); - #[cfg(target_os = "linux")] + #[cfg(any(target_os = "linux", target_os = "freebsd"))] test_mutex_libc_static_initializer_recursive(); - #[cfg(target_os = "linux")] + #[cfg(any(target_os = "linux", target_os = "freebsd"))] test_prctl_thread_name(); test_thread_local_errno(); - #[cfg(target_os = "linux")] + #[cfg(any(target_os = "linux", target_os = "freebsd"))] test_clocks(); }