Will Crichton 在他 2018 年 2 月题为“Memory Safety in Rust: A Case Study with C”的笔记中写道:
Rust provides the ability to take ownership of raw pointers, which we do using
slice::from_raw_parts_mut
andBox::from_raw
which tells Rust to treat the memory pointer as a heap-allocated array. After transferring ownership, assuming the memory is valid and of the right size/type, Rust applies its usual memory safety and containment checks.
上面提到的他的代码的相关部分是:
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
的文档状态(添加了强调):
Since the way Box allocates and releases memory is unspecified, the only valid pointer to pass to this function is the one taken from another Box via the
Box::into_raw
function.
为避免疑义,(实验)Heap
上面用于执行内存分配的 API(自从在 Rust 1.27.0 中删除)在其 alloc
中直接调用 __rust_alloc
方法——因此 ptr
不是从 Box::into_raw
获得的。
将指向新分配内存的原始指针传递给 Box::from_raw
以使 Rust 取得该内存的所有权并执行其通常的安全和包含检查是否有效(尽管不受支持)?特别是,当出现的 Box 被销毁时,Rust 会释放该内存吗?
如果不是,那么如何强制 Rust 取得这种非安全方法分配的内存所有权?
最佳答案
Is it valid, albeit unsupported, to pass to
Box::from_raw
raw pointers to freshly allocated memory
不,这是无效的。
In particular, will Rust deallocate that memory when the arising
Box
is destroyed?
是的,这就是它无效的原因。
内存分配器提供配对分配和释放例程。当您使用一个分配器分配一 block 内存时,您必须使用该分配器释放它。
如果你不这样做,当执行释放的分配器去执行它需要做的任何簿记时,它不会知道那 block 内存。实际执行分配的分配器永远不会将该内存标记为不可用。
这些担忧也不是虚构的。我有 submitted patches to GLib纠正发生分配/释放不匹配并导致实际问题的地方。
Rust to take such ownership of memory allocated
在原始指针级别,所有权在很大程度上是一种心态,就像在 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>
.
how can one force Rust
没有“强制”Rust 做任何事情的概念,更不用说像这样的低级细节了。例如,无法保证分配指针的 C 代码不会尝试释放指针本身。在 FFI 世界中,所有权是一种合作协议(protocol)。
另见:
关于pointers - 如何强制 Rust 获得非安全方法分配的内存的所有权?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54849928/