Crates.io | erasable |
lib.rs | erasable |
version | 1.2.1 |
source | src |
created_at | 2020-01-31 22:25:07.041154 |
updated_at | 2020-05-13 00:32:45.33887 |
description | Type-erased thin pointers. |
homepage | |
repository | https://github.com/CAD97/pointer-utils/tree/master/crates/erasable |
max_upload_size | |
id | 203770 |
size | 35,836 |
Erase pointers of their concrete type and store type-erased pointers.
This is roughly equivalent to C's void*
, but it does not use libc::c_void
.
There are two main useful reasons to type erase pointers in Rust:
?Sized
types. If an unsized type stores its metadata inline,
then it can implement Erasable
and be used behind type-erased pointers.
The type erased pointer does not have to carry the metadata,
and the fat pointer can be recovered from the inline metadata.
We provide the Thin
wrapper type to provide thin pointer types.impl ErasablePtr for Thin<P>
: the obvious impl; Thin
is erased internallyThin::ptr_eq
: easily compare pointer equality of two thin pointersUnfortunately, a subtle problem with the requirements of Erasable::unerase
on implementors was found, and needed to be corrected in this version.
It has always been the intent that a pointer of any provenance should roundtrip
through Erasable::erase
/unerase
without any impact on provenance validity
of any pointer. Unfortunately, in 1.0.0, Eraseable::unerase
explicitly suggested
the use of temporary shared references (&_
) in its implementation, which do not
hold up this desired semantics. To quote Erasable::unerase
's new documentation:
No references to the pointee at all should be created, as their mere temporary existence may impact the validity and usable provenance of other pointers to the same location.
Creating a shared reference sounds on the surface like it should be ok. After all, you have a known-valid pointer to your type, and you can borrow from whatever pointer was erased. However, in the face of raw pointers with a shared mutable provenance, this is problematic. If a write to the pointee location even potentially races with any invocation of
unerase
, and it creates a reference to the location, we have immediate undefined behavior for writing behind a shared ref.The root issue is that there may be external synchronization that this implementation has no way of knowing about. An implementation of this trait must only read the mimimum amount of data required to re-type the pointer, and must do so with a raw pointer read, or, if and only if there is a known
UnsafeCell
point (such as an atomic), a reference to thatUnsafeCell
point and the safe API of thatUnsafeCell
point.
For more information around the discovery of this issue see this Twitter thread.
To make this update easier, we additionally added const Erasable::ACK_1_1_0: bool
.
This value defaults to false
, but must be overriden to true
in new
implementations of Erasable
as an explicit acknowledgement of the new requirement.
To make finding impls that do not do so, the ERASABLE_ENFORCE_1_1_0_SEMANTICS
environment variable can be set to remove the default implementation,
explicitly breaking any implementor that did not override its value.
If you have a use of unerase
that would be made unsound by unerase
creating
a shared reference, then it is recommended to assert the value of ACK_1_1_0
to guard against old impls that may create a shared reference. Also, please tell
me what it is, because I have not been able to construct a reasonable example
that would be made unsound by this hole, just a theoretical attack vector.
Similarly, if you can show that this isn't required, get in touch.
I'd love to remove this hack if it turns out unnecessary after all
(but I think I'm confident ruling out that possibility).
ptr-union
: Pointer unions the size of a pointer.rc-borrow
: Borrowed forms of Rc
and Arc
.rc-box
: Known unique forms of Rc
and Arc
.slice-dst
: Support for custom slice-based DSTs.We require a minimum Rust version of 1.41.0. This is for an adjustment of local trait impl checking.
Minimum version support is only guaranteed with minimal version resolution
(-Z minimal-versions
/--minimal-versions
) due to how dependencies are handled.
The minimum version of Rust will only be incremented with minor version bumps,
not patch version bumps, and will be deliberate and clearly noted in change notes.
Licensed under either of
at your option.
If you are a highly paid worker at any company that prioritises profit over people, you can still use this crate. I simply wish you will unionise and push back against the obsession for growth, control, and power that is rampant in your workplace. Please take a stand against the horrible working conditions they inflict on your lesser paid colleagues, and more generally their disrespect for the very human rights they claim to fight for.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.