Skip to content

Commit c49129f

Browse files
committed
8308445: Linker should check that capture state segment is big enough
Reviewed-by: mcimadamore
1 parent fa79111 commit c49129f

File tree

4 files changed

+47
-2
lines changed

4 files changed

+47
-2
lines changed

src/java.base/share/classes/jdk/internal/foreign/abi/AbstractLinker.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ private final MethodHandle downcallHandle0(FunctionDescriptor function, Option..
9696
FunctionDescriptor fd = linkRequest.descriptor();
9797
MethodType type = fd.toMethodType();
9898
MethodHandle handle = arrangeDowncall(type, fd, linkRequest.options());
99+
handle = SharedUtils.maybeCheckCaptureSegment(handle, linkRequest.options());
99100
handle = SharedUtils.maybeInsertAllocator(fd, handle);
100101
return handle;
101102
});

src/java.base/share/classes/jdk/internal/foreign/abi/SharedUtils.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ private SharedUtils() {
7878
private static final MethodHandle MH_BUFFER_COPY;
7979
private static final MethodHandle MH_REACHABILITY_FENCE;
8080
public static final MethodHandle MH_CHECK_SYMBOL;
81+
private static final MethodHandle MH_CHECK_CAPTURE_SEGMENT;
8182

8283
public static final AddressLayout C_POINTER = ADDRESS
8384
.withTargetLayout(MemoryLayout.sequenceLayout(JAVA_BYTE));
@@ -110,6 +111,8 @@ public void close() {
110111
methodType(void.class, Object.class));
111112
MH_CHECK_SYMBOL = lookup.findStatic(SharedUtils.class, "checkSymbol",
112113
methodType(void.class, MemorySegment.class));
114+
MH_CHECK_CAPTURE_SEGMENT = lookup.findStatic(SharedUtils.class, "checkCaptureSegment",
115+
methodType(MemorySegment.class, MemorySegment.class));
113116
} catch (ReflectiveOperationException e) {
114117
throw new BootstrapMethodError(e);
115118
}
@@ -343,6 +346,23 @@ public static MethodHandle maybeInsertAllocator(FunctionDescriptor descriptor, M
343346
return handle;
344347
}
345348

349+
public static MethodHandle maybeCheckCaptureSegment(MethodHandle handle, LinkerOptions options) {
350+
if (options.hasCapturedCallState()) {
351+
// (<target address>, SegmentAllocator, <capture segment>, ...) -> ...
352+
handle = MethodHandles.filterArguments(handle, 2, MH_CHECK_CAPTURE_SEGMENT);
353+
}
354+
return handle;
355+
}
356+
357+
@ForceInline
358+
public static MemorySegment checkCaptureSegment(MemorySegment captureSegment) {
359+
Objects.requireNonNull(captureSegment);
360+
if (captureSegment.equals(MemorySegment.NULL)) {
361+
throw new IllegalArgumentException("Capture segment is NULL: " + captureSegment);
362+
}
363+
return captureSegment.asSlice(0, CapturableState.LAYOUT);
364+
}
365+
346366
@ForceInline
347367
public static void checkSymbol(MemorySegment symbol) {
348368
Objects.requireNonNull(symbol);

src/java.base/share/classes/jdk/internal/foreign/abi/fallback/FallbackLinker.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,6 @@
4949
import java.util.function.Consumer;
5050

5151
import static java.lang.foreign.ValueLayout.ADDRESS;
52-
import static java.lang.foreign.ValueLayout.JAVA_LONG;
5352
import static java.lang.invoke.MethodHandles.foldArguments;
5453

5554
public final class FallbackLinker extends AbstractLinker {
@@ -161,7 +160,7 @@ private static Object doDowncall(SegmentAllocator returnAllocator, Object[] args
161160

162161
MemorySegment capturedState = null;
163162
if (invData.capturedStateMask() != 0) {
164-
capturedState = (MemorySegment) args[argStart++];
163+
capturedState = SharedUtils.checkCaptureSegment((MemorySegment) args[argStart++]);
165164
MemorySessionImpl capturedStateImpl = ((AbstractMemorySegmentImpl) capturedState).sessionImpl();
166165
capturedStateImpl.acquire0();
167166
acquiredSessions.add(capturedStateImpl);

test/jdk/java/foreign/capturecallstate/TestCaptureCallState.java

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
import static java.lang.foreign.ValueLayout.JAVA_INT;
5151
import static java.lang.foreign.ValueLayout.JAVA_LONG;
5252
import static org.testng.Assert.assertEquals;
53+
import static org.testng.Assert.assertTrue;
5354

5455
public class TestCaptureCallState extends NativeTestHelper {
5556

@@ -85,6 +86,21 @@ public void testSavedThreadLocal(SaveValuesCase testCase) throws Throwable {
8586
}
8687
}
8788

89+
@Test(dataProvider = "invalidCaptureSegmentCases")
90+
public void testInvalidCaptureSegment(MemorySegment captureSegment,
91+
Class<?> expectedExceptionType, String expectedExceptionMessage) {
92+
Linker.Option stl = Linker.Option.captureCallState("errno");
93+
MethodHandle handle = downcallHandle("set_errno_V", FunctionDescriptor.ofVoid(C_INT), stl);
94+
95+
try {
96+
int testValue = 42;
97+
handle.invoke(captureSegment, testValue); // should throw
98+
} catch (Throwable t) {
99+
assertTrue(expectedExceptionType.isInstance(t));
100+
assertTrue(t.getMessage().matches(expectedExceptionMessage));
101+
}
102+
}
103+
88104
@DataProvider
89105
public static Object[][] cases() {
90106
List<SaveValuesCase> cases = new ArrayList<>();
@@ -128,4 +144,13 @@ static SaveValuesCase structCase(String name, Map<MemoryLayout, Object> fields)
128144
return new SaveValuesCase("set_errno_" + name, FunctionDescriptor.of(layout, JAVA_INT), "errno", check);
129145
}
130146

147+
@DataProvider
148+
public static Object[][] invalidCaptureSegmentCases() {
149+
return new Object[][]{
150+
{Arena.ofAuto().allocate(1), IndexOutOfBoundsException.class, ".*Out of bound access on segment.*"},
151+
{MemorySegment.NULL, IllegalArgumentException.class, ".*Capture segment is NULL.*"},
152+
{Arena.ofAuto().allocate(Linker.Option.captureStateLayout().byteSize() + 3).asSlice(3), // misaligned
153+
IllegalArgumentException.class, ".*Target offset incompatible with alignment constraints.*"},
154+
};
155+
}
131156
}

0 commit comments

Comments
 (0)