Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to initialize static struct on heap in a function?

I have a global struct that stores my objects and has complicated behavior. Besides the data it has a global id-generator for objects. They need them for their work too.

use std::sync::{Arc, Mutex};

static mut system_ptr: *mut Box<System> = 0 as *mut Box<System>;

struct System {
    data: Vec<Data>,
    id_mutex: Arc<Mutex<u32>>,
}

impl System {
    fn get_new_id() -> u32 {
        unsafe {
            let s = &mut *system_ptr;
            let mut data = s.id_mutex.lock().unwrap();
            *data += 1;
            *data
        }
    }
}

I am initializing that struct like this now:

fn main() {
    let s = System{data: Vec::new(), id_mutex: Arc::new(Mutex::new(0 as u32))};
    let mut s_box = Box::new(s);
    unsafe {
        system_ptr = &mut s_box as *mut Box<System>;
    }

    // here I have some work with the initialized "System"

}

When I move initialization code from main() to some function, the Box is dropped and I have a "use after free" error and a crash.

I've tried to use &'static but am not fluent enough with Rust's semantics for now, or it was bad idea.

Anyway, how can I move initialization of some Box'ed memory (raw pointer) to a function or method?

Edit: This is not a question about singleton, it's about initialization of any heap variable. Matt, thanks for the right understanding!

like image 210
Revertron Avatar asked Dec 30 '25 21:12

Revertron


1 Answers

You may may to use the lazy_static crate to initialize your static variable, and then you won't need to deal with raw pointers.

But if you do want to handle this yourself, you can do it like this:

static mut system_ptr: *mut System = 0 as *mut System;

fn init() {
    let mut system = Box::new(System(Vec::new()));
    unsafe {
        system_ptr = &mut *system;
    }
    std::mem::forget(system);
}

Passing the box to std::mem::forget leaks it intentionally, ensuring that its destructor never runs. Instead of storing a pointer to the Box (which is itself just a pointer in a local stack variable), we store a pointer directly to the value on the heap.

The upcoming Rust 1.4 release will have a Box::into_raw function which handles all of this for you. If you upgrade to Rust 1.4 (currently on the beta channel), you can replace the above code with:

fn init() {
    unsafe {
        system_ptr = Box::into_raw(Box::new(System(Vec::new())));
    }
}
like image 68
mbrubeck Avatar answered Jan 04 '26 04:01

mbrubeck



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!