转换::<&'a Arc<T>, &'a Weak<T>>(...) 安全吗?

3 unsafe rust

将对强的transmute共享引用转换为对a的共享引用是否安全?&Arc<T>&Weak<T>

换个角度问:以下安全功能是否健全,或者是否存在等待发生的漏洞?

pub fn as_weak<'a, T>(strong: &'a Arc<T>) -> &'a Weak<T> {
    unsafe { transmute::<&'a Arc<T>, &'a Weak<T>>(strong) }
}
Run Code Online (Sandbox Code Playgroud)

为什么我要这样做

我们有一个返回 a 的现有函数&Weak<T>。内部数据结构发生了一些变化,我现在有了一个Arc<T>以前有过的Weak<T>,但我需要保持 semver 与该函数接口的兼容性。如果不需要的话,我宁愿避免Weak<T>仅仅为了这个功能而需要存储实际的副本。

为什么我希望这是安全的

Arc<T>和的底层内存表示是相同的:指向内部结构的Weak<T>非空指针(或类似指针的值) ,其中包含强引用计数和弱引用计数以及内部值。Weak::new()ArcInnerT

Arc<T>还包含 a PhantomData<T>,但我的理解是,如果这改变了任何东西,它只会适用于 drop,这与这里的情况无关,因为我们只是改变共享引用,而不是拥有的值。

an 将对其内部指针执行的操作Arc<T>可能是 a 可能执行的操作的超集Weak<T>,因为它们具有相同的表示形式,但Arc保证内部T值仍然有效,而 whileWeak则不然。

鉴于这些事实,在我看来,一切都不会出错。但是,我以前没有编写过太多unsafe代码,也从未编写过这样的生产案例。我不确定我是否完全理解可能出现的问题。这种嬗变是否安全可靠,还是还有其他需要考虑的因素?

cdh*_*wie 5

不,这不合理。

Arc两者都没有Weak强制#[repr]特定的布局,因此它们都是#[repr(Rust)]默认的。根据Rustonomicon 部分有关repr(Rust)

struct A {
    a: i32,
    b: u64,
}

struct B {
    a: i32,
    b: u64,
}
Run Code Online (Sandbox Code Playgroud)

Rust确实保证 A 的两个实例的数据以完全相同的方式布局。然而,Rust目前保证 A 的实例与 B 的实例具有相同的字段排序或填充。

因此,您不能假设Arc<T>Weak<T>具有相同的布局。