1
Fork 0

Invalid dereferences for all non-local mutations

This commit is contained in:
dianqk 2025-03-25 22:21:18 +08:00
parent 4e05d858ad
commit 7d44887374
No known key found for this signature in database
8 changed files with 75 additions and 36 deletions

View file

@ -1728,12 +1728,18 @@ impl<'tcx> MutVisitor<'tcx> for VnState<'_, 'tcx> {
self.tcx self.tcx
} }
fn visit_place(&mut self, place: &mut Place<'tcx>, _: PlaceContext, location: Location) { fn visit_place(&mut self, place: &mut Place<'tcx>, context: PlaceContext, location: Location) {
self.simplify_place_projection(place, location); self.simplify_place_projection(place, location);
if context.is_mutating_use() && !place.projection.is_empty() {
// Non-local mutation maybe invalidate deref.
self.invalidate_derefs();
}
self.super_place(place, context, location);
} }
fn visit_operand(&mut self, operand: &mut Operand<'tcx>, location: Location) { fn visit_operand(&mut self, operand: &mut Operand<'tcx>, location: Location) {
self.simplify_operand(operand, location); self.simplify_operand(operand, location);
self.super_operand(operand, location);
} }
fn visit_statement(&mut self, stmt: &mut Statement<'tcx>, location: Location) { fn visit_statement(&mut self, stmt: &mut Statement<'tcx>, location: Location) {
@ -1751,22 +1757,18 @@ impl<'tcx> MutVisitor<'tcx> for VnState<'_, 'tcx> {
self.assign(local, value); self.assign(local, value);
Some(value) Some(value)
} else { } else {
// Non-local assignments maybe invalidate deref.
self.invalidate_derefs();
value value
}; };
let Some(value) = value else { return }; if let Some(value) = value {
if let Some(const_) = self.try_as_constant(value) {
if let Some(const_) = self.try_as_constant(value) { *rvalue = Rvalue::Use(Operand::Constant(Box::new(const_)));
*rvalue = Rvalue::Use(Operand::Constant(Box::new(const_))); } else if let Some(local) = self.try_as_local(value, location)
} else if let Some(local) = self.try_as_local(value, location) && *rvalue != Rvalue::Use(Operand::Move(local.into()))
&& *rvalue != Rvalue::Use(Operand::Move(local.into())) {
{ *rvalue = Rvalue::Use(Operand::Copy(local.into()));
*rvalue = Rvalue::Use(Operand::Copy(local.into())); self.reused_locals.insert(local);
self.reused_locals.insert(local); }
} }
return;
} }
self.super_statement(stmt, location); self.super_statement(stmt, location);
} }

View file

@ -10,8 +10,9 @@
StorageLive(_1); StorageLive(_1);
StorageLive(_2); StorageLive(_2);
- _2 = (); - _2 = ();
- _1 = Union32 { value: move _2 };
+ _2 = const (); + _2 = const ();
_1 = Union32 { value: move _2 }; + _1 = Union32 { value: const () };
StorageDead(_2); StorageDead(_2);
_0 = move _1 as u32 (Transmute); _0 = move _1 as u32 (Transmute);
StorageDead(_1); StorageDead(_1);

View file

@ -10,8 +10,9 @@
StorageLive(_1); StorageLive(_1);
StorageLive(_2); StorageLive(_2);
- _2 = (); - _2 = ();
- _1 = Union32 { value: move _2 };
+ _2 = const (); + _2 = const ();
_1 = Union32 { value: move _2 }; + _1 = Union32 { value: const () };
StorageDead(_2); StorageDead(_2);
_0 = move _1 as u32 (Transmute); _0 = move _1 as u32 (Transmute);
StorageDead(_1); StorageDead(_1);

View file

