如何强制 Rust 获得分配的内存的所有权,而不是通过其安全方法?

egg*_*yal 6 pointers memory-management heap-memory ownership rust

在 2018 年 2 月题为“ Rust 中的内存安全:C 案例研究”的笔记中,Will Crichton 写道:

拉斯特提供吃生的三分球,这是我们使用的所有权的能力slice::from_raw_parts_mut和Box::from_raw它告诉防锈处理内存指针作为堆中分配的数组。转让所有权后,假设内存有效且大小/类型正确,Rust 会应用其通常的内存安全和包含检查。

他上面提到的代码的相关部分是:

let mut new_data = unsafe {
    let ptr = Heap::default()
        .alloc(Layout::array::<isize>(new_capacity).unwrap())
        .unwrap() as *mut isize;
    Box::from_raw(slice::from_raw_parts_mut(ptr, new_capacity))
};
Run Code Online (Sandbox Code Playgroud)

但是,Box::from_raw状态文档(已添加强调):

由于 Box 分配和释放内存的方式未指定,因此传递给此函数的唯一有效指针是通过该函数从另一个 Box 获取的指针Box::into_raw。

为避免疑义,(实验)Heap上面使用API来执行存储器分配(因为在锈病1.27.0移除)直接调用__rust_alloc在其alloc方法和因此ptr是不从得Box::into_raw。

将Box::from_raw原始指针传递给新分配的内存以让 Rust 获得该内存的所有权并执行其通常的安全和包含检查是否有效,尽管不受支持?特别是,当出现的 Box 被销毁时,Rust 会释放该内存吗?

如果没有,怎么能一个强制锈病采取的记忆这种所有权不是通过其安全的方法分配其他?

She*_*ter 6

将Box::from_raw原始指针传递给新分配的内存是否有效,尽管不受支持

不,它无效。

特别是,当出现Box被销毁时,Rust 会释放该内存吗?

是的,这就是它无效的原因。

内存分配器提供成对的分配和释放例程。当你用一个分配器分配一块内存时,你必须用那个分配器释放它。

如果你不这样做,当执行释放的分配器去执行它需要做的任何簿记时,它不会知道那块内存。实际进行分配的分配器永远不会将该内存标记为不可用。

这些担忧也不是空穴来风。我已经向 GLib 提交了补丁,以纠正发生不匹配分配/解除分配并导致实际问题的地方。

Rust 获得分配的内存的所有权

在原始指针的级别上,所有权主要是一种心态,就像在 C 或 C++ 中一样。在这里拥有某物意味着您有责任适当地清理它。

malloc和free是成对的分配/解除分配方法。您可以创建自己的类型并Drop为其实现:

use libc::{free, malloc};
use std::{ffi::c_void, mem};

struct MallocBox(*mut i32);

impl MallocBox {
    fn new(v: i32) -> Self {
        unsafe {
            let p = malloc(mem::size_of::<i32>()) as *mut i32;
            *p = v;
            Self(p)
        }
    }
}

impl Drop for MallocBox {
    fn drop(&mut self) {
        unsafe { free(self.0 as *mut c_void) }
    }
}

fn main() {
    MallocBox::new(42);
}
Run Code Online (Sandbox Code Playgroud)

一个真正的实现也将实现Deref,可能还有许多其他特性,以便这种类型的使用符合人体工程学。

必须创建 a MallocBoxandJeMallocBox和 a会很烦人MyCustomAllocBox,这就是RFC 1398为分配器提出共享特征的原因。相关工作正在逐步转换Box<T>为Box<T, A: Alloc + Default = Global>.

如何强制 Rust

没有“强迫” Rust 做任何事情的概念,更不用说像这样的低级细节。例如,不能保证分配指针的 C 代码不会尝试释放指针本身。在 FFI 世界中,所有权是一种合作协议。


也可以看看:

  • 我实际上希望从 Rust 内部分配内存(以便实例化自定义 DST)。我的问题是,如果我使用 Rust 的分配器来分配内存,然后用一个(正确类型的)胖原始指针指向该内存,这样的指针是否可以传递给 `Box::from_raw` 以便 Rust 承担所有进一步的责任对于该内存(即所有权、借用、释放等)? (2认同)