-
Notifications
You must be signed in to change notification settings - Fork 394
Closed
Labels
A-aliasingArea: This affects the aliasing model (Stacked/Tree Borrows)Area: This affects the aliasing model (Stacked/Tree Borrows)C-supportCategory: Not necessarily a bug, but someone asking for supportCategory: Not necessarily a bug, but someone asking for support
Description
One of my tests recently started to fail under Miri with a stacked borrows violation error. I've now kind of minimised the test case but I don't really understand why it is a stacked borrow violation. For the test to fail, a custom global allocator is necessary. All the allocator does is zeroize memory on drop, and forward calls to the System
allocator.
#![deny(unsafe_op_in_unsafe_fn)]
use core::alloc::{GlobalAlloc, Layout};
use std::alloc::System;
/// # Safety
/// `ptr` must be valid for writes of `len` bytes
unsafe fn volatile_write_zeroize_mem(ptr: *mut u8, len: usize) {
for i in 0..len {
// ptr as usize + i can't overlow because `ptr` is valid for writes of `len`
let ptr_new: *mut u8 = ((ptr as usize) + i) as *mut u8;
// SAFETY: `ptr` is valid for writes of `len` bytes, so `ptr_new` is valid for a
// byte write
unsafe {
core::ptr::write_volatile(ptr_new, 0u8);
}
}
}
pub struct ZeroizeAlloc;
unsafe impl GlobalAlloc for ZeroizeAlloc {
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
// SAFETY: uphold by caller
unsafe { System.alloc(layout) }
}
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
// securely wipe the deallocated memory
// SAFETY: `ptr` is valid for writes of `layout.size()` bytes since it was
// previously successfully allocated (by the safety assumption on this function)
// and not yet deallocated
unsafe {
volatile_write_zeroize_mem(ptr, layout.size());
}
// SAFETY: uphold by caller
unsafe { System.dealloc(ptr, layout) }
}
unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
// SAFETY: uphold by caller
unsafe { System.alloc_zeroed(layout) }
}
}
#[global_allocator]
static GLOBAL: ZeroizeAlloc = ZeroizeAlloc;
fn main() {
let layout = Layout::new::<[u8; 16]>();
let ptr = unsafe { std::alloc::alloc_zeroed(layout) };
unsafe {
std::alloc::dealloc(ptr, layout);
}
}
Relevant fragment of the error:
error: Undefined Behavior: no item granting write access for deallocation to tag <3434> at alloc772 found in borrow stack
--> /home/niels/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys/unix/alloc.rs:42:9
|
42 | libc::free(ptr as *mut libc::c_void)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no item granting write access for deallocation to tag <3434> at alloc772 found in borrow stack
|
= help: this indicates a potential bug in the program: it performed an invalid operation, but the 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
= note: inside `std::sys::unix::alloc::<impl std::alloc::GlobalAlloc for std::alloc::System>::dealloc` at /home/niels/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys/unix/alloc.rs:42:9
note: inside `<ZeroizeAlloc as std::alloc::GlobalAlloc>::dealloc` at src/main.rs:37:18
--> src/main.rs:37:18
|
37 | unsafe { System.dealloc(ptr, layout) }
Full error log with pointer and allocation tracking (click to expand)
note: tracking was triggered
--> /home/niels/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys/unix/alloc.rs:14:13
|
14 | libc::malloc(layout.size()) as *mut u8
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ created allocation with id 772
|
= note: inside `std::sys::unix::alloc::<impl std::alloc::GlobalAlloc for std::alloc::System>::alloc` at /home/niels/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys/unix/alloc.rs:14:13
note: inside `<ZeroizeAlloc as std::alloc::GlobalAlloc>::alloc` at src/main.rs:25:18
--> src/main.rs:25:18
|
25 | unsafe { System.alloc(layout) }
| ^^^^^^^^^^^^^^^^^^^^
= note: inside `alloc::alloc::__rust_alloc` at src/main.rs:47:1
= note: inside `std::alloc::alloc` at /home/niels/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/alloc/src/alloc.rs:87:14
= note: inside `std::alloc::Global::alloc_impl` at /home/niels/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/alloc/src/alloc.rs:169:73
= note: inside `<std::alloc::Global as std::alloc::Allocator>::allocate` at /home/niels/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/alloc/src/alloc.rs:229:9
= note: inside `alloc::alloc::exchange_malloc` at /home/niels/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/alloc/src/alloc.rs:318:11
= note: inside `std::sys_common::thread_local_dtor::register_dtor_fallback` at /home/niels/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys_common/thread_local_dtor.rs:33:28
= note: inside `std::sys::unix::thread_local_dtor::register_dtor` at /home/niels/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys/unix/thread_local_dtor.rs:43:5
= note: inside `std::thread::__FastLocalKeyInner::<std::cell::RefCell<std::option::Option<std::sys_common::thread_info::ThreadInfo>>>::register_dtor` at /home/niels/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/thread/local.rs:577:17
= note: inside `std::sys_common::thread_info::THREAD_INFO::__getit` at /home/niels/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/thread/local.rs:220:29
= note: inside `std::thread::LocalKey::<std::cell::RefCell<std::option::Option<std::sys_common::thread_info::ThreadInfo>>>::try_with::<[closure@std::sys_common::thread_info::set::{closure#0}], ()>` at /home/niels/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/thread/local.rs:398:32
= note: inside `std::thread::LocalKey::<std::cell::RefCell<std::option::Option<std::sys_common::thread_info::ThreadInfo>>>::with::<[closure@std::sys_common::thread_info::set::{closure#0}], ()>` at /home/niels/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/thread/local.rs:375:9
= note: inside `std::sys_common::thread_info::set` at /home/niels/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys_common/thread_info.rs:42:5
= note: inside `std::rt::init` at /home/niels/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/rt.rs:86:9
= note: inside closure at /home/niels/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/rt.rs:127:42
= note: inside `std::panicking::r#try::do_call::<[closure@std::rt::lang_start_internal::{closure#1}], ()>` at /home/niels/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/panicking.rs:406:40
= note: inside `std::panicking::r#try::<(), [closure@std::rt::lang_start_internal::{closure#1}]>` at /home/niels/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/panicking.rs:370:19
= note: inside `std::panic::catch_unwind::<[closure@std::rt::lang_start_internal::{closure#1}], ()>` at /home/niels/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/panic.rs:133:14
= note: inside `std::rt::lang_start_internal` at /home/niels/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/rt.rs:127:5
= note: inside `std::rt::lang_start::<()>` at /home/niels/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/rt.rs:144:17
note: tracking was triggered
--> /home/niels/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys_common/thread_local_dtor.rs:41:35
|
41 | let list: Box<List> = Box::from_raw(ptr as *mut List);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ created tag 3434
|
= note: inside `std::sys_common::thread_local_dtor::register_dtor_fallback::run_dtors` at /home/niels/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys_common/thread_local_dtor.rs:41:35
note: tracking was triggered
--> /home/niels/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ptr/mod.rs:1128:9
|
1128 | intrinsics::volatile_store(dst, src);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ popped tracked tag for item [Unique for <3434>]
|
= note: inside `std::ptr::write_volatile::<u8>` at /home/niels/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ptr/mod.rs:1128:9
note: inside `volatile_write_zeroize_mem` at src/main.rs:15:13
--> src/main.rs:15:13
|
15 | core::ptr::write_volatile(ptr_new, 0u8);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: inside `<ZeroizeAlloc as std::alloc::GlobalAlloc>::dealloc` at src/main.rs:34:13
--> src/main.rs:34:13
|
34 | volatile_write_zeroize_mem(ptr, layout.size());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: inside `alloc::alloc::__rust_dealloc` at src/main.rs:47:1
= note: inside `std::alloc::dealloc` at /home/niels/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/alloc/src/alloc.rs:105:14
= note: inside `<std::alloc::Global as std::alloc::Allocator>::deallocate` at /home/niels/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/alloc/src/alloc.rs:242:22
= note: inside `alloc::alloc::box_free::<std::vec::Vec<(*mut u8, unsafe extern "C" fn(*mut u8))>, std::alloc::Global>` at /home/niels/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/alloc/src/alloc.rs:336:9
= note: inside `std::sys_common::thread_local_dtor::register_dtor_fallback::run_dtors` at /home/niels/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys_common/thread_local_dtor.rs:47:9
error: Undefined Behavior: no item granting write access for deallocation to tag <3434> at alloc772 found in borrow stack
--> /home/niels/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys/unix/alloc.rs:42:9
|
42 | libc::free(ptr as *mut libc::c_void)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no item granting write access for deallocation to tag <3434> at alloc772 found in borrow stack
|
= help: this indicates a potential bug in the program: it performed an invalid operation, but the 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
= note: inside `std::sys::unix::alloc::<impl std::alloc::GlobalAlloc for std::alloc::System>::dealloc` at /home/niels/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys/unix/alloc.rs:42:9
note: inside `<ZeroizeAlloc as std::alloc::GlobalAlloc>::dealloc` at src/main.rs:37:18
--> src/main.rs:37:18
|
37 | unsafe { System.dealloc(ptr, layout) }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: inside `alloc::alloc::__rust_dealloc` at src/main.rs:47:1
= note: inside `std::alloc::dealloc` at /home/niels/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/alloc/src/alloc.rs:105:14
= note: inside `<std::alloc::Global as std::alloc::Allocator>::deallocate` at /home/niels/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/alloc/src/alloc.rs:242:22
= note: inside `alloc::alloc::box_free::<std::vec::Vec<(*mut u8, unsafe extern "C" fn(*mut u8))>, std::alloc::Global>` at /home/niels/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/alloc/src/alloc.rs:336:9
= note: inside `std::sys_common::thread_local_dtor::register_dtor_fallback::run_dtors` at /home/niels/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys_common/thread_local_dtor.rs:47:9
error: aborting due to previous error
The strange thing is, when the volatile_write_zeroize_mem
call is moved from the dealloc
into main
(directly before the dealloc
) the example runs just fine.
Playground
Metadata
Metadata
Assignees
Labels
A-aliasingArea: This affects the aliasing model (Stacked/Tree Borrows)Area: This affects the aliasing model (Stacked/Tree Borrows)C-supportCategory: Not necessarily a bug, but someone asking for supportCategory: Not necessarily a bug, but someone asking for support