feedback-to-code/mozzarella huggingface dataset:
Repository: netty/netty
Issue: "ByteBuf copiedBuffer(ByteBuffer buffer)" in Netty 4.0.24 is NOT thread safe
Labels: defect

I'm not sure why this static method is not thread safe, but it bothers me a lot during the development. As the following code shows, the method firstly copy the position out and then set it back after copying. If there are two threads doing the same thing, the position may be stained.

```
    public static ByteBuf copiedBuffer(ByteBuffer buffer) {
        int length = buffer.remaining();
        if (length == 0) {
            return EMPTY_BUFFER;
        }
        byte[] copy = new byte[length];
        int position = buffer.position();
        try {
            buffer.get(copy);
        } finally {
            buffer.position(position);
        }
        return wrappedBuffer(copy).order(buffer.order());
    }
```


Issue comments:
@sefler1987 I think you are right... We should call duplicate on the buffer first. Let me fix it

Thank you so much~

Fixed by https://github.com/netty/netty/pull/3930


Pull request review comments:

Patch that resolved the issue:
diff --git a/buffer/src/main/java/io/netty/buffer/Unpooled.java b/buffer/src/main/java/io/netty/buffer/Unpooled.java
index 0c071071cbc..742c17f49cb 100644
--- a/buffer/src/main/java/io/netty/buffer/Unpooled.java
+++ b/buffer/src/main/java/io/netty/buffer/Unpooled.java
@@ -392,13 +392,11 @@ public static ByteBuf copiedBuffer(ByteBuffer buffer) {
             return EMPTY_BUFFER;
         }
         byte[] copy = new byte[length];
-        int position = buffer.position();
-        try {
-            buffer.get(copy);
-        } finally {
-            buffer.position(position);
-        }
-        return wrappedBuffer(copy).order(buffer.order());
+        // Duplicate the buffer so we not adjust the position during our get operation.
+        // See https://github.com/netty/netty/issues/3896
+        ByteBuffer duplicate = buffer.duplicate();
+        duplicate.get(copy);
+        return wrappedBuffer(copy).order(duplicate.order());
     }
 
     /**
@@ -561,11 +559,11 @@ public static ByteBuf copiedBuffer(ByteBuffer... buffers) {
 
         byte[] mergedArray = new byte[length];
         for (int i = 0, j = 0; i < buffers.length; i ++) {
-            ByteBuffer b = buffers[i];
+            // Duplicate the buffer so we not adjust the position during our get operation.
+            // See https://github.com/netty/netty/issues/3896
+            ByteBuffer b = buffers[i].duplicate();
             int bLen = b.remaining();
-            int oldPos = b.position();
             b.get(mergedArray, j, bLen);
-            b.position(oldPos);
             j += bLen;
         }
 


Test patch:
Repository: netty/netty
Issue: Http2ConnectionHandler breaks channelReadComplete pipeline notification
Labels: defect

Netty Version: 5.0.0-Alpha3-SNAPSHOT

Hi guys,

`Http2ConnectionHandler` overrides `channelReadComplete(...)` [here](https://github.com/netty/netty/blob/master/codec-http2/src/main/java/io/netty/handler/codec/http2/Http2ConnectionHandler.java#L421) but fails to pass notification further down the pipeline by calling `super.channelReadComplete(...)` or `ctx.fireChannelReadComplete(...)`.  I assume it should call `super.channelReadComplete(...)`, what are your thoughts? 

/cc @Scottmitch @nmittler @louiscryan as you guys know more about this :)


Issue comments:
@blucas makes sense. We love PRs as you know ;)

+1 to PRs :)

Let me fix this.

Fixed by https://github.com/netty/netty/pull/3948


Pull request review comments:

Patch that resolved the issue:
diff --git a/codec-http2/src/main/java/io/netty/handler/codec/http2/Http2ConnectionHandler.java b/codec-http2/src/main/java/io/netty/handler/codec/http2/Http2ConnectionHandler.java
index 844cef3c5ba..36073ed1bcc 100644
--- a/codec-http2/src/main/java/io/netty/handler/codec/http2/Http2ConnectionHandler.java
+++ b/codec-http2/src/main/java/io/netty/handler/codec/http2/Http2ConnectionHandler.java
@@ -455,7 +455,11 @@ public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise)
     public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
         // Trigger flush after read on the assumption that flush is cheap if there is nothing to write and that
         // for flow-control the read may release window that causes data to be written that can now be flushed.
-        flush(ctx);
+        try {
+            flush(ctx);
+        } finally {
+            super.channelReadComplete(ctx);
+        }
     }
 
     /**


Test patch:
Repository: netty/netty
Issue: Documentation: wrong class mentioned in setter
Labels: documentation

{@link ByteBufAllocator} -> {@link MessageSizeEstimator} on
https://github.com/netty/netty/blob/4.0/transport/src/main/java/io/netty/channel/ChannelConfig.java#L248

this effects 4.0, 4.1, and master branches


Issue comments:
@justinjhendrick - Thanks for pointing this out.  Also feel free to submit a PR and get credit for fixing :)

@Scottmitch, I would but my company wants to review any open source before we contribute. So, something small like this wouldn't be worth the time necessary for a review.

No worries I will fix it

> Am 18.07.2015 um 00:07 schrieb Justin Hendrick notifications@github.com:
> 
> @Scottmitch, I would but my company wants to review any open source before we contribute. So, something small like this wouldn't be worth the time necessary for a review.
> 
> —
> Reply to this email directly or view it on GitHub.

Fixed by https://github.com/netty/netty/pull/4003


Pull request review comments:

Patch that resolved the issue:
diff --git a/transport/src/main/java/io/netty/channel/ChannelConfig.java b/transport/src/main/java/io/netty/channel/ChannelConfig.java
index b7ec03c45e1..7871285cd0c 100644
--- a/transport/src/main/java/io/netty/channel/ChannelConfig.java
+++ b/transport/src/main/java/io/netty/channel/ChannelConfig.java
@@ -245,7 +245,7 @@ public interface ChannelConfig {
     MessageSizeEstimator getMessageSizeEstimator();
 
     /**
-     * Set the {@link ByteBufAllocator} which is used for the channel
+     * Set the {@link MessageSizeEstimator} which is used for the channel
      * to detect the size of a message.
      */
     ChannelConfig setMessageSizeEstimator(MessageSizeEstimator estimator);


