Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -56,18 +56,28 @@ public InPacketHandler(PacketListener packetListener, PacketDecoder decoder, Nam
}

@Override
protected void channelRead0(io.netty.channel.ChannelHandlerContext ctx, PacketsMessage message)
protected void channelRead0(ChannelHandlerContext ctx, PacketsMessage message)
throws Exception {
ByteBuf content = message.getContent();
ClientHead client = message.getClient();

if (content.refCnt() <= 0) {
return;
}

String debugData = null;

if (log.isTraceEnabled()) {
log.trace("In message: {} sessionId: {}", content.toString(CharsetUtil.UTF_8), client.getSessionId());
debugData = content.toString(CharsetUtil.UTF_8);
log.trace("In message: {} sessionId: {}", debugData, client.getSessionId());
}

int packetsProcessed = 0;
while (content.isReadable()) {
try {
if (content.refCnt() <= 0) {
break;
}
Comment on lines 76 to +80
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Verify current loop condition and nearby refCnt checks in InPacketHandler
rg -n -C3 'while\s*\(\s*content\.isReadable\(\)\s*\)|content\.refCnt\(\)\s*<=\s*0' \
  netty-socketio-core/src/main/java/com/socketio4j/socketio/handler/InPacketHandler.java

Repository: socketio4j/netty-socketio

Length of output: 557


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Get broader context of the method containing this code
rg -n -B20 'while\s*\(\s*content\.isReadable\(\)' \
  netty-socketio-core/src/main/java/com/socketio4j/socketio/handler/InPacketHandler.java | head -50

# Check method signature and any synchronization
rg -n 'public|private|protected|synchronized' \
  netty-socketio-core/src/main/java/com/socketio4j/socketio/handler/InPacketHandler.java | head -20

Repository: socketio4j/netty-socketio

Length of output: 1572


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Check if there's a lock or synchronization mechanism
rg -n 'synchronized|Lock|Mutex|ReentrantLock' \
  netty-socketio-core/src/main/java/com/socketio4j/socketio/handler/InPacketHandler.java

# Check for any documented thread-safety guarantees in the class
rg -n '@ThreadSafe|@NotThreadSafe|thread.safe|Thread.safe' \
  netty-socketio-core/src/main/java/com/socketio4j/socketio/handler/InPacketHandler.java

Repository: socketio4j/netty-socketio

Length of output: 51


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Check how PacketsMessage is created and if there's buffer retention
rg -n 'class PacketsMessage|new PacketsMessage' \
  netty-socketio-core/src/main/java/com/socketio4j/socketio/ -A5 | head -40

# Check if content/buffer is passed to async operations
rg -n 'executor|thread|async|Future|CompletableFuture' \
  netty-socketio-core/src/main/java/com/socketio4j/socketio/handler/InPacketHandler.java

Repository: socketio4j/netty-socketio

Length of output: 2543


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Check the broader decoding process and if it might release buffer
rg -n 'decoder\.decodePackets' \
  netty-socketio-core/src/main/java/com/socketio4j/socketio/handler/InPacketHandler.java -A2 -B2

# Check if packetListener or any callback might cause async operations
rg -n 'packetListener\.' \
  netty-socketio-core/src/main/java/com/socketio4j/socketio/handler/InPacketHandler.java -A2

Repository: socketio4j/netty-socketio

Length of output: 469


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Check PacketsMessage implementation for buffer retention
rg -n -A15 'public class PacketsMessage' \
  netty-socketio-core/src/main/java/com/socketio4j/socketio/messages/PacketsMessage.java

# Check if there's any retain/release in PacketsMessage
rg -n 'retain|release' \
  netty-socketio-core/src/main/java/com/socketio4j/socketio/messages/PacketsMessage.java

Repository: socketio4j/netty-socketio

Length of output: 520


🏁 Script executed:

#!/bin/bash
set -euo profiling

# Check the full channelRead0 method for try-finally or cleanup
rg -n -A50 'protected void channelRead0' \
  netty-socketio-core/src/main/java/com/socketio4j/socketio/handler/InPacketHandler.java | head -80

# Check if decoder.decodePackets has any async or yielding behavior
fd 'PacketDecoder' netty-socketio-core/src/main/java/ -type f

Repository: socketio4j/netty-socketio

Length of output: 123


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Check the full channelRead0 method for try-finally or cleanup
rg -n -A80 'protected void channelRead0' \
  netty-socketio-core/src/main/java/com/socketio4j/socketio/handler/InPacketHandler.java

# Check if decoder.decodePackets has any async or yielding behavior
fd 'PacketDecoder' netty-socketio-core/src/main/java/ -type f

Repository: socketio4j/netty-socketio

Length of output: 4572


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Double-check if there's a finally block or any cleanup after the while loop
rg -n -A150 'protected void channelRead0' \
  netty-socketio-core/src/main/java/com/socketio4j/socketio/handler/InPacketHandler.java | tail -80

Repository: socketio4j/netty-socketio

Length of output: 4022


Move the refCnt() check into the while loop condition to prevent dereferencing a released buffer.

Line 76 evaluates content.isReadable() before the refCnt guard executes at line 78. Between loop iterations, if the buffer is released externally, isReadable() will dereference a released ByteBuf. The early guard at line 64 only protects the initial state, not subsequent iterations. The suggested fix correctly addresses this by checking refCnt() > 0 in the while condition itself.

Suggested fix
-        while (content.isReadable()) {
+        while (content.refCnt() > 0 && content.isReadable()) {
             try {
-                if (content.refCnt() <= 0) {
-                    break;
-                }
                 Packet packet = decoder.decodePackets(content, client);
                 packetsProcessed++;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@netty-socketio-core/src/main/java/com/socketio4j/socketio/handler/InPacketHandler.java`
around lines 76 - 80, In InPacketHandler (inside the loop that iterates over the
ByteBuf named content) move the refCnt() guard into the loop condition so you
check content.refCnt() > 0 before calling content.isReadable(); specifically
replace the current while (content.isReadable()) { ... if (content.refCnt() <=
0) break; } pattern with a combined condition (e.g., while (content != null &&
content.refCnt() > 0 && content.isReadable()) ) to avoid dereferencing a
released ByteBuf between iterations and keep the existing early-return/cleanup
behavior intact.

Packet packet = decoder.decodePackets(content, client);
packetsProcessed++;

Expand Down Expand Up @@ -128,8 +138,8 @@ protected void channelRead0(io.netty.channel.ChannelHandlerContext ctx, PacketsM
client.getSessionId(), ns.getName());
}
} catch (Exception ex) {
String c = content.toString(CharsetUtil.UTF_8);
log.error("Error during data processing. Client sessionId: {}, data: {}", client.getSessionId(), c, ex);
log.error("Error during data processing. Client sessionId: {}, data: {}",
client.getSessionId(), (debugData != null ? debugData : "NULL"), ex);
throw ex;
}
}
Expand Down
Loading