Skip to content

Commit 7edd10e

Browse files
committed
8321786: SegmentAllocator:allocateFrom(ValueLayout, MemorySegment,ValueLayout,long,long) spec mismatch in exception scenario
Reviewed-by: mcimadamore
1 parent d75d876 commit 7edd10e

File tree

13 files changed

+218
-39
lines changed

13 files changed

+218
-39
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1016,7 +1016,7 @@ static PaddingLayout paddingLayout(long byteSize) {
10161016
* @throws IllegalArgumentException if {@code elementLayout.byteSize() % elementLayout.byteAlignment() != 0}
10171017
*/
10181018
static SequenceLayout sequenceLayout(long elementCount, MemoryLayout elementLayout) {
1019-
MemoryLayoutUtil.requireNonNegative(elementCount);
1019+
Utils.checkNonNegativeArgument(elementCount, "elementCount");
10201020
Objects.requireNonNull(elementLayout);
10211021
Utils.checkElementAlignment(elementLayout,
10221022
"Element layout size is not multiple of alignment");

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

Lines changed: 38 additions & 4 deletions
Large diffs are not rendered by default.

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
import jdk.internal.foreign.ArenaImpl;
3434
import jdk.internal.foreign.SlicingAllocator;
3535
import jdk.internal.foreign.StringSupport;
36+
import jdk.internal.foreign.Utils;
3637
import jdk.internal.vm.annotation.ForceInline;
3738

3839
/**
@@ -390,9 +391,10 @@ default MemorySegment allocateFrom(AddressLayout layout, MemorySegment value) {
390391
* with {@code source} is not {@linkplain MemorySegment.Scope#isAlive() alive}
391392
* @throws WrongThreadException if this method is called from a thread {@code T},
392393
* such that {@code source.isAccessibleBy(T) == false}
393-
* @throws IndexOutOfBoundsException if {@code elementCount * sourceElementLayout.byteSize()} overflows
394+
* @throws IllegalArgumentException if {@code elementCount * sourceElementLayout.byteSize()} overflows
395+
* @throws IllegalArgumentException if {@code elementCount < 0}
394396
* @throws IndexOutOfBoundsException if {@code sourceOffset > source.byteSize() - (elementCount * sourceElementLayout.byteSize())}
395-
* @throws IndexOutOfBoundsException if either {@code sourceOffset} or {@code elementCount} are {@code < 0}
397+
* @throws IndexOutOfBoundsException if {@code sourceOffset < 0}
396398
*/
397399
@ForceInline
398400
default MemorySegment allocateFrom(ValueLayout elementLayout,

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

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -153,9 +153,7 @@ public final MemorySegment reinterpret(Arena arena, Consumer<MemorySegment> clea
153153

154154
public MemorySegment reinterpretInternal(Class<?> callerClass, long newSize, Scope scope, Consumer<MemorySegment> cleanup) {
155155
Reflection.ensureNativeAccess(callerClass, MemorySegment.class, "reinterpret");
156-
if (newSize < 0) {
157-
throw new IllegalArgumentException("newSize < 0");
158-
}
156+
Utils.checkNonNegativeArgument(newSize, "newSize");
159157
if (!isNative()) throw new UnsupportedOperationException("Not a native segment");
160158
Runnable action = cleanup != null ?
161159
() -> cleanup.accept(SegmentFactories.makeNativeSegmentUnchecked(address(), newSize)) :
@@ -594,6 +592,7 @@ public static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout,
594592
MemorySegment dstSegment, ValueLayout dstElementLayout, long dstOffset,
595593
long elementCount) {
596594

595+
Utils.checkNonNegativeIndex(elementCount, "elementCount");
597596
AbstractMemorySegmentImpl srcImpl = (AbstractMemorySegmentImpl)srcSegment;
598597
AbstractMemorySegmentImpl dstImpl = (AbstractMemorySegmentImpl)dstSegment;
599598
if (srcElementLayout.byteSize() != dstElementLayout.byteSize()) {
@@ -625,7 +624,7 @@ public static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout,
625624
public static void copy(MemorySegment srcSegment, ValueLayout srcLayout, long srcOffset,
626625
Object dstArray, int dstIndex,
627626
int elementCount) {
628-
627+
Utils.checkNonNegativeIndex(elementCount, "elementCount");
629628
var dstInfo = Utils.BaseAndScale.of(dstArray);
630629
if (dstArray.getClass().componentType() != srcLayout.carrier()) {
631630
throw new IllegalArgumentException("Incompatible value layout: " + srcLayout);
@@ -652,7 +651,6 @@ public static void copy(MemorySegment srcSegment, ValueLayout srcLayout, long sr
652651
public static void copy(Object srcArray, int srcIndex,
653652
MemorySegment dstSegment, ValueLayout dstLayout, long dstOffset,
654653
int elementCount) {
655-
656654
var srcInfo = Utils.BaseAndScale.of(srcArray);
657655
if (srcArray.getClass().componentType() != dstLayout.carrier()) {
658656
throw new IllegalArgumentException("Incompatible value layout: " + dstLayout);

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

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -200,11 +200,8 @@ public static long pointeeByteAlign(AddressLayout addressLayout) {
200200
}
201201

202202
public static void checkAllocationSizeAndAlign(long byteSize, long byteAlignment) {
203-
// size should be >= 0
204-
if (byteSize < 0) {
205-
throw new IllegalArgumentException("Invalid allocation size : " + byteSize);
206-
}
207-
203+
// byteSize should be >= 0
204+
Utils.checkNonNegativeArgument(byteSize, "allocation size");
208205
checkAlign(byteAlignment);
209206
}
210207

@@ -216,6 +213,20 @@ public static void checkAlign(long byteAlignment) {
216213
}
217214
}
218215

216+
@ForceInline
217+
public static void checkNonNegativeArgument(long value, String name) {
218+
if (value < 0) {
219+
throw new IllegalArgumentException("The provided " + name + " is negative: " + value);
220+
}
221+
}
222+
223+
@ForceInline
224+
public static void checkNonNegativeIndex(long value, String name) {
225+
if (value < 0) {
226+
throw new IndexOutOfBoundsException("The provided " + name + " is negative: " + value);
227+
}
228+
}
229+
219230
private static long computePadding(long offset, long align) {
220231
boolean isAligned = offset == 0 || offset % align == 0;
221232
if (isAligned) {

src/java.base/share/classes/jdk/internal/foreign/layout/AbstractLayout.java

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -151,13 +151,8 @@ private static long requirePowerOfTwoAndGreaterOrEqualToOne(long value) {
151151
}
152152

153153
public long scale(long offset, long index) {
154-
if (offset < 0) {
155-
throw new IllegalArgumentException("Negative offset: " + offset);
156-
}
157-
if (index < 0) {
158-
throw new IllegalArgumentException("Negative index: " + index);
159-
}
160-
154+
Utils.checkNonNegativeArgument(offset, "offset");
155+
Utils.checkNonNegativeArgument(index, "index");
161156
return Math.addExact(offset, Math.multiplyExact(byteSize(), index));
162157
}
163158

src/java.base/share/classes/jdk/internal/foreign/layout/MemoryLayoutUtil.java

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,6 @@ public final class MemoryLayoutUtil {
3030
private MemoryLayoutUtil() {
3131
}
3232

33-
public static long requireNonNegative(long value) {
34-
if (value < 0) {
35-
throw new IllegalArgumentException("The provided value was negative: " + value);
36-
}
37-
return value;
38-
}
39-
4033
public static long requireByteSizeValid(long byteSize, boolean allowZero) {
4134
if ((byteSize == 0 && !allowZero) || byteSize < 0) {
4235
throw new IllegalArgumentException("Invalid byte size: " + byteSize);

test/jdk/java/foreign/TestLayouts.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -371,13 +371,13 @@ public void testVarHandleCaching() {
371371
}
372372

373373
@Test(expectedExceptions=IllegalArgumentException.class,
374-
expectedExceptionsMessageRegExp=".*Negative offset.*")
374+
expectedExceptionsMessageRegExp=".*offset is negative.*")
375375
public void testScaleNegativeOffset() {
376376
JAVA_INT.scale(-1, 0);
377377
}
378378

379379
@Test(expectedExceptions=IllegalArgumentException.class,
380-
expectedExceptionsMessageRegExp=".*Negative index.*")
380+
expectedExceptionsMessageRegExp=".*index is negative.*")
381381
public void testScaleNegativeIndex() {
382382
JAVA_INT.scale(0, -1);
383383
}

test/jdk/java/foreign/TestMemoryAccessInstance.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,13 @@ public <X, L extends ValueLayout> void badAccessOverflowInIndexedAccess(String t
164164
}
165165
}
166166

167+
@Test(dataProvider = "segmentAccessors")
168+
public <X, L extends ValueLayout> void negativeOffset(String testName, Accessor<X, L> accessor) {
169+
MemorySegment segment = MemorySegment.ofArray(new byte[100]);
170+
assertThrows(IndexOutOfBoundsException.class, () -> accessor.get(segment, -ValueLayout.JAVA_LONG.byteSize()));
171+
assertThrows(IndexOutOfBoundsException.class, () -> accessor.set(segment, -ValueLayout.JAVA_LONG.byteSize(), accessor.value));
172+
}
173+
167174
static final ByteOrder NE = ByteOrder.nativeOrder();
168175

169176
@DataProvider(name = "segmentAccessors")

test/jdk/java/foreign/TestScopedOperations.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
*/
2828

2929
import java.lang.foreign.Arena;
30+
import java.lang.foreign.MemoryLayout;
3031
import java.lang.foreign.MemorySegment;
3132
import java.lang.foreign.ValueLayout;
3233

@@ -135,6 +136,8 @@ public <Z> void testOpOutsideConfinement(String name, ScopedOperation<Z> scopedO
135136
ScopedOperation.ofScope(a -> a.allocateFrom(ValueLayout.JAVA_FLOAT, new float[]{0}), "Arena::allocateFrom/float");
136137
ScopedOperation.ofScope(a -> a.allocateFrom(ValueLayout.JAVA_LONG, new long[]{0}), "Arena::allocateFrom/long");
137138
ScopedOperation.ofScope(a -> a.allocateFrom(ValueLayout.JAVA_DOUBLE, new double[]{0}), "Arena::allocateFrom/double");
139+
var source = MemorySegment.ofArray(new byte[]{});
140+
ScopedOperation.ofScope(a -> a.allocateFrom(ValueLayout.JAVA_INT, source, JAVA_BYTE, 0, 1), "Arena::allocateFrom/5arg");
138141
};
139142

140143
@DataProvider(name = "scopedOperations")

0 commit comments

Comments
 (0)