Skip to content

Commit 1ff9ac7

Browse files
committed
8338731: MemoryLayout::offsetHandle can return a negative offset
Reviewed-by: pminborg, psandoz
1 parent 2e174c6 commit 1ff9ac7

File tree

3 files changed

+23
-10
lines changed

3 files changed

+23
-10
lines changed

src/java.base/share/classes/java/lang/foreign/MemoryLayout.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -574,7 +574,9 @@ public sealed interface MemoryLayout
574574
* <p>
575575
* For any given dynamic argument {@code x_i}, it must be that {@code 0 <= x_i < size_i},
576576
* where {@code size_i} is the size of the open path element associated with {@code x_i}.
577-
* Otherwise, the returned method handle throws {@link IndexOutOfBoundsException}.
577+
* Otherwise, the returned method handle throws {@link IndexOutOfBoundsException}. Moreover,
578+
* the value of {@code b} must be such that the computation for {@code offset} does not overflow,
579+
* or the returned method handle throws {@link ArithmeticException}.
578580
*
579581
* @apiNote The returned method handle can be used to compute a layout offset,
580582
* similarly to {@link #byteOffset(PathElement...)}, but more flexibly, as

src/java.base/share/classes/jdk/internal/foreign/LayoutPath.java

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ public class LayoutPath {
6666
private static final MethodHandle MH_SLICE_LAYOUT;
6767
private static final MethodHandle MH_CHECK_ENCL_LAYOUT;
6868
private static final MethodHandle MH_SEGMENT_RESIZE;
69-
private static final MethodHandle MH_ADD;
69+
private static final MethodHandle MH_ADD_EXACT;
7070

7171
static {
7272
try {
@@ -81,7 +81,7 @@ public class LayoutPath {
8181
MethodType.methodType(void.class, MemorySegment.class, long.class, MemoryLayout.class));
8282
MH_SEGMENT_RESIZE = lookup.findStatic(LayoutPath.class, "resizeSegment",
8383
MethodType.methodType(MemorySegment.class, MemorySegment.class));
84-
MH_ADD = lookup.findStatic(Long.class, "sum",
84+
MH_ADD_EXACT = lookup.findStatic(Math.class, "addExact",
8585
MethodType.methodType(long.class, long.class, long.class));
8686
} catch (Throwable ex) {
8787
throw new ExceptionInInitializerError(ex);
@@ -244,15 +244,18 @@ private static long addScaledOffset(long base, long index, long stride, long bou
244244
}
245245

246246
public MethodHandle offsetHandle() {
247-
MethodHandle mh = MethodHandles.insertArguments(MH_ADD, 0, offset);
247+
MethodHandle mh = MH_ADD_EXACT;
248248
for (int i = strides.length - 1; i >= 0; i--) {
249249
MethodHandle collector = MethodHandles.insertArguments(MH_ADD_SCALED_OFFSET, 2, strides[i], bounds[i]);
250-
// (J, ...) -> J to (J, J, ...) -> J
251-
// i.e. new coord is prefixed. Last coord will correspond to innermost layout
252-
mh = MethodHandles.collectArguments(mh, 0, collector);
253-
}
254-
255-
return mh;
250+
// (J, J, ...) -> J to (J, J, J, ...) -> J
251+
// 1. the leading argument is the base offset (externally provided).
252+
// 2. index arguments are added. The last index correspond to the innermost layout.
253+
// 3. overflow can only occur at the outermost layer, due to the final addition with the base offset.
254+
// This is because the layout API ensures (by construction) that all offsets generated from layout paths
255+
// are always < Long.MAX_VALUE.
256+
mh = MethodHandles.collectArguments(mh, 1, collector);
257+
}
258+
return MethodHandles.insertArguments(mh, 1, offset);
256259
}
257260

258261
private MemoryLayout rootLayout() {

test/jdk/java/foreign/TestLayoutPaths.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,14 @@ public void testOffsetHandleOOBIndex(MemoryLayout layout, PathElement[] pathElem
332332
}
333333
}
334334

335+
@Test(dataProvider = "testLayouts", expectedExceptions = ArithmeticException.class)
336+
public void testOffsetHandleOverflow(MemoryLayout layout, PathElement[] pathElements, long[] indexes,
337+
long expectedByteOffset) throws Throwable {
338+
MethodHandle byteOffsetHandle = layout.byteOffsetHandle(pathElements);
339+
byteOffsetHandle = byteOffsetHandle.asSpreader(long[].class, indexes.length);
340+
byteOffsetHandle.invoke(Long.MAX_VALUE, indexes);
341+
}
342+
335343
@Test(dataProvider = "testLayouts")
336344
public void testVarHandleBadSegment(MemoryLayout layout, PathElement[] pathElements, long[] indexes,
337345
long expectedByteOffset) throws Throwable {

0 commit comments

Comments
 (0)