gpt4 book ai didi

memory - Rust 无效指针与 Box::from_raw() Box::into_raw() 往返

转载 作者:行者123 更新时间:2023-12-02 23:16:05 31 4
gpt4 key购买 nike

在尝试创建一些 FFI 帮助程序代码时,我对 Box 这种看似简单的用法感到头疼。

当与具有字段的结构一起使用时,此处的示例似乎给出了 free(): invalidpointer 错误。

pub struct Handle(usize);

impl Handle {
pub fn from<T>(obj: T) -> Self {
let boxed = Box::new(obj);
let mut ptr = Box::into_raw(boxed);
Self::from_ptr_mut(&mut ptr)
}

pub fn from_ptr_mut<T>(ptr: &mut T) -> Self {
Self(ptr as *mut T as usize)
}

pub fn to_box<T>(self) -> Box<T> {
let obj: *mut T = self.to_ptr_mut();
unsafe { Box::from_raw(obj) }
}

pub fn to_ptr_mut<T>(self) -> *mut T {
self.0 as *mut T
}
}

#[allow(dead_code)]
struct Crashes { value: u64 }

impl Drop for Crashes {
fn drop(&mut self) {
println!("Crashes dropped");
}
}

fn crashes() {
let t = Crashes { value: 12 };
let a = Handle::from(t);
let b = a.to_box::<Crashes>();
drop(b);
}

struct Works;

impl Drop for Works {
fn drop(&mut self) {
println!("Works dropped");
}
}

fn works() {
let t = Works;
let a = Handle::from(t);
let b = a.to_box::<Works>();
drop(b);
}

fn main() {
works();
crashes();
}

您可以将其粘贴到 https://play.rust-lang.org/ 中,看看它如何抛出错误 free(): invalidpointer

drop 函数似乎在适当的时间被调用,但指针似乎不知何故无效

最佳答案

您最终在这里创建了一个双指针:

impl Handle {
pub fn from<T>(obj: T) -> Self {
let boxed = Box::new(obj);
let mut ptr = Box::into_raw(boxed);
Self::from_ptr_mut(&mut ptr)
}

pub fn from_ptr_mut<T>(ptr: &mut T) -> Self {
Self(ptr as *mut T as usize)
}
...
}

Box::into_raw返回一个指针,但随后您获取对该指针的可变引用,并将该地址存储为 usize 。您应该只使用 *mut TBox::into_raw 返回.

使用双指针编译非工作代码的原因是您的 from<T>和你的from_ptr_mut<T>可以采取完全不同的T参数。如果我们考虑类型 T传递至from<T>成为具体类型,那么在本例中您将调用 from_ptr_mut<U> (其中 U*mut T ),参数类型为 &mut *mut T .

它应该看起来像这样:

impl Handle {
pub fn from<T>(obj: T) -> Self {
let boxed = Box::new(obj);
let ptr = Box::into_raw(boxed);
Self::from_ptr_mut(ptr)
}

pub fn from_ptr_mut<T>(ptr: *mut T) -> Self {
Self(ptr as usize)
}
...
}

Working example in the playground.

<小时/>

即使我们处于unsafe的领域您可以通过设置参数 T 让编译器为您完成一些工作绑定(bind)到您的Handle结构。这样您就可以静态地防止加载与存储的类型不同的类型。

Playground example where Handle includes a PhantomData.

在第二个示例中,您不必告诉编译器您要检索哪个项目 a.to_box::<Crashes>() ,这很好,因为您不能通过指定错误的类型来引入未定义的行为。

关于memory - Rust 无效指针与 Box::from_raw() Box::into_raw() 往返,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59146268/

31 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com