Rust-GPU / Rust-CUDA

Ecosystem of libraries and tools for writing and executing fast GPU code fully in Rust.
Apache License 2.0
2.97k stars 112 forks source link

Fix: cast caused double free (use mem::forget) #105

Open DoeringChristian opened 1 year ago

DoeringChristian commented 1 year ago

Hi,

i found a double free in the cast function of the DeviceBuffer class. The following code would not work:

        let x = vec![0f32; 100].as_slice().as_dbuf().unwrap();
        dbg!(&x);
        println!("{:#x?}", x.as_device_ptr().as_raw());
        // dbg!(x.as_host_vec());
        let x = x.cast::<u8>();
        dbg!(&x);
        let x = x.cast::<f32>();
        dbg!(&x);
        dbg!(x.as_host_vec());

This returns with CUDA_ERROR_INVALID_VALUE. Looking at the trace using Nvidia Nsight Compute it can be seen that there occurs a double free.

Screenshot from 2023-03-20 09-12-56 It turns out that when the cast function returns it drops self and frees the buffer. The fix is to use std::mem::forget on self.

            let new_len = (size_of::<A>() * self.len) / size_of::<B>();
            let ret = Ok(DeviceBuffer {
                buf: self.buf.cast(),
                len: new_len,
            });
            unsafe{std::mem::forget(self);} // this is necessary to prevent double free
            ret

However I don't know if there is a better way than using std::mem::forget.