8321786: SegmentAllocator:allocateFrom(ValueLayout, MemorySegment,ValueLayout,long,long) spec mismatch in exception scenario

Reviewed-by: mcimadamore
This commit is contained in:
Per Minborg 2024-01-08 08:20:07 +00:00
parent d75d876edd
commit 7edd10e5fa
13 changed files with 218 additions and 39 deletions

@ -1016,7 +1016,7 @@ public sealed interface MemoryLayout
* @throws IllegalArgumentException if {@code elementLayout.byteSize() % elementLayout.byteAlignment() != 0}
*/
static SequenceLayout sequenceLayout(long elementCount, MemoryLayout elementLayout) {
MemoryLayoutUtil.requireNonNegative(elementCount);
Utils.checkNonNegativeArgument(elementCount, "elementCount");
Objects.requireNonNull(elementLayout);
Utils.checkElementAlignment(elementLayout,
"Element layout size is not multiple of alignment");

@ -44,6 +44,7 @@ import java.util.stream.Stream;
import jdk.internal.foreign.AbstractMemorySegmentImpl;
import jdk.internal.foreign.MemorySessionImpl;
import jdk.internal.foreign.SegmentFactories;
import jdk.internal.foreign.Utils;
import jdk.internal.javac.Restricted;
import jdk.internal.reflect.CallerSensitive;
import jdk.internal.vm.annotation.ForceInline;
@ -1591,6 +1592,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a>
* in the provided layout
* @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()}
* or {@code offset < 0}
*/
byte get(ValueLayout.OfByte layout, long offset);
@ -1609,6 +1611,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a>
* in the provided layout
* @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()}
* or {@code offset < 0}
* @throws IllegalArgumentException if this segment is
* {@linkplain #isReadOnly() read-only}
*/
@ -1629,6 +1632,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a>
* in the provided layout
* @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()}
* or {@code offset < 0}
*/
boolean get(ValueLayout.OfBoolean layout, long offset);
@ -1647,6 +1651,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a>
* in the provided layout
* @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()}
* or {@code offset < 0}
* @throws IllegalArgumentException if this segment is
* {@linkplain #isReadOnly() read-only}
*/
@ -1667,6 +1672,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a>
* in the provided layout
* @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()}
* or {@code offset < 0}
*/
char get(ValueLayout.OfChar layout, long offset);
@ -1685,6 +1691,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a>
* in the provided layout
* @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()}
* or {@code offset < 0}
* @throws IllegalArgumentException if this segment is
* {@linkplain #isReadOnly() read-only}
*/
@ -1705,6 +1712,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a>
* in the provided layout
* @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()}
* or {@code offset < 0}
*/
short get(ValueLayout.OfShort layout, long offset);
@ -1723,6 +1731,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a>
* in the provided layout
* @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()}
* or {@code offset < 0}
* @throws IllegalArgumentException if this segment is
* {@linkplain #isReadOnly() read-only}
*/
@ -1743,6 +1752,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a>
* in the provided layout
* @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()}
* or {@code offset < 0}
*/
int get(ValueLayout.OfInt layout, long offset);
@ -1761,6 +1771,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a>
* in the provided layout
* @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()}
* or {@code offset < 0}
* @throws IllegalArgumentException if this segment is
* {@linkplain #isReadOnly() read-only}
*/
@ -1781,6 +1792,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a>
* in the provided layout
* @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()}
* or {@code offset < 0}
*/
float get(ValueLayout.OfFloat layout, long offset);
@ -1799,6 +1811,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a>
* in the provided layout
* @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()}
* or {@code offset < 0}
* @throws IllegalArgumentException if this segment is
* {@linkplain #isReadOnly() read-only}
*/
@ -1819,6 +1832,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a>
* in the provided layout
* @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()}
* or {@code offset < 0}
*/
long get(ValueLayout.OfLong layout, long offset);
@ -1837,6 +1851,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a>
* in the provided layout
* @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()}
* or {@code offset < 0}
* @throws IllegalArgumentException if this segment is
* {@linkplain #isReadOnly() read-only}
*/
@ -1857,6 +1872,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a>
* in the provided layout
* @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()}
* or {@code offset < 0}
*/
double get(ValueLayout.OfDouble layout, long offset);
@ -1875,6 +1891,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a>
* in the provided layout
* @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()}
* or {@code offset < 0}
* @throws IllegalArgumentException if this segment is
* {@linkplain #isReadOnly() read-only}
*/
@ -1905,6 +1922,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a>
* in {@code T}
* @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()}
* or {@code offset < 0}
*/
MemorySegment get(AddressLayout layout, long offset);
@ -1923,8 +1941,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a>
* in the provided layout
* @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()}
* @throws UnsupportedOperationException if this segment is
* {@linkplain #isReadOnly() read-only}
* or {@code offset < 0}
* @throws IllegalArgumentException if {@code value} is not a
* {@linkplain #isNative() native} segment
* @throws IllegalArgumentException if this segment is
@ -1951,6 +1968,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* @throws IllegalArgumentException if {@code layout.byteAlignment() > layout.byteSize()}
* @throws IndexOutOfBoundsException if {@code index * layout.byteSize()} overflows
* @throws IndexOutOfBoundsException if {@code index * layout.byteSize() > byteSize() - layout.byteSize()}
* or {@code index < 0}
*/
byte getAtIndex(ValueLayout.OfByte layout, long index);
@ -1973,6 +1991,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* @throws IllegalArgumentException if {@code layout.byteAlignment() > layout.byteSize()}
* @throws IndexOutOfBoundsException if {@code index * layout.byteSize()} overflows
* @throws IndexOutOfBoundsException if {@code index * layout.byteSize() > byteSize() - layout.byteSize()}
* or {@code index < 0}
*/
boolean getAtIndex(ValueLayout.OfBoolean layout, long index);
@ -1995,6 +2014,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* @throws IllegalArgumentException if {@code layout.byteAlignment() > layout.byteSize()}
* @throws IndexOutOfBoundsException if {@code index * layout.byteSize()} overflows
* @throws IndexOutOfBoundsException if {@code index * layout.byteSize() > byteSize() - layout.byteSize()}
* or {@code index < 0}
*/
char getAtIndex(ValueLayout.OfChar layout, long index);
@ -2017,7 +2037,8 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* @throws IllegalArgumentException if {@code layout.byteAlignment() > layout.byteSize()}
* @throws IndexOutOfBoundsException if {@code index * layout.byteSize()} overflows
* @throws IndexOutOfBoundsException if {@code index * layout.byteSize() > byteSize() - layout.byteSize()}
* @throws UnsupportedOperationException if this segment is {@linkplain #isReadOnly() read-only}
* or {@code index < 0}
* @throws IllegalArgumentException if this segment is {@linkplain #isReadOnly() read-only}
*/
void setAtIndex(ValueLayout.OfChar layout, long index, char value);
@ -2040,6 +2061,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* @throws IllegalArgumentException if {@code layout.byteAlignment() > layout.byteSize()}
* @throws IndexOutOfBoundsException if {@code index * layout.byteSize()} overflows
* @throws IndexOutOfBoundsException if {@code index * layout.byteSize() > byteSize() - layout.byteSize()}
* or {@code index < 0}
*/
short getAtIndex(ValueLayout.OfShort layout, long index);
@ -2061,6 +2083,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* @throws IllegalArgumentException if {@code layout.byteAlignment() > layout.byteSize()}
* @throws IndexOutOfBoundsException if {@code index * layout.byteSize()} overflows
* @throws IndexOutOfBoundsException if {@code index * layout.byteSize() > byteSize() - layout.byteSize()}
* or {@code index < 0}
* @throws IllegalArgumentException if this segment is {@linkplain #isReadOnly() read-only}
*/
void setAtIndex(ValueLayout.OfByte layout, long index, byte value);
@ -2084,6 +2107,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* @throws IllegalArgumentException if {@code layout.byteAlignment() > layout.byteSize()}
* @throws IndexOutOfBoundsException if {@code index * layout.byteSize()} overflows
* @throws IndexOutOfBoundsException if {@code index * layout.byteSize() > byteSize() - layout.byteSize()}
* or {@code index < 0}
* @throws IllegalArgumentException if this segment is {@linkplain #isReadOnly() read-only}
*/
void setAtIndex(ValueLayout.OfBoolean layout, long index, boolean value);
@ -2107,6 +2131,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* @throws IllegalArgumentException if {@code layout.byteAlignment() > layout.byteSize()}
* @throws IndexOutOfBoundsException if {@code index * layout.byteSize()} overflows
* @throws IndexOutOfBoundsException if {@code index * layout.byteSize() > byteSize() - layout.byteSize()}
* or {@code index < 0}
* @throws IllegalArgumentException if this segment is {@linkplain #isReadOnly() read-only}
*/
void setAtIndex(ValueLayout.OfShort layout, long index, short value);
@ -2130,6 +2155,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* @throws IllegalArgumentException if {@code layout.byteAlignment() > layout.byteSize()}
* @throws IndexOutOfBoundsException if {@code index * layout.byteSize()} overflows
* @throws IndexOutOfBoundsException if {@code index * layout.byteSize() > byteSize() - layout.byteSize()}
* or {@code index < 0}
*/
int getAtIndex(ValueLayout.OfInt layout, long index);
@ -2152,6 +2178,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* @throws IllegalArgumentException if {@code layout.byteAlignment() > layout.byteSize()}
* @throws IndexOutOfBoundsException if {@code index * layout.byteSize()} overflows
* @throws IndexOutOfBoundsException if {@code index * layout.byteSize() > byteSize() - layout.byteSize()}
* or {@code index < 0}
* @throws IllegalArgumentException if this segment is {@linkplain #isReadOnly() read-only}
*/
void setAtIndex(ValueLayout.OfInt layout, long index, int value);
@ -2175,6 +2202,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* @throws IllegalArgumentException if {@code layout.byteAlignment() > layout.byteSize()}
* @throws IndexOutOfBoundsException if {@code index * layout.byteSize()} overflows
* @throws IndexOutOfBoundsException if {@code index * layout.byteSize() > byteSize() - layout.byteSize()}
* or {@code index < 0}
*/
float getAtIndex(ValueLayout.OfFloat layout, long index);
@ -2197,6 +2225,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* @throws IllegalArgumentException if {@code layout.byteAlignment() > layout.byteSize()}
* @throws IndexOutOfBoundsException if {@code index * layout.byteSize()} overflows
* @throws IndexOutOfBoundsException if {@code index * layout.byteSize() > byteSize() - layout.byteSize()}
* or {@code index < 0}
* @throws IllegalArgumentException if this segment is {@linkplain #isReadOnly() read-only}
*/
void setAtIndex(ValueLayout.OfFloat layout, long index, float value);
@ -2220,6 +2249,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* @throws IllegalArgumentException if {@code layout.byteAlignment() > layout.byteSize()}
* @throws IndexOutOfBoundsException if {@code index * layout.byteSize()} overflows
* @throws IndexOutOfBoundsException if {@code index * layout.byteSize() > byteSize() - layout.byteSize()}
* or {@code index < 0}
*/
long getAtIndex(ValueLayout.OfLong layout, long index);
@ -2242,6 +2272,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* @throws IllegalArgumentException if {@code layout.byteAlignment() > layout.byteSize()}
* @throws IndexOutOfBoundsException if {@code index * layout.byteSize()} overflows
* @throws IndexOutOfBoundsException if {@code index * layout.byteSize() > byteSize() - layout.byteSize()}
* or {@code index < 0}
* @throws IllegalArgumentException if this segment is {@linkplain #isReadOnly() read-only}
*/
void setAtIndex(ValueLayout.OfLong layout, long index, long value);
@ -2265,6 +2296,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* @throws IllegalArgumentException if {@code layout.byteAlignment() > layout.byteSize()}
* @throws IndexOutOfBoundsException if {@code index * layout.byteSize()} overflows
* @throws IndexOutOfBoundsException if {@code index * layout.byteSize() > byteSize() - layout.byteSize()}
* or {@code index < 0}
*/
double getAtIndex(ValueLayout.OfDouble layout, long index);
@ -2287,6 +2319,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* @throws IllegalArgumentException if {@code layout.byteAlignment() > layout.byteSize()}
* @throws IndexOutOfBoundsException if {@code index * layout.byteSize()} overflows
* @throws IndexOutOfBoundsException if {@code index * layout.byteSize() > byteSize() - layout.byteSize()}
* or {@code index < 0}
* @throws IllegalArgumentException if this segment is {@linkplain #isReadOnly() read-only}
*/
void setAtIndex(ValueLayout.OfDouble layout, long index, double value);
@ -2319,6 +2352,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* in {@code T}
* @throws IndexOutOfBoundsException if {@code index * layout.byteSize()} overflows
* @throws IndexOutOfBoundsException if {@code index * layout.byteSize() > byteSize() - layout.byteSize()}
* or {@code index < 0}
*/
MemorySegment getAtIndex(AddressLayout layout, long index);
@ -2341,7 +2375,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* @throws IllegalArgumentException if {@code layout.byteAlignment() > layout.byteSize()}
* @throws IndexOutOfBoundsException if {@code index * layout.byteSize()} overflows
* @throws IndexOutOfBoundsException if {@code index * layout.byteSize() > byteSize() - layout.byteSize()}
* @throws UnsupportedOperationException if this segment is {@linkplain #isReadOnly() read-only}
* or {@code index < 0}
* @throws IllegalArgumentException if {@code value} is not a {@linkplain #isNative() native} segment
* @throws IllegalArgumentException if this segment is
* {@linkplain #isReadOnly() read-only}

@ -33,6 +33,7 @@ import jdk.internal.foreign.AbstractMemorySegmentImpl;
import jdk.internal.foreign.ArenaImpl;
import jdk.internal.foreign.SlicingAllocator;
import jdk.internal.foreign.StringSupport;
import jdk.internal.foreign.Utils;
import jdk.internal.vm.annotation.ForceInline;
/**
@ -390,9 +391,10 @@ public interface SegmentAllocator {
* with {@code source} is not {@linkplain MemorySegment.Scope#isAlive() alive}
* @throws WrongThreadException if this method is called from a thread {@code T},
* such that {@code source.isAccessibleBy(T) == false}
* @throws IndexOutOfBoundsException if {@code elementCount * sourceElementLayout.byteSize()} overflows
* @throws IllegalArgumentException if {@code elementCount * sourceElementLayout.byteSize()} overflows
* @throws IllegalArgumentException if {@code elementCount < 0}
* @throws IndexOutOfBoundsException if {@code sourceOffset > source.byteSize() - (elementCount * sourceElementLayout.byteSize())}
* @throws IndexOutOfBoundsException if either {@code sourceOffset} or {@code elementCount} are {@code < 0}
* @throws IndexOutOfBoundsException if {@code sourceOffset < 0}
*/
@ForceInline
default MemorySegment allocateFrom(ValueLayout elementLayout,

@ -153,9 +153,7 @@ public abstract sealed class AbstractMemorySegmentImpl
public MemorySegment reinterpretInternal(Class<?> callerClass, long newSize, Scope scope, Consumer<MemorySegment> cleanup) {
Reflection.ensureNativeAccess(callerClass, MemorySegment.class, "reinterpret");
if (newSize < 0) {
throw new IllegalArgumentException("newSize < 0");
}
Utils.checkNonNegativeArgument(newSize, "newSize");
if (!isNative()) throw new UnsupportedOperationException("Not a native segment");
Runnable action = cleanup != null ?
() -> cleanup.accept(SegmentFactories.makeNativeSegmentUnchecked(address(), newSize)) :
@ -594,6 +592,7 @@ public abstract sealed class AbstractMemorySegmentImpl
MemorySegment dstSegment, ValueLayout dstElementLayout, long dstOffset,
long elementCount) {
Utils.checkNonNegativeIndex(elementCount, "elementCount");
AbstractMemorySegmentImpl srcImpl = (AbstractMemorySegmentImpl)srcSegment;
AbstractMemorySegmentImpl dstImpl = (AbstractMemorySegmentImpl)dstSegment;
if (srcElementLayout.byteSize() != dstElementLayout.byteSize()) {
@ -625,7 +624,7 @@ public abstract sealed class AbstractMemorySegmentImpl
public static void copy(MemorySegment srcSegment, ValueLayout srcLayout, long srcOffset,
Object dstArray, int dstIndex,
int elementCount) {
Utils.checkNonNegativeIndex(elementCount, "elementCount");
var dstInfo = Utils.BaseAndScale.of(dstArray);
if (dstArray.getClass().componentType() != srcLayout.carrier()) {
throw new IllegalArgumentException("Incompatible value layout: " + srcLayout);
@ -652,7 +651,6 @@ public abstract sealed class AbstractMemorySegmentImpl
public static void copy(Object srcArray, int srcIndex,
MemorySegment dstSegment, ValueLayout dstLayout, long dstOffset,
int elementCount) {
var srcInfo = Utils.BaseAndScale.of(srcArray);
if (srcArray.getClass().componentType() != dstLayout.carrier()) {
throw new IllegalArgumentException("Incompatible value layout: " + dstLayout);

@ -200,11 +200,8 @@ public final class Utils {
}
public static void checkAllocationSizeAndAlign(long byteSize, long byteAlignment) {
// size should be >= 0
if (byteSize < 0) {
throw new IllegalArgumentException("Invalid allocation size : " + byteSize);
}
// byteSize should be >= 0
Utils.checkNonNegativeArgument(byteSize, "allocation size");
checkAlign(byteAlignment);
}
@ -216,6 +213,20 @@ public final class Utils {
}
}
@ForceInline
public static void checkNonNegativeArgument(long value, String name) {
if (value < 0) {
throw new IllegalArgumentException("The provided " + name + " is negative: " + value);
}
}
@ForceInline
public static void checkNonNegativeIndex(long value, String name) {
if (value < 0) {
throw new IndexOutOfBoundsException("The provided " + name + " is negative: " + value);
}
}
private static long computePadding(long offset, long align) {
boolean isAligned = offset == 0 || offset % align == 0;
if (isAligned) {

@ -151,13 +151,8 @@ public abstract sealed class AbstractLayout<L extends AbstractLayout<L> & Memory
}
public long scale(long offset, long index) {
if (offset < 0) {
throw new IllegalArgumentException("Negative offset: " + offset);
}
if (index < 0) {
throw new IllegalArgumentException("Negative index: " + index);
}
Utils.checkNonNegativeArgument(offset, "offset");
Utils.checkNonNegativeArgument(index, "index");
return Math.addExact(offset, Math.multiplyExact(byteSize(), index));
}

@ -30,13 +30,6 @@ public final class MemoryLayoutUtil {
private MemoryLayoutUtil() {
}
public static long requireNonNegative(long value) {
if (value < 0) {
throw new IllegalArgumentException("The provided value was negative: " + value);
}
return value;
}
public static long requireByteSizeValid(long byteSize, boolean allowZero) {
if ((byteSize == 0 && !allowZero) || byteSize < 0) {
throw new IllegalArgumentException("Invalid byte size: " + byteSize);

@ -371,13 +371,13 @@ public class TestLayouts {
}
@Test(expectedExceptions=IllegalArgumentException.class,
expectedExceptionsMessageRegExp=".*Negative offset.*")
expectedExceptionsMessageRegExp=".*offset is negative.*")
public void testScaleNegativeOffset() {
JAVA_INT.scale(-1, 0);
}
@Test(expectedExceptions=IllegalArgumentException.class,
expectedExceptionsMessageRegExp=".*Negative index.*")
expectedExceptionsMessageRegExp=".*index is negative.*")
public void testScaleNegativeIndex() {
JAVA_INT.scale(0, -1);
}

@ -164,6 +164,13 @@ public class TestMemoryAccessInstance {
}
}
@Test(dataProvider = "segmentAccessors")
public <X, L extends ValueLayout> void negativeOffset(String testName, Accessor<X, L> accessor) {
MemorySegment segment = MemorySegment.ofArray(new byte[100]);
assertThrows(IndexOutOfBoundsException.class, () -> accessor.get(segment, -ValueLayout.JAVA_LONG.byteSize()));
assertThrows(IndexOutOfBoundsException.class, () -> accessor.set(segment, -ValueLayout.JAVA_LONG.byteSize(), accessor.value));
}
static final ByteOrder NE = ByteOrder.nativeOrder();
@DataProvider(name = "segmentAccessors")

@ -27,6 +27,7 @@
*/
import java.lang.foreign.Arena;
import java.lang.foreign.MemoryLayout;
import java.lang.foreign.MemorySegment;
import java.lang.foreign.ValueLayout;
@ -135,6 +136,8 @@ public class TestScopedOperations {
ScopedOperation.ofScope(a -> a.allocateFrom(ValueLayout.JAVA_FLOAT, new float[]{0}), "Arena::allocateFrom/float");
ScopedOperation.ofScope(a -> a.allocateFrom(ValueLayout.JAVA_LONG, new long[]{0}), "Arena::allocateFrom/long");
ScopedOperation.ofScope(a -> a.allocateFrom(ValueLayout.JAVA_DOUBLE, new double[]{0}), "Arena::allocateFrom/double");
var source = MemorySegment.ofArray(new byte[]{});
ScopedOperation.ofScope(a -> a.allocateFrom(ValueLayout.JAVA_INT, source, JAVA_BYTE, 0, 1), "Arena::allocateFrom/5arg");
};
@DataProvider(name = "scopedOperations")

@ -44,6 +44,8 @@ import java.nio.LongBuffer;
import java.nio.ShortBuffer;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.BiFunction;
import java.util.function.Function;
@ -189,6 +191,81 @@ public class TestSegmentAllocators {
}
}
// Invariant checking tests for the SegmentAllocator method:
// MemorySegment allocateFrom(ValueLayout elementLayout,
// MemorySegment source,
// ValueLayout sourceElementLayout,
// long sourceOffset,
// long elementCount) {
@Test
public void testAllocatorAllocateFromArguments() {
try (Arena arena = Arena.ofConfined()) {
var sourceElements = 2;
var source = arena.allocate(ValueLayout.JAVA_LONG, sourceElements);
var elementLayout = ValueLayout.JAVA_INT;
var sourceElementLayout = ValueLayout.JAVA_INT;
// IllegalArgumentException if {@code elementLayout.byteSize() != sourceElementLayout.byteSize()}
assertThrows(IllegalArgumentException.class, () ->
arena.allocateFrom(elementLayout, source, ValueLayout.JAVA_BYTE, 0, 1)
);
// IllegalArgumentException if source segment/offset
// are <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a>
// in the source element layout
assertThrows(IllegalArgumentException.class, () ->
arena.allocateFrom(elementLayout, source.asSlice(1), sourceElementLayout, 0, 1)
);
assertThrows(IllegalArgumentException.class, () ->
arena.allocateFrom(elementLayout, source, sourceElementLayout, 1, 1)
);
// IllegalArgumentException if {@code elementLayout.byteAlignment() > elementLayout.byteSize()}
assertThrows(IllegalArgumentException.class, () ->
arena.allocateFrom(elementLayout.withByteAlignment(elementLayout.byteAlignment() * 2), source, sourceElementLayout, 1, 1)
);
// IllegalStateException if the {@linkplain MemorySegment#scope() scope} associated
// with {@code source} is not {@linkplain MemorySegment.Scope#isAlive() alive}
// This is tested in TestScopedOperations
// WrongThreadException if this method is called from a thread {@code T},
// such that {@code source.isAccessibleBy(T) == false}
CompletableFuture<Arena> future = CompletableFuture.supplyAsync(Arena::ofConfined);
try {
Arena otherThreadArena = future.get();
assertThrows(WrongThreadException.class, () ->
otherThreadArena.allocateFrom(elementLayout, source, sourceElementLayout, 0, 1)
);
} catch (ExecutionException | InterruptedException e) {
fail("Unable to create arena", e);
}
// IllegalArgumentException if {@code elementCount * sourceElementLayout.byteSize()} overflows
assertThrows(IllegalArgumentException.class, () ->
arena.allocateFrom(elementLayout, source, sourceElementLayout, 0, Long.MAX_VALUE)
);
// IndexOutOfBoundsException if {@code sourceOffset > source.byteSize() - (elementCount * sourceElementLayout.byteSize())}
assertThrows(IndexOutOfBoundsException.class, () ->
arena.allocateFrom(elementLayout, source, sourceElementLayout, source.byteSize() - (1 * sourceElementLayout.byteAlignment()) + elementLayout.byteSize(), 1)
);
// IndexOutOfBoundsException if {@code sourceOffset < 0}
assertThrows(IndexOutOfBoundsException.class, () ->
arena.allocateFrom(elementLayout, source, sourceElementLayout, -elementLayout.byteSize(), 1)
);
// IllegalArgumentException if {@code elementCount < 0}
assertThrows(IllegalArgumentException.class, () ->
arena.allocateFrom(elementLayout, source, sourceElementLayout, 0, -1)
);
}
}
@Test
public void testArrayAllocateDelegation() {
AtomicInteger calls = new AtomicInteger();

@ -145,6 +145,66 @@ public class TestSegmentCopy {
MemorySegment.copy(segment, JAVA_BYTE.withByteAlignment(2), 0, segment, 0, 4);
}
@Test
public void testCopy5ArgWithNegativeValues() {
MemorySegment src = MemorySegment.ofArray(new byte[] {1, 2, 3, 4});
MemorySegment dst = MemorySegment.ofArray(new byte[] {1, 2, 3, 4});
assertThrows(IndexOutOfBoundsException.class, () ->
MemorySegment.copy(src, -1, dst, 0, 4)
);
assertThrows(IndexOutOfBoundsException.class, () ->
MemorySegment.copy(src, 0, dst, -1, 4)
);
assertThrows(IndexOutOfBoundsException.class, () ->
MemorySegment.copy(src, 0, dst, 0, -1)
);
}
@Test
public void testCopy7ArgWithNegativeValues() {
MemorySegment src = MemorySegment.ofArray(new byte[] {1, 2, 3, 4});
MemorySegment dst = MemorySegment.ofArray(new byte[] {1, 2, 3, 4});
assertThrows(IndexOutOfBoundsException.class, () ->
MemorySegment.copy(src, JAVA_BYTE, -1, dst, JAVA_BYTE, 0, 4)
);
assertThrows(IndexOutOfBoundsException.class, () ->
MemorySegment.copy(src, JAVA_BYTE, 0, dst, JAVA_BYTE, -1, 4)
);
assertThrows(IndexOutOfBoundsException.class, () ->
MemorySegment.copy(src, JAVA_BYTE, 0, dst, JAVA_BYTE, 0, -1)
);
}
@Test
public void testCopyFromArrayWithNegativeValues() {
MemorySegment src = MemorySegment.ofArray(new byte[] {1, 2, 3, 4});
byte[] dst = new byte[] {1, 2, 3, 4};
assertThrows(IndexOutOfBoundsException.class, () ->
MemorySegment.copy(src, JAVA_BYTE, -1, dst, 0, 4)
);
assertThrows(IndexOutOfBoundsException.class, () ->
MemorySegment.copy(src, JAVA_BYTE, 0, dst, -1, 4)
);
assertThrows(IndexOutOfBoundsException.class, () ->
MemorySegment.copy(src, JAVA_BYTE, 0, dst, 0, -1)
);
}
@Test
public void testCopyToArrayWithNegativeValues() {
byte[] src = new byte[] {1, 2, 3, 4};
MemorySegment dst = MemorySegment.ofArray(new byte[] {1, 2, 3, 4});
assertThrows(IndexOutOfBoundsException.class, () ->
MemorySegment.copy(src, -1, dst, JAVA_BYTE, 0, 4)
);
assertThrows(IndexOutOfBoundsException.class, () ->
MemorySegment.copy(src, 0, dst, JAVA_BYTE, -1, 4)
);
assertThrows(IndexOutOfBoundsException.class, () ->
MemorySegment.copy(src, 0, dst, JAVA_BYTE, 0, -1)
);
}
enum Type {
// Byte
BYTE(byte.class, JAVA_BYTE, i -> (byte)i),

@ -43,6 +43,7 @@ import java.util.function.IntFunction;
import java.util.function.Supplier;
import static java.lang.foreign.ValueLayout.JAVA_INT;
import static java.lang.foreign.ValueLayout.JAVA_LONG;
import static org.testng.Assert.*;
public class TestSegments {
@ -55,14 +56,13 @@ public class TestSegments {
@Test
public void testZeroLengthNativeSegment() {
try (Arena arena = Arena.ofConfined()) {
Arena session = arena;
var segment = session.allocate(0, 1);
var segment = arena.allocate(0, 1);
assertEquals(segment.byteSize(), 0);
MemoryLayout seq = MemoryLayout.sequenceLayout(0, JAVA_INT);
segment = session.allocate(seq);
segment = arena.allocate(seq);
assertEquals(segment.byteSize(), 0);
assertEquals(segment.address() % seq.byteAlignment(), 0);
segment = session.allocate(0, 4);
segment = arena.allocate(0, 4);
assertEquals(segment.byteSize(), 0);
assertEquals(segment.address() % 4, 0);
MemorySegment rawAddress = MemorySegment.ofAddress(segment.address());
@ -133,8 +133,7 @@ public class TestSegments {
@Test
public void testEqualsOffHeap() {
try (Arena arena = Arena.ofConfined()) {
Arena scope1 = arena;
MemorySegment segment = scope1.allocate(100, 1);
MemorySegment segment = arena.allocate(100, 1);
assertEquals(segment, segment.asReadOnly());
assertEquals(segment, segment.asSlice(0, 100));
assertNotEquals(segment, segment.asSlice(10, 90));