@ -5,11 +5,10 @@
let mut _0: (); let mut _0: ();
let _1: main::Un; let _1: main::Un;
let mut _2: u32; let mut _2: u32;
let mut _3: u32;
scope 1 { scope 1 {
debug un => _1; debug un => _1;
scope 3 (inlined std::mem::drop::<u32>) { scope 3 (inlined std::mem::drop::<u32>) {
debug _x => _3; debug _x => _2;
} }
} }
scope 2 (inlined val) { scope 2 (inlined val) {
@ -17,13 +16,10 @@
bb0: { bb0: {
StorageLive(_1); StorageLive(_1);
StorageLive(_2);
nop;
_1 = Un { us: const 1_u32 }; _1 = Un { us: const 1_u32 };
StorageLive(_2);
_2 = copy (_1.0: u32);
StorageDead(_2); StorageDead(_2);
StorageLive(_3);
_3 = copy (_1.0: u32);
StorageDead(_3);
StorageDead(_1); StorageDead(_1);
return; return;
} }

View file

@ -5,11 +5,10 @@
let mut _0: (); let mut _0: ();
let _1: main::Un; let _1: main::Un;
let mut _2: u32; let mut _2: u32;
let mut _3: u32;
scope 1 { scope 1 {
debug un => _1; debug un => _1;
scope 3 (inlined std::mem::drop::<u32>) { scope 3 (inlined std::mem::drop::<u32>) {
debug _x => _3; debug _x => _2;
} }
} }
scope 2 (inlined val) { scope 2 (inlined val) {
@ -17,13 +16,10 @@
bb0: { bb0: {
StorageLive(_1); StorageLive(_1);
StorageLive(_2);
nop;
_1 = Un { us: const 1_u32 }; _1 = Un { us: const 1_u32 };
StorageLive(_2);
_2 = copy (_1.0: u32);
StorageDead(_2); StorageDead(_2);
StorageLive(_3);
_3 = copy (_1.0: u32);
StorageDead(_3);
StorageDead(_1); StorageDead(_1);
return; return;
} }

View file

@ -20,7 +20,7 @@
StorageLive(_2); StorageLive(_2);
StorageLive(_3); StorageLive(_3);
_3 = &(*_1); _3 = &(*_1);
_2 = get(move _3) -> [return: bb1, unwind unreachable]; _2 = get::<Option<i32>>(move _3) -> [return: bb1, unwind unreachable];
} }
bb1: { bb1: {

View file

@ -9,15 +9,16 @@
#![crate_type = "lib"] #![crate_type = "lib"]
//@ test-mir-pass: GVN //@ test-mir-pass: GVN
#![allow(internal_features)] #![allow(internal_features)]
#![feature(rustc_attrs, core_intrinsics)] #![feature(core_intrinsics, custom_mir, rustc_attrs)]
use std::intrinsics::mir::*;
// EMIT_MIR simplify_aggregate_to_copy_miscompile.foo.GVN.diff // EMIT_MIR simplify_aggregate_to_copy_miscompile.foo.GVN.diff
#[no_mangle]
fn foo(v: &mut Option<i32>) -> Option<i32> { fn foo(v: &mut Option<i32>) -> Option<i32> {
// CHECK-LABEL: fn foo( // CHECK-LABEL: fn foo(
// CHECK-SAME: [[v:_.*]]: &mut Option<i32> // CHECK-SAME: [[v:_.*]]: &mut Option<i32>
// CHECK: [[v_alias_1:_.*]] = &(*_1) // CHECK: [[v_alias_1:_.*]] = &(*_1)
// CHECK-NEXT: [[v_alias_2:_.*]] = get(move [[v_alias_1]]) // CHECK-NEXT: [[v_alias_2:_.*]] = get::<Option<i32>>(move [[v_alias_1]])
// CHECK: (*[[v]]) = const Option::<i32>::None; // CHECK: (*[[v]]) = const Option::<i32>::None;
// CHECK-NOT: _0 = copy (*[[v_alias_2]]) // CHECK-NOT: _0 = copy (*[[v_alias_2]])
// CHECK: _0 = Option::<i32>::Some // CHECK: _0 = Option::<i32>::Some
@ -30,9 +31,31 @@ fn foo(v: &mut Option<i32>) -> Option<i32> {
} }
} }
#[no_mangle] pub enum Value {
V0(i32),
V1(i32),
}
// EMIT_MIR simplify_aggregate_to_copy_miscompile.set_discriminant.GVN.diff
#[custom_mir(dialect = "runtime", phase = "initial")]
fn set_discriminant(v: &mut Value) -> Value {
// CHECK-LABEL: fn set_discriminant(
mir! {
let v_: &Value;
{
Call(v_ = get(v), ReturnTo(ret), UnwindUnreachable())
}
ret = {
let col: i32 = Field(Variant(*v_, 0), 0);
SetDiscriminant(*v, 1);
RET = Value::V0(col);
Return()
}
}
}
#[inline(never)] #[inline(never)]
#[rustc_nounwind] #[rustc_nounwind]
fn get(v: &Option<i32>) -> &Option<i32> { fn get<T>(v: &T) -> &T {
v v
} }

View file

@ -0,0 +1,20 @@
- // MIR for `set_discriminant` before GVN
+ // MIR for `set_discriminant` after GVN
fn set_discriminant(_1: &mut Value) -> Value {
let mut _0: Value;
let mut _2: &Value;
let mut _3: i32;
bb0: {
_2 = get::<Value>(copy _1) -> [return: bb1, unwind unreachable];
}
bb1: {
_3 = copy (((*_2) as variant#0).0: i32);
discriminant((*_1)) = 1;
_0 = Value::V0(copy _3);
return;
}
}