Skip to content

Commit a0d817c

Browse files
committed
interpret: fix overlapping aggregate initialization
1 parent 7ad23f4 commit a0d817c

File tree

5 files changed

+66
-4
lines changed

5 files changed

+66
-4
lines changed

compiler/rustc_const_eval/src/interpret/place.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -858,7 +858,7 @@ where
858858
/// Also, if you use this you are responsible for validating that things get copied at the
859859
/// right type.
860860
#[instrument(skip(self), level = "trace")]
861-
fn copy_op_no_validate(
861+
pub(super) fn copy_op_no_validate(
862862
&mut self,
863863
src: &impl Projectable<'tcx, M::Provenance>,
864864
dest: &impl Writeable<'tcx, M::Provenance>,

compiler/rustc_const_eval/src/interpret/step.rs

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -310,7 +310,6 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
310310
operands: &IndexSlice<FieldIdx, mir::Operand<'tcx>>,
311311
dest: &PlaceTy<'tcx, M::Provenance>,
312312
) -> InterpResult<'tcx> {
313-
self.write_uninit(dest)?; // make sure all the padding ends up as uninit
314313
let (variant_index, variant_dest, active_field_index) = match *kind {
315314
mir::AggregateKind::Adt(_, variant_index, _, _, active_field_index) => {
316315
let variant_dest = self.project_downcast(dest, variant_index)?;
@@ -346,9 +345,20 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
346345
let field_index = active_field_index.unwrap_or(field_index);
347346
let field_dest = self.project_field(&variant_dest, field_index)?;
348347
let op = self.eval_operand(operand, Some(field_dest.layout))?;
349-
self.copy_op(&op, &field_dest)?;
348+
// We validate manually below so we don't have to do it here.
349+
self.copy_op_no_validate(&op, &field_dest, /*allow_transmute*/ false)?;
350350
}
351-
self.write_discriminant(variant_index, dest)
351+
self.write_discriminant(variant_index, dest)?;
352+
// Validate that the entire thing is valid, and reset padding that might be in between the
353+
// fields.
354+
if M::enforce_validity(self, dest.layout()) {
355+
self.validate_operand(
356+
dest,
357+
M::enforce_validity_recursively(self, dest.layout()),
358+
/*reset_provenance_and_padding*/ true,
359+
)?;
360+
}
361+
interp_ok(())
352362
}
353363

354364
/// Repeats `operand` into the destination. `dest` must have array type, and that type
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
//! This is like `pass/overlapping_assignment_aggregate_scalar.rs` but with a non-scalar
2+
//! type, and that makes it definite UB.
3+
#![feature(custom_mir, core_intrinsics)]
4+
#![allow(internal_features)]
5+
6+
use std::intrinsics::mir::*;
7+
8+
#[custom_mir(dialect = "runtime")]
9+
fn main() {
10+
mir! {
11+
let _1: ([u8; 1],);
12+
{
13+
_1.0 = [0_u8; 1];
14+
_1 = (_1.0, ); //~ERROR: overlapping ranges
15+
Return()
16+
}
17+
}
18+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
error: Undefined Behavior: `copy_nonoverlapping` called on overlapping ranges
2+
--> tests/fail/overlapping_assignment_aggregate.rs:LL:CC
3+
|
4+
LL | _1 = (_1.0, );
5+
| ^^^^^^^^^^^^^ Undefined Behavior occurred here
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 tests/fail/overlapping_assignment_aggregate.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: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#![feature(custom_mir, core_intrinsics)]
2+
#![allow(internal_features)]
3+
4+
use std::intrinsics::mir::*;
5+
6+
#[custom_mir(dialect = "runtime")]
7+
fn main() {
8+
mir! {
9+
let _1: (u8,);
10+
{
11+
_1.0 = 0_u8;
12+
// This is a scalar type, so overlap is (for now) not UB.
13+
// However, we used to treat such overlapping assignments incorrectly
14+
// (see <https://github.com/rust-lang/rust/issues/146383#issuecomment-3273224645>).
15+
_1 = (_1.0, );
16+
Return()
17+
}
18+
}
19+
}

0 commit comments

Comments
 (0)