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
The following program using latest version 1.8.1:
Triggers the following error on my laptop (the seed may depend on the architecture):