@@ -220,9 +220,10 @@ impl GlobalState {
220220}
221221
222222/// Error reporting
223- fn err_sb_ub ( msg : String ) -> InterpError < ' static > {
223+ fn err_sb_ub ( msg : String , help : Option < String > ) -> InterpError < ' static > {
224224 err_machine_stop ! ( TerminationInfo :: ExperimentalUb {
225225 msg,
226+ help,
226227 url: format!(
227228 "https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md"
228229 ) ,
@@ -320,12 +321,18 @@ impl<'tcx> Stack {
320321 if let Some ( call) = item. protector {
321322 if global. is_active ( call) {
322323 if let Some ( ( tag, _) ) = provoking_access {
323- Err ( err_sb_ub ( format ! (
324- "not granting access to tag {:?} because incompatible item is protected: {:?}" ,
325- tag, item
326- ) ) ) ?
324+ Err ( err_sb_ub (
325+ format ! (
326+ "not granting access to tag {:?} because incompatible item is protected: {:?}" ,
327+ tag, item
328+ ) ,
329+ None ,
330+ ) ) ?
327331 } else {
328- Err ( err_sb_ub ( format ! ( "deallocating while item is protected: {:?}" , item) ) ) ?
332+ Err ( err_sb_ub (
333+ format ! ( "deallocating while item is protected: {:?}" , item) ,
334+ None ,
335+ ) ) ?
329336 }
330337 }
331338 }
@@ -334,22 +341,21 @@ impl<'tcx> Stack {
334341
335342 /// Test if a memory `access` using pointer tagged `tag` is granted.
336343 /// If yes, return the index of the item that granted it.
344+ /// `range` refers the entire operation, and `offset` refers to the specific location in
345+ /// `range` that we are currently checking.
337346 fn access (
338347 & mut self ,
339348 access : AccessKind ,
340349 tag : SbTag ,
341- dbg_ptr : Pointer < AllocId > , // just for debug printing amd error messages
350+ ( alloc_id , range , offset ) : ( AllocId , AllocRange , Size ) , // just for debug printing and error messages
342351 global : & GlobalState ,
343352 ) -> InterpResult < ' tcx > {
344353 // Two main steps: Find granting item, remove incompatible items above.
345354
346355 // Step 1: Find granting item.
347- let granting_idx = self . find_granting ( access, tag) . ok_or_else ( || {
348- err_sb_ub ( format ! (
349- "no item granting {} to tag {:?} at {:?} found in borrow stack." ,
350- access, tag, dbg_ptr,
351- ) )
352- } ) ?;
356+ let granting_idx = self
357+ . find_granting ( access, tag)
358+ . ok_or_else ( || self . access_error ( access, tag, alloc_id, range, offset) ) ?;
353359
354360 // Step 2: Remove incompatible items above them. Make sure we do not remove protected
355361 // items. Behavior differs for reads and writes.
@@ -389,15 +395,15 @@ impl<'tcx> Stack {
389395 fn dealloc (
390396 & mut self ,
391397 tag : SbTag ,
392- dbg_ptr : Pointer < AllocId > , // just for debug printing amd error messages
398+ dbg_ptr : Pointer < AllocId > , // just for debug printing and error messages
393399 global : & GlobalState ,
394400 ) -> InterpResult < ' tcx > {
395401 // Step 1: Find granting item.
396402 self . find_granting ( AccessKind :: Write , tag) . ok_or_else ( || {
397403 err_sb_ub ( format ! (
398404 "no item granting write access for deallocation to tag {:?} at {:?} found in borrow stack" ,
399405 tag, dbg_ptr,
400- ) )
406+ ) , None )
401407 } ) ?;
402408
403409 // Step 2: Remove all items. Also checks for protectors.
@@ -412,23 +418,23 @@ impl<'tcx> Stack {
412418 /// `weak` controls whether this operation is weak or strong: weak granting does not act as
413419 /// an access, and they add the new item directly on top of the one it is derived
414420 /// from instead of all the way at the top of the stack.
421+ /// `range` refers the entire operation, and `offset` refers to the specific location in
422+ /// `range` that we are currently checking.
415423 fn grant (
416424 & mut self ,
417425 derived_from : SbTag ,
418426 new : Item ,
419- dbg_ptr : Pointer < AllocId > ,
427+ ( alloc_id , alloc_range , offset ) : ( AllocId , AllocRange , Size ) , // just for debug printing and error messages
420428 global : & GlobalState ,
421429 ) -> InterpResult < ' tcx > {
422430 // Figure out which access `perm` corresponds to.
423431 let access =
424432 if new. perm . grants ( AccessKind :: Write ) { AccessKind :: Write } else { AccessKind :: Read } ;
425433 // Now we figure out which item grants our parent (`derived_from`) this kind of access.
426434 // We use that to determine where to put the new item.
427- let granting_idx = self . find_granting ( access, derived_from)
428- . ok_or_else ( || err_sb_ub ( format ! (
429- "trying to reborrow for {:?} at {:?}, but parent tag {:?} does not have an appropriate item in the borrow stack" ,
430- new. perm, dbg_ptr, derived_from,
431- ) ) ) ?;
435+ let granting_idx = self
436+ . find_granting ( access, derived_from)
437+ . ok_or_else ( || self . grant_error ( derived_from, new, alloc_id, alloc_range, offset) ) ?;
432438
433439 // Compute where to put the new item.
434440 // Either way, we ensure that we insert the new item in a way such that between
@@ -447,7 +453,7 @@ impl<'tcx> Stack {
447453 // A "safe" reborrow for a pointer that actually expects some aliasing guarantees.
448454 // Here, creating a reference actually counts as an access.
449455 // This ensures F2b for `Unique`, by removing offending `SharedReadOnly`.
450- self . access ( access, derived_from, dbg_ptr , global) ?;
456+ self . access ( access, derived_from, ( alloc_id , alloc_range , offset ) , global) ?;
451457
452458 // We insert "as far up as possible": We know only compatible items are remaining
453459 // on top of `derived_from`, and we want the new item at the top so that we
@@ -467,6 +473,72 @@ impl<'tcx> Stack {
467473
468474 Ok ( ( ) )
469475 }
476+
477+ /// Report a descriptive error when `new` could not be granted from `derived_from`.
478+ fn grant_error (
479+ & self ,
480+ derived_from : SbTag ,
481+ new : Item ,
482+ alloc_id : AllocId ,
483+ alloc_range : AllocRange ,
484+ error_offset : Size ,
485+ ) -> InterpError < ' static > {
486+ let action = format ! (
487+ "trying to reborrow {:?}[{:#x}] with {:?} permission via tag {:?}" ,
488+ alloc_id,
489+ error_offset. bytes( ) ,
490+ new. perm,
491+ derived_from,
492+ ) ;
493+ err_sb_ub (
494+ format ! ( "{}{}" , action, self . error_cause( derived_from) ) ,
495+ Some ( Self :: operation_summary ( "a reborrow" , alloc_id, alloc_range) ) ,
496+ )
497+ }
498+
499+ /// Report a descriptive error when `access` is not permitted based on `tag`.
500+ fn access_error (
501+ & self ,
502+ access : AccessKind ,
503+ tag : SbTag ,
504+ alloc_id : AllocId ,
505+ alloc_range : AllocRange ,
506+ error_offset : Size ,
507+ ) -> InterpError < ' static > {
508+ let action = format ! (
509+ "attempting a {} at {}[{:#x}] via tag {:?}" ,
510+ access,
511+ alloc_id,
512+ error_offset. bytes( ) ,
513+ tag,
514+ ) ;
515+ err_sb_ub (
516+ format ! ( "{}{}" , action, self . error_cause( tag) ) ,
517+ Some ( Self :: operation_summary ( "an access" , alloc_id, alloc_range) ) ,
518+ )
519+ }
520+
521+ fn operation_summary (
522+ operation : & ' static str ,
523+ alloc_id : AllocId ,
524+ alloc_range : AllocRange ,
525+ ) -> String {
526+ format ! (
527+ "this error occurs as part of {} at {:?}[{:#x}..{:#x}]" ,
528+ operation,
529+ alloc_id,
530+ alloc_range. start. bytes( ) ,
531+ alloc_range. end( ) . bytes( )
532+ )
533+ }
534+
535+ fn error_cause ( & self , tag : SbTag ) -> & ' static str {
536+ if self . borrows . iter ( ) . any ( |item| item. tag == tag && item. perm != Permission :: Disabled ) {
537+ ", but that tag only grants SharedReadOnly permission for this memory"
538+ } else {
539+ ", but that tag does not exist in the borrow stack for this memory"
540+ }
541+ }
470542}
471543// # Stacked Borrows Core End
472544
@@ -566,7 +638,7 @@ impl Stacks {
566638 ) ;
567639 let global = & * extra. borrow ( ) ;
568640 self . for_each ( range, move |offset, stack| {
569- stack. access ( AccessKind :: Read , tag, Pointer :: new ( alloc_id, offset) , global)
641+ stack. access ( AccessKind :: Read , tag, ( alloc_id, range , offset) , global)
570642 } )
571643 }
572644
@@ -586,7 +658,7 @@ impl Stacks {
586658 ) ;
587659 let global = extra. get_mut ( ) ;
588660 self . for_each_mut ( range, move |offset, stack| {
589- stack. access ( AccessKind :: Write , tag, Pointer :: new ( alloc_id, offset) , global)
661+ stack. access ( AccessKind :: Write , tag, ( alloc_id, range , offset) , global)
590662 } )
591663 }
592664
@@ -693,7 +765,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
693765 } ;
694766 let item = Item { perm, tag : new_tag, protector } ;
695767 stacked_borrows. for_each ( range, |offset, stack| {
696- stack. grant ( orig_tag, item, Pointer :: new ( alloc_id, offset) , & * global)
768+ stack. grant ( orig_tag, item, ( alloc_id, range , offset) , & * global)
697769 } )
698770 } ) ?;
699771 return Ok ( ( ) ) ;
@@ -707,8 +779,9 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
707779 alloc_extra. stacked_borrows . as_mut ( ) . expect ( "we should have Stacked Borrows data" ) ;
708780 let global = memory_extra. stacked_borrows . as_mut ( ) . unwrap ( ) . get_mut ( ) ;
709781 let item = Item { perm, tag : new_tag, protector } ;
782+ let range = alloc_range ( base_offset, size) ;
710783 stacked_borrows. for_each_mut ( alloc_range ( base_offset, size) , |offset, stack| {
711- stack. grant ( orig_tag, item, Pointer :: new ( alloc_id, offset) , global)
784+ stack. grant ( orig_tag, item, ( alloc_id, range , offset) , global)
712785 } ) ?;
713786 Ok ( ( ) )
714787 }
0 commit comments