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中删除)在其__rust_alloc
方法中直接称为alloc
,因此ptr
不是从Box::into_raw
获得的。
是否有效,尽管不支持,将Box::from_raw
原始指针传递给新分配的内存,以便Rust获取该内存的所有权并执行其通常的安全和包容检查?特别是,当生成的Box被销毁时,Rust会释放那个内存吗?
如果没有,除了安全方法之外,如何强制Rust除了分配内存的所有权?
将
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
没有“强迫”Rust做任何事情的概念,更不用说像这样的低级别细节了。例如,不能保证分配指针的C代码不会尝试释放指针本身。在FFI世界中,所有权是一种合作协议。
也可以看看: