QXmlSimpleReader: add parameter entity length checks
The earlier patches fixed the size checks for the expansion of general
entities.
However, the parser also processes parameter entities.
While the W3C spec forbids referencing parameter entities from
general entities or from other parameter entities in the internal
subset of DTD, the QXmlSimpleReader's parser historically allows
it.
We can try to follow the specification, and thus change the
behavior, or just introduce the same entitiy expanstion limits,
as applied to the general entities. I chose the second approach.
Parameter entities are expanded in two places in parsePEReference(),
and each of them needs a limit.
1. A parameter entity included in the DTD.
Its replacement text is parsed again, so it can contain further
parameter entity references, and general entity references in
default attribute values of ATTLIST declarations. A parameter
entity reference can even be created with "%", which becomes a
plain '%' when the entity value is declared, and is only recognized
as a reference once the value is included in the DTD.
Handle it exactly like general entities: count the size in
insertXmlRef(). An internal parameter entity included in the DTD
starts the count of the outermost expansion, or continues it, and
every parameter or general entity expanded while it is on the
reference stack adds to the same counter. Replace the boolean
parameter of insertXmlRef() with an ExpansionCheck enum, so that
parameter entities can be reported with the '%' prefix in the error
message.
2. A parameter entity included in an entity value.
Here the thing that needs to be limited is the value that is being
built, not a single reference. That value is read from the
document, not from the reference stack, and each included parameter
entity is popped from the stack before the next reference is read.
The counter used for the expansions would therefore treat every
sibling reference in
<!ENTITY % b '%a;%a;%a;...'>
as a new outermost expansion, and restart counting each time.
Add a separate includedParameterEntitySize counter that sums up the
sizes of all parameter entities included in the entity value that is
currently being parsed, and reset it at the start of every entity
value.
Note that the first check will technically catch both cases. However,
it does not prevent the problem of a potentially uncontrolled expansion
of nested parameter entities - that's what the second check catches.
This fixes the remaining failing cases of the entityExpansionLimit()
test. Also new test cases are added:
* parameter_entity_run_in_DTD_huge_expansion makes sure that the
entity value is limited while it is being built, and not only after
the full expansion;
* entity_refs_in_parameter_entity verifies that general entity
references in a parameter entity are only expanded (and limited)
once the general entity that includes it is used in the document;
* parameter_entity_char_ref_in_DTD and
general_entity_in_parameter_entity_in_DTD cover the expansions of a
parameter entity included in the DTD.
Task-number: QTBUG-149213
Pick-to: 6.12 6.8 6.5 5.15
Change-Id: I173ddf67fd028c665ecbd1c58e4c4abf659e08db
Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>