slide-rs / atom Goto Github PK
View Code? Open in Web Editor NEWSafe atomic pointers
License: Apache License 2.0
Safe atomic pointers
License: Apache License 2.0
Hello,
It would be great to know what guarantees are available for each method in this crate. That will make it easier to determine which functions are usable in a given scenario.
Thanks for considering!
Hello,
It would be great to have some more atomic methods available in Atom. I envision the following signatures, which attempt to maintain parity with AtomicPtr
:
// https://doc.rust-lang.org/std/sync/atomic/struct.AtomicPtr.html#method.compare_and_swap
pub fn compare_and_swap(
&self,
current: Option<&P>,
new: Option<P>,
order: Ordering,
) -> Result<Option<P>, (Option<P>, *mut P)>;
// https://doc.rust-lang.org/std/sync/atomic/struct.AtomicPtr.html#method.compare_exchange
pub fn compare_exchange(
&self,
current: Option<&P>,
new: Option<P>,
success: Ordering,
failure: Ordering,
) -> Result<Option<P>, (Option<P>, *mut P)>;
// https://doc.rust-lang.org/std/sync/atomic/struct.AtomicPtr.html#method.compare_exchange_weak
pub fn compare_exchange_weak(
&self,
current: Option<&P>,
new: Option<P>,
success: Ordering,
failure: Ordering,
) -> Result<Option<P>, (Option<P>, *mut P)>;
Would you accept a PR for this?
Thanks for considering!
Thanks for considering!
Is this accurate? It seems to simply rely on the atomic_xchg intrinsics, and not implement any kind of re-trying to block on the atom like the docstring suggests.
Lines 64 to 66 in 2a606a0
The documentation for AtomSetOnce
stops mid-sentence with Meaning that AtomSetOnce is not usable as a
... . I would love to know how this sentence ends. The suspense is killing me! :D Seriously, though, what is AtomSetOnce not usable as? That would be pretty useful information to have.
This crate has the same issue as mystor/atomic_ref#5.
The following code segfaults on an AArch64 machine (but not on x86_64, which has a stronger memory model).
#![deny(unsafe_code)]
use atom::Atom;
use std::sync::atomic::Ordering;
fn main() {
let channel = &*Box::leak(Box::new(Atom::<&&'static u32>::new(&&42u32)));
std::thread::spawn(move || loop {
if let Some(ptr) = channel.take(Ordering::Relaxed) {
assert_eq!(**ptr, 42);
}
});
for i in 0..10000000 {
let b = Box::leak(Box::new(&42u32));
channel.swap(b, Ordering::Relaxed);
}
}
I noticed there's been a bunch of changes on master contributed by @dbkaplun that haven't made their way out onto the cargo crate. Most importantly, the latest release, 0.3.5 is missing dc096ef which fixes a fairly important soundness issue around the Send
trait's bounds.
Without this commit, it's possible to Send
across unsafe objects like Rc
and potentially run into data races like so:
#![forbid(unsafe_code)]
extern crate atom;
use atom::Atom;
use std::rc::Rc;
use std::sync::mpsc;
use std::{thread, time, mem};
const NUM_CLONES: usize = 10000000;
fn main() {
let x = Rc::new(());
let y = Rc::clone(&x);
// Place our Rc in the Atom through a Box.
let shared_atom = Atom::empty();
shared_atom.swap(Box::new(x));
let child = thread::spawn(move || {
// We now have the Rc shared across a thread.
let x = shared_atom.take().unwrap();
for _ in 0..NUM_CLONES {
let clone = x.clone();
mem::forget(clone);
}
});
for _ in 0..NUM_CLONES {
let clone = y.clone();
mem::forget(clone);
}
// Wait for the spawned thread to finish its cloning.
child.join().unwrap();
// We made NUM_CLONES on both threads plus 2 references in the main thread.
// But in reality we'll see that the strong_count varies across every run.
assert_eq!(Rc::strong_count(&y), (NUM_CLONES * 2) + 2);
}
This could lead to use-after-frees and is a fairly easy mistake to make.
E.g., if T == Box<Cell<u32>>
, AtomSetOnce<Box<Cell<u32>>>
could be shared between threads and allow the immutable borrowing of Box<Cell<u32>>
, which is Send + !Sync
, by multiple threads.
#[test]
fn dup_panic_safety() {
struct WeirdTy(String);
impl Clone for WeirdTy {
fn clone(&self) -> Self {
panic!("")
}
}
let x = AtomSetOnce::new(Box::new(WeirdTy("hoge".to_owned())));
std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
x.dup(Ordering::Acquire); // `v.clone()` panics, skipping `mem::forget(v)` and dropping `Box<WeirdTy>`
}));
// The `Box<WeirdTy>` is dropped again, causing a double-free
}
Demo
trait Engine {
fn eval(&self) -> String;
}
struct JSEngine {
name: String,
}
impl Engine for JSEngine {
fn eval(&self) -> String {
"js eval".to_string()
}
}
fn main() {
let engine: Arc<dyn Engine> = Arc::new(JSEngine {
name: "js1".to_string(),
});
println!("Results: {}", engine.eval());
let shared_atom = Atom::new(engine);
}
error[E0277]: the size for values of type `dyn Engine` cannot be known at compilation time
--> src/bin/main.rs:36:33
|
36 | let shared_atom = Atom::new(engine);
| ^^^^^^ doesn't have a size known at compile-time
|
= help: the trait `std::marker::Sized` is not implemented for `dyn Engine`
= note: required because of the requirements on the impl of `atom::IntoRawPtr` for `std::sync::Arc<dyn Engine>`
= note: required by `atom::Atom::<P>::new`
error[E0277]: the size for values of type `dyn Engine` cannot be known at compilation time
--> src/bin/main.rs:36:23
|
36 | let shared_atom = Atom::new(engine);
| ^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
:::~/.cargo/registry/src/github.com-1ecc6299db9ec823/atom-0.4.0/src/lib.rs:29:8
|
29 | P: IntoRawPtr + FromRawPtr,
| ---------- required by this bound in `atom::Atom`
|
= help: the trait `std::marker::Sized` is not implemented for `dyn Engine`
= note: required because of the requirements on the impl of `atom::IntoRawPtr` for `std::sync::Arc<dyn Engine>`
error: aborting due to 2 previous errors; 2 warnings emitted
For more information about this error, try `rustc --explain E0277`.
error: could not compile `foo`.
To learn more, run the command again with --verbose.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.