Skip to content

Use-after-free detected by miri #198

@wyfo

Description

@wyfo

The following program using latest version 1.8.1:

use std::{
    sync::atomic::{AtomicUsize, Ordering::Relaxed},
    thread,
};

use arc_swap::ArcSwap;

struct SpinBarrier(AtomicUsize);

impl SpinBarrier {
    fn new(n: usize) -> Self {
        Self(AtomicUsize::new(n))
    }

    fn wait(&self) {
        self.0.fetch_sub(1, Relaxed);
        while self.0.load(Relaxed) != 0 {}
    }

    fn wrap<R: Send>(&self, f: impl FnOnce() -> R + Send) -> impl FnOnce() -> R + Send {
        || {
            self.wait();
            f()
        }
    }
}

fn main() {
    let arcswap = ArcSwap::<usize>::new(0.into());
    let _guards = std::array::from_fn::<_, 8, _>(|_| arcswap.load());
    let barrier = SpinBarrier::new(3);
    thread::scope(|s| {
        s.spawn(barrier.wrap(|| arcswap.store(1.into())));
        s.spawn(barrier.wrap(|| arcswap.store(2.into())));
        barrier.wait();
        let a1 = arcswap.load();
        let a2 = arcswap.load();
        if **a1 != **a2 && **a1 != 0 {
            assert_eq!(**a2, **arcswap.load());
        }
    });
}

Triggers the following error on my laptop (the seed may depend on the architecture):

> MIRIFLAGS="-Zmiri-seed=3334" cargo +nightly miri run
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.01s
     Running `/Users/jope/.rustup/toolchains/nightly-aarch64-apple-darwin/bin/cargo-miri runner target/miri/aarch64-apple-darwin/debug/arc-swap-issue`
error: Undefined Behavior: in-bounds pointer arithmetic failed: alloc4748 has been freed, so this pointer is dangling
    --> /Users/jope/.rustup/toolchains/nightly-aarch64-apple-darwin/lib/rustlib/src/rust/library/alloc/src/sync.rs:1893:27
     |
1893 |             let arc_ptr = ptr.byte_sub(offset) as *mut ArcInner<T>;
     |                           ^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here
     |
     = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
     = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
help: alloc4748 was allocated here:
    --> src/main.rs:33:47
     |
  33 |         s.spawn(barrier.wrap(|| arcswap.store(1.into())));
     |                                               ^^^^^^^^
