Close streams that were leaked when the work on them failed - #614
Open
JakeHuneau wants to merge 1 commit into
Open
JakeHuneau wants to merge 1 commit into
JakeHuneau wants to merge 1 commit into
Conversation
Four places opened a stream, did some work and closed the stream afterwards, so the close was skipped whenever the work threw. The keystore load and save are the ones that matter. Both call through to an overload that throws OpenAS2Exception, which the catch around the hand written close only covers IOException, so every failure leaked the descriptor. The keystore is reloaded on a schedule, five minutes apart by default, so a keystore that consistently fails to load leaked a descriptor per refresh until the process could no longer open files. The save leaks an output stream held open on the keystore itself. The resender leaked on a resend file that failed to deserialise, the network module leaked in the handler that stores an invalid message, and the command registry never closed its stream on any path at all. All four now use try-with-resources so the stream is closed whichever way the work ends.
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.
Four places open a stream, do some work and close the stream afterwards, so the close is skipped whenever the work throws.
The one that matters
X509CertificateFactory.load(String, char[])andsave(String, char[]):load(InputStream, char[])declaresthrows OpenAS2Exceptionand wraps everything it catches intoWrappedException, so a wrong password or a corrupt file propagates past thecatch (IOException)and the close never runs.PKCS12CertificateFactoryreloads the keystore on a schedule, five minutes apart by default, so a keystore that consistently fails to load leaks a descriptor every refresh, roughly 288 a day, until the process can no longer open files. The failure is silent until then.savehas the identical shape and leaks an output stream held open on the keystore itself.The other three
DirectoryResenderModuleleaks on a resend file that fails to deserialise. Bounded, since a bad file is quarantined to the error directory, so it is one descriptor per bad file rather than per poll.NetModuleleaks in the handler that stores an invalid message, if the write fails.XMLCommandRegistry.refreshnever closes its stream on any path.All four now use try-with-resources.
Testing
182 tests pass, 2 new. The test counts the process's open descriptors through
/procacross repeated failed and successful loads, and skips where/procis unavailable so it does not fail the Windows matrix.Reverting just the keystore load to the hand written close makes it fail with "40 failed loads should not each hold a descriptor open, went from 125 to 165", which is one leaked descriptor per attempt exactly as described.