Auto merge of #2742 - RalfJung:targets, r=RalfJung

handle unknown targets more gracefully

In particular don't require a list of all OSes in the TLS machinery. Instead just fall back to doing nothing.
This commit is contained in:
bors 2022-12-28 09:51:40 +00:00
commit fbdf926e70
13 changed files with 92 additions and 60 deletions

View File

@ -47,7 +47,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
let min_align = match this.tcx.sess.target.arch.as_ref() {
"x86" | "arm" | "mips" | "powerpc" | "powerpc64" | "asmjs" | "wasm32" => 8,
"x86_64" | "aarch64" | "mips64" | "s390x" | "sparc64" => 16,
arch => bug!("Unsupported target architecture: {}", arch),
arch => bug!("unsupported target architecture for malloc: `{}`", arch),
};
// Windows always aligns, even small allocations.
// Source: <https://support.microsoft.com/en-us/help/286470/how-to-use-pageheap-exe-in-windows-xp-windows-2000-and-windows-server>
@ -320,7 +320,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
return Ok(Some(body));
}
this.handle_unsupported(format!("can't call foreign function: {link_name}"))?;
this.handle_unsupported(format!(
"can't call foreign function `{link_name}` on OS `{os}`",
os = this.tcx.sess.target.os,
))?;
return Ok(None);
}
}
@ -336,9 +339,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> {
let this = self.eval_context_mut();
let allocator_kind = if let Some(allocator_kind) = this.tcx.allocator_kind(()) {
allocator_kind
} else {
let Some(allocator_kind) = this.tcx.allocator_kind(()) else {
// in real code, this symbol does not exist without an allocator
return Ok(EmulateByNameResult::NotSupported);
};
@ -420,9 +421,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
let [ptr] = this.check_shim(abi, Abi::Rust, link_name, args)?;
let ptr = this.read_pointer(ptr)?;
let (alloc_id, _, _) = this.ptr_get_alloc_id(ptr).map_err(|_e| {
err_machine_stop!(TerminationInfo::Abort(
format!("pointer passed to miri_get_alloc_id must not be dangling, got {ptr:?}")
))
err_machine_stop!(TerminationInfo::Abort(format!(
"pointer passed to miri_get_alloc_id must not be dangling, got {ptr:?}"
)))
})?;
this.write_scalar(Scalar::from_u64(alloc_id.0.get()), dest)?;
}
@ -438,7 +439,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
let ptr = this.read_pointer(ptr)?;
let (alloc_id, offset, _) = this.ptr_get_alloc_id(ptr)?;
if offset != Size::ZERO {
throw_unsup_format!("pointer passed to miri_static_root must point to beginning of an allocated block");
throw_unsup_format!(
"pointer passed to miri_static_root must point to beginning of an allocated block"
);
}
this.machine.static_roots.push(alloc_id);
}
@ -453,7 +456,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
// We read this as a plain OsStr and write it as a path, which will convert it to the target.
let path = this.read_os_str_from_c_str(ptr)?.to_owned();
let (success, needed_size) = this.write_path_to_c_str(Path::new(&path), out, out_size)?;
let (success, needed_size) =
this.write_path_to_c_str(Path::new(&path), out, out_size)?;
// Return value: 0 on success, otherwise the size it would have needed.
this.write_int(if success { 0 } else { needed_size }, dest)?;
}
@ -505,11 +509,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
this.write_pointer(res, dest)?;
}
"calloc" => {
let [items, len] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let [items, len] =
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let items = this.read_machine_usize(items)?;
let len = this.read_machine_usize(len)?;
let size =
items.checked_mul(len).ok_or_else(|| err_ub_format!("overflow during calloc size computation"))?;
let size = items
.checked_mul(len)
.ok_or_else(|| err_ub_format!("overflow during calloc size computation"))?;
let res = this.malloc(size, /*zero_init:*/ true, MiriMemoryKind::C)?;
this.write_pointer(res, dest)?;
}
@ -519,7 +525,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
this.free(ptr, MiriMemoryKind::C)?;
}
"realloc" => {
let [old_ptr, new_size] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let [old_ptr, new_size] =
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let old_ptr = this.read_pointer(old_ptr)?;
let new_size = this.read_machine_usize(new_size)?;
let res = this.realloc(old_ptr, new_size, MiriMemoryKind::C)?;
@ -551,11 +558,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
};
match link_name.as_str() {
"__rust_alloc" => return this.emulate_allocator(Symbol::intern("__rg_alloc"), default),
"__rust_alloc" =>
return this.emulate_allocator(Symbol::intern("__rg_alloc"), default),
"miri_alloc" => {
default(this)?;
return Ok(EmulateByNameResult::NeedsJumping);
},
}
_ => unreachable!(),
}
}
@ -574,7 +582,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
)?;
// We just allocated this, the access is definitely in-bounds.
this.write_bytes_ptr(ptr.into(), iter::repeat(0u8).take(usize::try_from(size).unwrap())).unwrap();
this.write_bytes_ptr(
ptr.into(),
iter::repeat(0u8).take(usize::try_from(size).unwrap()),
)
.unwrap();
this.write_pointer(ptr, dest)
});
}
@ -600,7 +612,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
};
match link_name.as_str() {
"__rust_dealloc" => return this.emulate_allocator(Symbol::intern("__rg_dealloc"), default),
"__rust_dealloc" =>
return this.emulate_allocator(Symbol::intern("__rg_dealloc"), default),
"miri_dealloc" => {
default(this)?;
return Ok(EmulateByNameResult::NeedsJumping);
@ -609,7 +622,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
}
}
"__rust_realloc" => {
let [ptr, old_size, align, new_size] = this.check_shim(abi, Abi::Rust, link_name, args)?;
let [ptr, old_size, align, new_size] =
this.check_shim(abi, Abi::Rust, link_name, args)?;
let ptr = this.read_pointer(ptr)?;
let old_size = this.read_machine_usize(old_size)?;
let align = this.read_machine_usize(align)?;
@ -633,7 +647,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
// C memory handling functions
"memcmp" => {
let [left, right, n] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let [left, right, n] =
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let left = this.read_pointer(left)?;
let right = this.read_pointer(right)?;
let n = Size::from_bytes(this.read_machine_usize(n)?);
@ -653,7 +668,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
this.write_scalar(Scalar::from_i32(result), dest)?;
}
"memrchr" => {
let [ptr, val, num] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let [ptr, val, num] =
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let ptr = this.read_pointer(ptr)?;
let val = this.read_scalar(val)?.to_i32()?;
let num = this.read_machine_usize(num)?;
@ -676,7 +692,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
}
}
"memchr" => {
let [ptr, val, num] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let [ptr, val, num] =
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let ptr = this.read_pointer(ptr)?;
let val = this.read_scalar(val)?.to_i32()?;
let num = this.read_machine_usize(num)?;
@ -699,7 +716,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
let [ptr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let ptr = this.read_pointer(ptr)?;
let n = this.read_c_str(ptr)?.len();
this.write_scalar(Scalar::from_machine_usize(u64::try_from(n).unwrap(), this), dest)?;
this.write_scalar(
Scalar::from_machine_usize(u64::try_from(n).unwrap(), this),
dest,
)?;
}
// math functions (note that there are also intrinsics for some other functions)
@ -835,7 +855,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
let a = this.read_scalar(a)?.to_u64()?;
let b = this.read_scalar(b)?.to_u64()?;
#[allow(clippy::integer_arithmetic)] // adding two u64 and a u8 cannot wrap in a u128
#[allow(clippy::integer_arithmetic)]
// adding two u64 and a u8 cannot wrap in a u128
let wide_sum = u128::from(c_in) + u128::from(a) + u128::from(b);
#[allow(clippy::integer_arithmetic)] // it's a u128, we can shift by 64
let (c_out, sum) = ((wide_sum >> 64).truncate::<u8>(), wide_sum.truncate::<u64>());
@ -845,7 +866,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
let sum_field = this.place_field(dest, 1)?;
this.write_scalar(Scalar::from_u64(sum), &sum_field)?;
}
"llvm.x86.sse2.pause" if this.tcx.sess.target.arch == "x86" || this.tcx.sess.target.arch == "x86_64" => {
"llvm.x86.sse2.pause"
if this.tcx.sess.target.arch == "x86" || this.tcx.sess.target.arch == "x86_64" =>
{
let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
this.yield_active_thread();
}
@ -853,7 +876,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
let [arg] = this.check_shim(abi, Abi::Unadjusted, link_name, args)?;
let arg = this.read_scalar(arg)?.to_i32()?;
match arg {
15 => { // SY ("full system scope")
// SY ("full system scope")
15 => {
this.yield_active_thread();
}
_ => {
@ -863,11 +887,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
}
// Platform-specific shims
_ => match this.tcx.sess.target.os.as_ref() {
target if target_os_is_unix(target) => return shims::unix::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest),
"windows" => return shims::windows::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest),
target => throw_unsup_format!("the target `{}` is not supported", target),
}
_ =>
return match this.tcx.sess.target.os.as_ref() {
target_os if target_os_is_unix(target_os) =>
shims::unix::foreign_items::EvalContextExt::emulate_foreign_item_by_name(
this, link_name, abi, args, dest,
),
"windows" =>
shims::windows::foreign_items::EvalContextExt::emulate_foreign_item_by_name(
this, link_name, abi, args, dest,
),
_ => Ok(EmulateByNameResult::NotSupported),
},
};
// We only fall through to here if we did *not* hit the `_` arm above,
// i.e., if we actually emulated the function with one of the shims.

View File

@ -257,16 +257,11 @@ impl TlsDtorsState {
// And move to the final state.
self.0 = Done;
}
"wasi" | "none" => {
// No OS, no TLS dtors.
_ => {
// No TLS dtor support.
// FIXME: should we do something on wasi?
self.0 = Done;
}
os => {
throw_unsup_format!(
"the TLS machinery does not know how to handle OS `{os}`"
);
}
}
}
PthreadDtors(state) => {

View File

@ -596,13 +596,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
// Platform-specific shims
_ => {
let target_os = &*this.tcx.sess.target.os;
match target_os {
"android" => return shims::unix::android::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest),
"freebsd" => return shims::unix::freebsd::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest),
"linux" => return shims::unix::linux::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest),
"macos" => return shims::unix::macos::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest),
_ => panic!("unsupported Unix OS {target_os}"),
}
return match target_os {
"android" => shims::unix::android::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest),
"freebsd" => shims::unix::freebsd::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest),
"linux" => shims::unix::linux::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest),
"macos" => shims::unix::macos::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest),
_ => Ok(EmulateByNameResult::NotSupported),
};
}
};

View File

@ -1,5 +1,6 @@
//@only-target-linux
//@only-on-host
//@normalize-stderr-test: "OS `.*`" -> "$$OS"
extern "C" {
fn foo();
@ -7,6 +8,6 @@ extern "C" {
fn main() {
unsafe {
foo(); //~ ERROR: unsupported operation: can't call foreign function: foo
foo(); //~ ERROR: unsupported operation: can't call foreign function `foo`
}
}

View File

@ -1,8 +1,8 @@
error: unsupported operation: can't call foreign function: foo
error: unsupported operation: can't call foreign function `foo` on $OS
--> $DIR/function_not_in_so.rs:LL:CC
|
LL | foo();
| ^^^^^ can't call foreign function: foo
| ^^^^^ can't call foreign function `foo` on $OS
|
= help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support
= note: BACKTRACE:

View File

@ -1,3 +1,4 @@
//@normalize-stderr-test: "OS `.*`" -> "$$OS"
// Make sure we pretend the allocation symbols don't exist when there is no allocator
#![feature(lang_items, start)]
@ -10,7 +11,7 @@ extern "Rust" {
#[start]
fn start(_: isize, _: *const *const u8) -> isize {
unsafe {
__rust_alloc(1, 1); //~ERROR: unsupported operation: can't call foreign function: __rust_alloc
__rust_alloc(1, 1); //~ERROR: unsupported operation: can't call foreign function `__rust_alloc`
}
0

View File

@ -1,8 +1,8 @@
error: unsupported operation: can't call foreign function: __rust_alloc
error: unsupported operation: can't call foreign function `__rust_alloc` on $OS
--> $DIR/no_global_allocator.rs:LL:CC
|
LL | __rust_alloc(1, 1);
| ^^^^^^^^^^^^^^^^^^ can't call foreign function: __rust_alloc
| ^^^^^^^^^^^^^^^^^^ can't call foreign function `__rust_alloc` on $OS
|
= help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support
= note: BACKTRACE:

View File

@ -1,9 +1,11 @@
//@normalize-stderr-test: "OS `.*`" -> "$$OS"
fn main() {
extern "Rust" {
fn foo();
}
unsafe {
foo(); //~ ERROR: unsupported operation: can't call foreign function: foo
foo(); //~ ERROR: unsupported operation: can't call foreign function `foo`
}
}

View File

@ -1,8 +1,8 @@
error: unsupported operation: can't call foreign function: foo
error: unsupported operation: can't call foreign function `foo` on $OS
--> $DIR/unsupported_foreign_function.rs:LL:CC
|
LL | foo();
| ^^^^^ can't call foreign function: foo
| ^^^^^ can't call foreign function `foo` on $OS
|
= help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support
= note: BACKTRACE:

View File

@ -1,10 +1,11 @@
//! `signal()` is special on Linux and macOS that it's only supported within libstd.
//! The implementation is not complete enough to permit user code to call it.
//@ignore-target-windows: No libc on Windows
//@normalize-stderr-test: "OS `.*`" -> "$$OS"
fn main() {
unsafe {
libc::signal(libc::SIGPIPE, libc::SIG_IGN);
//~^ ERROR: unsupported operation: can't call foreign function: signal
//~^ ERROR: unsupported operation: can't call foreign function `signal`
}
}

View File

@ -1,12 +1,12 @@
error: unsupported operation: can't call foreign function: signal
--> $DIR/unsupported_signal.rs:LL:CC
error: unsupported operation: can't call foreign function `signal` on $OS
--> $DIR/unsupported_incomplete_function.rs:LL:CC
|
LL | libc::signal(libc::SIGPIPE, libc::SIG_IGN);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't call foreign function: signal
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't call foreign function `signal` on $OS
|
= help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support
= note: BACKTRACE:
= note: inside `main` at $DIR/unsupported_signal.rs:LL:CC
= note: inside `main` at $DIR/unsupported_incomplete_function.rs:LL:CC
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace

View File

@ -1,4 +1,5 @@
//@compile-flags: -Zmiri-panic-on-unsupported
//@normalize-stderr-test: "OS `.*`" -> "$$OS"
fn main() {
extern "Rust" {

View File

@ -1,2 +1,2 @@
thread 'main' panicked at 'unsupported Miri functionality: can't call foreign function: foo', $DIR/unsupported_foreign_function.rs:LL:CC
thread 'main' panicked at 'unsupported Miri functionality: can't call foreign function `foo` on $OS', $DIR/unsupported_foreign_function.rs:LL:CC
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace