-
Notifications
You must be signed in to change notification settings - Fork 1
Closed
Labels
bugSomething isn't workingSomething isn't working
Description
Hi there, we (Rust group @sslab-gatech) are scanning crates on crates.io for potential soundness bugs. We noticed that Singleton
implements Send and Sync unconiditionally:
Lines 82 to 85 in 203f1ae
// The Singleton need to implement Send & Sync to ensure cross core compile check mechanics | |
// this is safe as the inner RWLock ensures cross core safety | |
unsafe impl<T> Sync for Singleton<T> {} | |
unsafe impl<T> Send for Singleton<T> {} |
This is guarded by a RwLock
but violates RwLock
's own assumptions that Send
will have T: Send
and Sync
will be T: Send + Sync
. The way this is structured right now allows for data races from safe Rust code, for example:
#![forbid(unsafe_code)]
use ruspiro_singleton::Singleton;
use std::{cell::Cell, thread};
#[derive(Debug, Clone, Copy)]
enum RefOrInt<'a> { Ref(&'a u64), Int(u64) }
static SOME_INT: u64 = 123;
static STATIC_CELL : Singleton<Cell<RefOrInt>> = Singleton::lazy(&|| {
Cell::new(RefOrInt::Ref(&SOME_INT))
});
fn main() {
thread::spawn(move || {
loop {
STATIC_CELL.with_ref(|cell| {
// Repeatedly write Ref(&addr) and Int(0xdeadbeef) into the cell.
cell.set(RefOrInt::Ref(&SOME_INT));
cell.set(RefOrInt::Int(0xdeadbeef));
});
}
});
STATIC_CELL.with_ref(|cell| {
loop {
if let RefOrInt::Ref(addr) = cell.get() {
// Hope that between the time we pattern match the object as a
// `Ref`, it gets written to by the other thread.
if addr as *const u64 == &SOME_INT as *const u64 { continue; }
// Due to the data race, obtaining Ref(0xdeadbeef) is possible
println!("Pointer is now: {:p}", addr);
println!("Dereferencing addr will now segfault: {}", *addr);
}
}
});
}
This outputs:
Pointer is now: 0xdeadbeef
Return Code: -11 (SIGSEGV)
Metadata
Metadata
Assignees
Labels
bugSomething isn't workingSomething isn't working