Capability-based Aliasing Model #28
Description
This is a variant of the ACA model that has some advantages over it and is preferred by @ubsan.
Capabilities
The heart of the model is memory capabilities. In this model, each pointer or reference has a capability-set that describes which borrows it can alias with.
In more detail:
data AccessKind = Read | Write
data BorrowKey = BorrowKey {
bkId :: Unique,
bkLifetime :: Lifetime,
}
data Capability = Capability {
root :: BorrowKey,
memoryRange :: MemoryRange,
accessKinds :: Set AccessKind
capLifetime :: Lifetime,
}
Creation
Each borrow creates a BorrowKey
with the appropriate lifetime.
The capability-set of the newly-created borrow is the union of the capability keyed off the new BorrowKey
and the guarantor's capability set, restricted elementwise to the borrow's lifetime, memory range, and access kind.
Propagation
Capability sets are preserved when values are stored, loaded, or operated on in ways other than reborrows. I could not find a satisfying way of specifying that when InstCombine
-able integer operations and/or partial writes are allowed (and to define what an InstCombine
-able integer operation is), but that does not matter much in practice (e.g. the C spec is handwavy there).
Access Capability Set
The capability set of an access from Rust code is the accessing pointer/reference's capability set, plus a new freshly-created borrow key and capability that lasts only for the duration of the access.
Adding that borrow key has the effect of prohibiting data races.
The capability set of an access from foreign code (including intrinsics) is implementation-defined.
Garbage Collection
Borrow keys and capabilities whose lifetime has expired have no effect and can be ignored.
The aliasing rule
The actual aliasing rule is pretty similar to the ACA rule. UB through an aliasing violation occurs if there are 2 accesses (in no particular order) - the asserting access and the conflicting access, and a capability - the asserted capability - such that:
- The memory locations accessed by the 2 accesses, and the asserted capability's memory range overlap.
- At least one of the 2 accesses is a write.
- The asserted capability is within the asserting access's capability set.
- Both accesses are within the asserted capabilities' borrow key's lifetime, and after these capabilities were created.
- There is no access capability within the conflicting access's capability set
Where an access capability is a capability within the conflicting access's capability set such that
- The conflicting access's lifetime is within that capability's lifetime
- The access kind is within capability's access kinds
- The access capability's memory range contains the conflicting access's memory range.
- The access capability has the same borrow key as the asserted capability