Description
As revealed in rust-lang/reference#1657 there is not an immediately shared understanding on ZST statics and where they should go. There are two major ways to interpret "ZST statics do not overlap with other statics". One is "statics are their address ranges" and the other is "statics are their byte sets". We need to pick one.
Other relevant-seeming issues:
- What about: distributed slices (linkme) #545
- Must
static DATA: UnsafeCell = expr;
still== expr
bymain()
? #397 - Are statics confined to the size indicated by their type? #259
- Storing an object as &Header, but reading the data past the end of the header #256
- When are things guaranteed to have unique addresses? #206
Statics As Address Ranges
Expressed by @RalfJung as:
fn does_overlap(r1: Range<usize>, r2: Range<usize>) -> bool {
!(r1.end <= r2.start || r2.end <= r1.start)
}
Pros
- very straightforward definition, which removes some nonintuitive scenarios
- still allows placing a
static ZST: ()
at the start or end address of a givenstatic ARRAY: [u8; N]
- stronger, which may allow proving things more easily (i.e. optimizations)
Cons
- induces more UB if people combine Rust with linker scripts to reposition
static
s in ways that are incompatible with this rule - requires more R&D to develop a good alternative for people using linker control that doesn't cause UB left and right
Statics As Byte Sets
Elegantly phrased by @CAD97 as: "No byte of memory is contained in more than one static item."
This rule seems to be functionally equivalent to the other phrasing offered, which is "static
items cannot alias other static
items (using the definition of aliasing from the reference aliasing model)".
Pros
- potentially less UB for embedded developers
- makes the logic between "where a ZST allocation can go" and "where a ZST
&mut ()
can go" more uniform
Cons
- this rule allows some unexpected scenarios
- seems like it may be unnecessarily weak and may prove incompatible with LLVM
- hard to say if the patterns this enables will actually be sound-in-practice, even if we allow this
Constraints
We have some preexisting concerns. Each is pushing us in the opposite direction:
- LLVM doesn't seem to actually handle the notion of a
static ZST: ()
strictly nesting in anotherstatic ARRAY: [u8; N]
well. This does imply we may be passing up a number of optimizations if we adopt the byte-set rule, suggesting that we should pick the address-based rule.- Note that currently, LLVM doesn't seem to handle the notion of
static ZST: ()
... at all, really1
- Note that currently, LLVM doesn't seem to handle the notion of
- Embedded developers (including kernel and driver developers) often need the ability to slice-and-dice the address space. Some of this is done using fixed-size statics, but another common way to do this is using
static
s that are relocated using linker control (flags or linker scripts), which then have their addresses extracted and then composed with a pointer of ambiguous (or, slightly more rarely, known-appropriate) provenance. Often, both. If ZSTs are allowed to be nested in other statics, this has better composition and enables this rule.