Skip to content

Commit 45b2ea6

Browse files
committed
Add miri tests for new closure capture behavior
1 parent a106748 commit 45b2ea6

File tree

6 files changed

+137
-0
lines changed

6 files changed

+137
-0
lines changed
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// This test serves to document the change in semantics introduced by #138961.
2+
//
3+
// A corollary of partial-pattern.rs: while the tuple access showcases the
4+
// utility, it is actually the dereference performed by the pattern that
5+
// matters.
6+
7+
fn main() {
8+
// the inner reference is dangling
9+
let x: &&u32 = unsafe {
10+
let x: u32 = 42;
11+
&&* &raw const x
12+
};
13+
14+
let _ = || { //~ ERROR: encountered a dangling reference
15+
match x {
16+
&&_y => {},
17+
}
18+
};
19+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
error: Undefined Behavior: constructing invalid value: encountered a dangling reference (use-after-free)
2+
--> tests/fail/upvars/deref-in-pattern.rs:LL:CC
3+
|
4+
LL | let _ = || {
5+
| _____________^
6+
LL | | match x {
7+
LL | | &&_y => {},
8+
LL | | }
9+
LL | | };
10+
| |_____^ constructing invalid value: encountered a dangling reference (use-after-free)
11+
|
12+
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
13+
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
14+
= note: BACKTRACE:
15+
= note: inside `main` at tests/fail/upvars/deref-in-pattern.rs:LL:CC
16+
17+
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
18+
19+
error: aborting due to 1 previous error
20+
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// This test serves to document the change in semantics introduced by #138961.
2+
//
3+
// Previously, the closure would capture the entirety of x, and access *(*x).0
4+
// when called. Now, the closure only captures *(*x).0, which means that
5+
// a &*(*x).0 reborrow happens when the closure is constructed.
6+
//
7+
// Hence, if one of the references is dangling, this constitutes newly introduced UB
8+
// in the case where the closure doesn't get called. This isn't a big deal,
9+
// because why opsem only now considers this to be UB, the unsafe code
10+
// guidelines have long recommended against any handling of dangling references.
11+
12+
fn main() {
13+
// the inner references are dangling
14+
let x: &(&u32, &u32) = unsafe {
15+
let a = 21;
16+
let b = 37;
17+
let ra = &* &raw const a;
18+
let rb = &* &raw const b;
19+
&(ra, rb)
20+
};
21+
22+
let _ = || { //~ ERROR: encountered a dangling reference
23+
match x {
24+
(&_y, _) => {},
25+
}
26+
};
27+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
error: Undefined Behavior: constructing invalid value: encountered a dangling reference (use-after-free)
2+
--> tests/fail/upvars/partial-pattern.rs:LL:CC
3+
|
4+
LL | let _ = || {
5+
| _____________^
6+
LL | | match x {
7+
LL | | (&_y, _) => {},
8+
LL | | }
9+
LL | | };
10+
| |_____^ constructing invalid value: encountered a dangling reference (use-after-free)
11+
|
12+
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
13+
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
14+
= note: BACKTRACE:
15+
= note: inside `main` at tests/fail/upvars/partial-pattern.rs:LL:CC
16+
17+
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
18+
19+
error: aborting due to 1 previous error
20+
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// Motivated by #138961, this shows how invalid discriminants interact with
2+
// closure captures.
3+
#![feature(never_type)]
4+
5+
#[repr(C)]
6+
#[allow(dead_code)]
7+
enum E {
8+
V0, // discriminant: 0
9+
V1, // 1
10+
V2(!), // 2
11+
}
12+
13+
fn main() {
14+
assert_eq!(std::mem::size_of::<E>(), 4);
15+
16+
let val = 2u32;
17+
let ptr = (&raw const val).cast::<E>();
18+
let r = unsafe { &*ptr };
19+
let f = || {
20+
// After #138961, constructing the closure performs a reborrow of r.
21+
// Nevertheless, the discriminant is only actually inspected when the closure
22+
// is called.
23+
match r { //~ ERROR: read discriminant of an uninhabited enum variant
24+
E::V0 => {}
25+
E::V1 => {}
26+
E::V2(_) => {}
27+
}
28+
};
29+
30+
f();
31+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
error: Undefined Behavior: read discriminant of an uninhabited enum variant
2+
--> tests/fail/upvars/uninhabited-variant.rs:LL:CC
3+
|
4+
LL | match r {
5+
| ^ read discriminant of an uninhabited enum variant
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 closure at tests/fail/upvars/uninhabited-variant.rs:LL:CC
11+
note: inside `main`
12+
--> tests/fail/upvars/uninhabited-variant.rs:LL:CC
13+
|
14+
LL | 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 1 previous error
20+

0 commit comments

Comments
 (0)