8321387: SegmentAllocator:allocateFrom(AddressLayout, MemorySegment) does not throw stated UnsupportedOperationException

Reviewed-by: mcimadamore
This commit is contained in:
Per Minborg 2023-12-11 07:52:31 +00:00
parent ce108446ca
commit d13302f8b0
10 changed files with 99 additions and 36 deletions

View File

@ -631,6 +631,9 @@ public sealed interface MemoryLayout
* <li>The accessed memory segment must be
* {@link MemorySegment#isAccessibleBy(Thread) accessible} from the thread
* performing the access operation, or a {@link WrongThreadException} is thrown.</li>
* <li>For write operations, the accessed memory segment must not be
* {@link MemorySegment#isReadOnly() read only}, or an
* {@link IllegalArgumentException} is thrown.</li>
* <li>The {@linkplain MemorySegment#scope() scope} associated with the accessed
* segment must be {@linkplain MemorySegment.Scope#isAlive() alive}, or an
* {@link IllegalStateException} is thrown.</li>

View File

@ -869,7 +869,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* this segment is not {@linkplain Scope#isAlive() alive}
* @throws WrongThreadException if this method is called from a thread {@code T},
* such that {@code isAccessibleBy(T) == false}
* @throws UnsupportedOperationException if this segment is
* @throws IllegalArgumentException if this segment is
* {@linkplain #isReadOnly() read-only}
*/
MemorySegment fill(byte value);
@ -894,7 +894,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* {@code src} is not {@linkplain Scope#isAlive() alive}
* @throws WrongThreadException if this method is called from a thread {@code T},
* such that {@code src.isAccessibleBy(T) == false}
* @throws UnsupportedOperationException if this segment is
* @throws IllegalArgumentException if this segment is
* {@linkplain #isReadOnly() read-only}
* @return this segment
*/
@ -1269,6 +1269,8 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* this segment is not {@linkplain Scope#isAlive() alive}
* @throws WrongThreadException if this method is called from a thread {@code T},
* such that {@code isAccessibleBy(T) == false}
* @throws IllegalArgumentException if this segment is
* {@linkplain #isReadOnly() read-only}
*/
void setString(long offset, String str);
@ -1306,6 +1308,8 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* such that {@code isAccessibleBy(T) == false}
* @throws IllegalArgumentException if {@code charset} is not a
* {@linkplain StandardCharsets standard charset}
* @throws IllegalArgumentException if this segment is
* {@linkplain #isReadOnly() read-only}
*/
void setString(long offset, String str, Charset charset);
@ -1493,7 +1497,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* @throws IndexOutOfBoundsException if {@code dstOffset > dstSegment.byteSize() - bytes}
* @throws IndexOutOfBoundsException if either {@code srcOffset},
* {@code dstOffset} or {@code bytes} are {@code < 0}
* @throws UnsupportedOperationException if {@code dstSegment} is
* @throws IllegalArgumentException if {@code dstSegment} is
* {@linkplain #isReadOnly() read-only}
*/
@ForceInline
@ -1552,7 +1556,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* {@code dstSegment} is not {@linkplain Scope#isAlive() alive}
* @throws WrongThreadException if this method is called from a thread {@code T},
* such that {@code dstSegment.isAccessibleBy(T) == false}
* @throws UnsupportedOperationException if {@code dstSegment} is {@linkplain #isReadOnly() read-only}
* @throws IllegalArgumentException if {@code dstSegment} is {@linkplain #isReadOnly() read-only}
* @throws IndexOutOfBoundsException if {@code elementCount * srcLayout.byteSize()} overflows
* @throws IndexOutOfBoundsException if {@code elementCount * dtsLayout.byteSize()} overflows
* @throws IndexOutOfBoundsException if {@code srcOffset > srcSegment.byteSize() - (elementCount * srcLayout.byteSize())}
@ -1605,7 +1609,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
* @throws IllegalArgumentException if this segment is
* {@linkplain #isReadOnly() read-only}
*/
void set(ValueLayout.OfByte layout, long offset, byte value);
@ -1643,7 +1647,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
* @throws IllegalArgumentException if this segment is
* {@linkplain #isReadOnly() read-only}
*/
void set(ValueLayout.OfBoolean layout, long offset, boolean value);
@ -1681,7 +1685,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
* @throws IllegalArgumentException if this segment is
* {@linkplain #isReadOnly() read-only}
*/
void set(ValueLayout.OfChar layout, long offset, char value);
@ -1719,7 +1723,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
* @throws IllegalArgumentException if this segment is
* {@linkplain #isReadOnly() read-only}
*/
void set(ValueLayout.OfShort layout, long offset, short value);
@ -1757,7 +1761,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
* @throws IllegalArgumentException if this segment is
* {@linkplain #isReadOnly() read-only}
*/
void set(ValueLayout.OfInt layout, long offset, int value);
@ -1795,7 +1799,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
* @throws IllegalArgumentException if this segment is
* {@linkplain #isReadOnly() read-only}
*/
void set(ValueLayout.OfFloat layout, long offset, float value);
@ -1833,7 +1837,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
* @throws IllegalArgumentException if this segment is
* {@linkplain #isReadOnly() read-only}
*/
void set(ValueLayout.OfLong layout, long offset, long value);
@ -1871,7 +1875,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
* @throws IllegalArgumentException if this segment is
* {@linkplain #isReadOnly() read-only}
*/
void set(ValueLayout.OfDouble layout, long offset, double value);
@ -1921,8 +1925,10 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()}
* @throws UnsupportedOperationException if this segment is
* {@linkplain #isReadOnly() read-only}
* @throws UnsupportedOperationException if {@code value} is not a
* @throws IllegalArgumentException if {@code value} is not a
* {@linkplain #isNative() native} segment
* @throws IllegalArgumentException if this segment is
* {@linkplain #isReadOnly() read-only}
*/
void set(AddressLayout layout, long offset, MemorySegment value);
@ -2055,7 +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()}
* @throws UnsupportedOperationException if this segment is {@linkplain #isReadOnly() read-only}
* @throws IllegalArgumentException if this segment is {@linkplain #isReadOnly() read-only}
*/
void setAtIndex(ValueLayout.OfByte layout, long index, byte value);
@ -2078,7 +2084,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}
* @throws IllegalArgumentException if this segment is {@linkplain #isReadOnly() read-only}
*/
void setAtIndex(ValueLayout.OfBoolean layout, long index, boolean value);
@ -2101,7 +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()}
* @throws UnsupportedOperationException if this segment is {@linkplain #isReadOnly() read-only}
* @throws IllegalArgumentException if this segment is {@linkplain #isReadOnly() read-only}
*/
void setAtIndex(ValueLayout.OfShort layout, long index, short value);
@ -2146,7 +2152,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}
* @throws IllegalArgumentException if this segment is {@linkplain #isReadOnly() read-only}
*/
void setAtIndex(ValueLayout.OfInt layout, long index, int value);
@ -2191,7 +2197,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}
* @throws IllegalArgumentException if this segment is {@linkplain #isReadOnly() read-only}
*/
void setAtIndex(ValueLayout.OfFloat layout, long index, float value);
@ -2236,7 +2242,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}
* @throws IllegalArgumentException if this segment is {@linkplain #isReadOnly() read-only}
*/
void setAtIndex(ValueLayout.OfLong layout, long index, long value);
@ -2281,7 +2287,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}
* @throws IllegalArgumentException if this segment is {@linkplain #isReadOnly() read-only}
*/
void setAtIndex(ValueLayout.OfDouble layout, long index, double value);
@ -2336,7 +2342,9 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* @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}
* @throws UnsupportedOperationException if {@code value} is not a {@linkplain #isNative() native} segment
* @throws IllegalArgumentException if {@code value} is not a {@linkplain #isNative() native} segment
* @throws IllegalArgumentException if this segment is
* {@linkplain #isReadOnly() read-only}
*/
void setAtIndex(AddressLayout layout, long index, MemorySegment value);
@ -2460,7 +2468,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a>
* in the source element layout
* @throws IllegalArgumentException if {@code dstLayout.byteAlignment() > dstLayout.byteSize()}
* @throws UnsupportedOperationException if {@code dstSegment} is {@linkplain #isReadOnly() read-only}
* @throws IllegalArgumentException if {@code dstSegment} is {@linkplain #isReadOnly() read-only}
* @throws IndexOutOfBoundsException if {@code elementCount * dstLayout.byteSize()} overflows
* @throws IndexOutOfBoundsException if {@code dstOffset > dstSegment.byteSize() - (elementCount * dstLayout.byteSize())}
* @throws IndexOutOfBoundsException if {@code srcIndex > srcArray.length - elementCount}

View File

@ -350,7 +350,7 @@ public interface SegmentAllocator {
*
* @param layout the layout of the block of memory to be allocated
* @param value the value to be set in the newly allocated memory segment
* @throws UnsupportedOperationException if {@code value} is not
* @throws IllegalArgumentException if {@code value} is not
* a {@linkplain MemorySegment#isNative() native} segment
*/
default MemorySegment allocateFrom(AddressLayout layout, MemorySegment value) {
@ -670,9 +670,11 @@ public interface SegmentAllocator {
*
* @param segment the segment from which the returned allocator should slice from
* @return a new slicing allocator
* @throws IllegalArgumentException if the {@code segment} is
* {@linkplain MemorySegment#isReadOnly() read-only}
*/
static SegmentAllocator slicingAllocator(MemorySegment segment) {
Objects.requireNonNull(segment);
assertWritable(segment);
return new SlicingAllocator(segment);
}
@ -700,9 +702,19 @@ public interface SegmentAllocator {
* @param segment the memory segment to be recycled by the returned allocator
* @return an allocator that recycles an existing segment upon each new
* allocation request
* @throws IllegalArgumentException if the {@code segment} is
* {@linkplain MemorySegment#isReadOnly() read-only}
*/
static SegmentAllocator prefixAllocator(MemorySegment segment) {
return (AbstractMemorySegmentImpl)Objects.requireNonNull(segment);
assertWritable(segment);
return (AbstractMemorySegmentImpl)segment;
}
private static void assertWritable(MemorySegment segment) {
// Implicit null check
if (segment.isReadOnly()) {
throw new IllegalArgumentException("read-only segment");
}
}
@ForceInline

View File

@ -361,7 +361,7 @@ public abstract sealed class AbstractMemorySegmentImpl
@ForceInline
public void checkAccess(long offset, long length, boolean readOnly) {
if (!readOnly && this.readOnly) {
throw new UnsupportedOperationException("Attempt to write a read-only segment");
throw new IllegalArgumentException("Attempt to write a read-only segment");
}
checkBounds(offset, length);
}

View File

@ -26,12 +26,9 @@
* @run testng TestArrayCopy
*/
import java.lang.foreign.MemoryLayout;
import java.lang.foreign.MemorySegment;
import java.lang.foreign.ValueLayout;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.invoke.VarHandle;
import java.nio.ByteOrder;
import java.util.ArrayList;
@ -240,7 +237,7 @@ public class TestArrayCopy {
try {
helper.copyFromArray(srcArr, 0, SEG_LENGTH_BYTES / bytesPerElement, dstSeg, 0, ByteOrder.nativeOrder());
fail();
} catch (UnsupportedOperationException ex) {
} catch (IllegalArgumentException ex) {
//ok
}
}

View File

@ -87,7 +87,7 @@ public class TestMemoryAccess {
if (isRO) {
throw new AssertionError(); //not ok, memory should be immutable
}
} catch (UnsupportedOperationException ex) {
} catch (IllegalArgumentException ex) {
if (!isRO) {
throw new AssertionError(); //we should not have failed!
}
@ -121,7 +121,7 @@ public class TestMemoryAccess {
if (isRO) {
throw new AssertionError(); //not ok, memory should be immutable
}
} catch (UnsupportedOperationException ex) {
} catch (IllegalArgumentException ex) {
if (!isRO) {
throw new AssertionError(); //we should not have failed!
}
@ -185,7 +185,7 @@ public class TestMemoryAccess {
if (isRO) {
throw new AssertionError(); //not ok, memory should be immutable
}
} catch (UnsupportedOperationException ex) {
} catch (IllegalArgumentException ex) {
if (!isRO) {
throw new AssertionError(); //we should not have failed!
}

View File

@ -27,7 +27,6 @@
* @run testng/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_SEGMENT_FORCE_EXACT=true --enable-native-access=ALL-UNNAMED TestMemoryAccessInstance
*/
import java.lang.foreign.MemoryLayout;
import java.lang.foreign.MemorySegment;
import java.lang.foreign.Arena;
import java.lang.foreign.ValueLayout;

View File

@ -100,6 +100,16 @@ public class TestSegmentAllocators {
static final int SIZE_256M = 1024 * 1024 * 256;
@Test(expectedExceptions = IllegalArgumentException.class)
public void testReadOnlySlicingAllocator() {
SegmentAllocator.slicingAllocator(MemorySegment.ofArray(new int[0]).asReadOnly());
}
@Test(expectedExceptions = IllegalArgumentException.class)
public void testReadOnlyPrefixAllocator() {
SegmentAllocator.prefixAllocator(MemorySegment.ofArray(new int[0]).asReadOnly());
}
@Test
public void testBigAllocationInUnboundedSession() {
try (Arena arena = Arena.ofConfined()) {
@ -160,6 +170,25 @@ public class TestSegmentAllocators {
}
}
@Test(expectedExceptions = IllegalArgumentException.class,
expectedExceptionsMessageRegExp = ".*Heap segment not allowed.*")
public void testArenaAllocateFromHeapSegment() {
try (Arena arena = Arena.ofConfined()) {
var heapSegment = MemorySegment.ofArray(new int[]{1});
arena.allocateFrom(ValueLayout.ADDRESS, heapSegment);
}
}
@Test(expectedExceptions = IllegalArgumentException.class,
expectedExceptionsMessageRegExp = ".*Heap segment not allowed.*")
public void testAllocatorAllocateFromHeapSegment() {
try (Arena arena = Arena.ofConfined()) {
SegmentAllocator allocator = SegmentAllocator.prefixAllocator(arena.allocate(16));
var heapSegment = MemorySegment.ofArray(new int[]{1});
allocator.allocateFrom(ValueLayout.ADDRESS, heapSegment);
}
}
@Test
public void testArrayAllocateDelegation() {
AtomicInteger calls = new AtomicInteger();

View File

@ -76,7 +76,7 @@ public class TestSegmentCopy {
}
}
@Test(expectedExceptions = UnsupportedOperationException.class, dataProvider = "segmentKinds")
@Test(expectedExceptions = IllegalArgumentException.class, dataProvider = "segmentKinds")
public void testReadOnlyCopy(SegmentKind kind1, SegmentKind kind2) {
MemorySegment s1 = kind1.makeSegment(TEST_BYTE_SIZE);
MemorySegment s2 = kind2.makeSegment(TEST_BYTE_SIZE);
@ -84,6 +84,15 @@ public class TestSegmentCopy {
MemorySegment.copy(s1, Type.BYTE.layout, 0, s2.asReadOnly(), Type.BYTE.layout, 0, 0);
}
@Test(expectedExceptions = IllegalArgumentException.class,
expectedExceptionsMessageRegExp = ".*Attempt to write a read-only segment.*")
public void badCopy6Arg() {
try (Arena scope = Arena.ofConfined()) {
MemorySegment dest = scope.allocate(ValueLayout.JAVA_INT).asReadOnly();
MemorySegment.copy(new int[1],0, dest, ValueLayout.JAVA_INT, 0 ,1); // should throw
}
}
@Test(expectedExceptions = IndexOutOfBoundsException.class, dataProvider = "types")
public void testBadOverflow(Type type) {
if (type.layout.byteSize() > 1) {

View File

@ -325,12 +325,18 @@ public class TestSegments {
assertEquals(segment.scope(), arena.scope());
}
@Test(dataProvider = "segmentFactories", expectedExceptions = UnsupportedOperationException.class)
@Test(dataProvider = "segmentFactories", expectedExceptions = IllegalArgumentException.class)
public void testFillIllegalAccessMode(Supplier<MemorySegment> segmentSupplier) {
MemorySegment segment = segmentSupplier.get();
segment.asReadOnly().fill((byte) 0xFF);
}
@Test(dataProvider = "segmentFactories", expectedExceptions = IllegalArgumentException.class)
public void testFromStringIllegalAccessMode(Supplier<MemorySegment> segmentSupplier) {
MemorySegment segment = segmentSupplier.get();
segment.asReadOnly().setString(0, "a");
}
@Test(dataProvider = "segmentFactories")
public void testFillThread(Supplier<MemorySegment> segmentSupplier) throws Exception {
MemorySegment segment = segmentSupplier.get();