@@ -220,9 +220,10 @@ impl GlobalState {
220
220
}
221
221
222
222
/// Error reporting
223
- fn err_sb_ub ( msg : String ) -> InterpError < ' static > {
223
+ fn err_sb_ub ( msg : String , help : Option < String > ) -> InterpError < ' static > {
224
224
err_machine_stop ! ( TerminationInfo :: ExperimentalUb {
225
225
msg,
226
+ help,
226
227
url: format!(
227
228
"https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md"
228
229
) ,
@@ -320,12 +321,18 @@ impl<'tcx> Stack {
320
321
if let Some ( call) = item. protector {
321
322
if global. is_active ( call) {
322
323
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
+ ) ) ?
327
331
} 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
+ ) ) ?
329
336
}
330
337
}
331
338
}
@@ -334,22 +341,21 @@ impl<'tcx> Stack {
334
341
335
342
/// Test if a memory `access` using pointer tagged `tag` is granted.
336
343
/// If yes, return the index of the item that granted it.
344
+ /// `range` refers the entire operation, and `offset` refers to the specific offset into the
345
+ /// allocation that we are currently checking.
337
346
fn access (
338
347
& mut self ,
339
348
access : AccessKind ,
340
349
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
342
351
global : & GlobalState ,
343
352
) -> InterpResult < ' tcx > {
344
353
// Two main steps: Find granting item, remove incompatible items above.
345
354
346
355
// 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) ) ?;
353
359
354
360
// Step 2: Remove incompatible items above them. Make sure we do not remove protected
355
361
// items. Behavior differs for reads and writes.
@@ -389,15 +395,15 @@ impl<'tcx> Stack {
389
395
fn dealloc (
390
396
& mut self ,
391
397
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
393
399
global : & GlobalState ,
394
400
) -> InterpResult < ' tcx > {
395
401
// Step 1: Find granting item.
396
402
self . find_granting ( AccessKind :: Write , tag) . ok_or_else ( || {
397
403
err_sb_ub ( format ! (
398
404
"no item granting write access for deallocation to tag {:?} at {:?} found in borrow stack" ,
399
405
tag, dbg_ptr,
400
- ) )
406
+ ) , None )
401
407
} ) ?;
402
408
403
409
// Step 2: Remove all items. Also checks for protectors.
@@ -412,23 +418,23 @@ impl<'tcx> Stack {
412
418
/// `weak` controls whether this operation is weak or strong: weak granting does not act as
413
419
/// an access, and they add the new item directly on top of the one it is derived
414
420
/// 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.
415
423
fn grant (
416
424
& mut self ,
417
425
derived_from : SbTag ,
418
426
new : Item ,
419
- dbg_ptr : Pointer < AllocId > ,
427
+ ( alloc_id , alloc_range , offset ) : ( AllocId , AllocRange , Size ) , // just for debug printing and error messages
420
428
global : & GlobalState ,
421
429
) -> InterpResult < ' tcx > {
422
430
// Figure out which access `perm` corresponds to.
423
431
let access =
424
432
if new. perm . grants ( AccessKind :: Write ) { AccessKind :: Write } else { AccessKind :: Read } ;
425
433
// Now we figure out which item grants our parent (`derived_from`) this kind of access.
426
434
// 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) ) ?;
432
438
433
439
// Compute where to put the new item.
434
440
// Either way, we ensure that we insert the new item in a way such that between
@@ -447,7 +453,7 @@ impl<'tcx> Stack {
447
453
// A "safe" reborrow for a pointer that actually expects some aliasing guarantees.
448
454
// Here, creating a reference actually counts as an access.
449
455
// 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) ?;
451
457
452
458
// We insert "as far up as possible": We know only compatible items are remaining
453
459
// on top of `derived_from`, and we want the new item at the top so that we
@@ -467,6 +473,72 @@ impl<'tcx> Stack {
467
473
468
474
Ok ( ( ) )
469
475
}
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 {:?} for {:?} permission at {}[{:#x}]" ,
488
+ derived_from,
489
+ new. perm,
490
+ alloc_id,
491
+ error_offset. bytes( ) ,
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 {} using {:?} at {}[{:#x}]" ,
510
+ access,
511
+ tag,
512
+ alloc_id,
513
+ error_offset. bytes( ) ,
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 location"
538
+ } else {
539
+ ", but that tag does not exist in the borrow stack for this location"
540
+ }
541
+ }
470
542
}
471
543
// # Stacked Borrows Core End
472
544
@@ -566,7 +638,7 @@ impl Stacks {
566
638
) ;
567
639
let global = & * extra. borrow ( ) ;
568
640
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)
570
642
} )
571
643
}
572
644
@@ -586,7 +658,7 @@ impl Stacks {
586
658
) ;
587
659
let global = extra. get_mut ( ) ;
588
660
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)
590
662
} )
591
663
}
592
664
@@ -693,7 +765,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
693
765
} ;
694
766
let item = Item { perm, tag : new_tag, protector } ;
695
767
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)
697
769
} )
698
770
} ) ?;
699
771
return Ok ( ( ) ) ;
@@ -707,8 +779,9 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
707
779
alloc_extra. stacked_borrows . as_mut ( ) . expect ( "we should have Stacked Borrows data" ) ;
708
780
let global = memory_extra. stacked_borrows . as_mut ( ) . unwrap ( ) . get_mut ( ) ;
709
781
let item = Item { perm, tag : new_tag, protector } ;
782
+ let range = alloc_range ( base_offset, size) ;
710
783
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)
712
785
} ) ?;
713
786
Ok ( ( ) )
714
787
}
0 commit comments