取消引用 *const Mutex 恐慌

问题描述 投票:0回答:1

我目前正在研究 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());
}

我认为当

thing.vec
被调用时
runner.run()
应该有效,因为它是在
thing
仍然存在时被调用的,但是代码会出现恐慌。

我该如何解释这种行为?

rust unsafe
1个回答
1
投票

thing
is 在调用回调时有效,问题在于将
vec
添加到结构体以及从函数返回它都会 move 它,换句话说,它可以位于另一个内存位置比
callback_runner.data
指向的那个。

由于您正在取消引用悬空指针,因此您的代码包含 UB,幸运的是您遇到了错误,而不是在某个时候出现静默失败。

要解决这个问题,您必须确保在创建指向它的指针后,

vec
不会在内存中移动,例如通过(固定)
Box
将其放在堆上。

© www.soinside.com 2019 - 2024. All rights reserved.