Skip to content

Commit d9c5d39

Browse files
committed
Move to one Item impl, add call ID back to diagnostics
1 parent 7cfbc7e commit d9c5d39

12 files changed

+163
-147
lines changed

src/stacked_borrows.rs

+114-32
Original file line numberDiff line numberDiff line change
@@ -92,22 +92,90 @@ pub enum Permission {
9292
Disabled,
9393
}
9494

95-
/// An item in the per-location borrow stack.
96-
#[derive(Copy, Clone, Hash, PartialEq, Eq)]
97-
pub struct Item {
98-
/// The permission this item grants.
99-
perm: Permission,
100-
/// The pointers the permission is granted to.
101-
tag: SbTag,
102-
/// Whether or not there is a protector for this tag
103-
protected: bool,
95+
impl Permission {
96+
fn to_bits(self) -> u64 {
97+
match self {
98+
Permission::Unique => 0,
99+
Permission::SharedReadWrite => 1,
100+
Permission::SharedReadOnly => 2,
101+
Permission::Disabled => 3,
102+
}
103+
}
104+
105+
fn from_bits(perm: u64) -> Self {
106+
match perm {
107+
0 => Permission::Unique,
108+
1 => Permission::SharedReadWrite,
109+
2 => Permission::SharedReadOnly,
110+
3 => Permission::Disabled,
111+
_ => unreachable!(),
112+
}
113+
}
104114
}
105115

106-
impl fmt::Debug for Item {
107-
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
108-
write!(f, "[{:?} for {:?}]", self.perm, self.tag)
116+
mod item {
117+
use super::{Permission, SbTag};
118+
use std::fmt;
119+
120+
/// An item in the per-location borrow stack.
121+
#[derive(Copy, Clone, Hash, PartialEq, Eq)]
122+
pub struct Item(u64);
123+
124+
// An Item contains 3 bitfields:
125+
// * Bits 0-61 store an SbTag
126+
// * Bits 61-63 store a Permission
127+
// * Bit 64 stores a flag which indicates if we have a protector
128+
const TAG_MASK: u64 = u64::MAX >> 3;
129+
const PERM_MASK: u64 = 0x3 << 61;
130+
const PROTECTED_MASK: u64 = 0x1 << 63;
131+
132+
const PERM_SHIFT: u64 = 61;
133+
const PROTECTED_SHIFT: u64 = 63;
134+
135+
impl Item {
136+
pub fn new(tag: SbTag, perm: Permission, protected: bool) -> Self {
137+
assert!(tag.0.get() <= TAG_MASK);
138+
let packed_tag = tag.0.get();
139+
let packed_perm = perm.to_bits() << PERM_SHIFT;
140+
let packed_protected = (protected as u64) << PROTECTED_SHIFT;
141+
142+
let new = Self(packed_tag + packed_perm + packed_protected);
143+
144+
debug_assert!(new.tag() == tag);
145+
debug_assert!(new.perm() == perm);
146+
debug_assert!(new.protected() == protected);
147+
148+
new
149+
}
150+
151+
/// The pointers the permission is granted to.
152+
pub fn tag(self) -> SbTag {
153+
unsafe { SbTag(std::num::NonZeroU64::new_unchecked(self.0 & TAG_MASK)) }
154+
}
155+
156+
/// The permission this item grants.
157+
pub fn perm(self) -> Permission {
158+
Permission::from_bits((self.0 & PERM_MASK) >> PERM_SHIFT)
159+
}
160+
161+
/// Whether or not there is a protector for this tag
162+
pub fn protected(self) -> bool {
163+
self.0 & PROTECTED_MASK > 0
164+
}
165+
166+
/// Set the Permission stored in this Item to Permission::Disabled
167+
pub fn set_disabled(&mut self) {
168+
self.0 |= Permission::Disabled.to_bits() << PERM_SHIFT;
169+
}
170+
}
171+
172+
impl fmt::Debug for Item {
173+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
174+
write!(f, "[{:?} for {:?}]", self.perm(), self.tag())
175+
}
109176
}
110177
}
178+
pub use item::Item;
111179

112180
/// Extra per-allocation state.
113181
#[derive(Clone, Debug)]
@@ -134,7 +202,7 @@ pub struct GlobalStateInner {
134202
/// Those call IDs corresponding to functions that are still running.
135203
active_calls: FxHashSet<CallId>,
136204
/// All tags currently protected
137-
pub(crate) protected_tags: FxHashSet<SbTag>,
205+
pub(crate) protected_tags: FxHashMap<SbTag, CallId>,
138206
/// The pointer ids to trace
139207
tracked_pointer_tags: HashSet<SbTag>,
140208
/// The call ids to trace
@@ -199,7 +267,7 @@ impl GlobalStateInner {
199267
base_ptr_tags: FxHashMap::default(),
200268
next_call_id: NonZeroU64::new(1).unwrap(),
201269
active_calls: FxHashSet::default(),
202-
protected_tags: FxHashSet::default(),
270+
protected_tags: FxHashMap::default(),
203271
tracked_pointer_tags,
204272
tracked_call_ids,
205273
retag_fields,
@@ -281,7 +349,7 @@ impl<'tcx> Stack {
281349
/// Find the first write-incompatible item above the given one --
282350
/// i.e, find the height to which the stack will be truncated when writing to `granting`.
283351
fn find_first_write_incompatible(&self, granting: usize) -> usize {
284-
let perm = self.get(granting).unwrap().perm;
352+
let perm = self.get(granting).unwrap().perm();
285353
match perm {
286354
Permission::SharedReadOnly => bug!("Cannot use SharedReadOnly for writing"),
287355
Permission::Disabled => bug!("Cannot use Disabled for anything"),
@@ -293,7 +361,7 @@ impl<'tcx> Stack {
293361
// The SharedReadWrite *just* above us are compatible, to skip those.
294362
let mut idx = granting + 1;
295363
while let Some(item) = self.get(idx) {
296-
if item.perm == Permission::SharedReadWrite {
364+
if item.perm() == Permission::SharedReadWrite {
297365
// Go on.
298366
idx += 1;
299367
} else {
@@ -320,26 +388,33 @@ impl<'tcx> Stack {
320388
global: &GlobalStateInner,
321389
alloc_history: &mut AllocHistory,
322390
) -> InterpResult<'tcx> {
323-
if global.tracked_pointer_tags.contains(&item.tag) {
391+
if global.tracked_pointer_tags.contains(&item.tag()) {
324392
register_diagnostic(NonHaltingDiagnostic::PoppedPointerTag(
325393
*item,
326394
provoking_access.map(|(tag, _alloc_range, _size, access)| (tag, access)),
327395
));
328396
}
329397

330-
if item.protected && global.protected_tags.contains(&item.tag) {
398+
if !item.protected() {
399+
return Ok(());
400+
}
401+
402+
if let Some(call_id) = global.protected_tags.get(&item.tag()) {
331403
if let Some((tag, _alloc_range, _offset, _access)) = provoking_access {
332404
Err(err_sb_ub(
333405
format!(
334-
"not granting access to tag {:?} because incompatible item is protected: {:?}",
335-
tag, item
406+
"not granting access to tag {:?} because incompatible item is protected: {:?} (call {:?})",
407+
tag, item, call_id
336408
),
337409
None,
338-
tag.and_then(|tag| alloc_history.get_logs_relevant_to(tag, Some(item.tag))),
410+
tag.and_then(|tag| alloc_history.get_logs_relevant_to(tag, Some(item.tag()))),
339411
))?
340412
} else {
341413
Err(err_sb_ub(
342-
format!("deallocating while item is protected: {:?}", item),
414+
format!(
415+
"deallocating while item is protected: {:?} (call {:?})",
416+
item, call_id
417+
),
343418
None,
344419
None,
345420
))?
@@ -392,7 +467,7 @@ impl<'tcx> Stack {
392467
global,
393468
alloc_history,
394469
)?;
395-
alloc_history.log_invalidation(item.tag, alloc_range, current_span);
470+
alloc_history.log_invalidation(item.tag(), alloc_range, current_span);
396471
Ok(())
397472
})?;
398473
} else {
@@ -418,7 +493,7 @@ impl<'tcx> Stack {
418493
global,
419494
alloc_history,
420495
)?;
421-
alloc_history.log_invalidation(item.tag, alloc_range, current_span);
496+
alloc_history.log_invalidation(item.tag(), alloc_range, current_span);
422497
Ok(())
423498
})?;
424499
}
@@ -431,9 +506,9 @@ impl<'tcx> Stack {
431506
for i in 0..self.len() {
432507
let item = self.get(i).unwrap();
433508
// Skip disabled items, they cannot be matched anyway.
434-
if !matches!(item.perm, Permission::Disabled) {
509+
if !matches!(item.perm(), Permission::Disabled) {
435510
// We are looking for a strict upper bound, so add 1 to this tag.
436-
max = cmp::max(item.tag.0.checked_add(1).unwrap(), max);
511+
max = cmp::max(item.tag().0.checked_add(1).unwrap(), max);
437512
}
438513
}
439514
if let Some(unk) = self.unknown_bottom() {
@@ -497,7 +572,7 @@ impl<'tcx> Stack {
497572
) -> InterpResult<'tcx> {
498573
// Figure out which access `perm` corresponds to.
499574
let access =
500-
if new.perm.grants(AccessKind::Write) { AccessKind::Write } else { AccessKind::Read };
575+
if new.perm().grants(AccessKind::Write) { AccessKind::Write } else { AccessKind::Read };
501576

502577
// Now we figure out which item grants our parent (`derived_from`) this kind of access.
503578
// We use that to determine where to put the new item.
@@ -509,7 +584,7 @@ impl<'tcx> Stack {
509584
// Compute where to put the new item.
510585
// Either way, we ensure that we insert the new item in a way such that between
511586
// `derived_from` and the new one, there are only items *compatible with* `derived_from`.
512-
let new_idx = if new.perm == Permission::SharedReadWrite {
587+
let new_idx = if new.perm() == Permission::SharedReadWrite {
513588
assert!(
514589
access == AccessKind::Write,
515590
"this case only makes sense for stack-like accesses"
@@ -570,7 +645,7 @@ impl<'tcx> Stack {
570645
impl<'tcx> Stacks {
571646
/// Creates new stack with initial tag.
572647
fn new(size: Size, perm: Permission, tag: SbTag) -> Self {
573-
let item = Item { perm, tag, protected: false };
648+
let item = Item::new(tag, perm, false);
574649
let stack = Stack::new(item);
575650

576651
Stacks {
@@ -814,7 +889,14 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
814889
// protect anything that contains an UnsafeCell.
815890
if protect {
816891
this.frame_mut().extra.protected_tags.push(new_tag);
817-
this.machine.stacked_borrows.as_mut().unwrap().get_mut().protected_tags.insert(new_tag);
892+
let call_id = this.frame().extra.call_id;
893+
this.machine
894+
.stacked_borrows
895+
.as_mut()
896+
.unwrap()
897+
.get_mut()
898+
.protected_tags
899+
.insert(new_tag, call_id);
818900
}
819901
// FIXME: can't hold the current span handle across the borrows of self above
820902
let current_span = &mut this.machine.current_span();
@@ -862,7 +944,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
862944
// This fixes https://github.com/rust-lang/rust/issues/55005.
863945
false
864946
};
865-
let item = Item { perm, tag: new_tag, protected };
947+
let item = Item::new(new_tag, perm, protected);
866948
let mut global = this.machine.stacked_borrows.as_ref().unwrap().borrow_mut();
867949
stacked_borrows.for_each(range, |offset, stack, history, exposed_tags| {
868950
stack.grant(
@@ -888,7 +970,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
888970
.as_mut()
889971
.expect("we should have Stacked Borrows data")
890972
.borrow_mut();
891-
let item = Item { perm, tag: new_tag, protected: protect };
973+
let item = Item::new(new_tag, perm, protect);
892974
let range = alloc_range(base_offset, size);
893975
let mut global = machine.stacked_borrows.as_ref().unwrap().borrow_mut();
894976
let current_span = &mut machine.current_span(); // `get_alloc_extra_mut` invalidated our old `current_span`

src/stacked_borrows/diagnostics.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ impl AllocHistory {
141141
) -> InterpError<'tcx> {
142142
let action = format!(
143143
"trying to reborrow {derived_from:?} for {:?} permission at {}[{:#x}]",
144-
new.perm,
144+
new.perm(),
145145
alloc_id,
146146
error_offset.bytes(),
147147
);
@@ -187,7 +187,7 @@ fn error_cause(stack: &Stack, tag: SbTagExtra) -> &'static str {
187187
if let SbTagExtra::Concrete(tag) = tag {
188188
if (0..stack.len())
189189
.map(|i| stack.get(i).unwrap())
190-
.any(|item| item.tag == tag && item.perm != Permission::Disabled)
190+
.any(|item| item.tag() == tag && item.perm() != Permission::Disabled)
191191
{
192192
", but that tag only grants SharedReadOnly permission for this location"
193193
} else {

0 commit comments

Comments
 (0)