You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This commit is a fix for rust-lang#48493 where calling `Weak::new` where `T` is an
uninhabited type would segfault. The cause for this issue was pretty subtle and
the fix here is mostly a holdover until rust-lang#47650 is implemented.
The `Weak<!>` struct internally contains a `NonNull<RcBox<!>>`. The `RcBox<!>`
type is uninhabited, however, as it directly embeds the `!` type. Consequently
the size of `RcBox<!>` is zero, which means that `NonNull<RcBox<!>>` always
contains a pointer with a value of 1. Currently all boxes of zero-sized-types
are actually pointers to the address 1 (as they shouldn't be read anyway).
The problem comes about when later on we have a method called `Weak::inner`
which previously returned `&RcBox<T>`. This was actually invalid because the
instance of `&RcBox<T> ` never existed (only the uninitialized part). This
means that when we try to actually modify `&RcBox`'s weak count in the
destructor for `Weak::new` we're modifying the address 1! This ends up causing a
segfault.
This commit takes the strategy of modifying the `Weak::inner` method to return
an `Option<&RcBox<T>>` that is `None` whenever the size of `RcBox<T>` is 0 (so
it couldn't actually exist). This does unfortunately add more dispatch code to
operations like `Weak<Any>::clone`. Eventually the "correct" fix for this is to
have `RcBox<T>` store a union of `T` and a ZST like `()`, and that way the size
of `RcBox<T>` will never be 0 and we won't need this branch. Until rust-lang#47650 is
implemented, though, we can't use `union`s and unsized types together.
Closesrust-lang#48493
0 commit comments