-
Notifications
You must be signed in to change notification settings - Fork 3.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Adding a case to handle read-only BB. #4013
base: trunk
Are you sure you want to change the base?
Conversation
@@ -195,6 +196,8 @@ public Object run() | |||
{ | |||
BYTE_ARRAY_BASE_OFFSET = theUnsafe.arrayBaseOffset(byte[].class); | |||
DIRECT_BUFFER_ADDRESS_OFFSET = theUnsafe.objectFieldOffset(Buffer.class.getDeclaredField("address")); | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
remove space
// Heap ByteBuffer (Mutable) | ||
if (srcBuf.hasArray() && !srcBuf.isReadOnly()) | ||
{ | ||
src = theUnsafe.getObject(srcBuf, HEAP_HB_FIELD); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
rather than rely on the new logic, can we keep the old logic that has been safe for years? unsafe can break on us in jdk bumps so if we can avoid it in the 99.999% case that is best
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can you also update org.apache.cassandra.utils.Generators#bytes(int, int)
to include READ_ONLY_HEAP
, that way we can get better coverage?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
CI is finding this isn't enough, please update
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A few nits. The patch looks good overall.
I can also reproduce the segment failure by reverting the fix.
@@ -163,6 +163,7 @@ public static final class UnsafeOperations implements ByteOperations | |||
*/ | |||
static final long BYTE_ARRAY_BASE_OFFSET; | |||
static final long DIRECT_BUFFER_ADDRESS_OFFSET; | |||
static final long HEAP_HB_FIELD; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: append the same suffix, _OFFSET
to this field.
if (srcBuf.hasArray()) | ||
|
||
// Heap ByteBuffer (Mutable) | ||
if (srcBuf.hasArray() && !srcBuf.isReadOnly()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: srcBuf.hasArray()
already implies !srcBuf.isReadOnly()
, the second condition is redundant.
srcOffset = BYTE_ARRAY_BASE_OFFSET; | ||
|
||
if (src == null) | ||
throw new IllegalArgumentException("Unsupported ByteBuffer type: No backing array and not direct."); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: feel to me that it is an illegal state?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I just wanted to be sure we do not crash. But yes it makes sense.
if (src == null) | ||
throw new IllegalArgumentException("Unsupported ByteBuffer type: No backing array and not direct."); | ||
} | ||
// Direct ByteBuffer |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thanks for adding the comments for the conditions. 👍
if (srcBuf.hasArray()) | ||
{ | ||
src = srcBuf.array(); | ||
srcOffset = BYTE_ARRAY_BASE_OFFSET + srcBuf.arrayOffset(); | ||
} | ||
// Read-Only Heap ByteBuffer (Still has hb but read-only) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can you add these comments to all code paths modified?
else if (buffer1.isReadOnly() && !buffer1.isDirect()) | ||
{ | ||
obj1 = theUnsafe.getObject(buffer1, HEAP_HB_FIELD_OFFSET); | ||
offset1 = BYTE_ARRAY_BASE_OFFSET; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is this actually true? what about the following
ByteBuffer.wrap(new byte[42]).position(10).asReadOnly()
In this case won't the offset be BYTE_ARRAY_BASE_OFFSET + buffer1.arrayOffset()
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can you add a test that does ByteBuffer.wrap(new byte[42]).position(10).asReadOnly()
and make sure we actually return the correct data? My fear is this code will always start at offset=0 but we should start at offset=10 in this case?
Cassandra-20431
Fix JVM crash when writing read-only ByteBuffer in BufferedDataOutputStreamPlus
Ensure
BufferedDataOutputStreamPlus#write(ByteBuffer)
safely handles read-only buffers, preventing JVM crashes.patch by Sunil Ramchandra Pawar; reviewed by David Capwell for CASSANDRA-20431