Skip to content

Wait, how does placing ZST statics work again? #546

Open
@workingjubilee

Description

@workingjubilee

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:

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

  1. very straightforward definition, which removes some nonintuitive scenarios
  2. still allows placing a static ZST: () at the start or end address of a given static ARRAY: [u8; N]
  3. stronger, which may allow proving things more easily (i.e. optimizations)

Cons

  1. induces more UB if people combine Rust with linker scripts to reposition statics in ways that are incompatible with this rule
  2. 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

  1. potentially less UB for embedded developers
  2. makes the logic between "where a ZST allocation can go" and "where a ZST &mut () can go" more uniform

Cons

  1. this rule allows some unexpected scenarios
  2. seems like it may be unnecessarily weak and may prove incompatible with LLVM
  3. 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:

  1. LLVM doesn't seem to actually handle the notion of a static ZST: () strictly nesting in another static 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
  2. 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 statics 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.

Footnotes

  1. according to https://github.com/rust-lang/reference/pull/1657#issuecomment-2464528692 and https://llvm.godbolt.org/z/6qTvx3qxd

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions