Skip to content

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

@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