From e5df0cc770893d3139f7b5610e09eebe5df79ae1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 2 Jul 2022 20:10:44 -0400 Subject: [PATCH 1/4] adjust tests for removal of unsized_locals --- tests/fail/unsized-local.rs | 23 ++++++++++++++++++++ tests/fail/unsized-local.stderr | 14 ++++++++++++ tests/pass/dyn-traits.rs | 12 ++++------- tests/pass/unsized-tuple-impls.rs | 13 ----------- tests/pass/unsized.rs | 36 +++++++++++++++++++++++++++++++ 5 files changed, 77 insertions(+), 21 deletions(-) create mode 100644 tests/fail/unsized-local.rs create mode 100644 tests/fail/unsized-local.stderr delete mode 100644 tests/pass/unsized-tuple-impls.rs create mode 100644 tests/pass/unsized.rs diff --git a/tests/fail/unsized-local.rs b/tests/fail/unsized-local.rs new file mode 100644 index 00000000000..8dd07c585c6 --- /dev/null +++ b/tests/fail/unsized-local.rs @@ -0,0 +1,23 @@ +#![feature(unsized_locals)] +#![allow(incomplete_features)] + +fn main() { + pub trait Foo { + fn foo(self) -> String; + } + + struct A; + + impl Foo for A { + fn foo(self) -> String { + format!("hello") + } + } + + let x = *(Box::new(A) as Box); //~ERROR unsized locals are not supported + assert_eq!(x.foo(), format!("hello")); + + // I'm not sure whether we want this to work + let x = Box::new(A) as Box; + assert_eq!(x.foo(), format!("hello")); +} diff --git a/tests/fail/unsized-local.stderr b/tests/fail/unsized-local.stderr new file mode 100644 index 00000000000..8277bc4546c --- /dev/null +++ b/tests/fail/unsized-local.stderr @@ -0,0 +1,14 @@ +error: unsupported operation: unsized locals are not supported + --> $DIR/unsized-local.rs:LL:CC + | +LL | let x = *(Box::new(A) as Box); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unsized locals are not supported + | + = 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/unsized-local.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/pass/dyn-traits.rs b/tests/pass/dyn-traits.rs index 00667757b04..908d521a0d8 100644 --- a/tests/pass/dyn-traits.rs +++ b/tests/pass/dyn-traits.rs @@ -1,6 +1,3 @@ -#![feature(unsized_locals, unsized_fn_params)] -#![allow(incomplete_features)] - fn ref_box_dyn() { struct Struct(i32); @@ -75,6 +72,9 @@ fn new(w: Box) -> Whatever { assert!(unsafe { DROPPED }); } +// Disabled for now: unsized locals are not supported, +// their current MIR encoding is just not great. +/* fn unsized_dyn() { pub trait Foo { fn foo(self) -> String; @@ -95,7 +95,6 @@ fn foo(self) -> String { let x = Box::new(A) as Box; assert_eq!(x.foo(), format!("hello")); } - fn unsized_dyn_autoderef() { pub trait Foo { fn foo(self) -> String; @@ -140,12 +139,9 @@ fn foo(mut self) -> String { let x = Box::new(|| "hello".to_owned()) as Box String>; assert_eq!(&x.foo() as &str, "hello"); } +*/ fn main() { ref_box_dyn(); box_box_trait(); - - // "exotic" receivers - unsized_dyn(); - unsized_dyn_autoderef(); } diff --git a/tests/pass/unsized-tuple-impls.rs b/tests/pass/unsized-tuple-impls.rs deleted file mode 100644 index bbab1125a0a..00000000000 --- a/tests/pass/unsized-tuple-impls.rs +++ /dev/null @@ -1,13 +0,0 @@ -#![feature(unsized_tuple_coercion)] -use std::mem; - -fn main() { - let x: &(i32, i32, [i32]) = &(0, 1, [2, 3]); - let y: &(i32, i32, [i32]) = &(0, 1, [2, 3, 4]); - let mut a = [y, x]; - a.sort(); - assert_eq!(a, [x, y]); - - assert_eq!(&format!("{:?}", a), "[(0, 1, [2, 3]), (0, 1, [2, 3, 4])]"); - assert_eq!(mem::size_of_val(x), 16); -} diff --git a/tests/pass/unsized.rs b/tests/pass/unsized.rs new file mode 100644 index 00000000000..c7e0c792575 --- /dev/null +++ b/tests/pass/unsized.rs @@ -0,0 +1,36 @@ +#![feature(unsized_tuple_coercion)] +#![feature(unsized_fn_params)] + +use std::mem; + +fn unsized_tuple() { + let x: &(i32, i32, [i32]) = &(0, 1, [2, 3]); + let y: &(i32, i32, [i32]) = &(0, 1, [2, 3, 4]); + let mut a = [y, x]; + a.sort(); + assert_eq!(a, [x, y]); + + assert_eq!(&format!("{:?}", a), "[(0, 1, [2, 3]), (0, 1, [2, 3, 4])]"); + assert_eq!(mem::size_of_val(x), 16); +} + +fn unsized_params() { + pub fn f0(_f: dyn FnOnce()) {} + pub fn f1(_s: str) {} + pub fn f2(_x: i32, _y: [i32]) {} + pub fn f3(_p: dyn Send) {} + + let c: Box = Box::new(|| {}); + f0(*c); + let foo = "foo".to_string().into_boxed_str(); + f1(*foo); + let sl: Box::<[i32]> = [0, 1, 2].to_vec().into_boxed_slice(); + f2(5, *sl); + let p: Box = Box::new((1, 2)); + f3(*p); +} + +fn main() { + unsized_tuple(); + unsized_params(); +} From e9176c747e626383e37832514130d078b611f995 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 2 Jul 2022 20:28:39 -0400 Subject: [PATCH 2/4] test for better error location on stack pop --- tests/fail/data_race/stack_pop_race.rs | 22 ++++++++++++++++++++++ tests/fail/data_race/stack_pop_race.stderr | 20 ++++++++++++++++++++ 2 files changed, 42 insertions(+) create mode 100644 tests/fail/data_race/stack_pop_race.rs create mode 100644 tests/fail/data_race/stack_pop_race.stderr diff --git a/tests/fail/data_race/stack_pop_race.rs b/tests/fail/data_race/stack_pop_race.rs new file mode 100644 index 00000000000..fa81306b78c --- /dev/null +++ b/tests/fail/data_race/stack_pop_race.rs @@ -0,0 +1,22 @@ +// compile-flags: -Zmiri-preemption-rate=0 +use std::thread; + +#[derive(Copy, Clone)] +struct MakeSend(*const i32); +unsafe impl Send for MakeSend {} + +fn main() { race(0); } + +// Using an argument for the ptr to point to, since those do not get StorageDead. +fn race(local: i32) { + let ptr = MakeSend(&local as *const i32); + thread::spawn(move || { + let ptr = ptr; + let _val = unsafe { *ptr.0 }; + }); + // Make the other thread go first so that it does not UAF. + thread::yield_now(); + // Deallocating the local (when `main` returns) + // races with the read in the other thread. + // Make sure the error points at this function's end, not just the call site. +} //~ERROR Data race detected between Deallocate on thread `main` and Read on thread `` diff --git a/tests/fail/data_race/stack_pop_race.stderr b/tests/fail/data_race/stack_pop_race.stderr new file mode 100644 index 00000000000..e7e2ba7e8bd --- /dev/null +++ b/tests/fail/data_race/stack_pop_race.stderr @@ -0,0 +1,20 @@ +error: Undefined Behavior: Data race detected between Deallocate on thread `main` and Read on thread `` at ALLOC + --> $DIR/stack_pop_race.rs:LL:CC + | +LL | } + | ^ Data race detected between Deallocate on thread `main` and Read on thread `` at ALLOC + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: backtrace: + = note: inside `race` at $DIR/stack_pop_race.rs:LL:CC +note: inside `main` at $DIR/stack_pop_race.rs:LL:CC + --> $DIR/stack_pop_race.rs:LL:CC + | +LL | fn main() { race(0); } + | ^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + From 5fed3ebc26ae0a9b17c0099fa71df636644f7312 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 2 Jul 2022 21:17:35 -0400 Subject: [PATCH 3/4] adjust code for copy_op changes --- src/machine.rs | 2 +- src/shims/intrinsics.rs | 4 ++-- tests/pass/transmute_fat.rs | 1 + 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/machine.rs b/src/machine.rs index a2d9e9ced1a..12df9e271fb 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -169,7 +169,7 @@ fn fmt(ptr: &Pointer, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{:?}", sb)?; } Tag::Wildcard => { - write!(f, "[Wildcard]")?; + write!(f, "[wildcard]")?; } } diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 9cf9461715f..ab79438c734 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -68,12 +68,12 @@ fn call_intrinsic( "volatile_load" => { let [place] = check_arg_count(args)?; let place = this.deref_operand(place)?; - this.copy_op(&place.into(), dest)?; + this.copy_op(&place.into(), dest, /*allow_transmute*/ false)?; } "volatile_store" => { let [place, dest] = check_arg_count(args)?; let place = this.deref_operand(place)?; - this.copy_op(dest, &place.into())?; + this.copy_op(dest, &place.into(), /*allow_transmute*/ false)?; } "write_bytes" | "volatile_set_memory" => { diff --git a/tests/pass/transmute_fat.rs b/tests/pass/transmute_fat.rs index 1d2ec92a803..b752e5504d4 100644 --- a/tests/pass/transmute_fat.rs +++ b/tests/pass/transmute_fat.rs @@ -3,6 +3,7 @@ fn main() { // If we are careful, we can exploit data layout... + // This is a tricky case since we are transmuting a ScalarPair type to a non-ScalarPair type. let raw = unsafe { std::mem::transmute::<&[u8], [*const u8; 2]>(&[42]) }; let ptr: *const u8 = unsafe { std::mem::transmute_copy(&raw) }; assert_eq!(unsafe { *ptr }, 42); From b6602f5d11fb9da3de05eefc856d7ec102c23139 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 6 Jul 2022 21:45:47 -0400 Subject: [PATCH 4/4] rustup --- rust-version | 2 +- src/operator.rs | 2 ++ tests/fail/data_race/stack_pop_race.rs | 5 ++++- tests/fail/data_race/stack_pop_race.stderr | 4 ++-- tests/pass/unsized.rs | 2 +- 5 files changed, 10 insertions(+), 5 deletions(-) diff --git a/rust-version b/rust-version index 8f3b1d39fd0..37d1eb0fbde 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -7665c3543079ebc3710b676d0fd6951bedfd4b29 +8824d131619e58a38bde8bcf56401629b91a204a diff --git a/src/operator.rs b/src/operator.rs index e7a43ac9552..2c77830a6d1 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -35,11 +35,13 @@ fn binary_ptr_op( Immediate::Scalar(l) => (l.check_init()?.to_bits(size)?, 0), Immediate::ScalarPair(l1, l2) => (l1.check_init()?.to_bits(size)?, l2.check_init()?.to_bits(size)?), + Immediate::Uninit => throw_ub!(InvalidUninitBytes(None)), }; let right = match **right { Immediate::Scalar(r) => (r.check_init()?.to_bits(size)?, 0), Immediate::ScalarPair(r1, r2) => (r1.check_init()?.to_bits(size)?, r2.check_init()?.to_bits(size)?), + Immediate::Uninit => throw_ub!(InvalidUninitBytes(None)), }; let res = match bin_op { Eq => left == right, diff --git a/tests/fail/data_race/stack_pop_race.rs b/tests/fail/data_race/stack_pop_race.rs index fa81306b78c..bae88560014 100644 --- a/tests/fail/data_race/stack_pop_race.rs +++ b/tests/fail/data_race/stack_pop_race.rs @@ -1,3 +1,4 @@ +// ignore-windows: Concurrency on Windows is not supported yet. // compile-flags: -Zmiri-preemption-rate=0 use std::thread; @@ -5,7 +6,9 @@ struct MakeSend(*const i32); unsafe impl Send for MakeSend {} -fn main() { race(0); } +fn main() { + race(0); +} // Using an argument for the ptr to point to, since those do not get StorageDead. fn race(local: i32) { diff --git a/tests/fail/data_race/stack_pop_race.stderr b/tests/fail/data_race/stack_pop_race.stderr index e7e2ba7e8bd..ba830753f6e 100644 --- a/tests/fail/data_race/stack_pop_race.stderr +++ b/tests/fail/data_race/stack_pop_race.stderr @@ -11,8 +11,8 @@ LL | } note: inside `main` at $DIR/stack_pop_race.rs:LL:CC --> $DIR/stack_pop_race.rs:LL:CC | -LL | fn main() { race(0); } - | ^^^^^^^ +LL | race(0); + | ^^^^^^^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/pass/unsized.rs b/tests/pass/unsized.rs index c7e0c792575..d9beac4327d 100644 --- a/tests/pass/unsized.rs +++ b/tests/pass/unsized.rs @@ -24,7 +24,7 @@ pub fn f3(_p: dyn Send) {} f0(*c); let foo = "foo".to_string().into_boxed_str(); f1(*foo); - let sl: Box::<[i32]> = [0, 1, 2].to_vec().into_boxed_slice(); + let sl: Box<[i32]> = [0, 1, 2].to_vec().into_boxed_slice(); f2(5, *sl); let p: Box = Box::new((1, 2)); f3(*p);