Skip to content

Commit

Permalink
8280460: MemorySegment::allocateNative should be tolerant of zero-siz…
Browse files Browse the repository at this point in the history
…ed allocation requests

Reviewed-by: jvernee
  • Loading branch information
mcimadamore committed Feb 22, 2022
1 parent 5620d82 commit 8403a4d
Show file tree
Hide file tree
Showing 6 changed files with 36 additions and 10 deletions.
11 changes: 5 additions & 6 deletions src/java.base/share/classes/java/lang/foreign/MemorySegment.java
Original file line number Diff line number Diff line change
Expand Up @@ -839,7 +839,7 @@ static MemorySegment ofArray(double[] arr) {
* @param bytesSize the desired size.
* @param session the native segment memory session.
* @return a new native memory segment with given base address, size and memory session.
* @throws IllegalArgumentException if {@code bytesSize <= 0}.
* @throws IllegalArgumentException if {@code bytesSize < 0}.
* @throws IllegalStateException if {@code session} is not {@linkplain MemorySession#isAlive() alive}, or if access occurs from
* a thread other than the thread {@linkplain MemorySession#ownerThread() owning} {@code session}.
* @throws IllegalCallerException if access to this method occurs from a module {@code M} and the command line option
Expand All @@ -851,7 +851,7 @@ static MemorySegment ofAddress(MemoryAddress address, long bytesSize, MemorySess
Reflection.ensureNativeAccess(Reflection.getCallerClass());
Objects.requireNonNull(address);
Objects.requireNonNull(session);
if (bytesSize <= 0) {
if (bytesSize < 0) {
throw new IllegalArgumentException("Invalid size : " + bytesSize);
}
return NativeMemorySegmentImpl.makeNativeSegmentUnchecked(address, bytesSize, Scoped.toSessionImpl(session));
Expand All @@ -872,7 +872,6 @@ static MemorySegment ofAddress(MemoryAddress address, long bytesSize, MemorySess
* @param layout the layout of the off-heap memory block backing the native memory segment.
* @param session the segment memory session.
* @return a new native memory segment.
* @throws IllegalArgumentException if the specified layout has illegal size or alignment constraint.
* @throws IllegalStateException if {@code session} is not {@linkplain MemorySession#isAlive() alive}, or if access occurs from
* a thread other than the thread {@linkplain MemorySession#ownerThread() owning} {@code session}.
*/
Expand All @@ -897,7 +896,7 @@ static MemorySegment allocateNative(MemoryLayout layout, MemorySession session)
* @param bytesSize the size (in bytes) of the off-heap memory block backing the native memory segment.
* @param session the segment temporal bounds.
* @return a new native memory segment.
* @throws IllegalArgumentException if {@code bytesSize <= 0}.
* @throws IllegalArgumentException if {@code bytesSize < 0}.
* @throws IllegalStateException if {@code session} is not {@linkplain MemorySession#isAlive() alive}, or if access occurs from
* a thread other than the thread {@linkplain MemorySession#ownerThread() owning} {@code session}.
*/
Expand All @@ -917,14 +916,14 @@ static MemorySegment allocateNative(long bytesSize, MemorySession session) {
* @param alignmentBytes the alignment constraint (in bytes) of the off-heap memory block backing the native memory segment.
* @param session the segment memory session.
* @return a new native memory segment.
* @throws IllegalArgumentException if {@code bytesSize <= 0}, {@code alignmentBytes <= 0}, or if {@code alignmentBytes}
* @throws IllegalArgumentException if {@code bytesSize < 0}, {@code alignmentBytes <= 0}, or if {@code alignmentBytes}
* is not a power of 2.
* @throws IllegalStateException if {@code session} is not {@linkplain MemorySession#isAlive() alive}, or if access occurs from
* a thread other than the thread {@linkplain MemorySession#ownerThread() owning} {@code session}.
*/
static MemorySegment allocateNative(long bytesSize, long alignmentBytes, MemorySession session) {
Objects.requireNonNull(session);
if (bytesSize <= 0) {
if (bytesSize < 0) {
throw new IllegalArgumentException("Invalid allocation size : " + bytesSize);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,7 @@ default MemorySegment allocate(MemoryLayout layout) {
* @param elementLayout the array element layout.
* @param count the array element count.
* @return a segment for the newly allocated memory block.
* @throws IllegalArgumentException if {@code count < 0}.
*/
default MemorySegment allocateArray(MemoryLayout elementLayout, long count) {
Objects.requireNonNull(elementLayout);
Expand All @@ -322,6 +323,7 @@ default MemorySegment allocateArray(MemoryLayout elementLayout, long count) {
* @implSpec the default implementation for this method calls {@code this.allocate(bytesSize, 1)}.
* @param bytesSize the size (in bytes) of the block of memory to be allocated.
* @return a segment for the newly allocated memory block.
* @throws IllegalArgumentException if {@code bytesSize < 0}
*/
default MemorySegment allocate(long bytesSize) {
return allocate(bytesSize, 1);
Expand All @@ -332,6 +334,8 @@ default MemorySegment allocate(long bytesSize) {
* @param bytesSize the size (in bytes) of the block of memory to be allocated.
* @param bytesAlignment the alignment (in bytes) of the block of memory to be allocated.
* @return a segment for the newly allocated memory block.
* @throws IllegalArgumentException if {@code bytesSize < 0}, {@code alignmentBytes <= 0},
* or if {@code alignmentBytes} is not a power of 2.
*/
MemorySegment allocate(long bytesSize, long bytesAlignment);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,10 @@ public final MemorySegment fill(byte value){

@Override
public MemorySegment allocate(long bytesSize, long bytesAlignment) {
if (bytesAlignment <= 0 ||
((bytesAlignment & (bytesAlignment - 1)) != 0L)) {
throw new IllegalArgumentException("Invalid alignment constraint : " + bytesAlignment);
}
return asSlice(0, bytesSize);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,9 +113,9 @@ public static MemorySegment makeNativeSegment(long bytesSize, long alignmentByte
if (VM.isDirectMemoryPageAligned()) {
alignmentBytes = Math.max(alignmentBytes, nioAccess.pageSize());
}
long alignedSize = alignmentBytes > MAX_MALLOC_ALIGN ?
long alignedSize = Math.max(1L, alignmentBytes > MAX_MALLOC_ALIGN ?
bytesSize + (alignmentBytes - 1) :
bytesSize;
bytesSize);

nioAccess.reserveMemory(alignedSize, bytesSize);

Expand Down
2 changes: 1 addition & 1 deletion test/jdk/java/foreign/TestNative.java
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ public void testAddressAccess() {
public void testBadResize() {
try (MemorySession session = MemorySession.openConfined()) {
MemorySegment segment = MemorySegment.allocateNative(4, 1, session);
MemorySegment.ofAddress(segment.address(), 0, MemorySession.global());
MemorySegment.ofAddress(segment.address(), -1, MemorySession.global());
}
}

Expand Down
21 changes: 20 additions & 1 deletion test/jdk/java/foreign/TestSegments.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,10 @@
* @test
* @enablePreview
* @requires ((os.arch == "amd64" | os.arch == "x86_64") & sun.arch.data.model == "64") | os.arch == "aarch64"
* @run testng/othervm -Xmx4G -XX:MaxDirectMemorySize=1M TestSegments
* @run testng/othervm -Xmx4G -XX:MaxDirectMemorySize=1M --enable-native-access=ALL-UNNAMED TestSegments
*/

import java.lang.foreign.MemoryLayout;
import java.lang.foreign.MemorySegment;
import java.lang.foreign.MemorySession;
import java.lang.foreign.ValueLayout;
Expand All @@ -52,6 +53,24 @@ public void testBadAllocateAlign(long size, long align) {
MemorySegment.allocateNative(size, align, MemorySession.openImplicit());
}

@Test
public void testZeroLengthNativeSegment() {
try (MemorySession session = MemorySession.openConfined()) {
var segment = MemorySegment.allocateNative(0, session);
assertEquals(segment.byteSize(), 0);
MemoryLayout seq = MemoryLayout.sequenceLayout(0, JAVA_INT);
segment = MemorySegment.allocateNative(seq, session);
assertEquals(segment.byteSize(), 0);
assertEquals(segment.address().toRawLongValue() % seq.byteAlignment(), 0);
segment = MemorySegment.allocateNative(0, 4, session);
assertEquals(segment.byteSize(), 0);
assertEquals(segment.address().toRawLongValue() % 4, 0);
segment = MemorySegment.ofAddress(segment.address(), 0, session);
assertEquals(segment.byteSize(), 0);
assertEquals(segment.address().toRawLongValue() % 4, 0);
}
}

@Test(expectedExceptions = { OutOfMemoryError.class,
IllegalArgumentException.class })
public void testAllocateTooBig() {
Expand Down

0 comments on commit 8403a4d

Please sign in to comment.