help: alloc4748 was deallocated here:
    --> src/main.rs:34:33
     |
  34 |         s.spawn(barrier.wrap(|| arcswap.store(2.into())));
     |                                 ^^^^^^^^^^^^^^^^^^^^^^^
     = note: this is on thread `main`
     = note: stack backtrace:
             0: std::sync::Arc::<usize>::from_raw_in
                 at /Users/jope/.rustup/toolchains/nightly-aarch64-apple-darwin/lib/rustlib/src/rust/library/alloc/src/sync.rs:1893:27: 1893:47
             1: std::sync::Arc::<usize>::from_raw
                 at /Users/jope/.rustup/toolchains/nightly-aarch64-apple-darwin/lib/rustlib/src/rust/library/alloc/src/sync.rs:1645:18: 1645:47
             2: <std::sync::Arc<usize> as arc_swap::RefCnt>::from_ptr
                 at /Users/jope/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/arc-swap-1.8.1/src/ref_cnt.rs:123:9: 123:27
             3: arc_swap::strategy::hybrid::HybridProtection::<std::sync::Arc<usize>>::new
                 at /Users/jope/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/arc-swap-1.8.1/src/strategy/hybrid.rs:36:36: 36:52
             4: arc_swap::strategy::hybrid::HybridProtection::<std::sync::Arc<usize>>::fallback
                 at /Users/jope/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/arc-swap-1.8.1/src/strategy/hybrid.rs:84:43: 84:75
             5: <arc_swap::strategy::hybrid::HybridStrategy<arc_swap::strategy::hybrid::DefaultConfig> as arc_swap::strategy::sealed::InnerStrategy<std::sync::Arc<usize>>>::load::{closure#0}::{closure#0}
                 at /Users/jope/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/arc-swap-1.8.1/src/strategy/hybrid.rs:196:36: 196:77
             6: <arc_swap::strategy::hybrid::HybridStrategy<arc_swap::strategy::hybrid::DefaultConfig> as arc_swap::strategy::sealed::InnerStrategy<std::sync::Arc<usize>>>::load::{closure#0}
                 at /Users/jope/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/arc-swap-1.8.1/src/strategy/hybrid.rs:196:13: 196:78
             7: arc_swap::debt::list::LocalNode::with::<arc_swap::strategy::hybrid::HybridProtection<std::sync::Arc<usize>>, {closure@<arc_swap::strategy::hybrid::HybridStrategy<arc_swap::strategy::hybrid::DefaultConfig> as arc_swap::strategy::sealed::InnerStrategy<std::sync::Arc<usize>>>::load::{closure#0}}>::{closure#0}
                 at /Users/jope/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/arc-swap-1.8.1/src/debt/list.rs:231:17: 231:24
             8: std::thread::LocalKey::<arc_swap::debt::list::LocalNode>::try_with::<{closure@arc_swap::debt::list::LocalNode::with<arc_swap::strategy::hybrid::HybridProtection<std::sync::Arc<usize>>, {closure@<arc_swap::strategy::hybrid::HybridStrategy<arc_swap::strategy::hybrid::DefaultConfig> as arc_swap::strategy::sealed::InnerStrategy<std::sync::Arc<usize>>>::load::{closure#0}}>::{closure#0}}, arc_swap::strategy::hybrid::HybridProtection<std::sync::Arc<usize>>>
                 at /Users/jope/.rustup/toolchains/nightly-aarch64-apple-darwin/lib/rustlib/src/rust/library/std/src/thread/local.rs:513:12: 513:27
             9: arc_swap::debt::list::LocalNode::with::<arc_swap::strategy::hybrid::HybridProtection<std::sync::Arc<usize>>, {closure@<arc_swap::strategy::hybrid::HybridStrategy<arc_swap::strategy::hybrid::DefaultConfig> as arc_swap::strategy::sealed::InnerStrategy<std::sync::Arc<usize>>>::load::{closure#0}}>
                 at /Users/jope/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/arc-swap-1.8.1/src/debt/list.rs:225:9: 232:15
             10: <arc_swap::strategy::hybrid::HybridStrategy<arc_swap::strategy::hybrid::DefaultConfig> as arc_swap::strategy::sealed::InnerStrategy<std::sync::Arc<usize>>>::load
                 at /Users/jope/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/arc-swap-1.8.1/src/strategy/hybrid.rs:190:9: 197:11
             11: arc_swap::ArcSwapAny::<std::sync::Arc<usize>>::load
                 at /Users/jope/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/arc-swap-1.8.1/src/lib.rs:465:34: 465:63
             12: main::{closure#1}
                 at src/main.rs:37:18: 37:32
             13: std::thread::scope::<'_, {closure@src/main.rs:32:19: 32:22}, ()>::{closure#0}
                 at /Users/jope/.rustup/toolchains/nightly-aarch64-apple-darwin/lib/rustlib/src/rust/library/std/src/thread/scoped.rs:155:51: 155:60
             14: <std::panic::AssertUnwindSafe<{closure@std::thread::scope<'_, {closure@src/main.rs:32:19: 32:22}, ()>::{closure#0}}> as std::ops::FnOnce<()>>::call_once
                 at /Users/jope/.rustup/toolchains/nightly-aarch64-apple-darwin/lib/rustlib/src/rust/library/core/src/panic/unwind_safe.rs:274:9: 274:19
             15: std::panicking::catch_unwind::do_call::<std::panic::AssertUnwindSafe<{closure@std::thread::scope<'_, {closure@src/main.rs:32:19: 32:22}, ()>::{closure#0}}>, ()>
                 at /Users/jope/.rustup/toolchains/nightly-aarch64-apple-darwin/lib/rustlib/src/rust/library/std/src/panicking.rs:581:40: 581:43
             16: std::panicking::catch_unwind::<(), std::panic::AssertUnwindSafe<{closure@std::thread::scope<'_, {closure@src/main.rs:32:19: 32:22}, ()>::{closure#0}}>>
                 at /Users/jope/.rustup/toolchains/nightly-aarch64-apple-darwin/lib/rustlib/src/rust/library/std/src/panicking.rs:544:19: 544:88
             17: std::panic::catch_unwind::<std::panic::AssertUnwindSafe<{closure@std::thread::scope<'_, {closure@src/main.rs:32:19: 32:22}, ()>::{closure#0}}>, ()>
                 at /Users/jope/.rustup/toolchains/nightly-aarch64-apple-darwin/lib/rustlib/src/rust/library/std/src/panic.rs:359:14: 359:40
             18: main
                 at src/main.rs:32:5: 41:7

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

error: aborting due to 1 previous error

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