Bound the content model a schema expands into - #73
Merged
garydgregory merged 2 commits intoSep 1, 2026
Conversation
A schema loader expands a repeated particle into content-model nodes while building the DFA. That happens after parsing and without the reader, so the limits the injected reader carries never reach it, and a compact schema with a large maxOccurs was expanded unbounded on an implementation whose limit is opt-in: external Xerces applies it only under FEATURE_SECURE_PROCESSING, which the wrapper did not set (the stock JDK applies it unconditionally). Set FEATURE_SECURE_PROCESSING on the wrapped factory, failing closed as the other recipes do. The JAXP 1.5 ACCESS_EXTERNAL_* properties stay unset, so the caller-resolver opt-in path is unaffected; the schema tests covering it pass on Java 8 as well. The expansion is lazy on Xerces, so the new test validates an instance rather than only compiling the schema, and skips its unbounded control where the implementation applies the limit unconditionally. Assisted-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CLnTBsvmYtxzNTWVGNyz33
Updated the test class description for clarity.
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.
A schema loader expands a repeated particle into content-model nodes while building the DFA. That happens after parsing and without the reader, so none of the limits the injected secure reader carries can reach it — entity expansion is bounded there (
BillionLaughsTest), content-model expansion is not.The bound for it is the implementation's own secure-processing limit, and it is opt-in on external Xerces:
maxOccurLimitis installed only whenFEATURE_SECURE_PROCESSINGis set on theSchemaFactory, which the wrapper deliberately did not set. The stock JDK applies its limit unconditionally and was never affected.Measured on external Xerces through
SecureSchemaFactorywith a 512 MB heap, before this change:maxOccurs="10000"validated in 13.7 s,maxOccurs="100000"ended inOutOfMemoryError. Both are rejected once the feature is set.The fix sets
FEATURE_SECURE_PROCESSINGon the wrapped factory, failing closed through the same helper shape the other recipes use. The JAXP 1.5ACCESS_EXTERNAL_*properties are still not set explicitly, so the caller-resolver opt-in path the wrapper's Javadoc protects is untouched:schemaFetchesIdentifierOnlyOptIn(an identifier-onlyLSInput, the case where the implementation must fetch the named resource itself) andschemaResolvesAllowListedpass on every schema execution, on Java 8 as well as the default JDK.One behavioural note for reviewers: because the set fails closed, a
SchemaFactoryimplementation that rejectsFEATURE_SECURE_PROCESSINGnow throws instead of returning an unsecured factory. That matches the documented contract for a required setting, but it is a change for implementations outside the recognized set.The new
SchemaContentModelLimitTestvalidates an instance rather than only compiling the schema, because the expansion is lazy on Xerces —newSchemareturns in milliseconds whatevermaxOccurssays. Its unbounded control skips where the implementation applies the limit unconditionally, since there is no unbounded run to compare against.Verified with the full surefire matrix on the default JDK and on Java 8.
🤖 Generated with Claude Code