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