-
Notifications
You must be signed in to change notification settings - Fork 60
Is size guaranteed to be a multiple of alignment? #306
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
Comments
There's also the possibility of alignment 0 which is used in Ada to mean a value may not even be aligned to a storage unit (bitfields). It's maybe also worth considering whether bitfield support in Rust may wish to support this someday. |
I think this is an issue with terminology. Size is always a multiple of alignment, even in C++. From the docs for
It sounds like what you are referring to is the "size - tail padding"? I could imagine introducing some special behaviour for tail padding if it makes C++ interop easier, but I don't think that changes the size of the type for all other uses of the word "size". |
No, I'm suggesting the possibility that tail padding could be omitted entirely from the object, bringing down its size. This is what Swift does, for instance: https://developer.apple.com/documentation/swift/memorylayout. |
Swift is just changing the terminology. They're using the word "stride" instead of "size", and "size" to mean "size without padding". Code that cares about sizeof in C++ or sizeof in Rust would use stride in Swift. There is no meaningful difference beyond switching the words. |
Cc #176
We did not intend to exclude head/tail padding, so yeah this should probably be clarified. |
It looks like the reference considers this issue already settled. https://doc.rust-lang.org/reference/type-layout.html says
|
Indeed, but I wouldn't take that as a statement about what must be true in the future. But there is definitely code relying on the assumption, so changing this would be a backwards compatibility nightmare. I'm inclined to say we consider the matter settled until someone wants to seriously make a proposal for how to address that. |
I think entirely new targets might (big might!) be able to change it. for all current targets, it's essentially settled forever. |
Even on new targets, it's forced by the existence of https://doc.rust-lang.org/core/array/fn.from_ref.html so long as |
I think that's actually less of an issue; it just constrains arrays of undersized types to also be undersized at the final element. And frankly I see no issue with that. It's worth noting that But I'm not sure how I follow that it's target-specific. Unless you're suggesting using the speculative feature of targets that provide fewer valid assumptions as a way to force unsafe packages to opt-in to supporting these kinds of types. Which could be viable, I suppose, but it seems less like a target-specific thing to me as the folks working on C++ interop stories would love to see this on existing targets. |
Yes I'm saying that for existing targets you definitely can't break this promise (even if it was an accidental promise). but for a new target you can potentially do a lot of crazy things and then say "also if your code can't cope with this just don't use that crate on this target until it's updated (if ever)." should new targets do crazy things? probably not, but if a crazy thing has to be done a new target is about the only way to do it. |
It's currently documented in the reference that size must be a multiple of alignment. But it's not clear if this is an invariant guaranteed to hold forever, or whether it's something that might one day not hold true if we permit over-aligned types. The main obstacle to those, I believe, would be defining whether arrays are padded or not and how one might construct the other kind.
There has been some discussion about this in rust-lang/rfcs#1397 and elsewhere, but a use case has actually arisen now: C++ interop. C++ allows derived classes to make use of the base class's padding bytes, and also has an attribute
[[no_unique_address]]
that causes a struct field's tail padding to be reused. This relies on general assignment in C++ through pointers not being able to clobber padding, which is different from Rust. The discussion of the property applies to some other use cases as well e.g. of over-aligned stack variables (which are necessary in some cases such as crypto code). Currently the only way to get an aligned stack variable is to put it in an over-aligned type, which means wasting stack space entirely unnecessarily on padding.Note that the linked issue initially proposes enabling this by default; I do not think that should be permitted as I think the definition of padding that the UCG have arrived at is generally a good one. But alternative proposals, such as an opt-in attribute, would all rely on some facility to separate the stride and size of a type.
Layout
already shows that stride doesn't need an explicit representation, and additionally provides an API for code to easily calculate the layout of arrays in a way that is agnostic to whether or not this invariant holds.Given the Rust definition of padding, it seems more appropriate to treat such cases as if they do not actually have padding, and actually lower the size understood by Rust to omit the trailing padding.
While I'm here, I'd like to confirm that the omission of tail padding (or head padding, even) in the glossary is a mistake?
The text was updated successfully, but these errors were encountered: