-
Notifications
You must be signed in to change notification settings - Fork 9
Description
To make sure that there are no more issues like #3 in this crate, I decided to run its test suite in Miri. Unfortunately, that fails:
Miri backtrace
note: popped tracked tag for item [Unique for <277770> (call 232767)]
--> src/ring_buffer/mod.rs:100:9
|
100 | (&mut self.data as *mut _ as *mut A).add(index.to_usize())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ popped tracked tag for item [Unique for <277770> (call 232767)]
|
note: inside call to `ring_buffer::RingBuffer::<i32>::mut_ptr` at src/ring_buffer/iter.rs:84:33
--> src/ring_buffer/iter.rs:84:33
|
84 | Some(unsafe { &mut *self.buffer.mut_ptr(self.left_index.inc()) })
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: inside call to `<ring_buffer::iter::IterMut<i32, typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UTerm, typenum::bit::B1>, typenum::bit::B0>, typenum::bit::B0>, typenum::bit::B0>, typenum::bit::B0>, typenum::bit::B0>, typenum::bit::B0>> as std::iter::Iterator>::next` at /home/r/.rustup/toolchains/miri/lib/rustlib/src/rust/src/liballoc/vec.rs:2138:35
= note: inside call to `std::vec::Vec::<&mut i32>::extend_desugared::<ring_buffer::iter::IterMut<i32, typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UTerm, typenum::bit::B1>, typenum::bit::B0>, typenum::bit::B0>, typenum::bit::B0>, typenum::bit::B0>, typenum::bit::B0>, typenum::bit::B0>>>` at /home/r/.rustup/toolchains/miri/lib/rustlib/src/rust/src/liballoc/vec.rs:2031:9
= note: inside call to `<std::vec::Vec<&mut i32> as std::vec::SpecExtend<&mut i32, ring_buffer::iter::IterMut<i32, typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UTerm, typenum::bit::B1>, typenum::bit::B0>, typenum::bit::B0>, typenum::bit::B0>, typenum::bit::B0>, typenum::bit::B0>, typenum::bit::B0>>>>::spec_extend` at /home/r/.rustup/toolchains/miri/lib/rustlib/src/rust/src/liballoc/vec.rs:2026:9
= note: inside call to `<std::vec::Vec<&mut i32> as std::vec::SpecExtend<&mut i32, ring_buffer::iter::IterMut<i32, typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UTerm, typenum::bit::B1>, typenum::bit::B0>, typenum::bit::B0>, typenum::bit::B0>, typenum::bit::B0>, typenum::bit::B0>, typenum::bit::B0>>>>::from_iter` at /home/r/.rustup/toolchains/miri/lib/rustlib/src/rust/src/liballoc/vec.rs:1926:9
= note: inside call to `<std::vec::Vec<&mut i32> as std::iter::FromIterator<&mut i32>>::from_iter::<ring_buffer::iter::IterMut<i32, typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UTerm, typenum::bit::B1>, typenum::bit::B0>, typenum::bit::B0>, typenum::bit::B0>, typenum::bit::B0>, typenum::bit::B0>, typenum::bit::B0>>>` at /home/r/.rustup/toolchains/miri/lib/rustlib/src/rust/src/libcore/iter/traits/iterator.rs:1659:9
note: inside call to `<ring_buffer::iter::IterMut<i32, typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UTerm, typenum::bit::B1>, typenum::bit::B0>, typenum::bit::B0>, typenum::bit::B0>, typenum::bit::B0>, typenum::bit::B0>, typenum::bit::B0>> as std::iter::Iterator>::collect::<std::vec::Vec<&mut i32>>` at src/ring_buffer/mod.rs:1068:38
--> src/ring_buffer/mod.rs:1068:38
|
1068 | let out_vec: Vec<&mut i32> = chunk.iter_mut().collect();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
note: inside call to `ring_buffer::test::mut_ref_iter` at src/ring_buffer/mod.rs:1066:5
--> src/ring_buffer/mod.rs:1066:5
|
1066 | / fn mut_ref_iter() {
1067 | | let mut chunk: RingBuffer<i32> = (0..64).collect();
1068 | | let out_vec: Vec<&mut i32> = chunk.iter_mut().collect();
1069 | | let mut should_vec_p: Vec<i32> = (0..64).collect();
1070 | | let should_vec: Vec<&mut i32> = should_vec_p.iter_mut().collect();
1071 | | assert_eq!(should_vec, out_vec);
1072 | | }
| |_____^
= note: inside call to closure at /home/r/.rustup/toolchains/miri/lib/rustlib/src/rust/src/libcore/ops/function.rs:232:5
= note: inside call to `<[closure@src/ring_buffer/mod.rs:1066:5: 1072:6] as std::ops::FnOnce<()>>::call_once - shim` at /home/r/.rustup/toolchains/miri/lib/rustlib/src/rust/src/libcore/ops/function.rs:232:5
= note: inside call to `<fn() as std::ops::FnOnce<()>>::call_once - shim(fn())` at /home/r/.rustup/toolchains/miri/lib/rustlib/src/rust/src/libtest/lib.rs:518:5
= note: inside call to `test::__rust_begin_short_backtrace::<fn()>` at /home/r/.rustup/toolchains/miri/lib/rustlib/src/rust/src/libtest/lib.rs:509:30
= note: inside call to closure at /home/r/.rustup/toolchains/miri/lib/rustlib/src/rust/src/libcore/ops/function.rs:232:5
= note: inside call to `<[closure@DefId(46:631 ~ test[7b6d]::run_test[0]::{{closure}}[2]) 0:fn()] as std::ops::FnOnce<()>>::call_once - shim(vtable)` at /home/r/.rustup/toolchains/miri/lib/rustlib/src/rust/src/liballoc/boxed.rs:1017:9
= note: inside call to `<std::boxed::Box<dyn std::ops::FnOnce() + std::marker::Send> as std::ops::FnOnce<()>>::call_once` at /home/r/.rustup/toolchains/miri/lib/rustlib/src/rust/src/libstd/panic.rs:318:9
= note: inside call to `<std::panic::AssertUnwindSafe<std::boxed::Box<dyn std::ops::FnOnce() + std::marker::Send>> as std::ops::FnOnce<()>>::call_once` at /home/r/.rustup/toolchains/miri/lib/rustlib/src/rust/src/libstd/panicking.rs:331:40
= note: inside call to `std::panicking::r#try::do_call::<std::panic::AssertUnwindSafe<std::boxed::Box<dyn std::ops::FnOnce() + std::marker::Send>>, ()>` at /home/r/.rustup/toolchains/miri/lib/rustlib/src/rust/src/libstd/panicking.rs:274:15
= note: inside call to `std::panicking::r#try::<(), std::panic::AssertUnwindSafe<std::boxed::Box<dyn std::ops::FnOnce() + std::marker::Send>>>` at /home/r/.rustup/toolchains/miri/lib/rustlib/src/rust/src/libstd/panic.rs:394:14
= note: inside call to `std::panic::catch_unwind::<std::panic::AssertUnwindSafe<std::boxed::Box<dyn std::ops::FnOnce() + std::marker::Send>>, ()>` at /home/r/.rustup/toolchains/miri/lib/rustlib/src/rust/src/libtest/lib.rs:542:18
= note: inside call to `test::run_test_in_process` at /home/r/.rustup/toolchains/miri/lib/rustlib/src/rust/src/libtest/lib.rs:451:39
= note: inside call to closure at /home/r/.rustup/toolchains/miri/lib/rustlib/src/rust/src/libtest/lib.rs:476:13
= note: inside call to `test::run_test::run_test_inner` at /home/r/.rustup/toolchains/miri/lib/rustlib/src/rust/src/libtest/lib.rs:506:28
= note: inside call to `test::run_test` at /home/r/.rustup/toolchains/miri/lib/rustlib/src/rust/src/libtest/lib.rs:285:13
= note: inside call to `test::run_tests::<[closure@DefId(46:230 ~ test[7b6d]::console[0]::run_tests_console[0]::{{closure}}[2]) 0:&mut test::console::ConsoleTestState, 1:&mut std::boxed::Box<dyn test::formatters::OutputFormatter>]>` at /home/r/.rustup/toolchains/miri/lib/rustlib/src/rust/src/libtest/console.rs:280:5
= note: inside call to `test::run_tests_console` at /home/r/.rustup/toolchains/miri/lib/rustlib/src/rust/src/libtest/lib.rs:121:15
= note: inside call to `test::test_main` at /home/r/.rustup/toolchains/miri/lib/rustlib/src/rust/src/libtest/lib.rs:140:5
= note: inside call to `test::test_main_static`
= note: inside call to `main` at /home/r/.rustup/toolchains/miri/lib/rustlib/src/rust/src/libstd/rt.rs:67:34
= note: inside call to closure at /home/r/.rustup/toolchains/miri/lib/rustlib/src/rust/src/libstd/rt.rs:52:73
= note: inside call to closure at /home/r/.rustup/toolchains/miri/lib/rustlib/src/rust/src/libstd/sys_common/backtrace.rs:130:5
= note: inside call to `std::sys_common::backtrace::__rust_begin_short_backtrace::<[closure@DefId(1:6041 ~ std[e04c]::rt[0]::lang_start_internal[0]::{{closure}}[0]::{{closure}}[0]) 0:&dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe], i32>` at /home/r/.rustup/toolchains/miri/lib/rustlib/src/rust/src/libstd/rt.rs:52:13
= note: inside call to closure at /home/r/.rustup/toolchains/miri/lib/rustlib/src/rust/src/libstd/panicking.rs:331:40
= note: inside call to `std::panicking::r#try::do_call::<[closure@DefId(1:6040 ~ std[e04c]::rt[0]::lang_start_internal[0]::{{closure}}[0]) 0:&&dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe], i32>` at /home/r/.rustup/toolchains/miri/lib/rustlib/src/rust/src/libstd/panicking.rs:274:15
= note: inside call to `std::panicking::r#try::<i32, [closure@DefId(1:6040 ~ std[e04c]::rt[0]::lang_start_internal[0]::{{closure}}[0]) 0:&&dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe]>` at /home/r/.rustup/toolchains/miri/lib/rustlib/src/rust/src/libstd/panic.rs:394:14
= note: inside call to `std::panic::catch_unwind::<[closure@DefId(1:6040 ~ std[e04c]::rt[0]::lang_start_internal[0]::{{closure}}[0]) 0:&&dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe], i32>` at /home/r/.rustup/toolchains/miri/lib/rustlib/src/rust/src/libstd/rt.rs:51:25
= note: inside call to `std::rt::lang_start_internal` at /home/r/.rustup/toolchains/miri/lib/rustlib/src/rust/src/libstd/rt.rs:67:5
= note: inside call to `std::rt::lang_start::<()>`
= note: this note originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info)
error: Miri evaluation error: trying to reborrow for SharedReadOnly, but parent tag <277770> does not have an appropriate item in the borrow stack
--> /home/r/.rustup/toolchains/miri/lib/rustlib/src/rust/src/libcore/cmp.rs:1274:34
|
1274 | PartialEq::eq(*self, *other)
| ^^^^^^ trying to reborrow for SharedReadOnly, but parent tag <277770> does not have an appropriate item in the borrow stack
|
= note: inside call to `std::cmp::impls::<impl std::cmp::PartialEq for &mut i32>::eq` at /home/r/.rustup/toolchains/miri/lib/rustlib/src/rust/src/libcore/cmp.rs:1219:13
= note: inside call to `std::cmp::impls::<impl std::cmp::PartialEq for &&mut i32>::eq` at /home/r/.rustup/toolchains/miri/lib/rustlib/src/rust/src/libcore/slice/mod.rs:5820:52
= note: inside call to closure at /home/r/.rustup/toolchains/miri/lib/rustlib/src/rust/src/libcore/iter/traits/iterator.rs:2054:20
= note: inside call to closure at /home/r/.rustup/toolchains/miri/lib/rustlib/src/rust/src/libcore/iter/traits/iterator.rs:1877:21
= note: inside call to `<std::iter::Zip<std::slice::Iter<&mut i32>, std::slice::Iter<&mut i32>> as std::iter::Iterator>::try_fold::<(), [closure@DefId(2:4889 ~ core[4ac7]::iter[0]::traits[0]::iterator[0]::Iterator[0]::all[0]::check[0]::{{closure}}[0]) 0:[closure@DefId(2:7242 ~ core[4ac7]::slice[0]::{{impl}}[128]::equal[0]::{{closure}}[0])]], std::iter::LoopState<(), ()>>` at /home/r/.rustup/toolchains/miri/lib/rustlib/src/rust/src/libcore/iter/traits/iterator.rs:2057:9
= note: inside call to `<std::iter::Zip<std::slice::Iter<&mut i32>, std::slice::Iter<&mut i32>> as std::iter::Iterator>::all::<[closure@DefId(2:7242 ~ core[4ac7]::slice[0]::{{impl}}[128]::equal[0]::{{closure}}[0])]>` at /home/r/.rustup/toolchains/miri/lib/rustlib/src/rust/src/libcore/slice/mod.rs:5820:9
= note: inside call to `<[&mut i32] as core::slice::SlicePartialEq<&mut i32>>::equal` at /home/r/.rustup/toolchains/miri/lib/rustlib/src/rust/src/libcore/slice/mod.rs:5755:9
= note: inside call to `core::slice::<impl std::cmp::PartialEq for [&mut i32]>::eq` at /home/r/.rustup/toolchains/miri/lib/rustlib/src/rust/src/liballoc/vec.rs:2278:50
note: inside call to `<std::vec::Vec<&mut i32> as std::cmp::PartialEq>::eq` at /home/r/.rustup/toolchains/miri/lib/rustlib/src/rust/src/libcore/macros/mod.rs:70:21
--> src/ring_buffer/mod.rs:1071:9
|
1071 | assert_eq!(should_vec, out_vec);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: inside call to `ring_buffer::test::mut_ref_iter` at src/ring_buffer/mod.rs:1066:5
--> src/ring_buffer/mod.rs:1066:5
|
1066 | / fn mut_ref_iter() {
1067 | | let mut chunk: RingBuffer<i32> = (0..64).collect();
1068 | | let out_vec: Vec<&mut i32> = chunk.iter_mut().collect();
1069 | | let mut should_vec_p: Vec<i32> = (0..64).collect();
1070 | | let should_vec: Vec<&mut i32> = should_vec_p.iter_mut().collect();
1071 | | assert_eq!(should_vec, out_vec);
1072 | | }
| |_____^
= note: inside call to closure at /home/r/.rustup/toolchains/miri/lib/rustlib/src/rust/src/libcore/ops/function.rs:232:5
= note: inside call to `<[closure@src/ring_buffer/mod.rs:1066:5: 1072:6] as std::ops::FnOnce<()>>::call_once - shim` at /home/r/.rustup/toolchains/miri/lib/rustlib/src/rust/src/libcore/ops/function.rs:232:5
= note: inside call to `<fn() as std::ops::FnOnce<()>>::call_once - shim(fn())` at /home/r/.rustup/toolchains/miri/lib/rustlib/src/rust/src/libtest/lib.rs:518:5
= note: inside call to `test::__rust_begin_short_backtrace::<fn()>` at /home/r/.rustup/toolchains/miri/lib/rustlib/src/rust/src/libtest/lib.rs:509:30
= note: inside call to closure at /home/r/.rustup/toolchains/miri/lib/rustlib/src/rust/src/libcore/ops/function.rs:232:5
= note: inside call to `<[closure@DefId(46:631 ~ test[7b6d]::run_test[0]::{{closure}}[2]) 0:fn()] as std::ops::FnOnce<()>>::call_once - shim(vtable)` at /home/r/.rustup/toolchains/miri/lib/rustlib/src/rust/src/liballoc/boxed.rs:1017:9
= note: inside call to `<std::boxed::Box<dyn std::ops::FnOnce() + std::marker::Send> as std::ops::FnOnce<()>>::call_once` at /home/r/.rustup/toolchains/miri/lib/rustlib/src/rust/src/libstd/panic.rs:318:9
= note: inside call to `<std::panic::AssertUnwindSafe<std::boxed::Box<dyn std::ops::FnOnce() + std::marker::Send>> as std::ops::FnOnce<()>>::call_once` at /home/r/.rustup/toolchains/miri/lib/rustlib/src/rust/src/libstd/panicking.rs:331:40
= note: inside call to `std::panicking::r#try::do_call::<std::panic::AssertUnwindSafe<std::boxed::Box<dyn std::ops::FnOnce() + std::marker::Send>>, ()>` at /home/r/.rustup/toolchains/miri/lib/rustlib/src/rust/src/libstd/panicking.rs:274:15
= note: inside call to `std::panicking::r#try::<(), std::panic::AssertUnwindSafe<std::boxed::Box<dyn std::ops::FnOnce() + std::marker::Send>>>` at /home/r/.rustup/toolchains/miri/lib/rustlib/src/rust/src/libstd/panic.rs:394:14
= note: inside call to `std::panic::catch_unwind::<std::panic::AssertUnwindSafe<std::boxed::Box<dyn std::ops::FnOnce() + std::marker::Send>>, ()>` at /home/r/.rustup/toolchains/miri/lib/rustlib/src/rust/src/libtest/lib.rs:542:18
= note: inside call to `test::run_test_in_process` at /home/r/.rustup/toolchains/miri/lib/rustlib/src/rust/src/libtest/lib.rs:451:39
= note: inside call to closure at /home/r/.rustup/toolchains/miri/lib/rustlib/src/rust/src/libtest/lib.rs:476:13
= note: inside call to `test::run_test::run_test_inner` at /home/r/.rustup/toolchains/miri/lib/rustlib/src/rust/src/libtest/lib.rs:506:28
= note: inside call to `test::run_test` at /home/r/.rustup/toolchains/miri/lib/rustlib/src/rust/src/libtest/lib.rs:285:13
= note: inside call to `test::run_tests::<[closure@DefId(46:230 ~ test[7b6d]::console[0]::run_tests_console[0]::{{closure}}[2]) 0:&mut test::console::ConsoleTestState, 1:&mut std::boxed::Box<dyn test::formatters::OutputFormatter>]>` at /home/r/.rustup/toolchains/miri/lib/rustlib/src/rust/src/libtest/console.rs:280:5
= note: inside call to `test::run_tests_console` at /home/r/.rustup/toolchains/miri/lib/rustlib/src/rust/src/libtest/lib.rs:121:15
= note: inside call to `test::test_main` at /home/r/.rustup/toolchains/miri/lib/rustlib/src/rust/src/libtest/lib.rs:140:5
= note: inside call to `test::test_main_static`
= note: inside call to `main` at /home/r/.rustup/toolchains/miri/lib/rustlib/src/rust/src/libstd/rt.rs:67:34
= note: inside call to closure at /home/r/.rustup/toolchains/miri/lib/rustlib/src/rust/src/libstd/rt.rs:52:73
= note: inside call to closure at /home/r/.rustup/toolchains/miri/lib/rustlib/src/rust/src/libstd/sys_common/backtrace.rs:130:5
= note: inside call to `std::sys_common::backtrace::__rust_begin_short_backtrace::<[closure@DefId(1:6041 ~ std[e04c]::rt[0]::lang_start_internal[0]::{{closure}}[0]::{{closure}}[0]) 0:&dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe], i32>` at /home/r/.rustup/toolchains/miri/lib/rustlib/src/rust/src/libstd/rt.rs:52:13
= note: inside call to closure at /home/r/.rustup/toolchains/miri/lib/rustlib/src/rust/src/libstd/panicking.rs:331:40
= note: inside call to `std::panicking::r#try::do_call::<[closure@DefId(1:6040 ~ std[e04c]::rt[0]::lang_start_internal[0]::{{closure}}[0]) 0:&&dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe], i32>` at /home/r/.rustup/toolchains/miri/lib/rustlib/src/rust/src/libstd/panicking.rs:274:15
= note: inside call to `std::panicking::r#try::<i32, [closure@DefId(1:6040 ~ std[e04c]::rt[0]::lang_start_internal[0]::{{closure}}[0]) 0:&&dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe]>` at /home/r/.rustup/toolchains/miri/lib/rustlib/src/rust/src/libstd/panic.rs:394:14
= note: inside call to `std::panic::catch_unwind::<[closure@DefId(1:6040 ~ std[e04c]::rt[0]::lang_start_internal[0]::{{closure}}[0]) 0:&&dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe], i32>` at /home/r/.rustup/toolchains/miri/lib/rustlib/src/rust/src/libstd/rt.rs:51:25
= note: inside call to `std::rt::lang_start_internal` at /home/r/.rustup/toolchains/miri/lib/rustlib/src/rust/src/libstd/rt.rs:67:5
= note: inside call to `std::rt::lang_start::<()>`
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
My interpretation of what happens is that the problem is here:
sized-chunks/src/ring_buffer/iter.rs
Line 84 in d71d0ea
Some(unsafe { &mut *self.buffer.mut_ptr(self.left_index.inc()) }) |
This creates a fresh &mut RingBuffer
that is passed to RingBuffer::mut_ptr
. Any time a mutable reference is created it must be the unique pointer pointing to that memory -- all old aliases become invalid. We are still experimenting with the exact ruels for this; for further details, see this document.
The issue here is that this new mutably reference that got created here overaps with the mutable references that were handed out by the iterator previously. Thus those old references become invalid (their "lifetime ends"), but the caller still uses them later, leading to the error. This is a problem because Rust would like to perform optimizations based on the assumption that mutable references are truly unique -- code like this is incompatible with such optimizations.
Given that you are handling aliased pointers here (the buffer
pointer and the ones returned by next
overlap) and want to perform mutation, I think the only solution is to use raw pointers throughout. That way, the Rust compiler knows that nothing is unique, and does not do any optimizations. I think you can do that here by replacing the buffer
field with a raw pointer to the MaybeUninit<N::SizedType>
that lives inside the buffer. Then you never have to create a reference except for the ones returned by next
, and those do not overlap because they all point to different elements. Does that make sense?
Also Cc rust-lang/unsafe-code-guidelines#133: this crate would benefit from mutable references being "less eager" in asserting uniqueness. Unfortunately, it is not clear if that is possible and what the trade-offs are.