Skip to content

Commit f1f7560

Browse files
authored
Rollup merge of #105317 - RalfJung:retag-rework, r=oli-obk
make retagging work even with 'unstable' places This is based on top of #105301. Only the last two commits are new. While investigating rust-lang/unsafe-code-guidelines#381 I realized that we would have caught this issue much earlier if the add_retag pass wouldn't bail out on assignments of the form `*ptr = ...`. So this PR changes our retag strategy: - When a new reference is created via `Rvalue::Ref` (or a raw ptr via `Rvalue::AddressOf`), we do the retagging as part of just executing that address-taking operation. - For everything else, we still insert retags -- these retags basically serve to ensure that references stored in local variables (and their fields) are always freshly tagged, so skipping this for assignments like `*ptr = ...` is less egregious. r? ```@oli-obk```
2 parents e826a9a + 34c58e8 commit f1f7560

17 files changed

+302
-275
lines changed

compiler/rustc_const_eval/src/interpret/machine.rs

+14-2
Original file line numberDiff line numberDiff line change
@@ -373,9 +373,21 @@ pub trait Machine<'mir, 'tcx>: Sized {
373373
Ok(())
374374
}
375375

376-
/// Executes a retagging operation.
376+
/// Executes a retagging operation for a single pointer.
377+
/// Returns the possibly adjusted pointer.
377378
#[inline]
378-
fn retag(
379+
fn retag_ptr_value(
380+
_ecx: &mut InterpCx<'mir, 'tcx, Self>,
381+
_kind: mir::RetagKind,
382+
val: &ImmTy<'tcx, Self::Provenance>,
383+
) -> InterpResult<'tcx, ImmTy<'tcx, Self::Provenance>> {
384+
Ok(val.clone())
385+
}
386+
387+
/// Executes a retagging operation on a compound value.
388+
/// Replaces all pointers stored in the given place.
389+
#[inline]
390+
fn retag_place_contents(
379391
_ecx: &mut InterpCx<'mir, 'tcx, Self>,
380392
_kind: mir::RetagKind,
381393
_place: &PlaceTy<'tcx, Self::Provenance>,

compiler/rustc_const_eval/src/interpret/step.rs

+35-4
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use rustc_middle::mir;
88
use rustc_middle::mir::interpret::{InterpResult, Scalar};
99
use rustc_middle::ty::layout::LayoutOf;
1010

11-
use super::{InterpCx, Machine};
11+
use super::{ImmTy, InterpCx, Machine};
1212

1313
/// Classify whether an operator is "left-homogeneous", i.e., the LHS has the
1414
/// same type as the result.
@@ -108,7 +108,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
108108
// Stacked Borrows.
109109
Retag(kind, place) => {
110110
let dest = self.eval_place(**place)?;
111-
M::retag(self, *kind, &dest)?;
111+
M::retag_place_contents(self, *kind, &dest)?;
112112
}
113113

114114
Intrinsic(box ref intrinsic) => self.emulate_nondiverging_intrinsic(intrinsic)?,
@@ -247,10 +247,41 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
247247
self.write_scalar(Scalar::from_machine_usize(len, self), &dest)?;
248248
}
249249

250-
AddressOf(_, place) | Ref(_, _, place) => {
250+
Ref(_, borrow_kind, place) => {
251251
let src = self.eval_place(place)?;
252252
let place = self.force_allocation(&src)?;
253-
self.write_immediate(place.to_ref(self), &dest)?;
253+
let val = ImmTy::from_immediate(place.to_ref(self), dest.layout);
254+
// A fresh reference was created, make sure it gets retagged.
255+
let val = M::retag_ptr_value(
256+
self,
257+
if borrow_kind.allows_two_phase_borrow() {
258+
mir::RetagKind::TwoPhase
259+
} else {
260+
mir::RetagKind::Default
261+
},
262+
&val,
263+
)?;
264+
self.write_immediate(*val, &dest)?;
265+
}
266+
267+
AddressOf(_, place) => {
268+
// Figure out whether this is an addr_of of an already raw place.
269+
let place_base_raw = if place.has_deref() {
270+
let ty = self.frame().body.local_decls[place.local].ty;
271+
ty.is_unsafe_ptr()
272+
} else {
273+
// Not a deref, and thus not raw.
274+
false
275+
};
276+
277+
let src = self.eval_place(place)?;
278+
let place = self.force_allocation(&src)?;
279+
let mut val = ImmTy::from_immediate(place.to_ref(self), dest.layout);
280+
if !place_base_raw {
281+
// If this was not already raw, it needs retagging.
282+
val = M::retag_ptr_value(self, mir::RetagKind::Raw, &val)?;
283+
}
284+
self.write_immediate(*val, &dest)?;
254285
}
255286

256287
NullaryOp(null_op, ty) => {

compiler/rustc_middle/src/mir/syntax.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -400,7 +400,7 @@ impl std::fmt::Display for NonDivergingIntrinsic<'_> {
400400
#[derive(Copy, Clone, TyEncodable, TyDecodable, Debug, PartialEq, Eq, Hash, HashStable)]
401401
#[rustc_pass_by_value]
402402
pub enum RetagKind {
403-
/// The initial retag when entering a function.
403+
/// The initial retag of arguments when entering a function.
404404
FnEntry,
405405
/// Retag preparing for a two-phase borrow.
406406
TwoPhase,

compiler/rustc_mir_transform/src/add_retag.rs

+13-40
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,6 @@ use rustc_middle::ty::{self, Ty, TyCtxt};
1010

1111
pub struct AddRetag;
1212

13-
/// Determines whether this place is "stable": Whether, if we evaluate it again
14-
/// after the assignment, we can be sure to obtain the same place value.
15-
/// (Concurrent accesses by other threads are no problem as these are anyway non-atomic
16-
/// copies. Data races are UB.)
17-
fn is_stable(place: PlaceRef<'_>) -> bool {
18-
// Which place this evaluates to can change with any memory write,
19-
// so cannot assume deref to be stable.
20-
!place.has_deref()
21-
}
22-
2313
/// Determine whether this type may contain a reference (or box), and thus needs retagging.
2414
/// We will only recurse `depth` times into Tuples/ADTs to bound the cost of this.
2515
fn may_contain_reference<'tcx>(ty: Ty<'tcx>, depth: u32, tcx: TyCtxt<'tcx>) -> bool {
@@ -69,22 +59,10 @@ impl<'tcx> MirPass<'tcx> for AddRetag {
6959
let basic_blocks = body.basic_blocks.as_mut();
7060
let local_decls = &body.local_decls;
7161
let needs_retag = |place: &Place<'tcx>| {
72-
// FIXME: Instead of giving up for unstable places, we should introduce
73-
// a temporary and retag on that.
74-
is_stable(place.as_ref())
62+
!place.has_deref() // we're not eally interested in stores to "outside" locations, they are hard to keep track of anyway
7563
&& may_contain_reference(place.ty(&*local_decls, tcx).ty, /*depth*/ 3, tcx)
7664
&& !local_decls[place.local].is_deref_temp()
7765
};
78-
let place_base_raw = |place: &Place<'tcx>| {
79-
// If this is a `Deref`, get the type of what we are deref'ing.
80-
if place.has_deref() {
81-
let ty = &local_decls[place.local].ty;
82-
ty.is_unsafe_ptr()
83-
} else {
84-
// Not a deref, and thus not raw.
85-
false
86-
}
87-
};
8866

8967
// PART 1
9068
// Retag arguments at the beginning of the start block.
@@ -108,7 +86,7 @@ impl<'tcx> MirPass<'tcx> for AddRetag {
10886
}
10987

11088
// PART 2
111-
// Retag return values of functions. Also escape-to-raw the argument of `drop`.
89+
// Retag return values of functions.
11290
// We collect the return destinations because we cannot mutate while iterating.
11391
let returns = basic_blocks
11492
.iter_mut()
@@ -140,30 +118,25 @@ impl<'tcx> MirPass<'tcx> for AddRetag {
140118
}
141119

142120
// PART 3
143-
// Add retag after assignment.
121+
// Add retag after assignments where data "enters" this function: the RHS is behind a deref and the LHS is not.
144122
for block_data in basic_blocks {
145123
// We want to insert statements as we iterate. To this end, we
146124
// iterate backwards using indices.
147125
for i in (0..block_data.statements.len()).rev() {
148126
let (retag_kind, place) = match block_data.statements[i].kind {
149-
// Retag-as-raw after escaping to a raw pointer, if the referent
150-
// is not already a raw pointer.
151-
StatementKind::Assign(box (lplace, Rvalue::AddressOf(_, ref rplace)))
152-
if !place_base_raw(rplace) =>
153-
{
154-
(RetagKind::Raw, lplace)
155-
}
156127
// Retag after assignments of reference type.
157128
StatementKind::Assign(box (ref place, ref rvalue)) if needs_retag(place) => {
158-
let kind = match rvalue {
159-
Rvalue::Ref(_, borrow_kind, _)
160-
if borrow_kind.allows_two_phase_borrow() =>
161-
{
162-
RetagKind::TwoPhase
163-
}
164-
_ => RetagKind::Default,
129+
let add_retag = match rvalue {
130+
// Ptr-creating operations already do their own internal retagging, no
131+
// need to also add a retag statement.
132+
Rvalue::Ref(..) | Rvalue::AddressOf(..) => false,
133+
_ => true,
165134
};
166-
(kind, *place)
135+
if add_retag {
136+
(RetagKind::Default, *place)
137+
} else {
138+
continue;
139+
}
167140
}
168141
// Do nothing for the rest
169142
_ => continue,

compiler/rustc_mir_transform/src/generator.rs

-10
Original file line numberDiff line numberDiff line change
@@ -985,16 +985,6 @@ fn create_generator_drop_shim<'tcx>(
985985
tcx.mk_ptr(ty::TypeAndMut { ty: gen_ty, mutbl: hir::Mutability::Mut }),
986986
source_info,
987987
);
988-
if tcx.sess.opts.unstable_opts.mir_emit_retag {
989-
// Alias tracking must know we changed the type
990-
body.basic_blocks_mut()[START_BLOCK].statements.insert(
991-
0,
992-
Statement {
993-
source_info,
994-
kind: StatementKind::Retag(RetagKind::Raw, Box::new(Place::from(SELF_ARG))),
995-
},
996-
)
997-
}
998988

999989
// Make sure we remove dead blocks to remove
1000990
// unrelated code from the resume part of the function

compiler/rustc_mir_transform/src/shim.rs

-10
Original file line numberDiff line numberDiff line change
@@ -177,16 +177,6 @@ fn build_drop_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, ty: Option<Ty<'tcx>>)
177177
if ty.is_some() {
178178
// The first argument (index 0), but add 1 for the return value.
179179
let dropee_ptr = Place::from(Local::new(1 + 0));
180-
if tcx.sess.opts.unstable_opts.mir_emit_retag {
181-
// Function arguments should be retagged, and we make this one raw.
182-
body.basic_blocks_mut()[START_BLOCK].statements.insert(
183-
0,
184-
Statement {
185-
source_info,
186-
kind: StatementKind::Retag(RetagKind::Raw, Box::new(dropee_ptr)),
187-
},
188-
);
189-
}
190180
let patch = {
191181
let param_env = tcx.param_env_reveal_all_normalized(def_id);
192182
let mut elaborator =

src/test/mir-opt/inline/inline_retag.bar.Inline.after.mir

-4
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,7 @@ fn bar() -> bool {
3838
// + literal: Const { ty: &i32, val: Unevaluated(bar, [], Some(promoted[1])) }
3939
Retag(_10); // scope 1 at $DIR/inline_retag.rs:+2:7: +2:9
4040
_4 = &(*_10); // scope 1 at $DIR/inline_retag.rs:+2:7: +2:9
41-
Retag(_4); // scope 1 at $DIR/inline_retag.rs:+2:7: +2:9
4241
_3 = &(*_4); // scope 1 at $DIR/inline_retag.rs:+2:7: +2:9
43-
Retag(_3); // scope 1 at $DIR/inline_retag.rs:+2:7: +2:9
4442
StorageLive(_6); // scope 1 at $DIR/inline_retag.rs:+2:11: +2:14
4543
StorageLive(_7); // scope 1 at $DIR/inline_retag.rs:+2:11: +2:14
4644
_9 = const _; // scope 1 at $DIR/inline_retag.rs:+2:11: +2:14
@@ -49,9 +47,7 @@ fn bar() -> bool {
4947
// + literal: Const { ty: &i32, val: Unevaluated(bar, [], Some(promoted[0])) }
5048
Retag(_9); // scope 1 at $DIR/inline_retag.rs:+2:11: +2:14
5149
_7 = &(*_9); // scope 1 at $DIR/inline_retag.rs:+2:11: +2:14
52-
Retag(_7); // scope 1 at $DIR/inline_retag.rs:+2:11: +2:14
5350
_6 = &(*_7); // scope 1 at $DIR/inline_retag.rs:+2:11: +2:14
54-
Retag(_6); // scope 1 at $DIR/inline_retag.rs:+2:11: +2:14
5551
Retag(_3); // scope 2 at $DIR/inline_retag.rs:16:8: 16:9
5652
Retag(_6); // scope 2 at $DIR/inline_retag.rs:16:17: 16:18
5753
StorageLive(_11); // scope 2 at $DIR/inline_retag.rs:17:5: 17:7

src/test/mir-opt/retag.array_casts.SimplifyCfg-elaborate-drops.after.mir

-10
Original file line numberDiff line numberDiff line change
@@ -68,9 +68,7 @@ fn array_casts() -> () {
6868
StorageLive(_3); // scope 1 at $DIR/retag.rs:+2:13: +2:19
6969
StorageLive(_4); // scope 1 at $DIR/retag.rs:+2:13: +2:19
7070
_4 = &mut _1; // scope 1 at $DIR/retag.rs:+2:13: +2:19
71-
Retag(_4); // scope 1 at $DIR/retag.rs:+2:13: +2:19
7271
_3 = &raw mut (*_4); // scope 1 at $DIR/retag.rs:+2:13: +2:19
73-
Retag([raw] _3); // scope 1 at $DIR/retag.rs:+2:13: +2:19
7472
_2 = move _3 as *mut usize (Pointer(ArrayToPointer)); // scope 1 at $DIR/retag.rs:+2:13: +2:33
7573
StorageDead(_3); // scope 1 at $DIR/retag.rs:+2:32: +2:33
7674
StorageDead(_4); // scope 1 at $DIR/retag.rs:+2:33: +2:34
@@ -96,9 +94,7 @@ fn array_casts() -> () {
9694
StorageLive(_10); // scope 4 at $DIR/retag.rs:+6:13: +6:15
9795
StorageLive(_11); // scope 4 at $DIR/retag.rs:+6:13: +6:15
9896
_11 = &_8; // scope 4 at $DIR/retag.rs:+6:13: +6:15
99-
Retag(_11); // scope 4 at $DIR/retag.rs:+6:13: +6:15
10097
_10 = &raw const (*_11); // scope 4 at $DIR/retag.rs:+6:13: +6:15
101-
Retag([raw] _10); // scope 4 at $DIR/retag.rs:+6:13: +6:15
10298
_9 = move _10 as *const usize (Pointer(ArrayToPointer)); // scope 4 at $DIR/retag.rs:+6:13: +6:31
10399
StorageDead(_10); // scope 4 at $DIR/retag.rs:+6:30: +6:31
104100
StorageDead(_11); // scope 4 at $DIR/retag.rs:+6:31: +6:32
@@ -119,15 +115,13 @@ fn array_casts() -> () {
119115
StorageDead(_17); // scope 6 at $DIR/retag.rs:+7:33: +7:34
120116
_15 = (*_16); // scope 6 at $DIR/retag.rs:+7:25: +7:34
121117
_14 = &_15; // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
122-
Retag(_14); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
123118
StorageLive(_18); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
124119
_35 = const _; // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
125120
// mir::Constant
126121
// + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
127122
// + literal: Const { ty: &usize, val: Unevaluated(array_casts, [], Some(promoted[0])) }
128123
Retag(_35); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
129124
_18 = &(*_35); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
130-
Retag(_18); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
131125
Deinit(_13); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
132126
(_13.0: &usize) = move _14; // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
133127
(_13.1: &usize) = move _18; // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
@@ -164,15 +158,11 @@ fn array_casts() -> () {
164158
StorageLive(_30); // scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
165159
StorageLive(_31); // scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
166160
_31 = &(*_20); // scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
167-
Retag(_31); // scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
168161
_30 = &(*_31); // scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
169-
Retag(_30); // scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
170162
StorageLive(_32); // scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
171163
StorageLive(_33); // scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
172164
_33 = &(*_21); // scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
173-
Retag(_33); // scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
174165
_32 = &(*_33); // scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
175-
Retag(_32); // scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
176166
StorageLive(_34); // scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
177167
Deinit(_34); // scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
178168
discriminant(_34) = 0; // scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL

src/test/mir-opt/retag.core.ptr-drop_in_place.Test.SimplifyCfg-make_shim.after.mir

-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ fn std::ptr::drop_in_place(_1: *mut Test) -> () {
66
let mut _3: (); // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
77

88
bb0: {
9-
Retag([raw] _1); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
109
_2 = &mut (*_1); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
1110
_3 = <Test as Drop>::drop(move _2) -> bb1; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
1211
// mir::Constant

src/test/mir-opt/retag.main-{closure#0}.SimplifyCfg-elaborate-drops.after.mir

-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ fn main::{closure#0}(_1: &[closure@main::{closure#0}], _2: &i32) -> &i32 {
1515
_3 = _2; // scope 0 at $DIR/retag.rs:+1:18: +1:19
1616
Retag(_3); // scope 0 at $DIR/retag.rs:+1:18: +1:19
1717
_0 = &(*_2); // scope 1 at $DIR/retag.rs:+2:9: +2:10
18-
Retag(_0); // scope 1 at $DIR/retag.rs:+2:9: +2:10
1918
StorageDead(_3); // scope 0 at $DIR/retag.rs:+3:5: +3:6
2019
return; // scope 0 at $DIR/retag.rs:+3:6: +3:6
2120
}

0 commit comments

Comments
 (0)