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

Posted

技术标签:

【中文标题】怎样才能强制 Rust 获得分配的内存的所有权,而不是通过其安全方法分配的内存?【英文标题】:How can one force Rust to take ownership of memory allocated other than by its safe methods? 【发布时间】:2019-07-17 21:30:41 【问题描述】:

Will Crichton 在 2018 年 2 月题为“Memory Safety in Rust: A Case Study with C”的说明中写道:

Rust 提供了获取原始指针所有权的能力,我们使用 slice::from_raw_parts_mutBox::from_raw 来做到这一点,这告诉 Rust 将内存指针视为堆分配的数组。转移所有权后,假设内存有效且大小/类型正确,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))
;

但是,Box::from_raw 的文档指出(已添加重点):

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

为免生疑问,上面用于执行内存分配的(实验性)Heap API(自 Rust 1.27.0 中删除)在其 alloc 方法中直接调用 __rust_alloc,因此 ptr不是Box::into_raw获取的。

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

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

【问题讨论】:

Related PR from 2019-02-05 “如果不是,如何强制 Rust 获取非通过其安全方法分配的内存的所有权?”根据定义,这是没有意义的。另外,我建议不要将Box::from_raw 与不是来自Box 的指针一起使用,首先即使它“在某些情况下可能是正确的”,这也可能很快出错,其次,我怀疑一个好的API C 会照顾你释放资源,除了某些情况下你可以调用free,我认为最好调用free 来猜测 box 是否也会有。 【参考方案1】:

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

不,无效。

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

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

内存分配器提供配对分配和释放例程。当您使用一个分配器分配一块内存时,您必须使用该分配器释放它

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

这些担忧也没有解决。我已经submitted patches to GLib 纠正了发生不匹配分配/解除分配并导致实际问题的地方。

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

在原始指针级别,所有权很大程度上是一种心态,就像在 C 或 C++ 中一样。 拥有这里的东西意味着你有责任适当地清理它。

mallocfree 是配对分配/解除分配方法。您可以创建自己的类型并为其实现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);

真正的实现也会实现Deref 和可能的许多其他特征,因此这种类型使用起来符合人体工程学。

必须创建MallocBoxJeMallocBoxMyCustomAllocBox 会很烦人,这就是RFC 1398 为分配器提出共享特征的原因。相关work is progressing 将Box&lt;T&gt; 转换为Box&lt;T, A: Alloc + Default = Global&gt;

如何强行生锈

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


另见:

How do I handle an FFI unsized type that could be owned or borrowed? What is the better way to wrap a FFI struct that owns or borrows data?

【讨论】:

我实际上希望从 Rust 中分配内存(以实例化自定义 DST)。我的问题是,如果我使用 Rust 的分配器来分配内存,然后用(正确类型的)胖原始指针指向该内存,是否可以将此类指针传递给 Box::from_raw 以便 Rust 承担该内存的所有进一步责任(即所有权、借款、解除分配等)?

以上是关于怎样才能强制 Rust 获得分配的内存的所有权,而不是通过其安全方法分配的内存?的主要内容,如果未能解决你的问题,请参考以下文章

我怎样才能获得所有开放的会话?

Rust - 使用 Rayon 进行排列 - 向量内存分配错误

Rust 如何知道哪些类型拥有资源?

内存安全

我怎样才能在Laravel中获得cookie?

Rust 内存管理