Does This Crate Look Sound?

I was thinking of using this crate, but I was curious if anybody who is more accustomed to reviewing unsafe code could comment on their opinion as to it's soundness:

It looks really simple, so it probably isn't way to difficult to review.

Looks pretty sound to me so far.

1 Like

I've looked into this crate before, and it looks no less sound than TypeId comparison. The main unsafe part is in value(), which checks that TypeId::of::<T>() == TypeId::of::<U>() before transmuting RefT to RefU. Let Eq denote T == U, TypeIdEq denote TypeId::of::<T>() == TypeId::of::<U>(), RefEq denote RefT == RefU, and RefTrans denote that RefT can be soundly transmuted to RefU.

First, the bound RefT: Cismutable<'a, T, U, RefU> asserts by its safety contract that Eq ⇒ RefTrans. In the three impls of the trait, RefT and RefU are chosen such that Eq ⇒ RefEq. Since RefEq ⇒ RefTrans trivially, all three impls satisfy the safety contract.

Then, value() asserts TypeIdEq before assuming RefTrans, which is sound iff TypeIdEq ⇒ RefTrans. If we suppose that TypeIdEq ⇒ Eq, then TypeIdEq ⇒ RefTrans by the Cismutable contract, and the function is sound.

However, there is a minor caveat: there are known types for which TypeIdEq holds but Eq does not (#10389). This is considered a bug in the standard library, which relies on TypeIdEq ⇒ Eq in Box::downcast() and other functions, and it will most likely be mitigated or fixed in a later version. Thus, since the crate is sound iff TypeIdEq ⇒ Eq, I claim that it's no less sound than TypeId comparison in general.

5 Likes

In general, my first step towards answering this question for an arbitrary crate on GitHub is to look at its issue tickets and pull requests, including closed ones, maybe searching for "unsafe", "unsound", "soundness", "undefined behavior", and so on.

This particular crate, similarly to some other crates, is unsound because of the standard library bug that Legion Mammal mentions. The author believes that this is unlikely to matter in practice. There is one known case of someone apparently being bitten by the standard library bug in practice (cismute was not involved). The standard library bug has been unsolved since years before Rust 1.0, and efforts to solve it have failed.