@@ -3,7 +3,6 @@ use std::ops::Range;
33
44use rustc_data_structures:: fx:: FxHashMap ;
55use rustc_span:: { Span , SpanData } ;
6- use rustc_target:: abi:: Size ;
76
87use crate :: borrow_tracker:: tree_borrows:: {
98 perms:: { PermTransition , Permission } ,
@@ -14,18 +13,30 @@ use crate::borrow_tracker::{AccessKind, ProtectorKind};
1413use crate :: * ;
1514
1615/// Complete data for an event:
17- /// - `kind` is what happened to the permissions
18- /// - `access_kind` and `access_range` describe the access that caused the event
19- /// - `offset` allows filtering only the relevant events for a given memory location
20- /// (see how we perform the filtering in `History::extract_relevant`.
21- /// - `span` is the line of code in question
2216#[ derive( Clone , Debug ) ]
2317pub struct Event {
18+ /// Transformation of permissions that occured because of this event
2419 pub transition : PermTransition ,
20+ /// Kind of the access that triggered this event
2521 pub access_kind : AccessKind ,
22+ /// Relative position of the tag to the one used for the access
2623 pub is_foreign : bool ,
24+ /// User-visible range of the access
2725 pub access_range : AllocRange ,
28- pub offset : Size ,
26+ /// The transition recorded by this event only occured on a subrange of
27+ /// `access_range`: a single access on `access_range` triggers several events,
28+ /// each with their own mutually disjoint `transition_range`. No-op transitions
29+ /// should not be recorded as events, so the union of all `transition_range` is not
30+ /// necessarily the entire `access_range`.
31+ ///
32+ /// No data from any `transition_range` should ever be user-visible, because
33+ /// both the start and end of `transition_range` are entirely dependent on the
34+ /// internal representation of `RangeMap` which is supposed to be opaque.
35+ /// What will be shown in the error message is the first byte `error_offset` of
36+ /// the `TbError`, which should satisfy
37+ /// `event.transition_range.contains(error.error_offset)`.
38+ pub transition_range : Range < u64 > ,
39+ /// Line of code that triggered this event
2940 pub span : Span ,
3041}
3142
@@ -35,9 +46,9 @@ pub struct Event {
3546/// Available filtering methods include `History::forget` and `History::extract_relevant`.
3647#[ derive( Clone , Debug ) ]
3748pub struct History {
38- pub tag : BorTag ,
39- pub created : ( Span , Permission ) ,
40- pub events : Vec < Event > ,
49+ tag : BorTag ,
50+ created : ( Span , Permission ) ,
51+ events : Vec < Event > ,
4152}
4253
4354/// History formatted for use by `src/diagnostics.rs`.
@@ -60,12 +71,7 @@ impl HistoryData {
6071 // Format events from `new_history` into those recorded by `self`.
6172 //
6273 // NOTE: also converts `Span` to `SpanData`.
63- pub fn extend (
64- & mut self ,
65- new_history : History ,
66- tag_name : & ' static str ,
67- show_initial_state : bool ,
68- ) {
74+ fn extend ( & mut self , new_history : History , tag_name : & ' static str , show_initial_state : bool ) {
6975 let History { tag, created, events } = new_history;
7076 let this = format ! ( "the {tag_name} tag {tag:?}" ) ;
7177 let msg_initial_state = format ! ( ", in the initial state {}" , created. 1 ) ;
@@ -75,9 +81,16 @@ impl HistoryData {
7581 ) ;
7682
7783 self . events . push ( ( Some ( created. 0 . data ( ) ) , msg_creation) ) ;
78- for & Event { transition, access_kind, is_foreign, access_range, span, offset : _ } in & events
84+ for & Event {
85+ transition,
86+ access_kind,
87+ is_foreign,
88+ access_range,
89+ span,
90+ transition_range : _,
91+ } in & events
7992 {
80- // NOTE: `offset ` is explicitly absent from the error message, it has no significance
93+ // NOTE: `transition_range ` is explicitly absent from the error message, it has no significance
8194 // to the user. The meaningful one is `access_range`.
8295 self . events . push ( ( Some ( span. data ( ) ) , format ! ( "{this} then transitioned {transition} due to a {rel} {access_kind} at offsets {access_range:?}" , rel = if is_foreign { "foreign" } else { "child" } ) ) ) ;
8396 self . events . push ( ( None , format ! ( "this corresponds to {}" , transition. summary( ) ) ) ) ;
@@ -197,53 +210,28 @@ impl History {
197210 History { events : Vec :: new ( ) , created : self . created , tag : self . tag }
198211 }
199212
200- /// Reconstruct the history relevant to `error_offset` knowing that
201- /// its permission followed `complete_transition`.
202- ///
203- /// Here's how we do this:
204- /// - we know `full := complete_transition` the transition of the permission from
205- /// its initialization to the state just before the error was caused,
206- /// we want to find a chain of events that produces `full`
207- /// - we decompose `full` into `pre o post` where
208- /// `pre` is the best applicable transition from recorded events
209- /// - we select the event that caused `pre` and iterate
210- /// to find the chain of events that produces `full := post`
211- ///
212- /// To find the "best applicable transition" for full:
213- /// - eliminate events that cannot be applied because their offset is too big
214- /// - eliminate events that cannot be applied because their starting point is wrong
215- /// - select the one that happened closest to the range of interest
216- fn extract_relevant ( & self , complete_transition : PermTransition , error_offset : Size ) -> Self {
217- let mut selected_events: Vec < Event > = Vec :: new ( ) ;
218- let mut full = complete_transition;
219- while !full. is_noop ( ) {
220- let ( pre, post) = self
213+ /// Reconstruct the history relevant to `error_offset` by filtering
214+ /// only events whose range contains the offset we are interested in.
215+ fn extract_relevant ( & self , error_offset : u64 ) -> Self {
216+ History {
217+ events : self
221218 . events
222219 . iter ( )
223- . filter ( |e| e. offset <= error_offset)
224- . filter_map ( |pre_canditate| {
225- full. apply_start ( pre_canditate. transition )
226- . map ( |post_canditate| ( pre_canditate, post_canditate) )
227- } )
228- . max_by_key ( |( pre_canditate, _post_candidate) | pre_canditate. offset )
229- . unwrap ( ) ;
230- // If this occurs we will loop infinitely !
231- // Make sure to only put non-noop transitions in `History`.
232- assert ! ( !pre. transition. is_noop( ) ) ;
233- full = post;
234- selected_events. push ( pre. clone ( ) ) ;
220+ . filter ( |e| e. transition_range . contains ( & error_offset) )
221+ . cloned ( )
222+ . collect :: < Vec < _ > > ( ) ,
223+ created : self . created ,
224+ tag : self . tag ,
235225 }
236-
237- History { events : selected_events, created : self . created , tag : self . tag }
238226 }
239227}
240228
241229/// Failures that can occur during the execution of Tree Borrows procedures.
242230pub ( super ) struct TbError < ' node > {
243231 /// What failure occurred.
244232 pub error_kind : TransitionError ,
245- /// The byte at which the conflict occured .
246- pub error_offset : Size ,
233+ /// The offset (into the allocation) at which the conflict occurred .
234+ pub error_offset : u64 ,
247235 /// The tag on which the error was triggered.
248236 /// On protector violations, this is the tag that was protected.
249237 /// On accesses rejected due to insufficient permissions, this is the
@@ -261,12 +249,11 @@ impl TbError<'_> {
261249 /// Produce a UB error.
262250 pub fn build < ' tcx > ( self ) -> InterpError < ' tcx > {
263251 use TransitionError :: * ;
264- let started_as = self . conflicting_info . history . created . 1 ;
265252 let kind = self . access_kind ;
266253 let accessed = self . accessed_info ;
267254 let conflicting = self . conflicting_info ;
268255 let accessed_is_conflicting = accessed. tag == conflicting. tag ;
269- let ( pre_error , title, details, conflicting_tag_name) = match self . error_kind {
256+ let ( title, details, conflicting_tag_name) = match self . error_kind {
270257 ChildAccessForbidden ( perm) => {
271258 let conflicting_tag_name =
272259 if accessed_is_conflicting { "accessed" } else { "conflicting" } ;
@@ -280,7 +267,7 @@ impl TbError<'_> {
280267 details. push ( format ! (
281268 "the {conflicting_tag_name} tag {conflicting} has state {perm} which forbids child {kind}es"
282269 ) ) ;
283- ( perm , title, details, conflicting_tag_name)
270+ ( title, details, conflicting_tag_name)
284271 }
285272 ProtectedTransition ( transition) => {
286273 let conflicting_tag_name = "protected" ;
@@ -297,7 +284,7 @@ impl TbError<'_> {
297284 loss = transition. summary( ) ,
298285 ) ,
299286 ] ;
300- ( transition . started ( ) , title, details, conflicting_tag_name)
287+ ( title, details, conflicting_tag_name)
301288 }
302289 ProtectedDealloc => {
303290 let conflicting_tag_name = "strongly protected" ;
@@ -308,16 +295,15 @@ impl TbError<'_> {
308295 ) ,
309296 format!( "the {conflicting_tag_name} tag {conflicting} disallows deallocations" ) ,
310297 ] ;
311- ( started_as , title, details, conflicting_tag_name)
298+ ( title, details, conflicting_tag_name)
312299 }
313300 } ;
314- let pre_transition = PermTransition :: from ( started_as, pre_error) . unwrap ( ) ;
315301 let mut history = HistoryData :: default ( ) ;
316302 if !accessed_is_conflicting {
317303 history. extend ( self . accessed_info . history . forget ( ) , "accessed" , false ) ;
318304 }
319305 history. extend (
320- self . conflicting_info . history . extract_relevant ( pre_transition , self . error_offset ) ,
306+ self . conflicting_info . history . extract_relevant ( self . error_offset ) ,
321307 conflicting_tag_name,
322308 true ,
323309 ) ;
0 commit comments