agerasev/ringbuf

Miri gives a UB because of stacked borrows

Closed this issue · 1 comments

I run Miri on your crate and it gave an UB on push_access function. I don't have a clear understanding on stacked borrows yet, so I don't know how it can be fixed.

This is the output:

% cargo +nightly miri test
   Compiling ringbuf v0.2.7 (/home/oblique/git/ringbuf)
    Finished test [unoptimized + debuginfo] target(s) in 0.09s
     Running unittests src/lib.rs (target/miri/x86_64-unknown-linux-gnu/debug/deps/ringbuf-e44ea49f80c6b586)

running 39 tests
test tests::access::discard ... error: Undefined Behavior: trying to reborrow <220885> for SharedReadWrite permission at alloc84260[0x0], but that tag does not exist in the borrow stack for this location
   --> src/producer.rs:99:19
    |
99  |         let n = f(slices.0, slices.1);
    |                   ^^^^^^^^
    |                   |
    |                   trying to reborrow <220885> for SharedReadWrite permission at alloc84260[0x0], but that tag does not exist in the borrow stack for this location
    |                   this error occurs as part of a reborrow at alloc84260[0x0..0xa]
    |
    = 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 `producer::Producer::<i8>::push_access::<[closure@src/producer.rs:152:30: 159:14]>` at src/producer.rs:99:19
note: inside `producer::Producer::<i8>::push` at src/producer.rs:152:13
   --> src/producer.rs:152:13
    |
152 | /             self.push_access(|slice, _| {
153 | |                 if !slice.is_empty() {
154 | |                     mem::swap(slice.get_unchecked_mut(0), &mut elem_mu);
155 | |                     1
...   |
158 | |                 }
159 | |             })
    | |______________^
note: inside `tests::access::discard` at src/tests/access.rs:245:9
   --> src/tests/access.rs:245:9
    |
245 |         prod.push(i).unwrap();
    |         ^^^^^^^^^^^^
note: inside closure at src/tests/access.rs:237:1
   --> src/tests/access.rs:237:1
    |
236 |   #[test]
    |   ------- in this procedural macro expansion
237 | / fn discard() {
238 | |     // Initialize ringbuffer, prod and cons
239 | |     let rb = RingBuffer::<i8>::new(10);
240 | |     let (mut prod, mut cons) = rb.split();
...   |
279 | |     assert_eq!(cons.pop(), Some(0));
280 | | }
    | |_^
    = note: this error originates in the attribute macro `test` (in Nightly builds, run with -Z macro-backtrace for more info)

note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace

error: aborting due to previous error

error: test failed, to rerun pass '--lib'

I managed to fix the issue and opened a PR.