From 1440435865aa86a350094881b31005cb232424fc Mon Sep 17 00:00:00 2001 From: Chris Vest Date: Fri, 9 Sep 2022 15:14:40 -0700 Subject: [PATCH] Fix bug in forEachByte on nested composite bytebuf with leak detection (#12790) Motivation: An NPE could occur when forEachByte was called on nested leak-aware composite byte buffers. Modification: WrappedCompositeByteBuf extends CompositeByteBuf but must delegate all calls to the wrapped instance. Add delegation calls for forEachByteAsc0 and forEachByteDesc0. Without delegation, those calls would, from an outer composite buffer, go to the composite structure of the wrapper buffer, which have no components. Result: No more NPE when calling forEachByte on nested composite leak-aware buffers. Fixes #12787 --- .../netty/buffer/WrappedCompositeByteBuf.java | 10 ++++++ .../buffer/AbstractCompositeByteBufTest.java | 33 +++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/buffer/src/main/java/io/netty/buffer/WrappedCompositeByteBuf.java b/buffer/src/main/java/io/netty/buffer/WrappedCompositeByteBuf.java index faef8f88b2a..5a31a5e9b40 100644 --- a/buffer/src/main/java/io/netty/buffer/WrappedCompositeByteBuf.java +++ b/buffer/src/main/java/io/netty/buffer/WrappedCompositeByteBuf.java @@ -408,6 +408,16 @@ public int forEachByteDesc(int index, int length, ByteProcessor processor) { return wrapped.forEachByteDesc(index, length, processor); } + @Override + protected int forEachByteAsc0(int start, int end, ByteProcessor processor) throws Exception { + return wrapped.forEachByteAsc0(start, end, processor); + } + + @Override + protected int forEachByteDesc0(int rStart, int rEnd, ByteProcessor processor) throws Exception { + return wrapped.forEachByteDesc0(rStart, rEnd, processor); + } + @Override public final int hashCode() { return wrapped.hashCode(); diff --git a/buffer/src/test/java/io/netty/buffer/AbstractCompositeByteBufTest.java b/buffer/src/test/java/io/netty/buffer/AbstractCompositeByteBufTest.java index 20567176158..4bb21b15b19 100644 --- a/buffer/src/test/java/io/netty/buffer/AbstractCompositeByteBufTest.java +++ b/buffer/src/test/java/io/netty/buffer/AbstractCompositeByteBufTest.java @@ -15,6 +15,7 @@ */ package io.netty.buffer; +import io.netty.util.ByteProcessor; import io.netty.util.ReferenceCountUtil; import io.netty.util.internal.ObjectUtil; import io.netty.util.internal.PlatformDependent; @@ -1774,4 +1775,36 @@ public void sliceOfCompositeBufferMustThrowISEAfterDiscardBytes() { composite.release(); } } + + @Test + public void forEachByteOnNestedCompositeByteBufMustSeeEntireFlattenedContents() { + CompositeByteBuf buf = newCompositeBuffer(); + buf.addComponent(true, newCompositeBuffer().addComponents( + true, + wrappedBuffer(new byte[] {1, 2, 3}), + wrappedBuffer(new byte[] {4, 5, 6}))); + final byte[] arrayAsc = new byte[6]; + final byte[] arrayDesc = new byte[6]; + buf.forEachByte(new ByteProcessor() { + int index; + + @Override + public boolean process(byte value) throws Exception { + arrayAsc[index++] = value; + return true; + } + }); + buf.forEachByteDesc(new ByteProcessor() { + int index; + + @Override + public boolean process(byte value) throws Exception { + arrayDesc[index++] = value; + return true; + } + }); + assertArrayEquals(new byte[] {1, 2, 3, 4, 5, 6}, arrayAsc); + assertArrayEquals(new byte[] {6, 5, 4, 3, 2, 1}, arrayDesc); + buf.release(); + } }