diff --git a/buffer/src/main/java/io/netty/buffer/CompositeByteBuf.java b/buffer/src/main/java/io/netty/buffer/CompositeByteBuf.java index 32c712be17..d459890409 100644 --- a/buffer/src/main/java/io/netty/buffer/CompositeByteBuf.java +++ b/buffer/src/main/java/io/netty/buffer/CompositeByteBuf.java @@ -1605,8 +1605,7 @@ public class CompositeByteBuf extends AbstractReferenceCountedByteBuf implements case 0: return EMPTY_NIO_BUFFER; case 1: - Component c = components[0]; - return c.buf.internalNioBuffer(c.idx(index), length); + return components[0].internalNioBuffer(index, length); default: throw new UnsupportedOperationException(); } @@ -1884,6 +1883,16 @@ public class CompositeByteBuf extends AbstractReferenceCountedByteBuf implements return buf.duplicate().setIndex(idx(offset), idx(endOffset)); } + ByteBuffer internalNioBuffer(int index, int length) { + // We must not return the unwrapped buffer's internal buffer + // if it was originally added as a slice - this check of the + // slice field is threadsafe since we only care whether it + // was set upon Component construction, and we aren't + // attempting to access the referenced slice itself + return slice != null ? buf.nioBuffer(idx(index), length) + : buf.internalNioBuffer(idx(index), length); + } + void free() { // Release the slice if present since it may have a different // refcount to the unwrapped buf if it is a PooledSlicedByteBuf diff --git a/buffer/src/test/java/io/netty/buffer/AbstractCompositeByteBufTest.java b/buffer/src/test/java/io/netty/buffer/AbstractCompositeByteBufTest.java index 13cd6163ca..8fa6687791 100644 --- a/buffer/src/test/java/io/netty/buffer/AbstractCompositeByteBufTest.java +++ b/buffer/src/test/java/io/netty/buffer/AbstractCompositeByteBufTest.java @@ -967,7 +967,27 @@ public abstract class AbstractCompositeByteBufTest extends AbstractByteBufTest { @Override @Test public void testInternalNioBuffer() { - // ignore + CompositeByteBuf buf = compositeBuffer(); + assertEquals(0, buf.internalNioBuffer(0, 0).remaining()); + + // If non-derived buffer is added, its internal buffer should be returned + ByteBuf concreteBuffer = directBuffer().writeByte(1); + buf.addComponent(concreteBuffer); + assertSame(concreteBuffer.internalNioBuffer(0, 1), buf.internalNioBuffer(0, 1)); + buf.release(); + + // In derived cases, the original internal buffer must not be used + buf = compositeBuffer(); + concreteBuffer = directBuffer().writeByte(1); + buf.addComponent(concreteBuffer.slice()); + assertNotSame(concreteBuffer.internalNioBuffer(0, 1), buf.internalNioBuffer(0, 1)); + buf.release(); + + buf = compositeBuffer(); + concreteBuffer = directBuffer().writeByte(1); + buf.addComponent(concreteBuffer.duplicate()); + assertNotSame(concreteBuffer.internalNioBuffer(0, 1), buf.internalNioBuffer(0, 1)); + buf.release(); } @Test