Skip to content

Stacked borrows fails on {ChunksMut,ChunksExactMut}::__iterator_get_unchecked() #94231

Closed
@andylizi

Description

@andylizi

Description

fn main() {
    let mut arr1 = [0u8; 64];
    let arr2 = [0u8; 64];
    let mut iter = arr1.chunks_mut(8).zip(arr2.chunks(8));
    while let Some((chunk1, chunk2)) = iter.next() {
        dbg!(chunk2[0]);
        dbg!(chunk1[0]);
        iter.next();
        dbg!(chunk2[0]);
        dbg!(chunk1[0]);  // error here
    }
}

Running this code in Miri will produce the following output:

[src\main.rs:6] chunk2[0] = 0
[src\main.rs:7] chunk1[0] = 0
[src\main.rs:9] chunk2[0] = 0
error: Undefined Behavior: no item granting read access to tag <1832> at alloc906 found in borrow stack.
  --> src\main.rs:10:9
   |
10 |         dbg!(chunk1[0]);  // error here
   |         ^^^^^^^^^^^^^^^ no item granting read access to tag <1832> at alloc906 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

With -Zmiri-track-pointer-tag=1832,1585,12319

note: tracking was triggered
    --> \library\core\src\slice\iter.rs:1564:19
     |
1564 |         Self { v: slice, chunk_size: size }
     |                   ^^^^^ created tag 1585
     |
     = note: inside `std::slice::ChunksMut::<u8>::new` at \library\core\src\slice\iter.rs:1564:19
     = note: inside `core::slice::<impl [u8]>::chunks_mut` at \library\core\src\slice\mod.rs:828:9
note: inside `main` at src\main.rs:4:20
    --> src\main.rs:4:20
     |
4    |     let mut iter = arr1.chunks_mut(8).zip(arr2.chunks(8));
     |                    ^^^^^^^^^^^^^^^^^^

note: tracking was triggered
 --> src\main.rs:5:21
  |
5 |     while let Some((chunk1, chunk2)) = iter.next() {
  |                     ^^^^^^ created tag 1832
  |
  = note: inside `main` at src\main.rs:5:21

[src\main.rs:6] chunk2[0] = 0
[src\main.rs:7] chunk1[0] = 0

note: tracking was triggered
    --> \library\core\src\slice\iter.rs:1641:32
     |
1641 |             let len = cmp::min(self.v.len().unchecked_sub(start), self.chunk_size);
     |                                ^^^^^^^^^^^^ popped tracked tag for item [Unique for <1832>] due to Read access for <1585>
     |
     = note: inside `<std::slice::ChunksMut<u8> as std::iter::Iterator>::__iterator_get_unchecked` at \library\core\src\slice\iter.rs:1641:32
     = note: inside `<std::iter::Zip<std::slice::ChunksMut<u8>, std::slice::Chunks<u8>> as std::iter::adapters::zip::ZipImpl<std::slice::ChunksMut<u8>, std::slice::Chunks<u8>>>::next` at \library\core\src\iter\adapters\zip.rs:278:23
     = note: inside `<std::iter::Zip<std::slice::ChunksMut<u8>, std::slice::Chunks<u8>> as std::iter::Iterator>::next` at \library\core\src\iter\adapters\zip.rs:84:9
    --> \library\core\src\slice\iter.rs:1642:32
     |
1642 |             from_raw_parts_mut(self.v.as_mut_ptr().add(start), len)
     |                                ^^^^^^^^^^^^^^^^^^^ created tag 12319
     |
     = note: inside `<std::slice::ChunksMut<u8> as std::iter::Iterator>::__iterator_get_unchecked` at \library\core\src\slice\iter.rs:1642:32
    --> \library\core\src\slice\mod.rs:483:5
      |
  483 | /     pub const fn as_mut_ptr(&mut self) -> *mut T {
  484 | |         self as *mut [T] as *mut T
  485 | |     }
      | |_____^ popped tracked tag for item [Disabled for <1832>] due to Write access for <12319>
      |
      = note: inside `core::slice::<impl [u8]>::as_mut_ptr` at \library\core\src\slice\mod.rs:483:5
      = note: inside `<std::slice::ChunksMut<u8> as std::iter::Iterator>::__iterator_get_unchecked` at \library\core\src\slice\iter.rs:1642:32
     note: inside `main` at src\main.rs:8:9
    --> src\main.rs:8:9
     |
8    |         iter.next();
     |         ^^^^^^^^^^^
     = note

[src\main.rs:9] chunk2[0] = 0

error: Undefined Behavior: no item granting read access to tag <1832> at alloc906 found in borrow stack.
  --> src\main.rs:10:9
   |
10 |         dbg!(chunk1[0]);  // error here
   |         ^^^^^^^^^^^^^^^ no item granting read access to tag <1832> at alloc906 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

A few things to note here:

  1. Access to the mutable chunk will fail. For example arr1.chunks(8).zip(arr2.chunks_mut(8)) will fail on chunk2[0] instead.
  2. zip() is required. This is probably due to Zip uses __iterator_get_unchecked() internally rather than next().
  3. chunks_mut() and chunks_exact_mut() can both reproduce.
  4. array_chunks_mut() can't reproduce.

Environment

$ rustc --version --verbose
rustc 1.61.0-nightly (45e2c2881 2022-02-20)
binary: rustc
commit-hash: 45e2c2881d11324d610815bfff097e25c412199e
commit-date: 2022-02-20
host: x86_64-pc-windows-msvc
release: 1.61.0-nightly
LLVM version: 14.0.0

$ cargo miri --version
miri 0.1.0 (0db4090 2022-02-12)

Metadata

Metadata

Assignees

No one assigned

    Labels

    T-libsRelevant to the library team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions