Is it safe to transmute
a shared reference &
to a strong Arc<T>
into a shared reference &
to a Weak<T>
?
To ask another way: is the following safe function sound, or is it a vulnerability waiting to happen?
pub fn as_weak<'a, T>(strong: &'a Arc<T>) -> &'a Weak<T> {
unsafe { transmute::<&'a Arc<T>, &'a Weak<T>>(strong) }
}
We have an existing function that returns a &Weak<T>
. The internal data structure has changed a bit, and I now have an Arc<T>
where I previously had a Weak<T>
, but I need to maintain semver compatibility with this function's interface. I'd rather avoid needing to stash an actual Weak<T>
copy just for the sake of this function if I don't need to.
The underlying memory representations of Arc<T>
and Weak<T>
are the same: a not-null pointer (or pointer-like value for Weak::new()
) to an internal ArcInner
struct, which contains the strong and weak reference counts and the inner T
value.
Arc<T>
also contains a PhantomData<T>
, but my understanding is that if that changes anything, it would only apply on drop, which isn't relevant for the case here as we're only transmuting a shared reference, not an owned value.
The operations that an Arc<T>
will perform on its inner pointer are presumably a superset of those that may be performed by a Weak<T>
, since they have the same representation but Arc
carries a guarantee that the inner T
value is still alive, while Weak
does not.
Given these facts, it seems to me like nothing could go wrong. However, I haven't written much unsafe
code before, and never for a production case like this. I'm not confident that I fully understand the possible issues. Is this transmutation safe and sound, or are are there other factors that need to be considered?
No, this is not sound.
Neither Arc
nor Weak
has a #[repr]
forcing a particular layout, therefore they are both #[repr(Rust)]
by default. According to the Rustonomicon section about 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.
You cannot therefore assume that Arc<T>
and Weak<T>
have the same layout.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With