Skip to content

Commit bd2e38e

Browse files
committed
SB: track whether a retag occurred nested inside a field
1 parent 3271858 commit bd2e38e

9 files changed

+63
-37
lines changed

src/borrow_tracker/stacked_borrows/diagnostics.rs

+27-14
Original file line numberDiff line numberDiff line change
@@ -61,12 +61,15 @@ struct Invalidation {
6161
#[derive(Clone, Debug)]
6262
enum InvalidationCause {
6363
Access(AccessKind),
64-
Retag(Permission, RetagCause),
64+
Retag(Permission, RetagInfo),
6565
}
6666

6767
impl Invalidation {
6868
fn generate_diagnostic(&self) -> (String, SpanData) {
69-
let message = if let InvalidationCause::Retag(_, RetagCause::FnEntry) = self.cause {
69+
let message = if matches!(
70+
self.cause,
71+
InvalidationCause::Retag(_, RetagInfo { cause: RetagCause::FnEntry, .. })
72+
) {
7073
// For a FnEntry retag, our Span points at the caller.
7174
// See `DiagnosticCx::log_invalidation`.
7275
format!(
@@ -87,8 +90,8 @@ impl fmt::Display for InvalidationCause {
8790
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
8891
match self {
8992
InvalidationCause::Access(kind) => write!(f, "{kind}"),
90-
InvalidationCause::Retag(perm, kind) =>
91-
write!(f, "{perm:?} {retag}", retag = kind.summary()),
93+
InvalidationCause::Retag(perm, info) =>
94+
write!(f, "{perm:?} {retag}", retag = info.summary()),
9295
}
9396
}
9497
}
@@ -129,13 +132,13 @@ impl<'ecx, 'mir, 'tcx> DiagnosticCxBuilder<'ecx, 'mir, 'tcx> {
129132

130133
pub fn retag(
131134
machine: &'ecx MiriMachine<'mir, 'tcx>,
132-
cause: RetagCause,
135+
info: RetagInfo,
133136
new_tag: BorTag,
134137
orig_tag: ProvenanceExtra,
135138
range: AllocRange,
136139
) -> Self {
137140
let operation =
138-
Operation::Retag(RetagOp { cause, new_tag, orig_tag, range, permission: None });
141+
Operation::Retag(RetagOp { info, new_tag, orig_tag, range, permission: None });
139142

140143
DiagnosticCxBuilder { machine, operation }
141144
}
@@ -179,13 +182,19 @@ enum Operation {
179182

180183
#[derive(Debug, Clone)]
181184
struct RetagOp {
182-
cause: RetagCause,
185+
info: RetagInfo,
183186
new_tag: BorTag,
184187
orig_tag: ProvenanceExtra,
185188
range: AllocRange,
186189
permission: Option<Permission>,
187190
}
188191

192+
#[derive(Debug, Clone, Copy, PartialEq)]
193+
pub struct RetagInfo {
194+
pub cause: RetagCause,
195+
pub in_field: bool,
196+
}
197+
189198
#[derive(Debug, Clone, Copy, PartialEq)]
190199
pub enum RetagCause {
191200
Normal,
@@ -258,11 +267,11 @@ impl<'history, 'ecx, 'mir, 'tcx> DiagnosticCx<'history, 'ecx, 'mir, 'tcx> {
258267
pub fn log_invalidation(&mut self, tag: BorTag) {
259268
let mut span = self.machine.current_span();
260269
let (range, cause) = match &self.operation {
261-
Operation::Retag(RetagOp { cause, range, permission, .. }) => {
262-
if *cause == RetagCause::FnEntry {
270+
Operation::Retag(RetagOp { info, range, permission, .. }) => {
271+
if info.cause == RetagCause::FnEntry {
263272
span = self.machine.caller_span();
264273
}
265-
(*range, InvalidationCause::Retag(permission.unwrap(), *cause))
274+
(*range, InvalidationCause::Retag(permission.unwrap(), *info))
266275
}
267276
Operation::Access(AccessOp { kind, range, .. }) =>
268277
(*range, InvalidationCause::Access(*kind)),
@@ -374,7 +383,7 @@ impl<'history, 'ecx, 'mir, 'tcx> DiagnosticCx<'history, 'ecx, 'mir, 'tcx> {
374383
);
375384
err_sb_ub(
376385
format!("{action}{}", error_cause(stack, op.orig_tag)),
377-
Some(operation_summary(&op.cause.summary(), self.history.id, op.range)),
386+
Some(operation_summary(&op.info.summary(), self.history.id, op.range)),
378387
op.orig_tag.and_then(|orig_tag| self.get_logs_relevant_to(orig_tag, None)),
379388
)
380389
}
@@ -496,14 +505,18 @@ fn error_cause(stack: &Stack, prov_extra: ProvenanceExtra) -> &'static str {
496505
}
497506
}
498507

499-
impl RetagCause {
508+
impl RetagInfo {
500509
fn summary(&self) -> String {
501-
match self {
510+
let mut s = match self.cause {
502511
RetagCause::Normal => "retag",
503512
RetagCause::FnEntry => "function-entry retag",
504513
RetagCause::InPlaceFnPassing => "in-place function argument/return passing protection",
505514
RetagCause::TwoPhase => "two-phase retag",
506515
}
507-
.to_string()
516+
.to_string();
517+
if self.in_field {
518+
s.push_str(" (of a reference/box inside this compound type)");
519+
}
520+
s
508521
}
509522
}

src/borrow_tracker/stacked_borrows/mod.rs

+29-16
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,11 @@ pub mod diagnostics;
55
mod item;
66
mod stack;
77

8-
use log::trace;
98
use std::cmp;
109
use std::fmt::Write;
10+
use std::mem;
11+
12+
use log::trace;
1113

1214
use rustc_data_structures::fx::FxHashSet;
1315
use rustc_middle::mir::{Mutability, RetagKind};
@@ -24,7 +26,7 @@ use crate::borrow_tracker::{
2426
};
2527
use crate::*;
2628

27-
use diagnostics::RetagCause;
29+
use diagnostics::{RetagCause, RetagInfo};
2830
pub use item::{Item, Permission};
2931
pub use stack::Stack;
3032

@@ -623,7 +625,7 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<'
623625
size: Size,
624626
new_perm: NewPermission,
625627
new_tag: BorTag,
626-
retag_cause: RetagCause, // What caused this retag, for diagnostics only
628+
retag_info: RetagInfo, // diagnostics info about this retag
627629
) -> InterpResult<'tcx, Option<AllocId>> {
628630
let this = self.eval_context_mut();
629631

@@ -670,7 +672,7 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<'
670672
// FIXME: can this be done cleaner?
671673
let dcx = DiagnosticCxBuilder::retag(
672674
&this.machine,
673-
retag_cause,
675+
retag_info,
674676
new_tag,
675677
orig_tag,
676678
alloc_range(base_offset, size),
@@ -761,7 +763,7 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<'
761763
let global = machine.borrow_tracker.as_ref().unwrap().borrow();
762764
let dcx = DiagnosticCxBuilder::retag(
763765
machine,
764-
retag_cause,
766+
retag_info,
765767
new_tag,
766768
orig_tag,
767769
alloc_range(base_offset, size),
@@ -804,7 +806,7 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<'
804806
let global = this.machine.borrow_tracker.as_ref().unwrap().borrow();
805807
let dcx = DiagnosticCxBuilder::retag(
806808
&this.machine,
807-
retag_cause,
809+
retag_info,
808810
new_tag,
809811
orig_tag,
810812
alloc_range(base_offset, size),
@@ -834,7 +836,7 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<'
834836
&mut self,
835837
val: &ImmTy<'tcx, Provenance>,
836838
new_perm: NewPermission,
837-
cause: RetagCause, // What caused this retag, for diagnostics only
839+
info: RetagInfo, // diagnostics info about this retag
838840
) -> InterpResult<'tcx, ImmTy<'tcx, Provenance>> {
839841
let this = self.eval_context_mut();
840842
// We want a place for where the ptr *points to*, so we get one.
@@ -852,7 +854,7 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<'
852854
let new_tag = this.machine.borrow_tracker.as_mut().unwrap().get_mut().new_ptr();
853855

854856
// Reborrow.
855-
let alloc_id = this.sb_reborrow(&place, size, new_perm, new_tag, cause)?;
857+
let alloc_id = this.sb_reborrow(&place, size, new_perm, new_tag, info)?;
856858

857859
// Adjust pointer.
858860
let new_place = place.map_provenance(|p| {
@@ -886,12 +888,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
886888
) -> InterpResult<'tcx, ImmTy<'tcx, Provenance>> {
887889
let this = self.eval_context_mut();
888890
let new_perm = NewPermission::from_ref_ty(val.layout.ty, kind, this);
889-
let retag_cause = match kind {
891+
let cause = match kind {
890892
RetagKind::TwoPhase { .. } => RetagCause::TwoPhase,
891893
RetagKind::FnEntry => unreachable!(),
892894
RetagKind::Raw | RetagKind::Default => RetagCause::Normal,
893895
};
894-
this.sb_retag_reference(val, new_perm, retag_cause)
896+
this.sb_retag_reference(val, new_perm, RetagInfo { cause, in_field: false })
895897
}
896898

897899
fn sb_retag_place_contents(
@@ -906,7 +908,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
906908
RetagKind::FnEntry => RetagCause::FnEntry,
907909
RetagKind::Default => RetagCause::Normal,
908910
};
909-
let mut visitor = RetagVisitor { ecx: this, kind, retag_cause, retag_fields };
911+
let mut visitor =
912+
RetagVisitor { ecx: this, kind, retag_cause, retag_fields, in_field: false };
910913
return visitor.visit_value(place);
911914

912915
// The actual visitor.
@@ -915,17 +918,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
915918
kind: RetagKind,
916919
retag_cause: RetagCause,
917920
retag_fields: RetagFields,
921+
in_field: bool,
918922
}
919923
impl<'ecx, 'mir, 'tcx> RetagVisitor<'ecx, 'mir, 'tcx> {
920924
#[inline(always)] // yes this helps in our benchmarks
921925
fn retag_ptr_inplace(
922926
&mut self,
923927
place: &PlaceTy<'tcx, Provenance>,
924928
new_perm: NewPermission,
925-
retag_cause: RetagCause,
926929
) -> InterpResult<'tcx> {
927930
let val = self.ecx.read_immediate(&self.ecx.place_to_op(place)?)?;
928-
let val = self.ecx.sb_retag_reference(&val, new_perm, retag_cause)?;
931+
let val = self.ecx.sb_retag_reference(
932+
&val,
933+
new_perm,
934+
RetagInfo { cause: self.retag_cause, in_field: self.in_field },
935+
)?;
929936
self.ecx.write_immediate(*val, place)?;
930937
Ok(())
931938
}
@@ -943,7 +950,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
943950
fn visit_box(&mut self, place: &PlaceTy<'tcx, Provenance>) -> InterpResult<'tcx> {
944951
// Boxes get a weak protectors, since they may be deallocated.
945952
let new_perm = NewPermission::from_box_ty(place.layout.ty, self.kind, self.ecx);
946-
self.retag_ptr_inplace(place, new_perm, self.retag_cause)
953+
self.retag_ptr_inplace(place, new_perm)
947954
}
948955

949956
fn visit_value(&mut self, place: &PlaceTy<'tcx, Provenance>) -> InterpResult<'tcx> {
@@ -960,7 +967,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
960967
ty::Ref(..) => {
961968
let new_perm =
962969
NewPermission::from_ref_ty(place.layout.ty, self.kind, self.ecx);
963-
self.retag_ptr_inplace(place, new_perm, self.retag_cause)?;
970+
self.retag_ptr_inplace(place, new_perm)?;
964971
}
965972
ty::RawPtr(..) => {
966973
// We do *not* want to recurse into raw pointers -- wide raw pointers have
@@ -984,7 +991,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
984991
}
985992
};
986993
if recurse {
994+
let in_field = mem::replace(&mut self.in_field, true); // remember and restore old value
987995
self.walk_value(place)?;
996+
self.in_field = in_field;
988997
}
989998
}
990999
}
@@ -1011,7 +1020,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
10111020
access: Some(AccessKind::Write),
10121021
protector: Some(ProtectorKind::StrongProtector),
10131022
};
1014-
let _new_ptr = this.sb_retag_reference(&ptr, new_perm, RetagCause::InPlaceFnPassing)?;
1023+
let _new_ptr = this.sb_retag_reference(
1024+
&ptr,
1025+
new_perm,
1026+
RetagInfo { cause: RetagCause::InPlaceFnPassing, in_field: false },
1027+
)?;
10151028
// We just throw away `new_ptr`, so nobody can access this memory while it is protected.
10161029

10171030
Ok(())

tests/fail/both_borrows/buggy_split_at_mut.stack.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ LL | | )
88
| | ^
99
| | |
1010
| |_____________trying to retag from <TAG> for Unique permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location
11-
| this error occurs as part of retag at ALLOC[0x0..0x10]
11+
| this error occurs as part of retag (of a reference/box inside this compound type) at ALLOC[0x0..0x10]
1212
|
1313
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental
1414
= help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information

tests/fail/both_borrows/pass_invalid_shr_option.stack.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ LL | foo(some_xref);
55
| ^^^^^^^^^
66
| |
77
| trying to retag from <TAG> for SharedReadOnly permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location
8-
| this error occurs as part of retag at ALLOC[0x0..0x4]
8+
| this error occurs as part of retag (of a reference/box inside this compound type) at ALLOC[0x0..0x4]
99
|
1010
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental
1111
= help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information

tests/fail/both_borrows/pass_invalid_shr_tuple.stack.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ LL | foo(pair_xref);
55
| ^^^^^^^^^
66
| |
77
| trying to retag from <TAG> for SharedReadOnly permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location
8-
| this error occurs as part of retag at ALLOC[0x0..0x4]
8+
| this error occurs as part of retag (of a reference/box inside this compound type) at ALLOC[0x0..0x4]
99
|
1010
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental
1111
= help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information

tests/fail/both_borrows/return_invalid_shr_option.stack.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ LL | ret
55
| ^^^
66
| |
77
| trying to retag from <TAG> for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location
8-
| this error occurs as part of retag at ALLOC[0x4..0x8]
8+
| this error occurs as part of retag (of a reference/box inside this compound type) at ALLOC[0x4..0x8]
99
|
1010
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental
1111
= help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information

tests/fail/both_borrows/return_invalid_shr_tuple.stack.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ LL | ret
55
| ^^^
66
| |
77
| trying to retag from <TAG> for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location
8-
| this error occurs as part of retag at ALLOC[0x4..0x8]
8+
| this error occurs as part of retag (of a reference/box inside this compound type) at ALLOC[0x4..0x8]
99
|
1010
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental
1111
= help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information

tests/fail/stacked_borrows/return_invalid_mut_option.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ LL | ret
55
| ^^^
66
| |
77
| trying to retag from <TAG> for Unique permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location
8-
| this error occurs as part of retag at ALLOC[0x4..0x8]
8+
| this error occurs as part of retag (of a reference/box inside this compound type) at ALLOC[0x4..0x8]
99
|
1010
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental
1111
= help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information

tests/fail/stacked_borrows/return_invalid_mut_tuple.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ LL | ret
55
| ^^^
66
| |
77
| trying to retag from <TAG> for Unique permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location
8-
| this error occurs as part of retag at ALLOC[0x4..0x8]
8+
| this error occurs as part of retag (of a reference/box inside this compound type) at ALLOC[0x4..0x8]
99
|
1010
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental
1111
= help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information

0 commit comments

Comments
 (0)