Skip to content

Close the .xsb stream when XsbReader rejects a header - #107

Merged
pjfanning merged 1 commit into
apache:trunkfrom
pjfanning:leak-xsbreader-header
Sep 7, 2026
Merged

Close the .xsb stream when XsbReader rejects a header#107
pjfanning merged 1 commit into
apache:trunkfrom
pjfanning:leak-xsbreader-header

Conversation

@pjfanning

Copy link
Copy Markdown
Member

XsbReader(SchemaTypeSystemImpl, String handle, int filetype) opens the resource stream (typeSystem.getLoaderStream(...)) and only then validates the header. Every rejection path — wrong magic cookie, wrong major version, incompatible minor version, wrong file type — throws SchemaTypeLoaderException from inside the constructor, and StringPool.readFrom can throw on a truncated file too.

Because the constructor never returns, no caller ever holds a reference to call readEnd(), so the stream is leaked. SchemaTypeSystemImpl.initFromHeader() even has

} finally {
    if (reader != null) {
        reader.readEnd();
    }
}

but reader is still null in exactly this case. Each corrupt or version-mismatched .xsb on the classpath leaks a file handle (or a ZipFile entry stream).

The header parsing moves into a private readHeader() and the constructor releases the stream if it does not complete.

Added XsbReaderHeaderStreamTest, which feeds a tracking stream through a stub ResourceLoader and asserts it is closed. All four cases fail on trunk and pass with this change.

🤖 Generated with Claude Code

XsbReader(typeSystem, handle, filetype) opens the resource stream before it
validates the header, then throws SchemaTypeLoaderException for a bad magic
cookie, an incompatible major/minor version or the wrong file type - and
StringPool.readFrom can throw on a truncated file. The constructor never
returns in those cases, so no caller ever holds a reference to call readEnd()
and the stream is leaked.

SchemaTypeSystemImpl.initFromHeader already guards with
"finally { if (reader != null) reader.readEnd(); }", but reader is still null
for exactly this failure. Every corrupt or version-mismatched .xsb on the
classpath therefore leaks a file or zip-entry handle.

Move the header parsing into readHeader() and release the stream from the
constructor if it does not complete.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@pjfanning
pjfanning merged commit c9ef811 into apache:trunk Sep 7, 2026
3 checks passed
@pjfanning
pjfanning deleted the leak-xsbreader-header branch September 7, 2026 11:47
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.

1 participant