1 use smallvec::SmallVec;
3 use rustc_middle::mir::interpret::{AllocId, AllocRange};
4 use rustc_span::{Span, SpanData};
5 use rustc_target::abi::Size;
7 use crate::helpers::CurrentSpan;
8 use crate::stacked_borrows::{err_sb_ub, AccessKind};
11 use rustc_middle::mir::interpret::InterpError;
13 #[derive(Clone, Debug)]
14 pub struct AllocHistory {
15 // The time tags can be compressed down to one bit per event, by just storing a Vec<u8>
16 // where each bit is set to indicate if the event was a creation or a retag
18 creations: smallvec::SmallVec<[Event; 2]>,
19 invalidations: smallvec::SmallVec<[Event; 1]>,
20 protectors: smallvec::SmallVec<[Protection; 1]>,
23 #[derive(Clone, Debug)]
30 #[derive(Clone, Debug)]
32 parent: Option<SbTag>,
41 created: (AllocRange, SpanData),
42 invalidated: Option<(AllocRange, SpanData)>,
43 protected: Option<(SbTag, SpanData, SpanData)>,
48 pub fn new() -> Self {
51 creations: SmallVec::new(),
52 invalidations: SmallVec::new(),
53 protectors: SmallVec::new(),
59 parent: Option<SbTag>,
62 current_span: &mut CurrentSpan<'_, '_, '_>,
64 let span = current_span.get();
65 self.creations.push(Event { parent, tag, range, span });
66 self.current_time += 1;
69 pub fn log_invalidation(
73 current_span: &mut CurrentSpan<'_, '_, '_>,
75 let span = current_span.get();
76 self.invalidations.push(Event { parent: None, tag, range, span });
77 self.current_time += 1;
84 current_span: &mut CurrentSpan<'_, '_, '_>,
86 let span = current_span.get();
87 self.protectors.push(Protection { orig_tag, tag, span });
88 self.current_time += 1;
91 pub fn get_logs_relevant_to(
94 protector_tag: Option<SbTag>,
95 ) -> Option<TagHistory> {
96 let protected = protector_tag
97 .and_then(|protector| {
98 self.protectors.iter().find_map(|protection| {
99 if protection.tag == protector {
100 Some((protection.orig_tag, protection.span.data()))
106 .and_then(|(tag, call_span)| {
107 self.creations.iter().rev().find_map(|event| {
108 if event.tag == tag {
109 Some((event.parent?, event.span.data(), call_span))
116 let get_matching = |events: &[Event]| {
117 events.iter().rev().find_map(|event| {
118 if event.tag == tag { Some((event.range, event.span.data())) } else { None }
121 Some(TagHistory::Tagged {
123 created: get_matching(&self.creations)?,
124 invalidated: get_matching(&self.invalidations),
129 /// Report a descriptive error when `new` could not be granted from `derived_from`.
130 pub fn grant_error<'tcx>(
132 derived_from: ProvenanceExtra,
135 alloc_range: AllocRange,
138 ) -> InterpError<'tcx> {
139 let action = format!(
140 "trying to reborrow from {derived_from:?} for {new_perm:?} permission at {alloc_id:?}[{offset:#x}]",
141 new_perm = new.perm(),
142 offset = error_offset.bytes(),
145 format!("{}{}", action, error_cause(stack, derived_from)),
146 Some(operation_summary("a reborrow", alloc_id, alloc_range)),
147 derived_from.and_then(|derived_from| self.get_logs_relevant_to(derived_from, None)),
151 /// Report a descriptive error when `access` is not permitted based on `tag`.
152 pub fn access_error<'tcx>(
155 tag: ProvenanceExtra,
157 alloc_range: AllocRange,
160 ) -> InterpError<'tcx> {
161 let action = format!(
162 "attempting a {access} using {tag:?} at {alloc_id:?}[{offset:#x}]",
163 offset = error_offset.bytes(),
166 format!("{}{}", action, error_cause(stack, tag)),
167 Some(operation_summary("an access", alloc_id, alloc_range)),
168 tag.and_then(|tag| self.get_logs_relevant_to(tag, None)),
173 fn operation_summary(
174 operation: &'static str,
176 alloc_range: AllocRange,
178 format!("this error occurs as part of {operation} at {alloc_id:?}{alloc_range:?}")
181 fn error_cause(stack: &Stack, prov_extra: ProvenanceExtra) -> &'static str {
182 if let ProvenanceExtra::Concrete(tag) = prov_extra {
184 .map(|i| stack.get(i).unwrap())
185 .any(|item| item.tag() == tag && item.perm() != Permission::Disabled)
187 ", but that tag only grants SharedReadOnly permission for this location"
189 ", but that tag does not exist in the borrow stack for this location"
192 ", but no exposed tags have suitable permission in the borrow stack for this location"