-
Notifications
You must be signed in to change notification settings - Fork 15.3k
LangRef: allocated objects can grow #141338
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3327,6 +3327,19 @@ behavior is undefined: | |
| - the size of all allocated objects must be non-negative and not exceed the | ||
| largest signed integer that fits into the index type. | ||
|
|
||
| Allocated objects that are created with operations recognized by LLVM (such as | ||
| :ref:`alloca <i_alloca>`, heap allocation functions marked as such, and global | ||
| variables) may *not* change their size. (``realloc``-style operations do not | ||
| change the size of an existing allocated object; instead, they create a new | ||
| allocated object. Even if the object is at the same location as the old one, old | ||
| pointers cannot be used to access this new object.) However, allocated objects | ||
| can also be created by means not recognized by LLVM, e.g. by directly calling | ||
RalfJung marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| ``mmap``. Those allocated objects are allowed to grow to the right (i.e., | ||
|
||
| keeping the same base address, but increasing their size) while maintaining the | ||
| validity of existing pointers, as long as they always satisfy the properties | ||
| described above. Currently, allocated objects are not permitted to grow to the | ||
| left or to shrink, nor can they have holes. | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Given the restrictions, the compiler can't tell where the "beginning" of the object is, so I'm not sure forbidding growth to the left has any meaningful effect. I'm not sure what a "hole" is, in this context. I don't think we require that all bytes of an object have to be dereferenceable. It might make sense to forbid overlapping live objects, though.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
It does have the one effect that it simplifies specifying when
But pointer offset is meant to be freely reorderable, so we could move the two offsets next to each other. We also can combine adjacent
By "hole" I mean e.g.
Also, what exactly does
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
But you currently forbid shrinking?
I agree munmapping is problematic; overlapping objects would be hard to reason about. There are potentially useful "holes", though: mprotecting a page from a continuous range for a JIT would be a hole in the sense that reads aren't legal.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Yeah but I'd like to allow it in the future -- it seems more important to me than growing to the left.
I don't think an mprotect causing reads and writes to trap is fundamentally different from munmap for this purpose, or is it?
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Hmm, okay.
Alias analysis doesn't really care if an object is actually accessible at the moment; it just cares we don't overlap with some other object. Dereferenceability is only relevant if you want to do speculative loads. So you can separate dereferenceability from the rest of the properties of an allocation.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Right, but my example above used dereferenceability. So it is equally an example for why mprotect on the middle of an allocation could be problematic.
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think we currently do any optimizations along the lines of "x is deferenceable, and x+10 is dereferenceable, therefore x+5 is dereferenceable". It's something we could theoretically do, I guess. Might be useful for certain forms of vectorization, like an array of structs with padding. But I think we can probably capture most of the same optimizations by exposing the "page size" to optimizations, which is less likely to explode in weird ways. I guess we can revisit mprotected "holes" if it turns out to actually matter. I'm satisfied with the explanation for forbidding growth to the left. |
||
|
|
||
| .. _objectlifetime: | ||
|
|
||
| Object Lifetime | ||
|
|
@@ -11870,6 +11883,9 @@ if the ``getelementptr`` has any non-zero indices, the following rules apply: | |
| :ref:`based <pointeraliasing>` on. This means that it points into that | ||
|
||
| allocated object, or to its end. Note that the object does not have to be | ||
| live anymore; being in-bounds of a deallocated object is sufficient. | ||
| If the allocated object can grow, then the relevant size for being *in | ||
| bounds* is the maximal size the object could have while satisfying the | ||
| allocated object rules, not its current size. | ||
| * During the successive addition of offsets to the address, the resulting | ||
| pointer must remain *in bounds* of the allocated object at each step. | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The "heap allocation functions marked as such" part here is meant to capture everything LLVM recognizes as a heap allocation function. Is there a better way to say this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe "heap allocation functions with the
allocsizeattribute"?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doesn't LLVM also recognize
mallocas a special magic name?