为什么一个盒子指针传递给C,然后回到锈段错误?

问题描述 投票:5回答:2

一些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);
}
rust ffi
2个回答
8
投票

close,你最终建立一个Box<c_void>代替Box<Handle>的,因为你没有调用*mut c_void之前投的*mut HandleBox::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释放内存,这会导致段错误。


4
投票

问题是你不投的指针回到Handle指针,同时将其转化回Box,并得到了错误类型的Box

这工作:

fn close(h: *mut c_void) {
    let h = unsafe { Box::from_raw(h as *mut Handle) };
    //                               ^^^^^^^^^^^^^^
    drop(h);
}

在你的代码,hstd::boxed::Box<std::ffi::c_void>

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