elast0ny / shared_memory

A Rust wrapper around native shared memory for Linux and Windows
380 stars 51 forks source link

segmentation fault #95

Closed GOVYANSONG closed 1 year ago

GOVYANSONG commented 1 year ago

I was able to run the example where shared data is of primitive type e.g. u8 or usize. but when i tried to run the logic with struct or vec, the read side always returned segmentation fault:

write side:

{ let data_ptr = mutex.lock().unwrap(); let data = unsafe { &mut (data_ptr as *mut Vec) };

    //let sd : Entry = Entry { hashcode: 1, buff: vec![1, 2, 3, 4, 5]};
    let sd : Entry = Entry { hashcode: 1};
    serialize_into(data, &sd).unwrap();
}

read side:

{ let data_ptr = mutex.rlock().unwrap(); let data = unsafe { & (data_ptr as *const Vec) };

    eprintln!("{}", data[1]);

    match deserialize::<Entry>(data)
    {
        Ok(d) => eprint!("Data : {:?}", d),
        Err(e) =>  eprint!("Error deserializing data {}", e)
    }
}

any idea what is going on?

Polish-Civil commented 1 year ago
*data_ptr as *mut Vec

why is your data_ptr of type *Vec? shouldn't it be *u8?

Vec is resizable type, afaik Shmem holds pointer to some memory mapping with a static size.

GOVYANSONG commented 1 year ago

thanks for the information. I want to serialize a struct into vec and store it in the shared memory. not sure about the correct way to approach this with pointer to u8.

Polish-Civil commented 1 year ago

Well, you could do it in two steps, by simply serializing to temporary allocated Vec, so that you know exactly how many bytes whole serialized thing has.

use serde::*;

#[derive(Serialize, Deserialize)]
struct Data;

fn main() {
    let data = bincode::serialize(&Data).unwrap();
    let shared_mem_ptr: *mut u8 = todo!("grab shm ptr");
    let shared_mem_ptr_ofsetted: *mut u8 = unsafe {
        shared_mem_ptr.offset(todo!("location where to put struct data"));
    };
    let shared_mem_slice =
        unsafe { core::slice::from_raw_parts_mut(shared_mem_ptr_ofsetted, data.len()) };

    // serializing to shared mem:
    shared_mem_slice.copy_from_slice(&data);
    // deserializing from shared mem:
    let data_deserialized: Data = bincode::deserialize(&shared_mem_slice).unwrap();
}

Note that you would need to make appropriate decisions where in your shared memory you place your serialized data, the beginning and the size of the serialized data must be know ahead of time for this to work, so that reader knows from what point in the shared memory start reading from when de-serializing.

Alternatively, you could try and write Reader and Writer impls for the shared memory, so you can use serialize_with(writer, data) and deserialize_from(reader, data) which could take the starting offset to provide information where specific data type resides in the shared memory, and read from there. In this approach you only need to care about the starting point, the size of the remaining (start - shm_mem) just need to be enough to fit in the data, as its written to byte by byte.

Also please note that i'm unaware of any shenanigans regarding the flushing of the bytes, meaning the availability of them on the reader side, so i'm not sure if you would be able to know that you can successfully read whole thing on the reading side without more checks, for example making headers with some flags that the data is valid to be read from.

GOVYANSONG commented 1 year ago

Thanks a bunch for the detailed instructions. they are very helpful. I am now able to pass data struct through shared memory. I did not know about the usage of slice before.