A few weeks ago @Shnatsel reported zkat/miette#469 in miette. I noticed that the affected code was copied from eyre which in turn copied it from anyhow. Eyre already fixed it (eyre-rs/eyre@9f4ecc4) but anyhow still has the UB.
Adding this test to tests/test_context.rs,
#[test]
fn test_downcast_mut() {
let (mut err, dropped) = make_chain();
err.downcast_mut::<HighLevel>().unwrap().message = "high context";
err.downcast_mut::<MidLevel>().unwrap().message = "mid context";
err.downcast_mut::<LowLevel>().unwrap().message = "low error";
assert_eq!(err.downcast_ref::<HighLevel>().unwrap().message, "high context");
assert_eq!(err.downcast_ref::<MidLevel>().unwrap().message, "mid context");
assert_eq!(err.downcast_ref::<LowLevel>().unwrap().message, "low error");
assert!(dropped.none());
drop(err);
assert!(dropped.all());
}
and running cargo +nightly miri test --test test_context test_downcast_mut produces
error: Undefined Behavior: trying to retag from <135379> for Unique permission at alloc43804[0x38], but that tag only grants SharedReadOnly permission for this location
--> src/ptr.rs:170:18
|
170 | unsafe { &mut *self.ptr.as_ptr() }
| ^^^^^^^^^^^^^^^^^^^^^^^ this error occurs as part of retag at alloc43804[0x38..0x50]
|
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental
= help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information
help: <135379> was created by a SharedReadOnly retag at offsets [0x38..0x50]
--> src/ptr.rs:89:18
|
89 | ptr: NonNull::from(ptr),
| ^^^^^^^^^^^^^^^^^^
= note: this is on thread `test_downcast_m`
= note: stack backtrace:
0: anyhow::ptr::Mut::<'_, HighLevel>::deref_mut
at src/ptr.rs:170:18: 170:41
1: anyhow::error::<impl anyhow::Error>::downcast_mut::<HighLevel>
at src/error.rs:560:18: 560:46
2: test_downcast_mut
at tests/test_context.rs:124:5: 124:36
3: test_downcast_mut::{closure#0}
at tests/test_context.rs:121:23: 121:23
The diagnosis and fix is basically the same as for the other crates. The guilty code is
|
let addr = |
|
(vtable(self.inner.ptr).object_downcast)(self.inner.by_ref(), target)?.by_mut(); |
which coerces a
&T into a
&mut T. The fix is to extend the vtable with an
object_downcast_mut function which can avoid creating shared references and be used here.
A few weeks ago @Shnatsel reported zkat/miette#469 in miette. I noticed that the affected code was copied from eyre which in turn copied it from anyhow. Eyre already fixed it (eyre-rs/eyre@9f4ecc4) but anyhow still has the UB.
Adding this test to
tests/test_context.rs,and running
cargo +nightly miri test --test test_context test_downcast_mutproducesThe diagnosis and fix is basically the same as for the other crates. The guilty code is
anyhow/src/error.rs
Lines 558 to 559 in 917a169
&Tinto a&mut T. The fix is to extend the vtable with anobject_downcast_mutfunction which can avoid creating shared references and be used here.