Skip to content

Miri doesn't accept same algorithm with ArrayVec::retain while accepting Vec::retain #221

Description

@AngelicosPhosphoros

Configuration

arrayvec 0.7.2 default features

>cargo +nightly miri --version --verbose
miri 0.1.0 (cde87d1 2022-07-08)

>rustc +nightly --version --verbose
rustc 1.64.0-nightly (87588a2af 2022-07-13)
binary: rustc
commit-hash: 87588a2afd9ca903366f0deaf84d805f34469384
commit-date: 2022-07-13
host: x86_64-pc-windows-msvc
release: 1.64.0-nightly
LLVM version: 14.0.6

Code:

use arrayvec; // 0.7.2

use arrayvec::ArrayVec;
use std::mem::MaybeUninit;

fn retain_remove_vec(a: &mut Vec<MaybeUninit<String>>){
    let mut i = 0;
    a.retain(|x|{
        let res = if i % 2 == 0 {
            true
        }
        else{
            drop(unsafe{
                x.assume_init_read()
            });
            false
        };
        i += 1;
        res
    })
}

fn retain_remove_arrvec(a: &mut ArrayVec<MaybeUninit<String>, 5>){
    let mut i = 0;
    a.retain(|x|{
        let res = if i % 2 == 0 {
            true
        }
        else{
            drop(unsafe{
                x.assume_init_read()
            });
            false
        };
        i += 1;
        res
    })
}

fn main(){
    let mut v: Vec<_> = "ABCDE".chars()
        .map(|c|c.to_string())
        .map(MaybeUninit::new)
        .collect();
    retain_remove_vec(&mut v);
    v.into_iter().map(|x|unsafe{x.assume_init()}).for_each(drop);
    
    let mut v: ArrayVec<_, 5> = "ABCDE".chars()
        .map(|c|c.to_string())
        .map(MaybeUninit::new)
        .collect();
    retain_remove_arrvec(&mut v);
    v.into_iter().map(|x|unsafe{x.assume_init()}).for_each(drop);
}

Error

Miri output
error: Undefined Behavior: attempting a read access using <12341> at alloc4524[0x30], but that tag does not exist in the borrow stack for this location
    --> <skipped>\.rustup\toolchains\nightly-x86_64-pc-windows-msvc\lib\rustlib\src\rust\library\core\src\intrinsics.rs:2453:9
     |
2453 |         copy_nonoverlapping(src, dst, count)
     |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
     |         |
     |         attempting a read access using <12341> at alloc4524[0x30], but that tag does not exist in the borrow stack for this location
     |         this error occurs as part of an access at alloc4524[0x30..0x48]
     |
     = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows 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
help: <12341> was created by a retag at offsets [0x0..0x78]
    --> src\main.rs:25:5
     |
25   | /     a.retain(|x|{
26   | |         let res = if i % 2 == 0 {
27   | |             true
28   | |         }
...    |
36   | |         res
37   | |     })
     | |______^
help: <12341> was later invalidated at offsets [0x0..0x80]
    --> src\main.rs:25:5
     |
25   | /     a.retain(|x|{
26   | |         let res = if i % 2 == 0 {
27   | |             true
28   | |         }
...    |
36   | |         res
37   | |     })
     | |______^
     = note: backtrace:
     = note: inside `std::intrinsics::copy_nonoverlapping::<std::mem::MaybeUninit<std::string::String>>` at <skipped>\.rustup\toolchains\nightly-x86_64-pc-windows-msvc\lib\rustlib\src\rust\library\core\src\intrinsics.rs:2453:9
     = note: inside `arrayvec::ArrayVec::<T, CAP>::retain::process_one::<[closure@src\main.rs:25:14: 25:17], std::mem::MaybeUninit<std::string::String>, 5_usize, true>` at <skipped>\.cargo\registry\src\github.com-1ecc6299db9ec823\arrayvec-0.7.2\src\arrayvec.rs:511:21
     = note: inside `arrayvec::ArrayVec::<std::mem::MaybeUninit<std::string::String>, 5_usize>::retain::<[closure@src\main.rs:25:14: 25:17]>` at <skipped>\.cargo\registry\src\github.com-1ecc6299db9ec823\arrayvec-0.7.2\src\arrayvec.rs:527:13
note: inside `retain_remove_arrvec` at src\main.rs:25:5
    --> src\main.rs:25:5
     |
25   | /     a.retain(|x|{
26   | |         let res = if i % 2 == 0 {
27   | |             true
28   | |         }
...    |
36   | |         res
37   | |     })
     | |______^
note: inside `main` at src\main.rs:52:5
    --> src\main.rs:52:5
     |
52   |     retain_remove_arrvec(&mut v);
     |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
     = note: inside `<fn() as std::ops::FnOnce<()>>::call_once - shim(fn())` at <skipped>\.rustup\toolchains\nightly-x86_64-pc-windows-msvc\lib\rustlib\src\rust\library\core\src\ops\function.rs:248:5
     = note: inside `std::sys_common::backtrace::__rust_begin_short_backtrace::<fn(), ()>` at <skipped>\.rustup\toolchains\nightly-x86_64-pc-windows-msvc\lib\rustlib\src\rust\library\std\src\sys_common\backtrace.rs:122:18
     = note: inside closure at <skipped>\.rustup\toolchains\nightly-x86_64-pc-windows-msvc\lib\rustlib\src\rust\library\std\src\rt.rs:145:18
     = note: inside `std::ops::function::impls::<impl std::ops::FnOnce<()> for &dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe>::call_once` at <skipped>\.rustup\toolchains\nightly-x86_64-pc-windows-msvc\lib\rustlib\src\rust\library\core\src\ops\function.rs:280:13
     = note: inside `std::panicking::r#try::do_call::<&dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe, i32>` at <skipped>\.rustup\toolchains\nightly-x86_64-pc-windows-msvc\lib\rustlib\src\rust\library\std\src\panicking.rs:492:40
     = note: inside `std::panicking::r#try::<i32, &dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe>` at <skipped>\.rustup\toolchains\nightly-x86_64-pc-windows-msvc\lib\rustlib\src\rust\library\std\src\panicking.rs:456:19
     = note: inside `std::panic::catch_unwind::<&dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe, i32>` at <skipped>\.rustup\toolchains\nightly-x86_64-pc-windows-msvc\lib\rustlib\src\rust\library\std\src\panic.rs:137:14
     = note: inside closure at <skipped>\.rustup\toolchains\nightly-x86_64-pc-windows-msvc\lib\rustlib\src\rust\library\std\src\rt.rs:128:48
     = note: inside `std::panicking::r#try::do_call::<[closure@std::rt::lang_start_internal::{closure#2}], isize>` at <skipped>\.rustup\toolchains\nightly-x86_64-pc-windows-msvc\lib\rustlib\src\rust\library\std\src\panicking.rs:492:40
     = note: inside `std::panicking::r#try::<isize, [closure@std::rt::lang_start_internal::{closure#2}]>` at <skipped>\.rustup\toolchains\nightly-x86_64-pc-windows-msvc\lib\rustlib\src\rust\library\std\src\panicking.rs:456:19
     = note: inside `std::panic::catch_unwind::<[closure@std::rt::lang_start_internal::{closure#2}], isize>` at <skipped>\.rustup\toolchains\nightly-x86_64-pc-windows-msvc\lib\rustlib\src\rust\library\std\src\panic.rs:137:14
     = note: inside `std::rt::lang_start_internal` at <skipped>\.rustup\toolchains\nightly-x86_64-pc-windows-msvc\lib\rustlib\src\rust\library\std\src\rt.rs:128:20
     = note: inside `std::rt::lang_start::<()>` at <skipped>\.rustup\toolchains\nightly-x86_64-pc-windows-msvc\lib\rustlib\src\rust\library\std\src\rt.rs:144:17

error: aborting due to previous error

error: process didn't exit successfully: `<skipped>\.rustup\toolchains\nightly-x86_64-pc-windows-msvc\bin\cargo-miri.exe target\miri\x86_64-pc-windows-msvc\debug\test_miri_isolated.exe` (exit code: 1)

Extra Context

I need such strange iteration when I tried to implement retain_take(&mut self, condition: Predicate, consumer_of_removed: impl FnMut(T)).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions