Join GitHub today
GitHub is home to over 31 million developers working together to host and review code, manage projects, and build software together.
Sign upSeparate size and stride for types #1397
Comments
This comment has been minimized.
This comment has been minimized.
|
There's some discussion about this in rust-lang/rust#28951 |
This comment has been minimized.
This comment has been minimized.
|
I like how Swift has implemented various features we've only discussed. |
This comment has been minimized.
This comment has been minimized.
|
Neither of the following must become UB due to changes made to object layout. fn dummy(p: &T) {
unsafe {
// getelementptr inbounds
p.offset(1);
}
}
unsafe fn get_second(p: *const T) -> T {
ptr::read(p.offset(1))
} |
This comment has been minimized.
This comment has been minimized.
|
@mahkoh |
This comment has been minimized.
This comment has been minimized.
|
I think this is easily solved by requiring memory allocation to use the aligned size of an object instead of the packed size. That way |
This comment has been minimized.
This comment has been minimized.
|
@eddyb: Then the object cannot be smaller than the aligned_size_of because otherwise the first function is UB. @Amanieu: The first function can take a reference to |
This comment has been minimized.
This comment has been minimized.
|
@eddyb: Ah, I see what you meant. I'll update the code above. |
This comment has been minimized.
This comment has been minimized.
|
And to bring fn dummy2(p: &T) {
unsafe {
// getelementptr inbounds
(p as *const _ as *const u8).offset(mem::size_of::<T>());
}
}must not be UB either. |
This comment has been minimized.
This comment has been minimized.
|
@mahkoh: This isn't UB because, from my understanding, |
This comment has been minimized.
This comment has been minimized.
|
Still, this optimization seems to be impossible due to the issue mentioned in the OP:
The user is actually guaranteed this property for
While |
This comment has been minimized.
This comment has been minimized.
|
Ah, I had overlooked this issue, but this was one of the things I was thinking about while writing the Allocator RFC (#1398). I believe the (Update: in fact I had already commented (rust-lang/rust#28951 (comment)) about having thoughts related to this topic, though that comment is quite wishy-washy about what direction we should go in...) |
pnkfelix
added
T-lang
I-nominated
labels
Apr 12, 2016
This comment has been minimized.
This comment has been minimized.
|
(nominating because I think the lang team should be aware of the question here.) |
This comment has been minimized.
This comment has been minimized.
|
It looks like even arrays Making arrays to follow the same rule has benefits of making |
This comment has been minimized.
This comment has been minimized.
|
The first step towards supporting this would be to add |
This comment has been minimized.
This comment has been minimized.
|
Funnily enough, it seems this would actually break the code I have written for atomic-rs. This function might overwrite an adjacent value if it is embedded in the padding of the atomic object (which is just an The fix would be to use |
This comment has been minimized.
This comment has been minimized.
|
As pointed out in #1582, this would allow us to change the layout of tuples so that a tuple can be destructured into a single element and the rest of the tuple while still retaining a fairly space-efficient layout. That would, in turn, make it easier to support variadic generics. |
This comment has been minimized.
This comment has been minimized.
|
My feeling is that inhibiting writing a 3-byte struct like However, I don't have a great feeling for the number of actual odd-size structs, nor the number of nested ones, nor how often they hit memory. I guess one possibility for collecting data would be instrumenting the compiler to report/record this sort of info during compilation and run it on some programs (e.g. the bootstrap, servo, some things from the rest of the ecosystem) to get an idea (getting an idea for number of writes would require runtime instrumentation, I suppose). Theoretically it might good to also know about this in the precise of layout optimisations that reorder fields (e.g. |
pnkfelix
referenced this issue
Apr 28, 2016
Closed
docs: `size_of` is implemented as stride, but claims otherwise #33266
nikomatsakis
removed
the
I-nominated
label
May 5, 2016
canndrew
referenced this issue
May 11, 2016
Merged
all but the last field of a tuple must be Sized #1592
petrochenkov
referenced this issue
May 22, 2016
Closed
Implement conversion traits between arrays and uniform tuples. #33788
This comment has been minimized.
This comment has been minimized.
|
I just noticed a slight flaw with this scheme regarding DSTs. If the last element in a struct is even potentially unsized then it must remain the last element in the struct. For example consider This means that making a type support unsized type parameters with |
This comment has been minimized.
This comment has been minimized.
|
@Amanieu can't the layout vary based on the choice of types that the struct is instantiated with, and thus the constraints imposed on instantiations with an unsized type won't affect instantiations with all sized types? |
This comment has been minimized.
This comment has been minimized.
|
@pnkfelix No. Look at the example I gave in my comment:
Because |
This comment has been minimized.
This comment has been minimized.
|
@Amanieu oh, sorry for not reading carefully enough |
This comment has been minimized.
This comment has been minimized.
|
This is basically rust-lang/rust#17027 |
Amanieu commentedDec 6, 2015
The Swift ABI defines an interesting struct layout which defines the size of a type separately from its stride:
While rust doesn't define a stable ABI yet, I think using such a layout would be a breaking change due to assumptions that unsafe code make about
mem::size_of.In particular, unsafe code might assume that, when given a pointer
let x: *mut T, all bytes fromxtox + mem::size_of::<T>()can safely be overwritten. This would be incorrect when the padding bytes at the end ofTcontain fields of an outer struct.Is such an optimization worth considering? From a quick look at the rust source, it seems that all uses of
mem::size_ofwill continue to work fine if we define it as returning the stride (aligned size). I haven't looked at any external crates yet but I think they would continue to work fine as well. In any case this would be a breaking change and should be considered carefully.