Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InaccessibleObjectException;
import java.lang.reflect.InvocationTargetException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
Expand Down Expand Up @@ -81,9 +82,18 @@ public Object run() {
BYTE_ARRAY_BASE_OFFSET = UNSAFE.arrayBaseOffset(byte[].class);

// get the offset of the address field in a java.nio.Buffer object
long maybeOffset;
Field addressField = java.nio.Buffer.class.getDeclaredField("address");
addressField.setAccessible(true);
BYTE_BUFFER_ADDRESS_OFFSET = UNSAFE.objectFieldOffset(addressField);
try {
addressField.setAccessible(true);
maybeOffset = UNSAFE.objectFieldOffset(addressField);
} catch (InaccessibleObjectException e) {
maybeOffset = -1;
logger.debug(
"Cannot access the address field of java.nio.Buffer. DirectBuffer operations wont be available",
e);
}
BYTE_BUFFER_ADDRESS_OFFSET = maybeOffset;

Constructor<?> directBufferConstructor;
long address = -1;
Expand All @@ -109,6 +119,9 @@ public Object run() {
} catch (SecurityException e) {
logger.debug("Cannot get constructor for direct buffer allocation", e);
return e;
} catch (InaccessibleObjectException e) {
logger.debug("Cannot get constructor for direct buffer allocation", e);
return e;
}
}
});
Expand Down Expand Up @@ -156,7 +169,11 @@ public Object run() {
* @return address of the underlying memory.
*/
public static long getByteBufferAddress(ByteBuffer buf) {
return UNSAFE.getLong(buf, BYTE_BUFFER_ADDRESS_OFFSET);
if (BYTE_BUFFER_ADDRESS_OFFSET != -1) {
return UNSAFE.getLong(buf, BYTE_BUFFER_ADDRESS_OFFSET);
}
throw new UnsupportedOperationException(
"Byte buffer address cannot be obtained because sun.misc.Unsafe or java.nio.DirectByteBuffer.<init>(long, int) is not available");
}

private MemoryUtil() {}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,32 +20,27 @@
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.condition.JRE.JAVA_16;

import org.apache.arrow.memory.util.MemoryUtil;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.EnabledForJreRange;

public class TestOpens {
/** Instantiating the RootAllocator should poke MemoryUtil and fail. */
/** Accessing MemoryUtil.directBuffer should fail as add-opens is not configured. */
@Test
@EnabledForJreRange(min = JAVA_16)
public void testMemoryUtilFailsLoudly() {
// This test is configured by Maven to run WITHOUT add-opens. So this should fail on JDK16+
// (where JEP396 means that add-opens is required to access JDK internals).
// The test will likely fail in your IDE if it doesn't correctly pick this up.
Throwable e =
assertThrows(
Throwable.class,
() -> {
BufferAllocator allocator = new RootAllocator();
allocator.close();
});
Throwable e = assertThrows(Throwable.class, () -> MemoryUtil.directBuffer(0, 10));
boolean found = false;
while (e != null) {
e = e.getCause();
if (e instanceof RuntimeException
&& e.getMessage().contains("Failed to initialize MemoryUtil")) {
if (e instanceof UnsupportedOperationException
&& e.getMessage().contains("java.nio.DirectByteBuffer.<init>(long, int) not available")) {
found = true;
break;
}
e = e.getCause();
}
assertTrue(found, "Expected exception was not thrown");
}
Expand Down
Loading