MST

星途 面试题库

面试题:Rust中unsafe代码块的安全边界实践

假设你需要在Rust中调用一个C语言库函数,该函数会直接操作内存。请使用unsafe代码块实现这个调用,并解释你是如何确保代码在unsafe块中的安全边界,避免出现内存泄漏、空指针引用等问题。
38.3万 热度难度
编程语言Rust

知识考点

AI 面试

面试题答案

一键面试

以下是一个简单示例,假设C语言库函数为extern "C" void c_function(void* ptr, size_t len);,该函数接受一个指针和长度来操作内存。

extern "C" {
    fn c_function(ptr: *mut u8, len: usize);
}

fn main() {
    let mut data = vec![0u8; 10];
    let ptr = data.as_mut_ptr();
    let len = data.len();

    unsafe {
        c_function(ptr, len);
        // 确保在调用C函数后,Rust仍然管理这块内存
        std::mem::forget(data); 
        // 这里只是为了演示,实际可能需要恢复对data的管理,例如通过重新构造Vec
        // data = Vec::from_raw_parts(ptr, len, len);
    }
}

安全边界的确保

  1. 空指针引用
    • 在调用c_function之前,通过vec![0u8; 10]创建了一个Vec,它保证了as_mut_ptr()返回的指针是非空的。这样就避免了将空指针传递给C函数,从而防止空指针引用问题。
  2. 内存泄漏
    • Rust的Vec在超出作用域时会自动释放内存。但是在unsafe块中调用C函数时,C函数可能会修改Vec的内部状态,导致Rust无法正确管理内存。这里使用std::mem::forget(data)来告诉Rust暂时忘记对data的所有权,从而避免dataunsafe块结束时被双重释放(因为C函数可能已经释放了它或者改变了它的状态)。如果C函数没有释放内存,之后可以通过Vec::from_raw_parts(ptr, len, len)重新构造Vec,让Rust继续管理这块内存,确保没有内存泄漏。
    • 此外,在传递指针给C函数时,传递了正确的长度信息len,这样C函数在操作内存时不会越界访问,避免因内存越界导致未定义行为和潜在的内存泄漏。