Skip to content

Commit 7b55507

Browse files
committed
fix ICE on deallocation error and avoid redundant find_granting on retag
1 parent 9056df4 commit 7b55507

File tree

5 files changed

+68
-22
lines changed

5 files changed

+68
-22
lines changed

src/stacked_borrows/diagnostics.rs

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -373,10 +373,12 @@ impl<'span, 'history, 'ecx, 'mir, 'tcx> DiagnosticCx<'span, 'history, 'ecx, 'mir
373373

374374
/// Report a descriptive error when `new` could not be granted from `derived_from`.
375375
#[inline(never)] // This is only called on fatal code paths
376-
pub(super) fn grant_error(&self, perm: Permission, stack: &Stack) -> InterpError<'tcx> {
376+
pub(super) fn grant_error(&self, stack: &Stack) -> InterpError<'tcx> {
377377
let Operation::Retag(op) = &self.operation else {
378378
unreachable!("grant_error should only be called during a retag")
379379
};
380+
let perm =
381+
op.permission.expect("`start_grant` must be called before calling `grant_error`");
380382
let action = format!(
381383
"trying to retag from {:?} for {:?} permission at {:?}[{:#x}]",
382384
op.orig_tag,
@@ -394,8 +396,11 @@ impl<'span, 'history, 'ecx, 'mir, 'tcx> DiagnosticCx<'span, 'history, 'ecx, 'mir
394396
/// Report a descriptive error when `access` is not permitted based on `tag`.
395397
#[inline(never)] // This is only called on fatal code paths
396398
pub(super) fn access_error(&self, stack: &Stack) -> InterpError<'tcx> {
397-
let Operation::Access(op) = &self.operation else {
398-
unreachable!("access_error should only be called during an access")
399+
// Deallocation and retagging also do an access as part of their thing, so handle that here, too.
400+
let op = match &self.operation {
401+
Operation::Access(op) => op,
402+
Operation::Retag(_) => return self.grant_error(stack),
403+
Operation::Dealloc(_) => return self.dealloc_error(stack),
399404
};
400405
let action = format!(
401406
"attempting a {access} using {tag:?} at {alloc_id:?}[{offset:#x}]",
@@ -447,14 +452,16 @@ impl<'span, 'history, 'ecx, 'mir, 'tcx> DiagnosticCx<'span, 'history, 'ecx, 'mir
447452
}
448453

449454
#[inline(never)] // This is only called on fatal code paths
450-
pub fn dealloc_error(&self) -> InterpError<'tcx> {
455+
pub fn dealloc_error(&self, stack: &Stack) -> InterpError<'tcx> {
451456
let Operation::Dealloc(op) = &self.operation else {
452457
unreachable!("dealloc_error should only be called during a deallocation")
453458
};
454459
err_sb_ub(
455460
format!(
456-
"no item granting write access for deallocation to tag {:?} at {:?} found in borrow stack",
457-
op.tag, self.history.id,
461+
"attemtping deallocation using {tag:?} at {alloc_id:?}{cause}",
462+
tag = op.tag,
463+
alloc_id = self.history.id,
464+
cause = error_cause(stack, op.tag),
458465
),
459466
None,
460467
op.tag.and_then(|tag| self.get_logs_relevant_to(tag, None)),

src/stacked_borrows/mod.rs

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -476,8 +476,7 @@ impl<'tcx> Stack {
476476
) -> InterpResult<'tcx> {
477477
// Step 1: Make a write access.
478478
// As part of this we do regular protector checking, i.e. even weakly protected items cause UB when popped.
479-
self.access(AccessKind::Write, tag, global, dcx, exposed_tags)
480-
.map_err(|_| dcx.dealloc_error())?;
479+
self.access(AccessKind::Write, tag, global, dcx, exposed_tags)?;
481480

482481
// Step 2: Pretend we remove the remaining items, checking if any are strongly protected.
483482
for idx in (0..self.len()).rev() {
@@ -509,10 +508,6 @@ impl<'tcx> Stack {
509508
// Simple case: We are just a regular memory access, and then push our thing on top,
510509
// like a regular stack.
511510
// This ensures F2b for `Unique`, by removing offending `SharedReadOnly`.
512-
// FIXME: we are calling `find_granting` first since `access` will otherwise ICE in `dcx.access_error`...
513-
let _granting_idx = self
514-
.find_granting(access, derived_from, exposed_tags)
515-
.map_err(|()| dcx.grant_error(new.perm(), self))?;
516511
self.access(access, derived_from, global, dcx, exposed_tags)?;
517512

518513
// We insert "as far up as possible": We know only compatible items are remaining
@@ -528,7 +523,7 @@ impl<'tcx> Stack {
528523
// We use that to determine where to put the new item.
529524
let granting_idx = self
530525
.find_granting(AccessKind::Write, derived_from, exposed_tags)
531-
.map_err(|()| dcx.grant_error(new.perm(), self))?;
526+
.map_err(|()| dcx.grant_error(self))?;
532527

533528
let (Some(granting_idx), ProvenanceExtra::Concrete(_)) = (granting_idx, derived_from) else {
534529
// The parent is a wildcard pointer or matched the unknown bottom.
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
//@error-pattern: /deallocation .* tag does not exist in the borrow stack/
2+
use std::alloc::{alloc, dealloc, Layout};
3+
4+
fn main() {
5+
unsafe {
6+
let x = alloc(Layout::from_size_align_unchecked(1, 1));
7+
let ptr1 = (&mut *x) as *mut u8;
8+
let ptr2 = (&mut *ptr1) as *mut u8;
9+
// Invalidate ptr2 by writing to ptr1.
10+
ptr1.write(0);
11+
// Deallocate through ptr2.
12+
dealloc(ptr2, Layout::from_size_align_unchecked(1, 1));
13+
}
14+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
error: Undefined Behavior: attemtping deallocation using <TAG> at ALLOC, but that tag does not exist in the borrow stack for this location
2+
--> RUSTLIB/alloc/src/alloc.rs:LL:CC
3+
|
4+
LL | unsafe { __rust_dealloc(ptr, layout.size(), layout.align()) }
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attemtping deallocation using <TAG> at ALLOC, but that tag does not exist in the borrow stack for this location
6+
|
7+
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental
8+
= help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information
9+
help: <TAG> was created by a SharedReadWrite retag at offsets [0x0..0x1]
10+
--> $DIR/illegal_deALLOC.rs:LL:CC
11+
|
12+
LL | let ptr2 = (&mut *ptr1) as *mut u8;
13+
| ^^^^^^^^^^^^
14+
help: <TAG> was later invalidated at offsets [0x0..0x1] by a write access
15+
--> $DIR/illegal_deALLOC.rs:LL:CC
16+
|
17+
LL | ptr1.write(0);
18+
| ^^^^^^^^^^^^^
19+
= note: BACKTRACE:
20+
= note: inside `std::alloc::dealloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC
21+
note: inside `main` at $DIR/illegal_deALLOC.rs:LL:CC
22+
--> $DIR/illegal_deALLOC.rs:LL:CC
23+
|
24+
LL | dealloc(ptr2, Layout::from_size_align_unchecked(1, 1));
25+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
26+
27+
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
28+
29+
error: aborting due to previous error
30+

tests/fail/stacked_borrows/notunpin_dereferenceable_fakeread.stderr

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,24 @@
11
error: Undefined Behavior: attempting a write access using <TAG> at ALLOC[0x0], but that tag does not exist in the borrow stack for this location
22
--> $DIR/notunpin_dereferenceable_fakeread.rs:LL:CC
33
|
4-
LL | *fieldref = 0;
5-
| ^^^^^^^^^^^^^
6-
| |
7-
| attempting a write access using <TAG> at ALLOC[0x0], but that tag does not exist in the borrow stack for this location
8-
| this error occurs as part of an access at ALLOC[0x0..0x4]
4+
LL | *fieldref = 0;
5+
| ^^^^^^^^^^^^^
6+
| |
7+
| attempting a write access using <TAG> at ALLOC[0x0], but that tag does not exist in the borrow stack for this location
8+
| this error occurs as part of an access at ALLOC[0x0..0x4]
99
|
1010
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental
1111
= help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information
1212
help: <TAG> was created by a Unique retag at offsets [0x0..0x4]
1313
--> $DIR/notunpin_dereferenceable_fakeread.rs:LL:CC
1414
|
15-
LL | let fieldref = &mut *(&mut x.0 as *mut i32);
16-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
15+
LL | let fieldref = &mut *(&mut x.0 as *mut i32);
16+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1717
help: <TAG> was later invalidated at offsets [0x0..0x4] by a SharedReadWrite retag
1818
--> $DIR/notunpin_dereferenceable_fakeread.rs:LL:CC
1919
|
20-
LL | let _xref = &mut x;
21-
| ^^^^^^
20+
LL | let _xref = &mut x;
21+
| ^^^^^^
2222
= note: BACKTRACE:
2323
= note: inside `main` at $DIR/notunpin_dereferenceable_fakeread.rs:LL:CC
2424

0 commit comments

Comments
 (0)