Skip to content

Commit 84ece53

Browse files
authored
Unrolled build for rust-lang#126154
Rollup merge of rust-lang#126154 - RalfJung:storage-live, r=compiler-errors StorageLive: refresh storage (instead of UB) when local is already live Blocked on [this FCP](rust-lang#99160 (comment)), which also contains the motivation. Fixes rust-lang#99160 Fixes rust-lang#98896 (by declaring it not-a-bug) Fixes rust-lang#119366 Fixes rust-lang/unsafe-code-guidelines#129
2 parents 5978f35 + 408c8eb commit 84ece53

File tree

7 files changed

+71
-11
lines changed

7 files changed

+71
-11
lines changed

compiler/rustc_const_eval/messages.ftl

-2
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,6 @@ const_eval_division_by_zero =
7373
dividing by zero
7474
const_eval_division_overflow =
7575
overflow in signed division (dividing MIN by -1)
76-
const_eval_double_storage_live =
77-
StorageLive on a local that was already live
7876
7977
const_eval_dyn_call_not_a_method =
8078
`dyn` call trying to call something that is not a method

compiler/rustc_const_eval/src/interpret/eval_context.rs

+3-5
Original file line numberDiff line numberDiff line change
@@ -1100,11 +1100,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
11001100
Operand::Immediate(Immediate::Uninit)
11011101
});
11021102

1103-
// StorageLive expects the local to be dead, and marks it live.
1103+
// If the local is already live, deallocate its old memory.
11041104
let old = mem::replace(&mut self.frame_mut().locals[local].value, local_val);
1105-
if !matches!(old, LocalValue::Dead) {
1106-
throw_ub_custom!(fluent::const_eval_double_storage_live);
1107-
}
1105+
self.deallocate_local(old)?;
11081106
Ok(())
11091107
}
11101108

@@ -1118,7 +1116,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
11181116
assert!(local != mir::RETURN_PLACE, "Cannot make return place dead");
11191117
trace!("{:?} is now dead", local);
11201118

1121-
// It is entirely okay for this local to be already dead (at least that's how we currently generate MIR)
1119+
// If the local is already dead, this is a NOP.
11221120
let old = mem::replace(&mut self.frame_mut().locals[local].value, LocalValue::Dead);
11231121
self.deallocate_local(old)?;
11241122
Ok(())

compiler/rustc_middle/src/mir/syntax.rs

+7-4
Original file line numberDiff line numberDiff line change
@@ -361,16 +361,19 @@ pub enum StatementKind<'tcx> {
361361
/// At any point during the execution of a function, each local is either allocated or
362362
/// unallocated. Except as noted below, all locals except function parameters are initially
363363
/// unallocated. `StorageLive` statements cause memory to be allocated for the local while
364-
/// `StorageDead` statements cause the memory to be freed. Using a local in any way (not only
365-
/// reading/writing from it) while it is unallocated is UB.
364+
/// `StorageDead` statements cause the memory to be freed. In other words,
365+
/// `StorageLive`/`StorageDead` act like the heap operations `allocate`/`deallocate`, but for
366+
/// stack-allocated local variables. Using a local in any way (not only reading/writing from it)
367+
/// while it is unallocated is UB.
366368
///
367369
/// Some locals have no `StorageLive` or `StorageDead` statements within the entire MIR body.
368370
/// These locals are implicitly allocated for the full duration of the function. There is a
369371
/// convenience method at `rustc_mir_dataflow::storage::always_storage_live_locals` for
370372
/// computing these locals.
371373
///
372-
/// If the local is already allocated, calling `StorageLive` again is UB. However, for an
373-
/// unallocated local an additional `StorageDead` all is simply a nop.
374+
/// If the local is already allocated, calling `StorageLive` again will implicitly free the
375+
/// local and then allocate fresh uninitilized memory. If a local is already deallocated,
376+
/// calling `StorageDead` again is a NOP.
374377
StorageLive(Local),
375378

376379
/// See `StorageLive` above.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#![feature(core_intrinsics, custom_mir)]
2+
use std::intrinsics::mir::*;
3+
4+
#[custom_mir(dialect = "runtime")]
5+
fn main() {
6+
mir! {
7+
let val: i32;
8+
{
9+
val = 42; //~ERROR: accessing a dead local variable
10+
StorageLive(val); // too late... (but needs to be here to make `val` not implicitly live)
11+
Return()
12+
}
13+
}
14+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
error: Undefined Behavior: accessing a dead local variable
2+
--> $DIR/storage-live-dead-var.rs:LL:CC
3+
|
4+
LL | val = 42;
5+
| ^^^^^^^^ accessing a dead local variable
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/storage-live-dead-var.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+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#![feature(core_intrinsics, custom_mir)]
2+
use std::intrinsics::mir::*;
3+
4+
#[custom_mir(dialect = "runtime")]
5+
fn main() {
6+
mir! {
7+
let val: i32;
8+
let _val2: i32;
9+
{
10+
StorageLive(val);
11+
val = 42;
12+
StorageLive(val); // reset val to `uninit`
13+
_val2 = val; //~ERROR: uninitialized
14+
Return()
15+
}
16+
}
17+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
error: Undefined Behavior: constructing invalid value: encountered uninitialized memory, but expected an integer
2+
--> $DIR/storage-live-resets-var.rs:LL:CC
3+
|
4+
LL | _val2 = val;
5+
| ^^^^^^^^^^^ constructing invalid value: encountered uninitialized memory, but expected an integer
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/storage-live-resets-var.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)