威尔·克里顿(Will Crichton)在2018年2月的便条“Memory Safety in Rust:A Case Study with C”中写道:



上面提到的他的代码的相关部分是:

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 的文档说明了(强调):



为避免疑问,上面用于执行内存分配(从Rust 1.27.0中删除)的(实验性) Heap API在其 __rust_alloc 方法中直接称为alloc,因此未从ptr获得Box::into_raw

尽管不支持,将Box::from_raw原始指针传递给新分配的内存是否有效,以使Rust拥有该内存的所有权并执行其通常的安全性和遏制性检查?特别是,当出现的Box被销毁时,Rust是否会重新分配该内存?

如果不是,除了强制使用安全方法外,如何迫使Rust拥有这样分配的内存所有权?

最佳答案



不,这是无效的。



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

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

如果不这样做,那么当进行分配的分配器执行其需要做的任何簿记操作时,它就不会知道那部分内存。实际进行分配的分配器永远不会将该内存标记为不可用。

这些问题也没有得到解决。我使用submitted patches to GLib来纠正发生分配/释放分配不匹配并在野外引起实际问题的地方。



就原始指针而言,所有权在很大程度上是一种心态,就像在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以及可能的许多其他特征,以便使用这种类型的人体工程学。

必须创建MallocBoxJeMallocBox以及MyCustomAllocBox会很烦人,这就是RFC 1398为分配器提出共享特征的原因。相关的work is progressingBox<T>转换为Box<T, A: Alloc + Default = Global>



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

也可以看看:
  • 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?
  • 10-02 02:26
    查看更多