transmute::<&'a Arc<T>, &'a Weak<T>>(…)是否安全?

3

将共享引用&转换为强Arc<T>类型,然后再转换为Weak<T>类型的共享引用,这样做是否安全?

换句话说:下面的函数sound吗?还是存在潜在漏洞?

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

为什么我想这样做

我们有一个现有的函数,返回一个&Weak<T>。内部数据结构有些变化,我现在有一个Arc<T>,之前有一个Weak<T>,但我需要保持与该函数接口的semver兼容性。如果不需要,我宁愿避免只为此函数存储一个实际的Weak<T>副本。

为什么我希望这是安全的

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

Arc<T>中还包含一个PhantomData<T>,但我的理解是,如果有任何变化,它只会在释放时应用,这对于我们仅转换共享引用而不是拥有值的情况并不相关。

Arc<T>将对其内部指针执行的操作可能是Weak<T>可以执行的操作的超集,因为它们具有相同的表示,但Arc提供了一个保证,即内部T值仍然存在,而Weak则没有。

考虑到这些事实,我认为不会出现任何问题。然而,我之前没有写过太多unsafe代码,也从未像这样为生产案例编写过。我不确定我完全理解可能出现的问题。这种转换是否安全可靠,或者还需要考虑其他因素?

1个回答

5

不,这是不对的。

ArcWeak 都没有强制要求特定布局的 #[repr],因此它们都默认为 #[repr(Rust)]。 根据《Rustonomicon》关于 repr(Rust) 的部分所述:

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

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

Rust does guarantee that two instances of A have their data laid out in exactly the same way. However Rust does not currently guarantee that an instance of A has the same field ordering or padding as an instance of B.

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


1
谢谢解释。这很糟糕,但是很有道理。我已经在rust-internals上发布了我的第一个帖子,以查看是否有人有兴趣添加必要的#[repr(transparent)]以启用此功能。链接:https://internals.rust-lang.org/t/marking-arc-rc-weak-as-repr-transparent/17171?u=jeremybanks - user19567871
1
我在IRLO上得到了一些有用的反馈。显然,即使将Arc/Rc/Weak类型标记为#[repr(transparent)],仍然不适合转换它们,因为只要字段是私有的,表示仍被视为私有。因此,这种转换只能由标准库本身安全地执行。让我们看看Rust团队对此的看法:Rust PR#100472:添加函数Arc/Rc :: as_weak(…)以将&Arc/Rc转换为&Weak - user19567871

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接