Skip to content

Commit fd02b78

Browse files
committed
interpret: reset provenance on typed copies
1 parent 58be2fd commit fd02b78

15 files changed

+212
-3
lines changed

src/concurrency/data_race.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -637,7 +637,7 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> {
637637
// The program didn't actually do a read, so suppress the memory access hooks.
638638
// This is also a very special exception where we just ignore an error -- if this read
639639
// was UB e.g. because the memory is uninitialized, we don't want to know!
640-
let old_val = this.run_for_validation(|| this.read_scalar(dest)).ok();
640+
let old_val = this.run_for_validation(|this| this.read_scalar(dest)).ok();
641641
this.allow_data_races_mut(move |this| this.write_scalar(val, dest))?;
642642
this.validate_atomic_store(dest, atomic)?;
643643
this.buffered_atomic_write(val, dest, atomic, old_val)

src/intrinsics/mod.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -152,8 +152,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
152152
// ```
153153
// Would not be considered UB, or the other way around (`is_val_statically_known(0)`).
154154
"is_val_statically_known" => {
155-
let [arg] = check_arg_count(args)?;
156-
this.validate_operand(arg, /*recursive*/ false)?;
155+
let [_arg] = check_arg_count(args)?;
156+
// FIXME: should we check for validity here? It's tricky because we do not have a
157+
// place. Codegen does not seem to set any attributes like `noundef` for intrinsic
158+
// calls, so we don't *have* to do anything.
157159
let branch: bool = this.machine.rng.get_mut().gen();
158160
this.write_scalar(Scalar::from_bool(branch), dest)?;
159161
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
use std::mem;
2+
3+
// Doing a copy at integer type should lose provenance.
4+
// This tests the unoptimized base case.
5+
fn main() {
6+
let ptrs = [(&42, true)];
7+
let ints: [(usize, bool); 1] = unsafe { mem::transmute(ptrs) };
8+
let ptr = (&raw const ints[0].0).cast::<&i32>();
9+
let _val = unsafe { *ptr.read() }; //~ERROR: dangling
10+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
error: Undefined Behavior: constructing invalid value: encountered a dangling reference ($HEX[noalloc] has no provenance)
2+
--> $DIR/int_copy_looses_provenance0.rs:LL:CC
3+
|
4+
LL | let _val = unsafe { *ptr.read() };
5+
| ^^^^^^^^^^ constructing invalid value: encountered a dangling reference ($HEX[noalloc] has no provenance)
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/int_copy_looses_provenance0.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 1 previous error
15+
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
use std::mem;
2+
3+
// Doing a copy at integer type should lose provenance.
4+
// This tests the optimized-array case of integer copies.
5+
fn main() {
6+
let ptrs = [&42];
7+
let ints: [usize; 1] = unsafe { mem::transmute(ptrs) };
8+
let ptr = (&raw const ints[0]).cast::<&i32>();
9+
let _val = unsafe { *ptr.read() }; //~ERROR: dangling
10+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
error: Undefined Behavior: constructing invalid value: encountered a dangling reference ($HEX[noalloc] has no provenance)
2+
--> $DIR/int_copy_looses_provenance1.rs:LL:CC
3+
|
4+
LL | let _val = unsafe { *ptr.read() };
5+
| ^^^^^^^^^^ constructing invalid value: encountered a dangling reference ($HEX[noalloc] has no provenance)
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/int_copy_looses_provenance1.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 1 previous error
15+
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
use std::mem;
2+
3+
// Doing a copy at integer type should lose provenance.
4+
// This tests the case where provenacne is hiding in the metadata of a pointer.
5+
fn main() {
6+
let ptrs = [(&42, &42)];
7+
// Typed copy at wide pointer type (with integer-typed metadata).
8+
let ints: [*const [usize]; 1] = unsafe { mem::transmute(ptrs) };
9+
// Get a pointer to the metadata field.
10+
let ptr = (&raw const ints[0]).wrapping_byte_add(mem::size_of::<*const ()>()).cast::<&i32>();
11+
let _val = unsafe { *ptr.read() }; //~ERROR: dangling
12+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
error: Undefined Behavior: constructing invalid value: encountered a dangling reference ($HEX[noalloc] has no provenance)
2+
--> $DIR/int_copy_looses_provenance2.rs:LL:CC
3+
|
4+
LL | let _val = unsafe { *ptr.read() };
5+
| ^^^^^^^^^^ constructing invalid value: encountered a dangling reference ($HEX[noalloc] has no provenance)
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/int_copy_looses_provenance2.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 1 previous error
15+
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#![feature(strict_provenance)]
2+
use std::mem;
3+
4+
#[repr(C, usize)]
5+
#[allow(unused)]
6+
enum E {
7+
Var1(usize),
8+
Var2(usize),
9+
}
10+
11+
// Doing a copy at integer type should lose provenance.
12+
// This tests the case where provenacne is hiding in the discriminant of an enum.
13+
fn main() {
14+
assert_eq!(mem::size_of::<E>(), 2*mem::size_of::<usize>());
15+
16+
// We want to store provenance in the enum discriminant, but the value still needs to
17+
// be valid atfor the type. So we split provenance and data.
18+
let ptr = &42;
19+
let ptr = ptr as *const i32;
20+
let ptrs = [(ptr.with_addr(0), ptr)];
21+
// Typed copy at the enum type.
22+
let ints: [E; 1] = unsafe { mem::transmute(ptrs) };
23+
// Read the discriminant.
24+
let discr = unsafe { (&raw const ints[0]).cast::<*const i32>().read() };
25+
// Take the provenance from there, together with the original address.
26+
let ptr = discr.with_addr(ptr.addr());
27+
// There should be no provenance is `discr`, so this should be UB.
28+
let _val = unsafe { *ptr }; //~ERROR: dangling
29+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
error: Undefined Behavior: memory access failed: expected a pointer to 4 bytes of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance)
2+
--> $DIR/int_copy_looses_provenance3.rs:LL:CC
3+
|
4+
LL | let _val = unsafe { *ptr };
5+
| ^^^^ memory access failed: expected a pointer to 4 bytes of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance)
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/int_copy_looses_provenance3.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 1 previous error
15+

0 commit comments

Comments
 (0)