Skip to content
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

Open
wants to merge 5 commits into
base: trunk
Choose a base branch
from

Conversation

sunil9977
Copy link
Contributor

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

@@ -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"));

Copy link
Contributor

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);
Copy link
Contributor

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

Copy link
Contributor

@dcapwell dcapwell left a 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?

Copy link
Contributor

@dcapwell dcapwell left a 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

Copy link
Contributor

@yifan-c yifan-c left a 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;
Copy link
Contributor

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())
Copy link
Contributor

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.");
Copy link
Contributor

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?

Copy link
Contributor Author

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
Copy link
Contributor

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)
Copy link
Contributor

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;
Copy link
Contributor

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()?

Copy link
Contributor

@dcapwell dcapwell left a 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?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants