Skip to content

Commit 3d24970

Browse files
committed
Auto merge of rust-lang#115608 - RalfJung:fn-arg-validity, r=oli-obk
miri: catch function calls where the argument is caller-invalid / the return value callee-invalid When doing a type-changing copy, we must validate the data both at the old and new type. Fixes rust-lang/miri#3017
2 parents 69ec430 + 73d8dcb commit 3d24970

9 files changed

+108
-4
lines changed

compiler/rustc_const_eval/src/interpret/place.rs

+7
Original file line numberDiff line numberDiff line change
@@ -796,6 +796,13 @@ where
796796
dest: &impl Writeable<'tcx, M::Provenance>,
797797
allow_transmute: bool,
798798
) -> InterpResult<'tcx> {
799+
// Generally for transmutation, data must be valid both at the old and new type.
800+
// But if the types are the same, the 2nd validation below suffices.
801+
if src.layout().ty != dest.layout().ty && M::enforce_validity(self, src.layout()) {
802+
self.validate_operand(&src.to_op(self)?)?;
803+
}
804+
805+
// Do the actual copy.
799806
self.copy_op_no_validate(src, dest, allow_transmute)?;
800807

801808
if M::enforce_validity(self, dest.layout()) {

src/tools/miri/tests/fail/validity/cast_fn_ptr1.stderr src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_arg.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
error: Undefined Behavior: constructing invalid value: encountered a null reference
2-
--> $DIR/cast_fn_ptr1.rs:LL:CC
2+
--> $DIR/cast_fn_ptr_invalid_callee_arg.rs:LL:CC
33
|
44
LL | g(0usize as *const i32)
55
| ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a null reference
66
|
77
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
88
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
99
= note: BACKTRACE:
10-
= note: inside `main` at $DIR/cast_fn_ptr1.rs:LL:CC
10+
= note: inside `main` at $DIR/cast_fn_ptr_invalid_callee_arg.rs:LL:CC
1111

1212
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
1313

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
#![allow(internal_features)]
2+
#![feature(core_intrinsics, custom_mir)]
3+
4+
use std::intrinsics::mir::*;
5+
use std::num::NonZeroU32;
6+
use std::ptr;
7+
8+
// This function supposedly returns a NonZeroU32, but actually returns something invalid in a way that
9+
// never materializes a bad NonZeroU32 value: we take a pointer to the return place and cast the pointer
10+
// type. That way we never get an "invalid value constructed" error inside the function, it can
11+
// only possibly be detected when the return value is passed to the caller.
12+
#[custom_mir(dialect = "runtime", phase = "optimized")]
13+
fn f() -> NonZeroU32 {
14+
mir! {
15+
{
16+
let tmp = ptr::addr_of_mut!(RET);
17+
let ptr = tmp as *mut u32;
18+
*ptr = 0;
19+
Return()
20+
}
21+
}
22+
}
23+
24+
fn main() {
25+
let f: fn() -> u32 = unsafe { std::mem::transmute(f as fn() -> NonZeroU32) };
26+
// There's a NonZeroU32-to-u32 transmute happening here
27+
f(); //~ERROR: expected something greater or equal to 1
28+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
error: Undefined Behavior: constructing invalid value: encountered 0, but expected something greater or equal to 1
2+
--> $DIR/cast_fn_ptr_invalid_callee_ret.rs:LL:CC
3+
|
4+
LL | f();
5+
| ^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1
6+
|
7+
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
8+
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
9+
= note: BACKTRACE:
10+
= note: inside `main` at $DIR/cast_fn_ptr_invalid_callee_ret.rs:LL:CC
11+
12+
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
13+
14+
error: aborting due to previous error
15+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
#![allow(internal_features)]
2+
#![feature(core_intrinsics, custom_mir)]
3+
4+
use std::intrinsics::mir::*;
5+
use std::num::NonZeroU32;
6+
use std::ptr;
7+
8+
fn f(c: u32) {
9+
println!("{c}");
10+
}
11+
12+
// Call that function in a bad way, with an invalid NonZeroU32, but without
13+
// ever materializing this as a NonZeroU32 value outside the call itself.
14+
#[custom_mir(dialect = "runtime", phase = "optimized")]
15+
fn call(f: fn(NonZeroU32)) {
16+
mir! {
17+
let _res: ();
18+
{
19+
let c = 0;
20+
let tmp = ptr::addr_of!(c);
21+
let ptr = tmp as *const NonZeroU32;
22+
// The call site now is a NonZeroU32-to-u32 transmute.
23+
Call(_res = f(*ptr), retblock) //~ERROR: expected something greater or equal to 1
24+
}
25+
retblock = {
26+
Return()
27+
}
28+
}
29+
}
30+
31+
fn main() {
32+
let f: fn(NonZeroU32) = unsafe { std::mem::transmute(f as fn(u32)) };
33+
call(f);
34+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
error: Undefined Behavior: constructing invalid value: encountered 0, but expected something greater or equal to 1
2+
--> $DIR/cast_fn_ptr_invalid_caller_arg.rs:LL:CC
3+
|
4+
LL | Call(_res = f(*ptr), retblock)
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1
6+
|
7+
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
8+
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
9+
= note: BACKTRACE:
10+
= note: inside `call` at $DIR/cast_fn_ptr_invalid_caller_arg.rs:LL:CC
11+
note: inside `main`
12+
--> $DIR/cast_fn_ptr_invalid_caller_arg.rs:LL:CC
13+
|
14+
LL | call(f);
15+
| ^^^^^^^
16+
17+
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
18+
19+
error: aborting due to previous error
20+

src/tools/miri/tests/fail/validity/cast_fn_ptr2.stderr src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_ret.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
error: Undefined Behavior: constructing invalid value: encountered a null reference
2-
--> $DIR/cast_fn_ptr2.rs:LL:CC
2+
--> $DIR/cast_fn_ptr_invalid_caller_ret.rs:LL:CC
33
|
44
LL | let _x = g();
55
| ^^^ constructing invalid value: encountered a null reference
66
|
77
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
88
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
99
= note: BACKTRACE:
10-
= note: inside `main` at $DIR/cast_fn_ptr2.rs:LL:CC
10+
= note: inside `main` at $DIR/cast_fn_ptr_invalid_caller_ret.rs:LL:CC
1111

1212
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
1313

0 commit comments

Comments
 (0)