Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[pointer] Support read-only aliasing; use in TryFromBytes::is_bit_valid #2336

Open
joshlf opened this issue Feb 13, 2025 · 0 comments
Open

Comments

@joshlf
Copy link
Member

joshlf commented Feb 13, 2025

TryFromBytes::is_bit_valid is currently generic over aliasing, permitting both Shared and Exclusive Ptrs.

In adding support for runtime-checked type-to-type transmutation (#1359), we ran into a problem. TryFromBytes::is_bit_valid needs to be able to read the bytes of its referent, but cannot assume that those bytes are bit-valid, so it takes a Ptr<Self> with Initialized validity. Such a Ptr is equivalent to a Ptr<[u8]> with Valid validity.

A checked transmute which uses TryFromBytes::is_bit_valid thus takes a type through three representations:

  • Src with validity Valid
  • Dst with validity Initialized
  • Dst with validity Valid

Current TryFromBytes methods always take &[u8] or &mut [u8] as a source type. As a result, two representation paths are possible (note that, here, & and &mut are used as shorthand for shared or exclusive Ptrs):

  • &[u8] -> &[u8] -> &Dst
  • &mut [u8] -> &mut [u8] -> &mut Dst

The middle types in both cases are actually Initialized Ptr<Dst>s, but these have the same validity as [u8].

When supporting source types other than [u8], this can become problematic. Consider transmuting a bool into a bool:

  • &bool -> &[u8] -> &bool
  • &mut bool -> &mut [u8] -> &mut bool

Shared references are not problematic, but exclusive references pose a problem: An Initialized Ptr<bool>, which is effectively a &mut [u8], can be used to write arbitrary bytes to its referent. However, this permits writing arbitrary bytes which will later be observed as a &mut bool, which is unsound. Thus, the first step (&mut bool -> &mut [u8]) is unsound.

It would be tempting to solve this using reborrowing: First reborrow &mut bool as &bool, then convert it to a Ptr<bool, (Shared, Valid)> in order to call <bool as TryFromBytes>::is_bit_valid. Unfortunately, this is insufficient: types with interior mutability can use this type to mutate their referent despite being behind a shared Ptr.


The solution proposed by this issue is a read-only type. This could be instantiated as a ReadOnly type a la #1760 or as a new aliasing mode, although the former is probably simpler. Unlike #1760, this ReadOnly type would disable any mutation whatsoever, including through &mut references. In particular, ReadOnly<T>: AsRef<T> where T: Immutable.

Since neither &ReadOnly<T> nor &mut ReadOnly<T> permit mutation, sequences like the following would be sound:

  • &mut bool -> &mut ReadOnly<[u8]> -> &mut bool
  • &Cell<bool> -> &ReadOnly<Cell<[u8]>> -> &bool

In order to make this work, we'd need to figure out how to prevent a &mut ReadOnly<T> from being overwritten in its entirety (e.g. via mem::swap). This limitation may require us to abandon ReadOnly as a type and instead make it an aliasing invariant.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant