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
TryFromBytes::is_bit_valid is currently generic over aliasing, permitting both Shared and ExclusivePtrs.
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 InitializedPtr<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 InitializedPtr<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.
The text was updated successfully, but these errors were encountered:
TryFromBytes::is_bit_valid
is currently generic over aliasing, permitting bothShared
andExclusive
Ptr
s.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 aPtr<Self>
withInitialized
validity. Such aPtr
is equivalent to aPtr<[u8]>
withValid
validity.A checked transmute which uses
TryFromBytes::is_bit_valid
thus takes a type through three representations:Src
with validityValid
Dst
with validityInitialized
Dst
with validityValid
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 exclusivePtr
s):&[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 abool
into abool
:&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 aPtr<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 sharedPtr
.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, thisReadOnly
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. viamem::swap
). This limitation may require us to abandonReadOnly
as a type and instead make it an aliasing invariant.The text was updated successfully, but these errors were encountered: