Skip to content

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

Open
@AngelicosPhosphoros

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)).

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