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

What are the guarantees over ZST pointers #503

Closed
celinval opened this issue Apr 9, 2024 · 11 comments
Closed

What are the guarantees over ZST pointers #503

celinval opened this issue Apr 9, 2024 · 11 comments

Comments

@celinval
Copy link

celinval commented Apr 9, 2024

Hi, we've been trying to understand what's the correct way to model ZST pointers. What is UB and what has well defined behavior.

  1. Does a ZST pointer have provenance?
  2. Does ZST pointer identity hold?
  3. If it point to a ZST field in a structure, will it always be inbounds?
  4. Will the address of a static ZST always fall in the memory section of statics? Will the address of a local ZST always point to a location in the stack frame?
  5. Should a ZST pointer comparison take provenance into account or just the address?

Thanks!

@Lokathor
Copy link
Contributor

Lokathor commented Apr 9, 2024

  1. I think you mean "provenance", and yes technically they do.
  2. Not sure what you're asking. a == a will be true for a ZST pointer, if that's what you mean.
  3. A pointer to a field of a struct will be inbounds of the full struct, yeah.
  4. This is not guaranteed in any way. In fact, some people would like this to specifically not be the case so that ZST address values can be const folded.
  5. Pointer comparison doesn't compare provenance, just the address (and possibly more with a DST, but we'll ignore that for now). EDIT: see What are the guarantees over ZST pointers #503 (comment)

@chorman0773
Copy link
Contributor

For almost all purposes related to provenance, a pointer to a ZST is not distinct from a pointer to another type.
There are additional guarantees in terms of what operations are valid, when that operation is done with zero size. For example, memory accesses of zero size are trivially valid when well-aligned.

@celinval
Copy link
Author

celinval commented Apr 9, 2024

  1. I think you mean "provenance", and yes technically they do.

Sorry, my phone keeps auto correcting provenance for some reason. Or maybe it was my brain malfunction. 🤷🏻‍♀️

@celinval
Copy link
Author

celinval commented Apr 9, 2024

5. Pointer comparison doesn't compare provenance, just the address (and possibly more with a DST, but we'll ignore that for now).

I thought that was still up for debate from reading this issue: #239

@RalfJung
Copy link
Member

RalfJung commented Apr 10, 2024

For further information on provenance, see the RFC. The pointee type and being a reference vs a raw pointer makes no difference for provenance.

I thought that was still up for debate from reading this issue: #239

Yes, we haven't made an official t-lang decision on this. But at this point it seems unlikely that provenance will affect pointer comparison. The main unknown here is how to resolve #328.

On today's Rust, provenance does not affect pointer comparison.

Will the address of a static ZST always fall in the memory section of statics? Will the address of a local ZST always point to a location in the stack frame?

The Rust specification does not have a notion of memory sections for statics or stack frames. All allocated objects are placed at arbitrary locations in memory and there is no guarantee whatsoever that stack allocations are in "the stack" or Box allocations are on "the heap".


I think this answers all questions, or would you like further clarification?

@tautschnig
Copy link

The Rust specification does not have a notion of memory sections for statics or stack frames. All allocated objects are placed at arbitrary locations in memory and there is no guarantee whatsoever that stack allocations are in "the stack" or Box allocations are on "the heap".

https://doc.rust-lang.org/reference/variables.html says that "A local variable (or stack-local allocation) holds a value directly, allocated within the stack's memory." (And https://doc.rust-lang.org/reference/memory-allocation-and-lifetime.html says something about Box and heap, but indeed does not promise that all Box allocations would be on the heap.)

@RalfJung
Copy link
Member

RalfJung commented Apr 10, 2024

That should be fixed then, these guarantees make no sense on the level of the Rust spec. Stack and heap as distinct parts of the address space are target-specific notions that do not exist in the Abstract Machine.

@celinval
Copy link
Author

For example, memory accesses of zero size are trivially valid when well-aligned.

I think that would be a simple way to go about it, since these are no-op, but if I understand it correctly, a zero-size access is invalid if the pointer points to a deallocated memory, correct? I'm assuming that's because of provenance.

I am curious if provenance is also taken into account if the pointer is out-of-bounds of the original object? Would a zero-size access be valid in out-of-bounds pointers?

@RalfJung
Copy link
Member

RalfJung commented Apr 17, 2024

if I understand it correctly, a zero-size access is invalid if the pointer points to a deallocated memory, correct? I'm assuming that's because of provenance.

This used to be the case but we decided to change it and allow more code. See rust-lang/rust#117945. Once that is fully implemented, zero-sized accesses will ignore provenance.

I am curious if provenance is also taken into account if the pointer is out-of-bounds of the original object? Would a zero-size access be valid in out-of-bounds pointers?

Under the current rules as implemented by Miri today, that would be UB. But rust-lang/rust#117945 will make it allowed.

@celinval
Copy link
Author

I think this answers all my questions. Thank you!

@RalfJung
Copy link
Member

Sure, happy to help. :)

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

5 participants