gpt4 book ai didi

rust - 通过原始指针克隆类型删除的 Arc 是否安全?

转载 作者:行者123 更新时间:2023-12-04 19:25:01 24 4
gpt4 key购买 nike

我正在处理包装在 Arc 中的数据。 ,我有时最终会使用 into_raw 获取指向基础数据的原始指针。我的用例还需要类型删除,因此原始指针通常会转换为 *const c_void ,然后在重建 Arc 时转换回适当的具体类型.

我遇到了能够克隆 Arc 的情况。无需知道基础数据的具体类型。据我了解,重建 Arc 应该是安全的。仅用于调用 clone 的虚拟类型,只要我从未真正取消引用数据。因此,例如,这应该是安全的:

pub unsafe fn clone_raw(handle: *const c_void) -> *const c_void {
let original = Arc::from_raw(handle);
let copy = original.clone();
mem::forget(original);
Arc::into_raw(copy)
}

有什么我遗漏的东西会使这实际上不安全吗?另外,我认为答案将适用于 Rc也一样,但如果有任何差异,请告诉我!

最佳答案

这几乎总是不安全的。

一个 Arc<T>只是一个指向堆分配结构的指针,大致看起来像

struct ArcInner<T: ?Sized> {
strong: atomic::AtomicUsize,
weak: atomic::AtomicUsize,
data: T, // You get a raw pointer to this element
}
into_raw()给你一个指向 data的指针元素。 Arc::from_raw()的执行接受这样一个指针,假定它是指向 data 的指针- ArcInner<T> 中的元素, 回到内存中并假设找到一个 ArcInner<T>那里。这个假设取决于 T 的内存布局。 ,特别是它的对齐,因此它在 ArcInner 中的确切位置.

如果您调用 into_raw()Arc<U>然后调用 from_raw()好像是 Arc<V>在哪里 UV对齐方式不同,偏移量计算 where U/ VArcInner将是错误的,调用 .clone()会破坏数据结构。取消引用 T因此不需要触发内存不安全。

在实践中,这可能不是问题:因为 data是两个 usize 之后的第三个元素-元素,大多数 T可能会以相同的方式对齐。但是,如果 stdlib 实现发生变化,或者您最终为这个假设错误的平台编译,则重建 Arc<V>::from_rawArc<U> 创建 V 的内存布局在哪里和 U不同会不安全和崩溃。

更新:

再想一想,我将我的投票从“可能是安全的,但令人毛骨悚然”降级为“很可能不安全”,因为我总能做到
#[repr(align(32))]
struct Foo;

let foo = Arc::new(Foo);

在此示例中 Foo将对齐到 32 个字节,使 ArcInner<Foo>大小为 32 字节 (8+8+16+0) 而 ArcInner<()>只有 16 个字节 (8+8+0+0)。由于没有办法知道 T的对齐方式是什么是在类型被删除后,无法重建有效的 Arc .

有一个在实践中可能是安全的逃生舱口:通过包装 T进入另一个 BoxArcInner<T>的布局总是一样的。为了对任何用户强制执行此操作,您可以执行类似的操作
struct ArcBox<T>(Arc<Box<T>>)

并实现 Deref在那。使用 ArcBox而不是 Arc强制 ArcInner 的内存布局总是一样的,因为 T在另一个指针后面。然而,这意味着所有访问 T需要双重取消引用,这可能会严重影响性能。

关于rust - 通过原始指针克隆类型删除的 Arc 是否安全?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59671647/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com