将对强的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代码,也从未编写过这样的生产案例。我不确定我是否完全理解可能出现的问题。这种嬗变是否安全可靠,还是还有其他需要考虑的因素?
不,这不合理。
Arc两者都没有Weak强制#[repr]特定的布局,因此它们都是#[repr(Rust)]默认的。根据Rustonomicon 部分有关repr(Rust):
Run Code Online (Sandbox Code Playgroud)struct A { a: i32, b: u64, } struct B { a: i32, b: u64, }Rust确实保证 A 的两个实例的数据以完全相同的方式布局。然而,Rust目前不保证 A 的实例与 B 的实例具有相同的字段排序或填充。
因此,您不能假设Arc<T>和Weak<T>具有相同的布局。