-
Notifications
You must be signed in to change notification settings - Fork 283
Fix ByteBuf memory leak in blob deserialization error paths #3177
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Fix ByteBuf memory leak in blob deserialization error paths #3177
Conversation
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #3177 +/- ##
============================================
+ Coverage 64.24% 69.73% +5.49%
- Complexity 10398 12809 +2411
============================================
Files 840 931 +91
Lines 71755 79178 +7423
Branches 8611 9431 +820
============================================
+ Hits 46099 55216 +9117
+ Misses 23004 21040 -1964
- Partials 2652 2922 +270 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
When CRC validation fails during blob deserialization in MessageFormatRecord, the ByteBuf allocated by Utils.readNettyByteBufFromCrcInputStream() was not being released, causing a memory leak. The issue affected all three blob format versions (V1, V2, V3) in their respective deserializeBlobRecord() methods. When corrupt data triggered a MessageFormatException during CRC validation, the allocated ByteBuf slice remained unreleased. Changes: - Extract CRC validation logic into validateCrcAndManageByteBuf() helper method - Implement try-finally pattern to ensure ByteBuf.release() on validation failure - Apply fix consistently across Blob_Format_V1, V2, and V3 deserializers - Add comprehensive leak detection tests using custom ByteBuf wrappers Tests: - MessageFormatCorruptDataLeakTest verifies ByteBuf cleanup on corrupt data - Parameterized tests cover all blob format versions (V1, V2, V3) - Control tests ensure no false positives on successful deserialization - Uses SliceCapturingByteBuf wrapper via DelegateByteBuf to track slice creation
4274356 to
52076f2
Compare
| throw new MessageFormatException("corrupt data while parsing blob content", | ||
| MessageFormatErrorCodes.DataCorrupt); | ||
| } | ||
| validateCrcAndManageByteBuf(crcStream, dataStream, byteBuf, logger); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hmm, this one is tricky. The reason why we are not releasing this ByteBuf anywhere is because we didn't increase the refCounter when creating this ByteBuf. In readNettyByteBufFromCrcInputStream, we use slice method to create this ByteBuf, instead of retainedSlice.
If we call release on the failure here, then we would have to increase the refCounter by calling retainedSlice, but that would mean in the success path, we also have to call release one more time.
It does seems like a good idea to call retain/release here, since it shows the clear ownership of each ByteBuf. But in this case, we would have update other files on the success path to release this ByteBuf. What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Take a look at how this is handled in GetBlobOperation.handleBody() and subsequent calls. The chunkBuf within the BlobData is owned by the caller and it's their responsibility to release. If MessageFormatRecord.deserializeBlob() throws, GetBlobOperation.handleBody() never handles the bytebuf here or in the input stream.
In my read and testing of Utils.readNettyByteBufFromCrcInputStream() it always returns a Bytebuf passing the ownership (and the responsibility to release) to the caller. Thus if validateCrcAndManageByteBuf fails we must release here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's another path where we improve the memory management expectations in readNettyByteBufFromCrcInputStream and it's callers which is probably preferred but a slightly larger change. Let me pull this back to draft and spend some more time in testing that approach.
Summary
When CRC validation fails during blob deserialization in MessageFormatRecord, the bytebuf allocated by Utils.readNettyByteBufFromCrcInputStream() was not being released, causing a memory leak.
The issue affected all three blob format versions (V1, V2, V3) in their respective deserializeBlobRecord() methods. When corrupt data triggered a MessageFormatException during CRC validation, the allocated bytebuf slice remained unreleased.
Changes:
Testing Done