Test patch:
Repository: netty/netty
Issue: MemoryRegionCache$Entry objects are not recycled

Netty Version: 4.0.30.Final

MemoryRegionCache$Entry instances are allocated from a Recycler but not recycled when done using them, leading to a lot of GCed objects.


Issue comments:

Pull request review comments:

Patch that resolved the issue:
diff --git a/buffer/src/main/java/io/netty/buffer/PoolThreadCache.java b/buffer/src/main/java/io/netty/buffer/PoolThreadCache.java
index 3792c3e65ae..425f657ca96 100644
--- a/buffer/src/main/java/io/netty/buffer/PoolThreadCache.java
+++ b/buffer/src/main/java/io/netty/buffer/PoolThreadCache.java
@@ -386,7 +386,14 @@ protected abstract void initBuf(PoolChunk<T> chunk, long handle,
          */
         @SuppressWarnings("unchecked")
         public final boolean add(PoolChunk<T> chunk, long handle) {
-            return queue.offer(newEntry(chunk, handle));
+            Entry<T> entry = newEntry(chunk, handle);
+            boolean queued = queue.offer(entry);
+            if (!queued) {
+                // If it was not possible to cache the chunk, immediately recycle the entry
+                entry.recycle();
+            }
+
+            return queued;
         }
 
         /**
@@ -398,6 +405,7 @@ public final boolean allocate(PooledByteBuf<T> buf, int reqCapacity) {
                 return false;
             }
             initBuf(entry.chunk, entry.handle, buf, reqCapacity);
+            entry.recycle();
 
             // allocations is not thread-safe which is fine as this is only called from the same thread all time.
             ++ allocations;


Test patch:
Repository: netty/netty
Issue: PlatformDependent.throwException() with null argument takes down the JVM
Labels: defect

I'm not sure if it's a bug or feature but it's certainly not easy to debug.

Netty 4.1.0-Beta6-SNAPSHOT

```
#
# A fatal error has been detected by the Java Runtime Environment:
#
#  SIGSEGV (0xb) at pc=0x00007f80fbe956c9, pid=1196, tid=140191066928896
#
# JRE version: Java(TM) SE Runtime Environment (8.0_40-b25) (build 1.8.0_40-b25)
# Java VM: Java HotSpot(TM) 64-Bit Server VM (25.40-b25 mixed mode linux-amd64 compressed oops)
# Problematic frame:
# V  [libjvm.so+0x5756c9]  Exceptions::_throw(Thread*, char const*, int, Handle, char const*)+0x1d9
#
# Failed to write core dump. Core dumps have been disabled. To enable core dumping, try "ulimit -c unlimited" before starting Java again
#
# An error report file with more information is saved as:
# /<path>/hs_err_pid1196.log
#
# If you would like to submit a bug report, please visit:
#   http://bugreport.sun.com/bugreport/
#
```


Issue comments:
@rkapsi - Is `PlatformDependent.throwException(null)` called from Netty code, and if so do you know where from?

@Scottmitch no, not from Netty code. It was some code I wrote and one can argue it was my own fault (given the nature of that class) but I wish it'd have failed more gracefully.

@rkapsi - Humm I guess at least in the case of unsafe we should ensure the language specification is honored:

http://docs.oracle.com/javase/specs/jls/se8/html/jls-14.html#jls-14.18

>  If evaluation of the Expression completes normally, producing a null value, then an instance V' of class NullPointerException is created and thrown instead of null. The throw statement then completes abruptly, the reason being a throw with value V'.

@trustin @normanmaurer - WDYT?

I have a PR pending for this.

+1. Thanks for taking care.


Pull request review comments:
Maybe renaming t to cause might make the exception message more sense?

Will do.


Patch that resolved the issue:
diff --git a/common/src/main/java/io/netty/util/internal/PlatformDependent0.java b/common/src/main/java/io/netty/util/internal/PlatformDependent0.java
index e72627a18d3..ef9e3b09186 100644
--- a/common/src/main/java/io/netty/util/internal/PlatformDependent0.java
+++ b/common/src/main/java/io/netty/util/internal/PlatformDependent0.java
@@ -30,6 +30,8 @@
 import java.util.concurrent.atomic.AtomicLongFieldUpdater;
 import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
 
+import static io.netty.util.internal.ObjectUtil.checkNotNull;
+
 /**
  * The {@link PlatformDependent} operations which requires access to {@code sun.misc.*}.
  */
@@ -137,8 +139,9 @@ static boolean hasUnsafe() {
         return UNSAFE != null;
     }
 
-    static void throwException(Throwable t) {
-        UNSAFE.throwException(t);
+    static void throwException(Throwable cause) {
+        // JVM has been observed to crash when passing a null argument. See https://github.com/netty/netty/issues/4131.
+        UNSAFE.throwException(checkNotNull(cause, "cause"));
     }
 
     static void freeDirectBuffer(ByteBuffer buffer) {


Test patch:
Repository: netty/netty
Issue: Build fails on OSX

just wanted to build Netty master (mvn clean install) on a clean machine and building `microbench` fails

```
Failed to execute goal on project netty-microbench: 
Could not resolve dependencies for project io.netty:netty-microbench:jar:5.0.0.Alpha3-SNAPSHOT:
Failure to find io.netty:netty-transport-native-epoll:jar:osx-x86_64:5.0.0.Alpha3-SNAPSHOT
```

I am running on El Capitan, Java 1.8u60 and Maven 3.3.3. 

I am not familiar enough with Maven to fix this quickly, but can look into it if none if you know of a quick resolution either. 


Issue comments:
I guess all the native transport related stuff should only be built/triggered when a Linux only maven profile is enabled.

yes, that's also how the pom file seems to be set up, but idk how this "conditional dependency" stuff works in maven.

aww i think I have a fix.

@buchgr @normanmaurer CI build was successful and I just squashed the 2 commits.

Fixed


Pull request review comments:
this is just cause I also got warnings, that referring to props without a `project` prefix is deprecated.


Patch that resolved the issue:
diff --git a/microbench/pom.xml b/microbench/pom.xml
index f9946800489..087f99b0685 100644
--- a/microbench/pom.xml
+++ b/microbench/pom.xml
@@ -68,7 +68,6 @@
       <groupId>${project.groupId}</groupId>
       <artifactId>netty-transport-native-epoll</artifactId>
       <version>${project.version}</version>
-      <classifier>${epoll.classifier}</classifier>
     </dependency>
     <dependency>
       <groupId>junit</groupId>
diff --git a/pom.xml b/pom.xml
index 222128a3fcb..fb67986e9e5 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1196,11 +1196,11 @@
           <archive>
             <manifestEntries>
               <Bundle-ManifestVersion>2</Bundle-ManifestVersion>
-              <Bundle-Name>${name}</Bundle-Name>
-              <Bundle-SymbolicName>${groupId}.${artifactId}.source</Bundle-SymbolicName>
-              <Bundle-Vendor>${organization.name}</Bundle-Vendor>
+              <Bundle-Name>${project.name}</Bundle-Name>
+              <Bundle-SymbolicName>${project.groupId}.${project.artifactId}.source</Bundle-SymbolicName>
+              <Bundle-Vendor>${project.organization.name}</Bundle-Vendor>
               <Bundle-Version>${parsedVersion.osgiVersion}</Bundle-Version>
-              <Eclipse-SourceBundle>${groupId}.${artifactId};version="${parsedVersion.osgiVersion}";roots:="."</Eclipse-SourceBundle>
+              <Eclipse-SourceBundle>${project.groupId}.${project.artifactId};version="${parsedVersion.osgiVersion}";roots:="."</Eclipse-SourceBundle>
             </manifestEntries>
           </archive>
         </configuration>


Test patch:
Repository: netty/netty
Issue: DefaultHttp2Headers has memory leak when being cleared

When calling DefaultHttp2Headers.clear the firstNonPseudoHeaders reference holds onto data that has just been cleared


Issue comments:
@louiscryan can be closed ?

@louiscryan - Thanks for the fix!


Pull request review comments:

Patch that resolved the issue:
diff --git a/codec-http2/src/main/java/io/netty/handler/codec/http2/DefaultHttp2Headers.java b/codec-http2/src/main/java/io/netty/handler/codec/http2/DefaultHttp2Headers.java
index 7a4bfe60435..69b1e17e079 100644
--- a/codec-http2/src/main/java/io/netty/handler/codec/http2/DefaultHttp2Headers.java
+++ b/codec-http2/src/main/java/io/netty/handler/codec/http2/DefaultHttp2Headers.java
@@ -90,6 +90,12 @@ public DefaultHttp2Headers(boolean validate) {
               validate ? HTTP2_NAME_VALIDATOR : NameValidator.NOT_NULL);
     }
 
+    @Override
+    public Http2Headers clear() {
+        this.firstNonPseudo = head;
+        return super.clear();
+    }
+
     @Override
     public Http2Headers method(CharSequence value) {
         set(PseudoHeaderName.METHOD.value(), value);


Test patch:
diff --git a/codec-http2/src/test/java/io/netty/handler/codec/http2/DefaultHttp2HeadersTest.java b/codec-http2/src/test/java/io/netty/handler/codec/http2/DefaultHttp2HeadersTest.java
index 5885ea153ce..eb187c9d4ad 100644
--- a/codec-http2/src/test/java/io/netty/handler/codec/http2/DefaultHttp2HeadersTest.java
+++ b/codec-http2/src/test/java/io/netty/handler/codec/http2/DefaultHttp2HeadersTest.java
@@ -22,6 +22,7 @@
 
 import java.util.Map.Entry;
 
+import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
@@ -74,6 +75,16 @@ public void testHeaderNameValidation() {
         headers.add(of("Foo"), of("foo"));
     }
 
+    @Test
+    public void testClearResetsPseudoHeaderDivision() {
+        DefaultHttp2Headers http2Headers = new DefaultHttp2Headers();
+        http2Headers.method("POST");
+        http2Headers.set("some", "value");
+        http2Headers.clear();
+        http2Headers.method("GET");
+        assertEquals(1, http2Headers.names().size());
+    }
+
     private static void verifyAllPseudoHeadersPresent(Http2Headers headers) {
         for (PseudoHeaderName pseudoName : PseudoHeaderName.values()) {
             assertNotNull(headers.get(pseudoName.value()));
Repository: netty/netty
Issue: Headers.set(self) and Headers.setAll(self) are inconsistent

The former will throw, the latter is a no-op.


Issue comments:
@louiscryan I think this can be closed ?

@louiscryan - thanks!


Pull request review comments:

Patch that resolved the issue:
diff --git a/codec/src/main/java/io/netty/handler/codec/DefaultHeaders.java b/codec/src/main/java/io/netty/handler/codec/DefaultHeaders.java
index 995a9268144..ead9f0a5562 100644
--- a/codec/src/main/java/io/netty/handler/codec/DefaultHeaders.java
+++ b/codec/src/main/java/io/netty/handler/codec/DefaultHeaders.java
@@ -539,7 +539,7 @@ public T setShort(K name, short value) {
     public T set(Headers<? extends K, ? extends V, ?> headers) {
         checkNotNull(headers, "headers");
         if (headers == this) {
-            throw new IllegalArgumentException("can't add to itself.");
+            return thisT();
         }
         clear();
         if (headers instanceof DefaultHeaders) {


Test patch:
diff --git a/codec-http/src/test/java/io/netty/handler/codec/http/HttpHeadersTest.java b/codec-http/src/test/java/io/netty/handler/codec/http/HttpHeadersTest.java
index bfd93b5143d..a4ab3eb3335 100644
--- a/codec-http/src/test/java/io/netty/handler/codec/http/HttpHeadersTest.java
+++ b/codec-http/src/test/java/io/netty/handler/codec/http/HttpHeadersTest.java
@@ -76,9 +76,11 @@ public void testAddSelf() {
         headers.add(headers);
     }
 
-    @Test(expected = IllegalArgumentException.class)
-    public void testSetSelf() {
+    @Test
+    public void testSetSelfIsNoOp() {
         HttpHeaders headers = new DefaultHttpHeaders(false);
+        headers.add("name", "value");
         headers.set(headers);
+        assertEquals(1, headers.size());
     }
 }
diff --git a/codec/src/test/java/io/netty/handler/codec/DefaultHeadersTest.java b/codec/src/test/java/io/netty/handler/codec/DefaultHeadersTest.java
index 5f8472c3854..ceee0b80be6 100644
--- a/codec/src/test/java/io/netty/handler/codec/DefaultHeadersTest.java
+++ b/codec/src/test/java/io/netty/handler/codec/DefaultHeadersTest.java
@@ -390,9 +390,11 @@ public void testAddSelf() {
         headers.add(headers);
     }
 
-    @Test(expected = IllegalArgumentException.class)
-    public void testSetSelf() {
+    @Test
+    public void testSetSelfIsNoOp() {
         TestDefaultHeaders headers = newInstance();
+        headers.add("name", "value");
         headers.set(headers);
+        assertEquals(1, headers.size());
     }
 }
Repository: netty/netty
Issue: AsciiString.contentEqualsIgnoreCase does not work correctly for AsciiString comparison
Labels: defect

Netty Version: master (6c0fef133baa4afce11953110a6947732d87ec8e)

`AsciiString.contentEqualsIgnoreCase` fails when checking for equality between two `AsciiString` objects. For example 

``` java
// returns true, should return false 
new AsciiString("foo").contentEqualsIgnoreCase(new AsciiString("bar"));
```

The issue is due to [the following line](https://github.com/netty/netty/blob/master/common/src/main/java/io/netty/util/AsciiString.java#L533)

I think I've tracked this down to the following commit: https://github.com/netty/netty/commit/ba6ce5449ee852b782dde9a11933f6a09b123e22

Pull request to follow


Issue comments:
Fixed by https://github.com/netty/netty/pull/4565


Pull request review comments:

Patch that resolved the issue:
diff --git a/common/src/main/java/io/netty/util/AsciiString.java b/common/src/main/java/io/netty/util/AsciiString.java
index ceb5bf0ca59..8baf6851c4a 100644
--- a/common/src/main/java/io/netty/util/AsciiString.java
+++ b/common/src/main/java/io/netty/util/AsciiString.java
@@ -530,7 +530,7 @@ public boolean contentEqualsIgnoreCase(CharSequence string) {
         if (string.getClass() == AsciiString.class) {
             AsciiString rhs = (AsciiString) string;
             for (int i = arrayOffset(), j = rhs.arrayOffset(); i < length(); ++i, ++j) {
-                if (!equalsIgnoreCase(value[i], value[j])) {
+                if (!equalsIgnoreCase(value[i], rhs.value[j])) {
                     return false;
                 }
             }


Test patch:
diff --git a/common/src/test/java/io/netty/util/AsciiStringCharacterTest.java b/common/src/test/java/io/netty/util/AsciiStringCharacterTest.java
index cbec28140d3..08f2bab2c21 100644
--- a/common/src/test/java/io/netty/util/AsciiStringCharacterTest.java
+++ b/common/src/test/java/io/netty/util/AsciiStringCharacterTest.java
@@ -240,6 +240,16 @@ public void testEqualsIgnoreCase() {
         assertThat(AsciiString.contentEqualsIgnoreCase(null, "foo"), is(false));
         assertThat(AsciiString.contentEqualsIgnoreCase("bar", null), is(false));
         assertThat(AsciiString.contentEqualsIgnoreCase("FoO", "fOo"), is(true));
+
+        // Test variations (Ascii + String, Ascii + Ascii, String + Ascii)
+        assertThat(AsciiString.contentEqualsIgnoreCase(new AsciiString("FoO"), "fOo"), is(true));
+        assertThat(AsciiString.contentEqualsIgnoreCase(new AsciiString("FoO"), new AsciiString("fOo")), is(true));
+        assertThat(AsciiString.contentEqualsIgnoreCase("FoO", new AsciiString("fOo")), is(true));
+
+        // Test variations (Ascii + String, Ascii + Ascii, String + Ascii)
+        assertThat(AsciiString.contentEqualsIgnoreCase(new AsciiString("FoO"), "bAr"), is(false));
+        assertThat(AsciiString.contentEqualsIgnoreCase(new AsciiString("FoO"), new AsciiString("bAr")), is(false));
+        assertThat(AsciiString.contentEqualsIgnoreCase("FoO", new AsciiString("bAr")), is(false));
     }
 
     @Test
Repository: netty/netty
Issue: Javadoc Fail: ChannelOutboundHandlerAdapter - deregister (4.1)

The description of the method `deregister` in the class ChannelOutboundHandlerAdapter says:

> Calls **ChannelHandlerContext.close(ChannelPromise)** to forward to the next ChannelOutboundHandler in the ChannelPipeline. Sub-classes may override this method to change behavior.

Should it not be the following?

> Calls **ChannelHandlerContext.deregister(ChannelPromise)** to forward to the next ChannelOutboundHandler in the ChannelPipeline. Sub-classes may override this method to change behavior.

Greetings from Germany,
mike


Issue comments:

Pull request review comments:

Patch that resolved the issue:
diff --git a/transport/src/main/java/io/netty/channel/ChannelOutboundHandlerAdapter.java b/transport/src/main/java/io/netty/channel/ChannelOutboundHandlerAdapter.java
index c0a68971237..fa968925de9 100644
--- a/transport/src/main/java/io/netty/channel/ChannelOutboundHandlerAdapter.java
+++ b/transport/src/main/java/io/netty/channel/ChannelOutboundHandlerAdapter.java
@@ -18,7 +18,7 @@
 import java.net.SocketAddress;
 
 /**
- * Skelton implementation of a {@link ChannelOutboundHandler}. This implementation just forwards each method call via
+ * Skeleton implementation of a {@link ChannelOutboundHandler}. This implementation just forwards each method call via
  * the {@link ChannelHandlerContext}.
  */
 public class ChannelOutboundHandlerAdapter extends ChannelHandlerAdapter implements ChannelOutboundHandler {
@@ -72,7 +72,7 @@ public void close(ChannelHandlerContext ctx, ChannelPromise promise)
     }
 
     /**
-     * Calls {@link ChannelHandlerContext#close(ChannelPromise)} to forward
+     * Calls {@link ChannelHandlerContext#deregister(ChannelPromise)} to forward
      * to the next {@link ChannelOutboundHandler} in the {@link ChannelPipeline}.
      *
      * Sub-classes may override this method to change behavior.
@@ -94,7 +94,7 @@ public void read(ChannelHandlerContext ctx) throws Exception {
     }
 
     /**
-     * Calls {@link ChannelHandlerContext#write(Object)} to forward
+     * Calls {@link ChannelHandlerContext#write(Object, ChannelPromise)} to forward
      * to the next {@link ChannelOutboundHandler} in the {@link ChannelPipeline}.
      *
      * Sub-classes may override this method to change behavior.


Test patch: