Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
workingjubilee opened this issue Nov 8, 2024 · 0 comments
Open

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

workingjubilee opened this issue Nov 8, 2024 · 0 comments

Comments

@workingjubilee
Copy link
Member

workingjubilee commented Nov 8, 2024

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant