From 73d8dcb803aad67df31abe99f573a2320282bc60 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 6 Sep 2023 16:36:00 +0200 Subject: miri: catch function calls where the argument is caller-invalid / the return value callee-invalid --- src/tools/miri/tests/fail/validity/cast_fn_ptr1.rs | 13 --------- .../miri/tests/fail/validity/cast_fn_ptr1.stderr | 15 ---------- src/tools/miri/tests/fail/validity/cast_fn_ptr2.rs | 15 ---------- .../miri/tests/fail/validity/cast_fn_ptr2.stderr | 15 ---------- .../validity/cast_fn_ptr_invalid_callee_arg.rs | 13 +++++++++ .../validity/cast_fn_ptr_invalid_callee_arg.stderr | 15 ++++++++++ .../validity/cast_fn_ptr_invalid_callee_ret.rs | 28 ++++++++++++++++++ .../validity/cast_fn_ptr_invalid_callee_ret.stderr | 15 ++++++++++ .../validity/cast_fn_ptr_invalid_caller_arg.rs | 34 ++++++++++++++++++++++ .../validity/cast_fn_ptr_invalid_caller_arg.stderr | 20 +++++++++++++ .../validity/cast_fn_ptr_invalid_caller_ret.rs | 15 ++++++++++ .../validity/cast_fn_ptr_invalid_caller_ret.stderr | 15 ++++++++++ 12 files changed, 155 insertions(+), 58 deletions(-) delete mode 100644 src/tools/miri/tests/fail/validity/cast_fn_ptr1.rs delete mode 100644 src/tools/miri/tests/fail/validity/cast_fn_ptr1.stderr delete mode 100644 src/tools/miri/tests/fail/validity/cast_fn_ptr2.rs delete mode 100644 src/tools/miri/tests/fail/validity/cast_fn_ptr2.stderr create mode 100644 src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_arg.rs create mode 100644 src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_arg.stderr create mode 100644 src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_ret.rs create mode 100644 src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_ret.stderr create mode 100644 src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_arg.rs create mode 100644 src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_arg.stderr create mode 100644 src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_ret.rs create mode 100644 src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_ret.stderr (limited to 'src/tools') diff --git a/src/tools/miri/tests/fail/validity/cast_fn_ptr1.rs b/src/tools/miri/tests/fail/validity/cast_fn_ptr1.rs deleted file mode 100644 index 6ab73569c63..00000000000 --- a/src/tools/miri/tests/fail/validity/cast_fn_ptr1.rs +++ /dev/null @@ -1,13 +0,0 @@ -//@compile-flags: -Zmiri-permissive-provenance - -fn main() { - // Cast a function pointer such that on a call, the argument gets transmuted - // from raw ptr to reference. This is ABI-compatible, so it's not the call that - // should fail, but validation should. - fn f(_x: &i32) {} - - let g: fn(*const i32) = unsafe { std::mem::transmute(f as fn(&i32)) }; - - g(0usize as *const i32) - //~^ ERROR: encountered a null reference -} diff --git a/src/tools/miri/tests/fail/validity/cast_fn_ptr1.stderr b/src/tools/miri/tests/fail/validity/cast_fn_ptr1.stderr deleted file mode 100644 index 133e4b2c16a..00000000000 --- a/src/tools/miri/tests/fail/validity/cast_fn_ptr1.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error: Undefined Behavior: constructing invalid value: encountered a null reference - --> $DIR/cast_fn_ptr1.rs:LL:CC - | -LL | g(0usize as *const i32) - | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a null reference - | - = 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 `main` at $DIR/cast_fn_ptr1.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/src/tools/miri/tests/fail/validity/cast_fn_ptr2.rs b/src/tools/miri/tests/fail/validity/cast_fn_ptr2.rs deleted file mode 100644 index 64ddb563be5..00000000000 --- a/src/tools/miri/tests/fail/validity/cast_fn_ptr2.rs +++ /dev/null @@ -1,15 +0,0 @@ -//@compile-flags: -Zmiri-permissive-provenance - -fn main() { - // Cast a function pointer such that when returning, the return value gets transmuted - // from raw ptr to reference. This is ABI-compatible, so it's not the call that - // should fail, but validation should. - fn f() -> *const i32 { - 0usize as *const i32 - } - - let g: fn() -> &'static i32 = unsafe { std::mem::transmute(f as fn() -> *const i32) }; - - let _x = g(); - //~^ ERROR: encountered a null reference -} diff --git a/src/tools/miri/tests/fail/validity/cast_fn_ptr2.stderr b/src/tools/miri/tests/fail/validity/cast_fn_ptr2.stderr deleted file mode 100644 index 21001f2b460..00000000000 --- a/src/tools/miri/tests/fail/validity/cast_fn_ptr2.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error: Undefined Behavior: constructing invalid value: encountered a null reference - --> $DIR/cast_fn_ptr2.rs:LL:CC - | -LL | let _x = g(); - | ^^^ constructing invalid value: encountered a null reference - | - = 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 `main` at $DIR/cast_fn_ptr2.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/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_arg.rs b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_arg.rs new file mode 100644 index 00000000000..6ab73569c63 --- /dev/null +++ b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_arg.rs @@ -0,0 +1,13 @@ +//@compile-flags: -Zmiri-permissive-provenance + +fn main() { + // Cast a function pointer such that on a call, the argument gets transmuted + // from raw ptr to reference. This is ABI-compatible, so it's not the call that + // should fail, but validation should. + fn f(_x: &i32) {} + + let g: fn(*const i32) = unsafe { std::mem::transmute(f as fn(&i32)) }; + + g(0usize as *const i32) + //~^ ERROR: encountered a null reference +} diff --git a/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_arg.stderr b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_arg.stderr new file mode 100644 index 00000000000..21e403b47f8 --- /dev/null +++ b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_arg.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: constructing invalid value: encountered a null reference + --> $DIR/cast_fn_ptr_invalid_callee_arg.rs:LL:CC + | +LL | g(0usize as *const i32) + | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a null reference + | + = 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 `main` at $DIR/cast_fn_ptr_invalid_callee_arg.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/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_ret.rs b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_ret.rs new file mode 100644 index 00000000000..7cdc15c6094 --- /dev/null +++ b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_ret.rs @@ -0,0 +1,28 @@ +#![allow(internal_features)] +#![feature(core_intrinsics, custom_mir)] + +use std::intrinsics::mir::*; +use std::num::NonZeroU32; +use std::ptr; + +// This function supposedly returns a NonZeroU32, but actually returns something invalid in a way that +// never materializes a bad NonZeroU32 value: we take a pointer to the return place and cast the pointer +// type. That way we never get an "invalid value constructed" error inside the function, it can +// only possibly be detected when the return value is passed to the caller. +#[custom_mir(dialect = "runtime", phase = "optimized")] +fn f() -> NonZeroU32 { + mir! { + { + let tmp = ptr::addr_of_mut!(RET); + let ptr = tmp as *mut u32; + *ptr = 0; + Return() + } + } +} + +fn main() { + let f: fn() -> u32 = unsafe { std::mem::transmute(f as fn() -> NonZeroU32) }; + // There's a NonZeroU32-to-u32 transmute happening here + f(); //~ERROR: expected something greater or equal to 1 +} diff --git a/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_ret.stderr b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_ret.stderr new file mode 100644 index 00000000000..ccfb8890939 --- /dev/null +++ b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_ret.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: constructing invalid value: encountered 0, but expected something greater or equal to 1 + --> $DIR/cast_fn_ptr_invalid_callee_ret.rs:LL:CC + | +LL | f(); + | ^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1 + | + = 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 `main` at $DIR/cast_fn_ptr_invalid_callee_ret.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/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_arg.rs b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_arg.rs new file mode 100644 index 00000000000..ee80186d4b5 --- /dev/null +++ b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_arg.rs @@ -0,0 +1,34 @@ +#![allow(internal_features)] +#![feature(core_intrinsics, custom_mir)] + +use std::intrinsics::mir::*; +use std::num::NonZeroU32; +use std::ptr; + +fn f(c: u32) { + println!("{c}"); +} + +// Call that function in a bad way, with an invalid NonZeroU32, but without +// ever materializing this as a NonZeroU32 value outside the call itself. +#[custom_mir(dialect = "runtime", phase = "optimized")] +fn call(f: fn(NonZeroU32)) { + mir! { + let _res: (); + { + let c = 0; + let tmp = ptr::addr_of!(c); + let ptr = tmp as *const NonZeroU32; + // The call site now is a NonZeroU32-to-u32 transmute. + Call(_res = f(*ptr), retblock) //~ERROR: expected something greater or equal to 1 + } + retblock = { + Return() + } + } +} + +fn main() { + let f: fn(NonZeroU32) = unsafe { std::mem::transmute(f as fn(u32)) }; + call(f); +} diff --git a/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_arg.stderr b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_arg.stderr new file mode 100644 index 00000000000..234c2804008 --- /dev/null +++ b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_arg.stderr @@ -0,0 +1,20 @@ +error: Undefined Behavior: constructing invalid value: encountered 0, but expected something greater or equal to 1 + --> $DIR/cast_fn_ptr_invalid_caller_arg.rs:LL:CC + | +LL | Call(_res = f(*ptr), retblock) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1 + | + = 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 `call` at $DIR/cast_fn_ptr_invalid_caller_arg.rs:LL:CC +note: inside `main` + --> $DIR/cast_fn_ptr_invalid_caller_arg.rs:LL:CC + | +LL | call(f); + | ^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_ret.rs b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_ret.rs new file mode 100644 index 00000000000..64ddb563be5 --- /dev/null +++ b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_ret.rs @@ -0,0 +1,15 @@ +//@compile-flags: -Zmiri-permissive-provenance + +fn main() { + // Cast a function pointer such that when returning, the return value gets transmuted + // from raw ptr to reference. This is ABI-compatible, so it's not the call that + // should fail, but validation should. + fn f() -> *const i32 { + 0usize as *const i32 + } + + let g: fn() -> &'static i32 = unsafe { std::mem::transmute(f as fn() -> *const i32) }; + + let _x = g(); + //~^ ERROR: encountered a null reference +} diff --git a/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_ret.stderr b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_ret.stderr new file mode 100644 index 00000000000..bd9866acbd4 --- /dev/null +++ b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_ret.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: constructing invalid value: encountered a null reference + --> $DIR/cast_fn_ptr_invalid_caller_ret.rs:LL:CC + | +LL | let _x = g(); + | ^^^ constructing invalid value: encountered a null reference + | + = 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 `main` at $DIR/cast_fn_ptr_invalid_caller_ret.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + -- cgit 1.4.1-3-g733a5