Skip to content

Singleton needs bounds on its Send/Sync traits #10

@ammaraskar

Description

@ammaraskar

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:

// 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 working

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions