威尔·克里顿(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分配和释放内存的方式, 传递给该函数的唯一有效指针 是通过{{3}从另一个Box获取的指针}功能。
为免生疑问,上面使用的(实验性)Box::into_raw
API在其Heap
方法中直接调用了__rust_alloc
来执行内存分配(从Rust 1.27.0中删除)。因此不是从ptr
获得的。{p>
传递给Box::into_raw
原始指针到新分配的内存,以使Rust拥有该内存的所有权并执行其通常的安全性和遏制性检查,是否有效?特别是,当出现的Box被销毁时,Rust是否会重新分配该内存?
如果没有, 怎么能迫使Rust拥有这种通过安全方法分配的内存所有权?
答案 0 :(得分:4)
传递给
Box::from_raw
原始指针到新分配的内存是否有效,尽管不受支持
否,它无效。
尤其是当出现的
Box
被销毁时,Rust是否会重新分配该内存?
是的,这就是它无效的原因。
内存分配器提供了成对分配和释放例程。当您使用一个分配器分配一块内存时,您必须使用该分配器释放它。
如果不这样做,那么当进行分配的分配器执行其需要做的任何簿记操作时,它将不知道那部分内存。实际进行分配的分配器永远不会将该内存标记为不可用。
这些问题也没有得到解决。我已经submitted patches to GLib纠正了分配/解除分配不匹配并在野外引起实际问题的地方。
必须拥有分配的内存的所有权
就原始指针而言,所有权在很大程度上是一种心态,就像在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世界中,所有权是一种合作协议。
另请参阅: