怎样才能强制 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_mut
和Box::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++ 中一样。 拥有这里的东西意味着你有责任适当地清理它。
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);
真正的实现也会实现Deref
和可能的许多其他特征,因此这种类型使用起来符合人体工程学。
必须创建MallocBox
和JeMallocBox
和MyCustomAllocBox
会很烦人,这就是RFC 1398 为分配器提出共享特征的原因。相关work is progressing 将Box<T>
转换为Box<T, A: Alloc + Default = Global>
。
如何强行生锈
没有“强迫”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 获得分配的内存的所有权,而不是通过其安全方法分配的内存?的主要内容,如果未能解决你的问题,请参考以下文章