Repository: netty/netty
Issue: NPE with Paranoid leak detector and using a ByteProcessor on a CompositeBuffer of CompositeBuffer

### Expected behavior

No exception

### Actual behavior

Getting a NullPointerException

```
Caused by: java.lang.NullPointerException
    at io.netty.buffer.CompositeByteBuf.toComponentIndex0(CompositeByteBuf.java:930)
    at io.netty.buffer.CompositeByteBuf.forEachByteAsc0(CompositeByteBuf.java:672)
    at io.netty.buffer.CompositeByteBuf.forEachByteAsc0(CompositeByteBuf.java:682)
    at io.netty.buffer.AbstractByteBuf.forEachByte(AbstractByteBuf.java:1281)
    at io.netty.buffer.WrappedCompositeByteBuf.forEachByte(WrappedCompositeByteBuf.java:393)
    at io.netty.buffer.AdvancedLeakAwareCompositeByteBuf.forEachByte(AdvancedLeakAwareCompositeByteBuf.java:657)
```

### Steps to reproduce

* set ResourceLeakDetector in Paranoid mode
* create a CompositeBuffer of CompositeBuffer of Buffers
* run a ByteProcessor on the ByteBuf

### Minimal yet complete reproducer code (or URL to code)

[netty-paranoid-leak.zip](https://github.com/netty/netty/files/9535586/netty-paranoid-leak.zip)

### Netty version

4.1.81.Final

### JVM version (e.g. `java -version`)

11.0.16

### OS version (e.g. `uname -a`)

Ubuntu 20.04.5 LTS

Issue comments:
Thanks for the report.

Pull request review comments:

Patch that resolved the issue:
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();


Test patch:
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();
+    }
 }