Skip to content

fix: close getObject response stream for buffering transformers - #524

Merged
sharmabikram merged 5 commits into
mainfrom
shbikram/getobject-stream-leak
Oct 5, 2026
Merged

sharmabikram merged 5 commits into
mainfrom
shbikram/getobject-stream-leak

Conversation

@sharmabikram

@sharmabikram sharmabikram commented Sep 24, 2026 •

Copy link
Copy Markdown
Contributor

close getObject response stream for buffering transformers. Fixes #518.

Issue #, if available:

Description of changes:

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.

Check any applicable:

  • Were any files moved? Moving files changes their URL, which breaks all hyperlinks to the files.

@sharmabikram
sharmabikram requested a review from a team as a code owner September 24, 2026 21:43
* the response stream: buffering transformers do not need the connection left open (so the client
* closes the stream and avoids the leak), while streaming transformers do (the caller closes it).
*/
public class S3EncryptionClientGetObjectStreamCloseTest {

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.

This doesn't actually test the updated getObject method, no? Just properties about the SDK classes themselves? So I don't think this would actually fail without the fix

// materialized result, so the stream must be closed here to release its buffers. Streaming
// transformers (e.g. toInputStream) return the stream for the caller to read and close.
if (!responseTransformer.needsConnectionLeftOpen()) {
joinFutureGet.close();

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.

This doesn't close the stream if some exception is thrown in the try block, let's move this to a finally block

S3EncryptionClient.getObject never closed the ResponseInputStream from the
toBlockingInputStream() pipeline, leaking Netty direct memory on every call
with a buffering transformer (getObjectAsBytes, toFile). Close the stream when
the transformer does not need the connection left open; streaming transformers
(toInputStream) still return the stream for the caller to close. Fixes #518.
@sharmabikram
sharmabikram force-pushed the shbikram/getobject-stream-leak branch from 42f58b4 to 55d84e2 Compare September 26, 2026 22:55
sharmabikram and others added 3 commits October 2, 2026 11:35
Replace the SDK-contract test with one that drives S3EncryptionClient.getObject
through a real S3AsyncClient backed by an in-memory transport, so it fails
without the stream close: a transformer that stops reading early or throws
must release the response stream, while toInputStream leaves it open for the
caller.

Log instead of throw when closing the stream fails, so a close failure does not
mask the transformed result or the original exception.
Comment thread src/main/java/software/amazon/encryption/s3/S3EncryptionClient.java
@sharmabikram
sharmabikram merged commit af191c6 into main Oct 5, 2026
25 checks passed
@sharmabikram
sharmabikram deleted the shbikram/getobject-stream-leak branch October 5, 2026 22:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Memory leak in S3EncryptionClient.getObject()

3 participants