@xiaoheng1 good point... are you willing to open a PR ? @normanmaurer I am glad to，i will open a PR. #9306 Fix public int read() throws IOException method exceeds the limit of length
nit: merge both lines  Call buf.release() and in.close() Call buf2.release() and in2.close() @normanmaurer ok, i add it.
ByteBufInputStream.read() may have a problem
i use netty4.1.34

souce code:

```
public int read() throws IOException {
        if (!buffer.isReadable()) {
            return -1;
        }
        return buffer.readByte() & 0xff;
    }
```
In my opinion, the buffer.isReadable() method should not be used here to judge, but the available() method should be used. Because ByteBufInputStream is passed in length when constructing, so if the buffer.isReadable() method is used here If judged, it may exceed the limit of length, which is unreasonable.
buffer/src/main/java/io/netty/buffer/ByteBufInputStream.java
buffer/src/main/java/io/netty/buffer/ByteBufInputStream.java
buffer/src/test/java/io/netty/buffer/ByteBufStreamTest.java
diff --git a/buffer/src/main/java/io/netty/buffer/ByteBufInputStream.java b/buffer/src/main/java/io/netty/buffer/ByteBufInputStream.java
index 038cd8db459..c0b116c1483 100644
--- a/buffer/src/main/java/io/netty/buffer/ByteBufInputStream.java
+++ b/buffer/src/main/java/io/netty/buffer/ByteBufInputStream.java
@@ -163,7 +163,8 @@ public boolean markSupported() {
 
     @Override
     public int read() throws IOException {
-        if (!buffer.isReadable()) {
+        int available = available();
+        if (available == 0) {
             return -1;
         }
         return buffer.readByte() & 0xff;

diff --git a/buffer/src/test/java/io/netty/buffer/ByteBufStreamTest.java b/buffer/src/test/java/io/netty/buffer/ByteBufStreamTest.java
index 222ddcf7ee7..989e160b22a 100644
--- a/buffer/src/test/java/io/netty/buffer/ByteBufStreamTest.java
+++ b/buffer/src/test/java/io/netty/buffer/ByteBufStreamTest.java
@@ -212,4 +212,39 @@ public void testReadLine() throws Exception {
         assertEquals(charCount, count);
         in.close();
     }
+
+    @Test
+    public void testRead() throws Exception {
+        // case1
+        ByteBuf buf = Unpooled.buffer(16);
+        buf.writeBytes(new byte[]{1, 2, 3, 4, 5, 6});
+
+        ByteBufInputStream in = new ByteBufInputStream(buf, 3);
+
+        assertEquals(1, in.read());
+        assertEquals(2, in.read());
+        assertEquals(3, in.read());
+        assertEquals(-1, in.read());
+        assertEquals(-1, in.read());
+        assertEquals(-1, in.read());
+
+        buf.release();
+        in.close();
+
+        // case2
+        ByteBuf buf2 = Unpooled.buffer(16);
+        buf2.writeBytes(new byte[]{1, 2, 3, 4, 5, 6});
+
+        ByteBufInputStream in2 = new ByteBufInputStream(buf2, 4);
+
+        assertEquals(1, in2.read());
+        assertEquals(2, in2.read());
+        assertEquals(3, in2.read());
+        assertEquals(4, in2.read());
+        assertNotEquals(5, in2.read());
+        assertEquals(-1, in2.read());
+
+        buf2.release();
+        in2.close();
+    }
 }
