一些C代码调用到锈open
呼叫低于它返回一个指针。后来C代码通过完全相同的指针返回到它试图下降(免费)它close
功能。它出现segfaults在free(3)
。为什么?
use std::os::raw::{c_int, c_void};
struct Handle;
extern "C" fn open(_readonly: c_int) -> *mut c_void {
let h = Handle;
let h = Box::new(h);
return Box::into_raw(h) as *mut c_void;
}
extern "C" fn close(h: *mut c_void) {
let h = unsafe { Box::from_raw(h) };
// XXX This segfaults - why?
drop(h);
}
在close
,你最终建立一个Box<c_void>
代替Box<Handle>
的,因为你没有调用*mut c_void
之前投的*mut Handle
回Box::from_raw
。
fn close(h: *mut c_void) {
let h = unsafe { Box::from_raw(h as *mut Handle) };
drop(h);
}
顺便说一句,Box
实际上不分配一个零大小的类型的任何存储器(例如Handle
这里),并使用一个固定的非零指针值代替(其在当前实现中,是该类型的对准;一个零大小的类型具有默认为1比对)。对于盒装零大小类型的析构函数知道不要尝试在这个虚拟内存地址释放内存,但c_void
不是零大小的类型(有大小为1),所以Box<c_void>
析构函数试图在地址0x1
释放内存,这会导致段错误。
问题是你不投的指针回到Handle
指针,同时将其转化回Box
,并得到了错误类型的Box
。
这工作:
fn close(h: *mut c_void) {
let h = unsafe { Box::from_raw(h as *mut Handle) };
// ^^^^^^^^^^^^^^
drop(h);
}
在你的代码,h
是std::boxed::Box<std::ffi::c_void>
。