bitvec icon indicating copy to clipboard operation
bitvec copied to clipboard

Does bitveco-rs/bitvec need SafeU8 when there is "split_at_mut"?

Open mstankus opened this issue 3 years ago • 1 comments

I am new to programming rust. I am looking at this crate (bitvecto-rs/bitvec). I see that there are bitsafe types which are mutable (https://docs.rs/bitvec/latest/bitvec/access/trait.BitSafe.html). These bits are "volatile", which makes me uncomfortable because it works around the type system, in my opinion. However, I was under the impressions that "split_at_mut" could always handle these types of issues. If it is not too much trouble, could you fill me in to the issue.

mstankus avatar Aug 22 '22 19:08 mstankus

You may be interested in https://bitvecto-rs.github.io/bitvec/memory-model.html. The gist is that [T]::split_at_mut only splits slices into smaller slices. The Rust standard library has no facility to deal with the fact that bitvec can split individual data elements into multiple subslices.

Because I use the slice reference system, including the &/&mut rule set, I need an API that allows users to have &mut BitSlice<uint, _> (where uint stands in for any of the unsigned integer fundamentals) behave in the same patterns that &mut [uint] does, including the crucial fact that &BitSlice<uint, _> cannot cause data mutations.

In order to tolerate multiple handles aliasing the same memory location, BitSlice::split_at_mut attaches a taint marker, changing the uint type parameter to <uint as BitStore>::Alias. If I did not create the BitSafeUint type family, then this would route directly to either Cell<uint> or AtomicUint.

However, &BitSlice<Cell<uint>, _> and &BitSlice<AtomicUint, _> both allow mutation, in keeping with the fact that Cell and atomics exist specifically to allow multiple aliasing over single locations.

So the BitSafeUint family exists to follow the type-system rules -- one data location may be modified by many handles -- but restrict mutation to only handles that were actually granted a mutability permission. After calling BitSlice::split_at_mut, you may then degrade one of your &mut BitSlice<uint, _> references to &BitSlice<uint, _>, and then that reference can no longer modify any of the bits that it is able to see, and its reads from the memory it targets are still able to tolerate the fact that other &mut BitSlice handles which touch the referent location may exist, and may write to their bits.

If I did not change the type parameter at all, then this would be a race condition.

bitvec's type system is carefully crafted to propagate the entire Rust and LLVM memory models about whole elements down to the level of individual bits. Just as Rust creates additional rules atop the few axioms that LLVM uses, I am required to add even more rules that Rust itself doesn't intrinsically have, but nevertheless expects in order for any of this to be legal.

A BitSlice<BitSafeUint, _> region has API capabilities that look exactly like a [uint] region, but its codegen routes through the UnsafeCell family because it may secretly be aliasing under the hood in a way that the Rust compiler and LLVM can see, but the user shouldn't. In general, this type family should never actually appear in user code, and should be considered an implementation detail that merely can't be made invisible.

myrrlyn avatar Sep 04 '22 05:09 myrrlyn