rust-lang-nursery / lazy-static.rs

A small macro for defining lazy evaluated static variables in Rust.
Apache License 2.0
1.9k stars 111 forks source link

unsafe lazy_static that's not Sync ? #135

Closed asomers closed 5 years ago

asomers commented 5 years ago

would it be possible to create an unsafe version of the macro that allows the type to be non-Sync? I would like to use it in an FFI context. The calling C code requires me to provide a global mutable structure containing raw pointers.

KodrAus commented 5 years ago

Hi @asomers :wave:

An unsafe variant of lazy_static is probably out-of-scope for this library, but you can use Rust's own unsafe mutable static feature to provide a global mutable structure:

struct Pointers {
    a: *mut u8,
    b: *mut u8,
}

impl Pointers {
    const UNINIT: Self = Pointers {
        a: std::ptr::null_mut(),
        b: std::ptr::null_mut(),
    };
}

static mut POINTERS: Pointers = Pointers::UNINIT;

fn main() {
    // Working with 'static mut is unsafe
    // You're responsible for ensuring the mutable state is
    //  only aliased and accessed correctly
    unsafe {
        let pointers = &mut POINTERS;

         // Pass through FFI
    }
}
asomers commented 5 years ago

That helps! It makes it possible, but not easy, to do what I want. Using that technique, I can't initialize the variable with non-const functions like mem::zeroed() or mem::uninitialized(). That's why I was hoping there would be a way to do it with lazy_static. Do you know of any way to initialize non-Sync static variables with mem::zeroed()?

asomers commented 5 years ago

Ok, I found a great hack. I can run code in a constructor function as soon as my library gets loaded, before the application can access it with dlsym.

#[export_name = "mysymbol"]
pub static mut MYSYMBOL: Option<Foo> = None;

#[link_section = ".init_array"]
pub static INITIALIZE: extern "C" fn() = rust_ctor;

#[no_mangle]
pub extern "C" fn rust_ctor() {
    unsafe {
        MYSYMBOL = Some(Foo::new())
    }
}

Thanks for the help. I'm going to close the issue now.

benniebendiksen commented 2 years ago

Ok, I found a great hack. I can run code in a constructor function as soon as my library gets loaded, before the application can access it with dlsym.

#[export_name = "mysymbol"]
pub static mut MYSYMBOL: Option<Foo> = None;

#[link_section = ".init_array"]
pub static INITIALIZE: extern "C" fn() = rust_ctor;

#[no_mangle]
pub extern "C" fn rust_ctor() {
    unsafe {
        MYSYMBOL = Some(Foo::new())
    }
}

Thanks for the help. I'm going to close the issue now.

Thank you for this; this really saved me from a multi-day bind. Still, why not just use a mutex around your global mutable var and ditch the unsafe keyword when accessing it?