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
Show file tree
Hide file tree
Changes from all commits
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
12 changes: 12 additions & 0 deletions src/java.base/share/classes/java/lang/foreign/Linker.java
Expand Up @@ -34,6 +34,7 @@
import jdk.internal.reflect.Reflection;

import java.lang.invoke.MethodHandle;
import java.nio.ByteOrder;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
Expand Down Expand Up @@ -195,6 +196,17 @@
* <td style="text-align:center;">{@link MemorySegment}</td>
* </tbody>
* </table></blockquote>
* <p>
* All the native linker implementations limit the function descriptors that they support to those that contain
* only so-called <em>canonical</em> layouts. A canonical layout has the following characteristics:
* <ol>
* <li>Its alignment constraint is set to its <a href="MemoryLayout.html#layout-align">natural alignment</a></li>
* <li>If it is a {@linkplain ValueLayout value layout}, its {@linkplain ValueLayout#order() byte order} is
* the {@linkplain ByteOrder#nativeOrder() native byte order}.
* <li>If it is a {@linkplain GroupLayout group layout}, its size is a multiple of its alignment constraint, and</li>
* <li>It does not contain padding other than what is strictly required to align its non-padding layout elements,
* or to satisfy constraint 3</li>
* </ol>
*
* <h3 id="function-pointers">Function pointers</h3>
*
Expand Down
Expand Up @@ -25,6 +25,7 @@
package jdk.internal.foreign.abi;

import jdk.internal.foreign.SystemLookup;
import jdk.internal.foreign.Utils;
import jdk.internal.foreign.abi.aarch64.linux.LinuxAArch64Linker;
import jdk.internal.foreign.abi.aarch64.macos.MacOsAArch64Linker;
import jdk.internal.foreign.abi.aarch64.windows.WindowsAArch64Linker;
Expand All @@ -40,9 +41,14 @@
import java.lang.foreign.FunctionDescriptor;
import java.lang.foreign.Linker;
import java.lang.foreign.MemorySegment;
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;
import java.nio.ByteOrder;
import java.util.Objects;

public abstract sealed class AbstractLinker implements Linker permits LinuxAArch64Linker, MacOsAArch64Linker,
Expand All @@ -62,7 +68,7 @@ private record LinkRequest(FunctionDescriptor descriptor, LinkerOptions options)
public MethodHandle downcallHandle(FunctionDescriptor function, Option... options) {
Objects.requireNonNull(function);
Objects.requireNonNull(options);
checkHasNaturalAlignment(function);
checkLayouts(function);
LinkerOptions optionSet = LinkerOptions.forDowncall(function, options);

return DOWNCALL_CACHE.get(new LinkRequest(function, optionSet), linkRequest -> {
Expand All @@ -80,7 +86,7 @@ public MemorySegment upcallStub(MethodHandle target, FunctionDescriptor function
Objects.requireNonNull(arena);
Objects.requireNonNull(target);
Objects.requireNonNull(function);
checkHasNaturalAlignment(function);
checkLayouts(function);
SharedUtils.checkExceptions(target);
LinkerOptions optionSet = LinkerOptions.forUpcall(function, options);

Expand All @@ -101,22 +107,64 @@ public SystemLookup defaultLookup() {
return SystemLookup.getInstance();
}

// Current limitation of the implementation:
// We don't support packed structs on some platforms,
// so reject them here explicitly
private static void checkHasNaturalAlignment(FunctionDescriptor descriptor) {
descriptor.returnLayout().ifPresent(AbstractLinker::checkHasNaturalAlignmentRecursive);
descriptor.argumentLayouts().forEach(AbstractLinker::checkHasNaturalAlignmentRecursive);
/** {@return byte order used by this linker} */
protected abstract ByteOrder linkerByteOrder();

private void checkLayouts(FunctionDescriptor descriptor) {
descriptor.returnLayout().ifPresent(this::checkLayoutsRecursive);
descriptor.argumentLayouts().forEach(this::checkLayoutsRecursive);
}

private static void checkHasNaturalAlignmentRecursive(MemoryLayout layout) {
private void checkLayoutsRecursive(MemoryLayout layout) {
checkHasNaturalAlignment(layout);
if (layout instanceof GroupLayout gl) {
for (MemoryLayout member : gl.memberLayouts()) {
checkHasNaturalAlignmentRecursive(member);
if (layout instanceof ValueLayout vl) {
checkByteOrder(vl);
} else 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) {
checkHasNaturalAlignmentRecursive(sl.elementLayout());
checkLayoutsRecursive(sl.elementLayout());
}
}

// check for trailing padding
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 there is no excess padding between 'memberLayout' and
// the previous layout
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("Member layout '" + memberLayout + "', of '" + parent + "'" +
" found at unexpected offset: " + offset + " != " + expectedOffset);
}
}

Expand All @@ -125,4 +173,10 @@ private static void checkHasNaturalAlignment(MemoryLayout layout) {
throw new IllegalArgumentException("Layout bit alignment must be natural alignment: " + layout);
}
}

private void checkByteOrder(ValueLayout vl) {
if (vl.order() != linkerByteOrder()) {
throw new IllegalArgumentException("Layout does not have the right byte order: " + vl);
}
}
}
Expand Up @@ -32,6 +32,7 @@
import java.lang.foreign.FunctionDescriptor;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodType;
import java.nio.ByteOrder;

/**
* ABI implementation based on ARM document "Procedure Call Standard for
Expand Down Expand Up @@ -60,4 +61,9 @@ protected MethodHandle arrangeDowncall(MethodType inferredMethodType, FunctionDe
protected UpcallStubFactory arrangeUpcall(MethodType targetType, FunctionDescriptor function, LinkerOptions options) {
return CallArranger.LINUX.arrangeUpcall(targetType, function, options);
}

@Override
protected ByteOrder linkerByteOrder() {
return ByteOrder.LITTLE_ENDIAN;
}
}
Expand Up @@ -32,6 +32,7 @@
import java.lang.foreign.FunctionDescriptor;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodType;
import java.nio.ByteOrder;

/**
* ABI implementation for macOS on Apple silicon. Based on AAPCS with
Expand Down Expand Up @@ -60,4 +61,9 @@ protected MethodHandle arrangeDowncall(MethodType inferredMethodType, FunctionDe
protected UpcallStubFactory arrangeUpcall(MethodType targetType, FunctionDescriptor function, LinkerOptions options) {
return CallArranger.MACOS.arrangeUpcall(targetType, function, options);
}

@Override
protected ByteOrder linkerByteOrder() {
return ByteOrder.LITTLE_ENDIAN;
}
}
Expand Up @@ -33,6 +33,7 @@
import java.lang.foreign.FunctionDescriptor;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodType;
import java.nio.ByteOrder;

/**
* ABI implementation for Windows/AArch64. Based on AAPCS with
Expand All @@ -57,4 +58,9 @@ protected MethodHandle arrangeDowncall(MethodType inferredMethodType, FunctionDe
protected UpcallStubFactory arrangeUpcall(MethodType targetType, FunctionDescriptor function, LinkerOptions options) {
return CallArranger.WINDOWS.arrangeUpcall(targetType, function, options);
}

@Override
protected ByteOrder linkerByteOrder() {
return ByteOrder.LITTLE_ENDIAN;
}
}
Expand Up @@ -43,6 +43,7 @@
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.ref.Reference;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
Expand Down Expand Up @@ -117,6 +118,11 @@ protected UpcallStubFactory arrangeUpcall(MethodType targetType, FunctionDescrip
};
}

@Override
protected ByteOrder linkerByteOrder() {
return ByteOrder.nativeOrder();
}

private static MemorySegment makeCif(MethodType methodType, FunctionDescriptor function, FFIABI abi, Arena scope) {
MemorySegment argTypes = scope.allocate(function.argumentLayouts().size() * ADDRESS.byteSize());
List<MemoryLayout> argLayouts = function.argumentLayouts();
Expand Down
Expand Up @@ -32,6 +32,7 @@
import java.lang.foreign.FunctionDescriptor;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodType;
import java.nio.ByteOrder;

public final class LinuxRISCV64Linker extends AbstractLinker {

Expand All @@ -56,4 +57,9 @@ protected MethodHandle arrangeDowncall(MethodType inferredMethodType, FunctionDe
protected UpcallStubFactory arrangeUpcall(MethodType targetType, FunctionDescriptor function, LinkerOptions options) {
return LinuxRISCV64CallArranger.arrangeUpcall(targetType, function, options);
}

@Override
protected ByteOrder linkerByteOrder() {
return ByteOrder.LITTLE_ENDIAN;
}
}
Expand Up @@ -31,6 +31,7 @@
import java.lang.foreign.FunctionDescriptor;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodType;
import java.nio.ByteOrder;

/**
* ABI implementation based on System V ABI AMD64 supplement v.0.99.6
Expand Down Expand Up @@ -58,4 +59,9 @@ protected MethodHandle arrangeDowncall(MethodType inferredMethodType, FunctionDe
protected UpcallStubFactory arrangeUpcall(MethodType targetType, FunctionDescriptor function, LinkerOptions options) {
return CallArranger.arrangeUpcall(targetType, function, options);
}

@Override
protected ByteOrder linkerByteOrder() {
return ByteOrder.LITTLE_ENDIAN;
}
}
Expand Up @@ -30,6 +30,7 @@
import java.lang.foreign.FunctionDescriptor;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodType;
import java.nio.ByteOrder;

/**
* ABI implementation based on Windows ABI AMD64 supplement v.0.99.6
Expand Down Expand Up @@ -57,4 +58,9 @@ protected MethodHandle arrangeDowncall(MethodType inferredMethodType, FunctionDe
protected UpcallStubFactory arrangeUpcall(MethodType targetType, FunctionDescriptor function, LinkerOptions options) {
return CallArranger.arrangeUpcall(targetType, function, options);
}

@Override
protected ByteOrder linkerByteOrder() {
return ByteOrder.LITTLE_ENDIAN;
}
}
39 changes: 38 additions & 1 deletion test/jdk/java/foreign/TestIllegalLink.java
Expand Up @@ -59,7 +59,7 @@ public void testIllegalLayouts(FunctionDescriptor desc, String expectedException
fail("Expected IllegalArgumentException was not thrown");
} catch (IllegalArgumentException e) {
assertTrue(e.getMessage().contains(expectedExceptionMessage),
e.getMessage() + " != " + expectedExceptionMessage);
e.getMessage() + " does not contain " + expectedExceptionMessage);
}
}

Expand Down Expand Up @@ -154,7 +154,44 @@ public static Object[][] types() {
))),
"Layout bit alignment must be natural alignment"
},
{
FunctionDescriptor.ofVoid(MemoryLayout.structLayout(
ValueLayout.JAVA_INT,
MemoryLayout.paddingLayout(32), // no excess padding
ValueLayout.JAVA_INT)),
"unexpected offset"
},
{
FunctionDescriptor.of(C_INT.withOrder(nonNativeOrder())),
"Layout does not have the right byte order"
},
{
FunctionDescriptor.of(MemoryLayout.structLayout(C_INT.withOrder(nonNativeOrder()))),
"Layout does not have the right byte order"
},
{
FunctionDescriptor.of(MemoryLayout.structLayout(MemoryLayout.sequenceLayout(C_INT.withOrder(nonNativeOrder())))),
"Layout does not have the right byte order"
},
{
FunctionDescriptor.ofVoid(MemoryLayout.structLayout(
ValueLayout.JAVA_LONG,
ValueLayout.JAVA_INT)), // missing trailing padding
"has unexpected size"
},
{
FunctionDescriptor.ofVoid(MemoryLayout.structLayout(
ValueLayout.JAVA_INT,
MemoryLayout.paddingLayout(32))), // too much trailing padding
"has unexpected size"
},
};
}

private static ByteOrder nonNativeOrder() {
return ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN
? ByteOrder.BIG_ENDIAN
: ByteOrder.LITTLE_ENDIAN;
}

}
3 changes: 2 additions & 1 deletion test/jdk/java/foreign/TestUpcallStructScope.java
Expand Up @@ -58,7 +58,8 @@ public class TestUpcallStructScope extends NativeTestHelper {
static final MemoryLayout S_PDI_LAYOUT = MemoryLayout.structLayout(
C_POINTER.withName("p0"),
C_DOUBLE.withName("p1"),
C_INT.withName("p2")
C_INT.withName("p2"),
MemoryLayout.paddingLayout(32)
);

static {
Expand Down