rust 取消引用 *const Mutex死机

yeotifhr  于 12个月前  发布在  其他
关注(0)|答案(1)|浏览(100)

我目前正在研究一个FFI库的安全绑定,这是我遇到的问题的最小实现。

fn test_weird_thing() {
    use std::sync::Mutex;
                
    struct WeirdThing<'a> {
        vec: Mutex<Vec<i32>>,
        callback_runner: &'a CallbackRunner,
    }

    // Hypothetical FFI Struct///
    struct CallbackRunner {
        callback: extern "C" fn(*const Mutex<Vec<i32>>),
        data: *const Mutex<Vec<i32>>,
    }

    impl CallbackRunner {
        extern "C" fn default_callback(_vec: *const Mutex<Vec<i32>>) {}

        fn new() -> Self {
            CallbackRunner {
                callback: Self::default_callback,
                data: std::ptr::null(),
            }
        }

        fn set_callback(
            &mut self, callback: extern "C" fn(*const Mutex<Vec<i32>>), 
            data: *const Mutex<Vec<i32>>
        ) { 
            self.data = data;
            self.callback = callback;
        }

        fn run(&self) {
            (self.callback)(self.data);
        }
    }
    /////////////////////////////

    impl<'a> WeirdThing<'a> {
        fn new(runner: &'a mut CallbackRunner) -> Self {
            let vec = Mutex::new(Vec::new());
            runner.set_callback(Self::callback, &vec as *const Mutex<Vec<i32>>);
            WeirdThing { vec, callback_runner: runner }
        }

        extern "C" fn callback(vec: *const Mutex<Vec<i32>>) {
            let vec = unsafe { &*vec };
            let mut vec = vec.lock().unwrap();
            vec.push(1);
        }

        fn do_thing(&self) -> Vec<i32> {
            self.callback_runner.run();
            self.vec.lock().unwrap().clone()
        }
    }

    let mut runner = CallbackRunner::new();
    let thing = WeirdThing::new(&mut runner);
    debug!("Thing: {:?}", thing.do_thing());
}

我认为当runner.run()被调用时thing.vec应该是有效的,因为它是在thing仍然存在的时候被调用的,但是代码出现了异常。
我该如何解释这种行为?

nszi6y05

nszi6y051#

thing在你调用回调函数的时候是有效的,问题是无论是将vec添加到结构体还是从函数返回都会移动它,换句话说,它可能位于callback_runner.data指向的内存位置之外的另一个内存位置。
由于你正在解引用一个悬空指针,你的代码包含UB,幸运的是你得到了一个错误,而不是一个无声的失败。
要解决这个问题,您必须确保在创建指向vec的指针后,它不会在内存中移动,例如,将它与(固定的)Box放在堆上。
我已经画出了in this answer how to create a pointer to something you create within the function,你应该能够把它应用到你的问题中。

相关问题