Fix IndexOutOfBoundsException in StompSubframeDecoder on heartbeat#16539
Merged
Conversation
normanmaurer
approved these changes
Mar 25, 2026
Member
|
@daguimu did you sign our ICLA yet ? https://netty.io/s/icla |
Contributor
Author
Yes, I just signed it! 😊 |
… heartbeat frames StompSubframeDecoder.skipControlCharacters() reads bytes in a loop without checking if the buffer has readable bytes remaining. When a STOMP heartbeat (just a LF byte) arrives, the method consumes the control character and then attempts to read beyond the buffer, causing an IndexOutOfBoundsException. Add a buffer.isReadable() check before each readByte() call so that heartbeat-only data is handled gracefully without throwing. Fixes netty#10678
730f619 to
4cdc3d8
Compare
Contributor
Author
|
I've rebased onto the latest 4.1. This PR is ready for merge. Thanks for the review! |
Member
|
@daguimu thanks a lot. |
netty-project-bot
pushed a commit
that referenced
this pull request
Mar 25, 2026
…16539) ## Problem `StompSubframeDecoder.skipControlCharacters()` reads bytes in an infinite loop without checking if the buffer has readable bytes remaining. When a STOMP heartbeat frame (just a LF byte) arrives, the method consumes the control character and then attempts to read beyond the buffer, causing an IndexOutOfBoundsException. ## Root Cause The `skipControlCharacters` method has an unconditional `buffer.readByte()` call inside a `for (;;)` loop with no `buffer.isReadable()` guard. When the buffer contains only control characters (heartbeat), all bytes are consumed and the next `readByte()` fails. ## Fix Add a `buffer.isReadable()` check before each `readByte()` call. When the buffer is exhausted (heartbeat-only data), the method returns gracefully and the decoder waits for more data. ## Tests Added - `testHeartbeatOnlyDoesNotThrowException` - Single LF heartbeat byte does not cause exception - `testMultipleHeartbeatsDoNotThrowException` - Multiple consecutive LF bytes handled correctly - `testCarriageReturnLineFeedHeartbeat` - CR+LF heartbeat handled correctly - `testHeartbeatFollowedByFrame` - Heartbeat before a real STOMP frame, frame decodes correctly - `testHeartbeatBetweenFrames` - Heartbeat between two frames, both decode correctly - `testHeartbeatSentSeparatelyThenFrame` - Heartbeat in separate write, then frame in second write ## Impact Minimal - only adds a single `isReadable()` guard. No behavioral change for normal STOMP frames. Fixes #10678 (cherry picked from commit 6f6ac4b)
Contributor
|
Auto-port PR for 4.2: #16543 |
Contributor
|
Could not create auto-port PR. |
chrisvest
pushed a commit
to chrisvest/netty
that referenced
this pull request
Mar 25, 2026
…etty#16539) ## Problem `StompSubframeDecoder.skipControlCharacters()` reads bytes in an infinite loop without checking if the buffer has readable bytes remaining. When a STOMP heartbeat frame (just a LF byte) arrives, the method consumes the control character and then attempts to read beyond the buffer, causing an IndexOutOfBoundsException. ## Root Cause The `skipControlCharacters` method has an unconditional `buffer.readByte()` call inside a `for (;;)` loop with no `buffer.isReadable()` guard. When the buffer contains only control characters (heartbeat), all bytes are consumed and the next `readByte()` fails. ## Fix Add a `buffer.isReadable()` check before each `readByte()` call. When the buffer is exhausted (heartbeat-only data), the method returns gracefully and the decoder waits for more data. ## Tests Added - `testHeartbeatOnlyDoesNotThrowException` - Single LF heartbeat byte does not cause exception - `testMultipleHeartbeatsDoNotThrowException` - Multiple consecutive LF bytes handled correctly - `testCarriageReturnLineFeedHeartbeat` - CR+LF heartbeat handled correctly - `testHeartbeatFollowedByFrame` - Heartbeat before a real STOMP frame, frame decodes correctly - `testHeartbeatBetweenFrames` - Heartbeat between two frames, both decode correctly - `testHeartbeatSentSeparatelyThenFrame` - Heartbeat in separate write, then frame in second write ## Impact Minimal - only adds a single `isReadable()` guard. No behavioral change for normal STOMP frames. Fixes netty#10678 (cherry picked from commit 6f6ac4b)
Member
|
5.0 port: #16552 |
chrisvest
added a commit
that referenced
this pull request
Mar 27, 2026
…artbeat (#16539) (#16552) 5.0 port of #16539 The code is already correct in the 5.0 branch, but it can't hurt to bring over the tests. --- ## Problem `StompSubframeDecoder.skipControlCharacters()` reads bytes in an infinite loop without checking if the buffer has readable bytes remaining. When a STOMP heartbeat frame (just a LF byte) arrives, the method consumes the control character and then attempts to read beyond the buffer, causing an IndexOutOfBoundsException. ## Root Cause The `skipControlCharacters` method has an unconditional `buffer.readByte()` call inside a `for (;;)` loop with no `buffer.isReadable()` guard. When the buffer contains only control characters (heartbeat), all bytes are consumed and the next `readByte()` fails. ## Fix Add a `buffer.isReadable()` check before each `readByte()` call. When the buffer is exhausted (heartbeat-only data), the method returns gracefully and the decoder waits for more data. ## Tests Added - `testHeartbeatOnlyDoesNotThrowException` - Single LF heartbeat byte does not cause exception - `testMultipleHeartbeatsDoNotThrowException` - Multiple consecutive LF bytes handled correctly - `testCarriageReturnLineFeedHeartbeat` - CR+LF heartbeat handled correctly - `testHeartbeatFollowedByFrame` - Heartbeat before a real STOMP frame, frame decodes correctly - `testHeartbeatBetweenFrames` - Heartbeat between two frames, both decode correctly - `testHeartbeatSentSeparatelyThenFrame` - Heartbeat in separate write, then frame in second write ## Impact Minimal - only adds a single `isReadable()` guard. No behavioral change for normal STOMP frames. Fixes #10678 (cherry picked from commit 6f6ac4b) Co-authored-by: Guimu <[email protected]>
normanmaurer
pushed a commit
that referenced
this pull request
Mar 27, 2026
…on heartbeat (#16543) Auto-port of #16539 to 4.2 Cherry-picked commit: 6f6ac4b --- ## Problem `StompSubframeDecoder.skipControlCharacters()` reads bytes in an infinite loop without checking if the buffer has readable bytes remaining. When a STOMP heartbeat frame (just a LF byte) arrives, the method consumes the control character and then attempts to read beyond the buffer, causing an IndexOutOfBoundsException. ## Root Cause The `skipControlCharacters` method has an unconditional `buffer.readByte()` call inside a `for (;;)` loop with no `buffer.isReadable()` guard. When the buffer contains only control characters (heartbeat), all bytes are consumed and the next `readByte()` fails. ## Fix Add a `buffer.isReadable()` check before each `readByte()` call. When the buffer is exhausted (heartbeat-only data), the method returns gracefully and the decoder waits for more data. ## Tests Added - `testHeartbeatOnlyDoesNotThrowException` - Single LF heartbeat byte does not cause exception - `testMultipleHeartbeatsDoNotThrowException` - Multiple consecutive LF bytes handled correctly - `testCarriageReturnLineFeedHeartbeat` - CR+LF heartbeat handled correctly - `testHeartbeatFollowedByFrame` - Heartbeat before a real STOMP frame, frame decodes correctly - `testHeartbeatBetweenFrames` - Heartbeat between two frames, both decode correctly - `testHeartbeatSentSeparatelyThenFrame` - Heartbeat in separate write, then frame in second write ## Impact Minimal - only adds a single `isReadable()` guard. No behavioral change for normal STOMP frames. Fixes #10678 Co-authored-by: Guimu <[email protected]>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
StompSubframeDecoder.skipControlCharacters()reads bytes in an infinite loop without checking if the buffer has readable bytes remaining. When a STOMP heartbeat frame (just a LF byte) arrives, the method consumes the control character and then attempts to read beyond the buffer, causing an IndexOutOfBoundsException.Root Cause
The
skipControlCharactersmethod has an unconditionalbuffer.readByte()call inside afor (;;)loop with nobuffer.isReadable()guard. When the buffer contains only control characters (heartbeat), all bytes are consumed and the nextreadByte()fails.Fix
Add a
buffer.isReadable()check before eachreadByte()call. When the buffer is exhausted (heartbeat-only data), the method returns gracefully and the decoder waits for more data.Tests Added
testHeartbeatOnlyDoesNotThrowException- Single LF heartbeat byte does not cause exceptiontestMultipleHeartbeatsDoNotThrowException- Multiple consecutive LF bytes handled correctlytestCarriageReturnLineFeedHeartbeat- CR+LF heartbeat handled correctlytestHeartbeatFollowedByFrame- Heartbeat before a real STOMP frame, frame decodes correctlytestHeartbeatBetweenFrames- Heartbeat between two frames, both decode correctlytestHeartbeatSentSeparatelyThenFrame- Heartbeat in separate write, then frame in second writeImpact
Minimal - only adds a single
isReadable()guard. No behavioral change for normal STOMP frames.Fixes #10678