Skip to content

Release the Locale when a SAX load is abandoned - #117

Merged
pjfanning merged 1 commit into
apache:trunkfrom
pjfanning:leak-saxloader-error-path
Sep 7, 2026
Merged

Release the Locale when a SAX load is abandoned#117
pjfanning merged 1 commit into
apache:trunkfrom
pjfanning:leak-saxloader-error-path

Conversation

@pjfanning

Copy link
Copy Markdown
Member

SaxLoader.postLoad() exists to drop the loader's references to the document it just built:

void postLoad(Cur c) {
    // fix garbage collection of Locale -> Xobj -> STL
    _locale = null;
    _context = null;
}

It only runs when the parse completes. Every failure path leaves both fields set — the four catch blocks call _context.abort() and rethrow without clearing them, and an IOException out of _xr.parse(is) is not caught at all, so it does not even abort.

That matters because the XMLReader holds the SaxLoader as its content, DTD, error, lexical and declaration handler. When xmlbeans creates the reader itself the loader becomes garbage anyway, but XmlOptions.setLoadUseXMLReader(...) lets a caller supply a reader that outlives the parse — and callers reuse XmlOptions. A failed load then pins the partly built document and its SchemaTypeLoader on that reader until the next parse, which is exactly the Locale -> Xobj -> STL chain the comment above is about.

This aborts and clears from a finally, which also covers the previously uncaught IOException path. The per-catch _context.abort() calls go away, and the catch (RuntimeException e) block existed only to abort before rethrowing, so it goes too.

Added SaxLoaderAbortTest: it supplies its own XMLReader, parses, then reflects on the reader's content handler to check _locale and _context are cleared. The two failure cases fail on trunk and pass with this change; the success case passes either way and pins the existing postLoad behaviour.

Full suite: 3173 tests pass (170 skipped).

🤖 Generated with Claude Code

SaxLoader.postLoad() nulls _locale and _context - "fix garbage collection of
Locale -> Xobj -> STL" - but it only runs when the parse completes. Every
failure path leaves both set: the four catch blocks abort the context and
rethrow without clearing them, and an IOException out of _xr.parse() is not
caught at all, so it does not even abort.

The XMLReader holds the SaxLoader as its content, DTD, error, lexical and
declaration handler. With a caller-supplied reader
(XmlOptions.setLoadUseXMLReader) that reader outlives the parse, so a failed
load pins the partly built document and its SchemaTypeLoader until the next
parse on that reader.

Abort and clear from a finally instead, which also covers the IOException path.
The per-catch _context.abort() calls go away, and the RuntimeException catch
existed only to abort before rethrowing.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@pjfanning
pjfanning merged commit 4fdde0c into apache:trunk Sep 7, 2026
3 checks passed
@pjfanning
pjfanning deleted the leak-saxloader-error-path branch September 7, 2026 13:41
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