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

8303002: Reject packed structs from linker #13164

Closed
wants to merge 52 commits into from
Closed
Changes from 1 commit
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
71bd224
Generate delta
minborg Mar 17, 2023
bc1a2ee
Remove Panama-specific content
minborg Mar 17, 2023
8929b54
Remove extra line
minborg Mar 17, 2023
bb2f443
Update after first round of comments
minborg Mar 20, 2023
d68a9d2
Update src/java.base/share/classes/java/lang/foreign/AddressLayout.java
minborg Mar 21, 2023
7a78948
Update src/java.base/share/classes/java/lang/foreign/SymbolLookup.java
minborg Mar 21, 2023
a71518c
Remove MemoryInspection classes
minborg Mar 21, 2023
4626a54
Improve Linker javadocs
minborg Mar 21, 2023
21ef060
Add example for Option::captureStateLayout
minborg Mar 21, 2023
f203800
Fix typo -> shared arena
minborg Mar 22, 2023
192050d
Fix formating and modifier order
minborg Mar 22, 2023
45febe9
Disalow padding layouts of size zero
minborg Mar 22, 2023
6df28a7
Improve javadocs for Linker::captureStateLayout
minborg Mar 22, 2023
0e34aca
Check byte order of layouts passed to linker
JornVernee Mar 16, 2023
fbcd6fd
Reject packed structs and structs with extra padding
JornVernee Mar 23, 2023
e11fc6b
fix check for padding. Add check for trailing padding too
JornVernee Mar 23, 2023
4ea68de
Apply RISCV port patch
minborg Mar 28, 2023
c972658
Add snippet to Linker.Option.captureStateLayout()
minborg Mar 28, 2023
fc5b5de
Make checking method handle zero case
minborg Mar 28, 2023
37aaf3b
Fix typos in Arena
minborg Mar 28, 2023
7bac48d
Update Linker.downcallHandle() javadoc
minborg Mar 28, 2023
c4e7714
Use @return
minborg Mar 28, 2023
cba8260
Add bug number
minborg Mar 28, 2023
3dab13d
Make fallbacklinker.c consistent with downcallLinker.cpp
minborg Mar 28, 2023
bc29c6f
Merge with master
minborg Mar 28, 2023
e7471d0
Update copyright years
minborg Mar 28, 2023
24bea62
Fix copyrigth year issues
minborg Mar 28, 2023
0f3895f
fix ULE when intializing LibFallback
JornVernee Mar 28, 2023
0698b9e
add javadoc + fixes for trailing padding
JornVernee Mar 28, 2023
819214b
Merge branch 'PR_21' into RejectPacked
JornVernee Mar 28, 2023
54e49e0
Remove unused method and declare class final
minborg Mar 29, 2023
846eaf3
Merge pull request #1 from JornVernee/Fix_ULE
minborg Mar 29, 2023
c787a28
Cleanup finality
minborg Mar 29, 2023
a0d84f5
Update src/java.base/share/classes/java/lang/foreign/MemorySegment.java
minborg Mar 30, 2023
928ad35
Update src/java.base/share/classes/java/lang/foreign/MemorySegment.java
minborg Mar 30, 2023
3a4d9f6
Update JEP number and name
minborg Apr 5, 2023
183d351
Improve code snipet
minborg Apr 5, 2023
0ee65ac
Merge master
minborg Apr 5, 2023
adab1b8
8305087: MemoryLayout API checks should be more eager
minborg Apr 6, 2023
c199944
8305369: Issues in zero-length memory segment javadoc section
minborg Apr 6, 2023
d3ea0a3
account for missing mincore on WSL in TestByteBuffer
JornVernee Apr 11, 2023
5de9087
Merge branch 'master' into PR_21_V2
minborg Apr 12, 2023
6164abe
Merge pull request #2 from JornVernee/WSL_BB
minborg Apr 12, 2023
6e99eab
rename has_port
JornVernee Apr 12, 2023
91f43d1
Merge pull request #3 from JornVernee/IsForeignLinkerSupported
minborg Apr 13, 2023
54d526d
Merge branch 'PR_21' into RejectPacked
JornVernee Apr 18, 2023
eaf0c9c
fix TestIllegalLink
JornVernee Apr 18, 2023
46ac0b6
review comments
JornVernee Apr 20, 2023
d213301
polish wording
JornVernee Apr 20, 2023
9ed997b
polish pt. 2
JornVernee Apr 20, 2023
62cd5ee
restrictions -> characteristics
JornVernee Apr 20, 2023
df9f2eb
Merge branch 'master' into RejectPacked
JornVernee Apr 28, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 11 additions & 3 deletions src/java.base/share/classes/java/lang/foreign/Linker.java
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
Copy link
Contributor

@mcimadamore mcimadamore Apr 18, 2023

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...

Copy link
Member Author

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.

* descriptors that they support to those that contain only so-called <em>canonical</em> layouts. These layouts
* have the following restrictions:
Copy link
Contributor

@mcimadamore mcimadamore Apr 18, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's better to phrase this more or less as:

A canonical layout has the following characteristics:
* Its alignment constraint is equal to its natural alignment
* If the layout is a value layout (linkplain), its byte order matches that of the platform in which the JVM is executing (link to nativeOrder())
*  If the layout is a group layout (linkplain), it must not contain more padding layout (linkplain) elements than those strictly necessary to satisfy the alignment constraints of the non-padding elements of the group layout.

Copy link
Contributor

Choose a reason for hiding this comment

The 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?

Copy link
Member Author

Choose a reason for hiding this comment

The 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.

Copy link
Member Author

Choose a reason for hiding this comment

The 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);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for uniformity, shoudn't this check be inside an if (layout instanceof ValueLayout) ... ?

Copy link
Member Author

Choose a reason for hiding this comment

The 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);
}
}
8 changes: 7 additions & 1 deletion test/jdk/java/foreign/TestIllegalLink.java
Original file line number Diff line number Diff line change
@@ -191,7 +191,13 @@ public static Object[][] types() {
FunctionDescriptor.ofVoid(MemoryLayout.structLayout(
ValueLayout.JAVA_LONG,
ValueLayout.JAVA_INT)), // missing trailing padding
"Layout lacks trailing padding"
"has unexpected size"
},
{
FunctionDescriptor.ofVoid(MemoryLayout.structLayout(
ValueLayout.JAVA_INT,
MemoryLayout.paddingLayout(32))), // too much trailing padding
"has unexpected size"
},
};
}