-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
Avoid double-free in content branch of NettyHttpRequest.buildBody #6712
Conversation
How is this issue manifesting itself? Are you seeing warnings etc? |
You get this stack trace in logs:
basically, |
Is this related to #6705? |
I found it when debugging #6705 but it's not directly related |
I don't understand the CI failures. I can't reproduce them locally, and the github actions logs aren't helpful. Is there a way to see more details, maybe a gradle build scan? |
74352ee
to
5fb78d8
Compare
When concatenating `receivedContent` data into a CompositeByteBuf, we call `addComponent` with the content buffers of the individual `receivedContent` items. `addComponent` takes "ownership" of the buffers, so we need to retain them once so that freeing the composite buffer does not free the `receivedContent` items.
@@ -304,7 +304,8 @@ protected Object buildBody() { | |||
for (ByteBufHolder holder : receivedContent) { | |||
ByteBuf content = holder.content(); | |||
if (content != null) { | |||
byteBufs.addComponent(true, content); | |||
// need to retain content, because for addComponent "ownership of buffer is transferred to this CompositeByteBuf." | |||
byteBufs.addComponent(true, content.retain()); |
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.
The content is already retained when the addContent
method is called. Can you explain why it needs to be retained again and how retaining the content twice wouldn't lead to a memory leak without an additional release?
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.
The retain in addContent is on the attribute. It does not affect the buffer itself.
The release of the attribute in receivedContent is done in NettyHttpRequest.release
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.
How can you be sure that addContent
is always called with an attribute? It can be called even if the request is not multipart
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 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.
The other cases are probably HttpData, which is handled by the receivedData
branch?
But it should be safe anyway. When a holder is added, it is retained, and it is released when the request is released. For this new retain, the corresponding release is when the composite buffer is released by the caller. So there is a corresponding release for each retain.
This is an attempt at a fix for the flaky FuzzyInputSpec. Can't reproduce that locally, but this code is obviously buggy, so this might help. `body` is a memoized supplier, but `NettyHttpRequest.release` checks whether it's a reference counted object. The supplier is never reference counted, but the object it supplies might be. This patch stores the unwrapped value as a separate field so that it can be released properly. The test for #6712 still passes, so this doesn't seem to regress the issue that the patch that caused this leak fixed.
* Release unwrapped body in NettyHttpRequest This is an attempt at a fix for the flaky FuzzyInputSpec. Can't reproduce that locally, but this code is obviously buggy, so this might help. `body` is a memoized supplier, but `NettyHttpRequest.release` checks whether it's a reference counted object. The supplier is never reference counted, but the object it supplies might be. This patch stores the unwrapped value as a separate field so that it can be released properly. The test for #6712 still passes, so this doesn't seem to regress the issue that the patch that caused this leak fixed. * fix setBody * Release buffers in tests Co-authored-by: jameskleeh <james.kleeh@gmail.com>
* Release unwrapped body in NettyHttpRequest This is an attempt at a fix for the flaky FuzzyInputSpec. Can't reproduce that locally, but this code is obviously buggy, so this might help. `body` is a memoized supplier, but `NettyHttpRequest.release` checks whether it's a reference counted object. The supplier is never reference counted, but the object it supplies might be. This patch stores the unwrapped value as a separate field so that it can be released properly. The test for #6712 still passes, so this doesn't seem to regress the issue that the patch that caused this leak fixed. * fix setBody * Release buffers in tests Co-authored-by: jameskleeh <james.kleeh@gmail.com>
When concatenating
receivedContent
data into a CompositeByteBuf, we calladdComponent
with the content buffers of the individualreceivedContent
items.addComponent
takes "ownership" of the buffers, so we need to retain them once so that freeing the composite buffer does not free thereceivedContent
items.