-
Notifications
You must be signed in to change notification settings - Fork 5.8k
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
8303002: Reject packed structs from linker #13164
Changes from 1 commit
71bd224
bc1a2ee
8929b54
bb2f443
d68a9d2
7a78948
a71518c
4626a54
21ef060
f203800
192050d
45febe9
6df28a7
0e34aca
fbcd6fd
e11fc6b
4ea68de
c972658
fc5b5de
37aaf3b
7bac48d
c4e7714
cba8260
3dab13d
bc29c6f
e7471d0
24bea62
0f3895f
0698b9e
819214b
54e49e0
846eaf3
c787a28
a0d84f5
928ad35
3a4d9f6
183d351
0ee65ac
adab1b8
c199944
d3ea0a3
5de9087
6164abe
6e99eab
91f43d1
54d526d
eaf0c9c
46ac0b6
d213301
9ed997b
62cd5ee
df9f2eb
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 |
---|---|---|
|
@@ -197,9 +197,17 @@ | |
* </tbody> | ||
* </table></blockquote> | ||
* <p> | ||
* Note that due to limited ABI specification coverage, none of the native linker implementations supports | ||
* packed structs (those that lack the padding needed to align their fields) or structs with excess padding | ||
* (more than is required to align a field) being passed by value. | ||
* Due to limited ABI specification coverage, all the native linker implementations limit the function | ||
* descriptors that they support to those that contain only so-called <em>canonical</em> layouts. These layouts | ||
* have the following restrictions: | ||
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 think it's better to phrase this more or less as:
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. Also, isn't it the case that, for structs, we want the size of the layout to be a multiple of its alignment constraint? 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. The third item in the list is for group size needing to be a multiple of the alignment constraint, the forth item refers to that, so I'll keep the ordered list. WRT byte order: I think it's fine to just say "native byte order". Keep it simple. Or do you think there might be confusion about the meaning of "native"? (It looks like not even ByteOrder::nativeOrder explains that term: https://docs.oracle.com/en/java/javase/20/docs/api/java.base/java/nio/ByteOrder.html#nativeOrder()) "padding layout elements" is not quite right I think, since they also have to be the right size. I think saying just "padding" is more accurate (and simpler). I'll switch to using plain links instead. 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. Uploaded another version |
||
* <ol> | ||
* <li>The layout must have its alignment constraint set to its <a href="MemoryLayout.html#layout-align">natural alignment</a></li> | ||
* <li>If the layout is a {@link ValueLayout}, it must have a {@linkplain ValueLayout#order() byte order} that matches | ||
* the {@linkplain ByteOrder#nativeOrder() native byte order}</li> | ||
* <li>If the layout is a {@link GroupLayout}, its size must be a multiple of its alignment constraint</li> | ||
* <li>If the layout is a {@link GroupLayout}, it must not contain excess padding. Padding is considered excess if it is | ||
* not strictly required to align a non-padding layout, or to satisfy constraint 3</li> | ||
* </ol> | ||
* | ||
* <h3 id="function-pointers">Function pointers</h3> | ||
* | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -44,6 +44,7 @@ | |
import java.lang.foreign.PaddingLayout; | ||
import java.lang.foreign.SequenceLayout; | ||
import java.lang.foreign.StructLayout; | ||
import java.lang.foreign.UnionLayout; | ||
import java.lang.foreign.ValueLayout; | ||
import java.lang.invoke.MethodHandle; | ||
import java.lang.invoke.MethodType; | ||
|
@@ -110,45 +111,58 @@ public SystemLookup defaultLookup() { | |
protected abstract ByteOrder linkerByteOrder(); | ||
|
||
private void checkLayouts(FunctionDescriptor descriptor) { | ||
descriptor.returnLayout().ifPresent(l -> checkLayoutsRecursive(l, 0, 0)); | ||
descriptor.argumentLayouts().forEach(l -> checkLayoutsRecursive(l, 0, 0)); | ||
descriptor.returnLayout().ifPresent(this::checkLayoutsRecursive); | ||
descriptor.argumentLayouts().forEach(this::checkLayoutsRecursive); | ||
} | ||
|
||
private void checkLayoutsRecursive(MemoryLayout layout, long lastUnpaddedOffset , long offset) { | ||
private void checkLayoutsRecursive(MemoryLayout layout) { | ||
checkHasNaturalAlignment(layout); | ||
checkOffset(layout, lastUnpaddedOffset, offset); | ||
checkByteOrder(layout); | ||
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. for uniformity, shoudn't this check be inside an 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. Yes, will do. |
||
if (layout instanceof GroupLayout gl) { | ||
checkGroupSize(gl); | ||
for (MemoryLayout member : gl.memberLayouts()) { | ||
checkLayoutsRecursive(member, lastUnpaddedOffset, offset); | ||
|
||
if (gl instanceof StructLayout) { | ||
offset += member.bitSize(); | ||
if (!(member instanceof PaddingLayout)) { | ||
lastUnpaddedOffset = offset; | ||
} | ||
if (layout instanceof StructLayout sl) { | ||
long offset = 0; | ||
long lastUnpaddedOffset = 0; | ||
for (MemoryLayout member : sl.memberLayouts()) { | ||
// check element offset before recursing so that an error points at the | ||
// outermost layout first | ||
checkMemberOffset(sl, member, lastUnpaddedOffset, offset); | ||
checkLayoutsRecursive(member); | ||
|
||
offset += member.bitSize(); | ||
if (!(member instanceof PaddingLayout)) { | ||
lastUnpaddedOffset = offset; | ||
} | ||
} | ||
checkGroupSize(sl, lastUnpaddedOffset); | ||
} else if (layout instanceof UnionLayout ul) { | ||
long maxUnpaddedLayout = 0; | ||
for (MemoryLayout member : ul.memberLayouts()) { | ||
checkLayoutsRecursive(member); | ||
if (!(member instanceof PaddingLayout)) { | ||
maxUnpaddedLayout = Long.max(maxUnpaddedLayout, member.bitSize()); | ||
} | ||
} | ||
checkGroupSize(ul, maxUnpaddedLayout); | ||
} else if (layout instanceof SequenceLayout sl) { | ||
checkLayoutsRecursive(sl.elementLayout(), lastUnpaddedOffset, offset); | ||
checkLayoutsRecursive(sl.elementLayout()); | ||
} | ||
} | ||
|
||
// check for trailing padding | ||
private static void checkGroupSize(GroupLayout gl) { | ||
if (gl.bitSize() % gl.bitAlignment() != 0) { | ||
throw new IllegalArgumentException("Layout lacks trailing padding: " + gl); | ||
private static void checkGroupSize(GroupLayout gl, long maxUnpaddedOffset) { | ||
long expectedSize = Utils.alignUp(maxUnpaddedOffset, gl.bitAlignment()); | ||
if (gl.bitSize() != expectedSize) { | ||
throw new IllegalArgumentException("Layout '" + gl + "' has unexpected size: " | ||
+ gl.bitSize() + " != " + expectedSize); | ||
} | ||
} | ||
|
||
// checks both that a layout is aligned within the root, | ||
// and also that there is no excess padding between it and | ||
// checks both that there is no excess padding between 'memberLayout' and | ||
// the previous layout | ||
private static void checkOffset(MemoryLayout layout, long lastUnpaddedOffset, long offset) { | ||
long expectedOffset = Utils.alignUp(lastUnpaddedOffset, layout.bitAlignment()); | ||
private static void checkMemberOffset(StructLayout parent, MemoryLayout memberLayout, | ||
long lastUnpaddedOffset, long offset) { | ||
long expectedOffset = Utils.alignUp(lastUnpaddedOffset, memberLayout.bitAlignment()); | ||
if (expectedOffset != offset) { | ||
throw new IllegalArgumentException("Layout '" + layout + "'" + | ||
throw new IllegalArgumentException("Member layout '" + memberLayout + "', of '" + parent + "'" + | ||
" found at unexpected offset: " + offset + " != " + expectedOffset); | ||
} | ||
} | ||
|
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.
All the native linker implementations support function function descriptors that contain only so-called...
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.
So, just drop the 'Due to limited ABI specification coverage'? I guess it's not really needed.