1
0
mirror of https://gitlab.gnome.org/GNOME/libxml2.git synced 2024-10-26 12:25:09 +03:00

entities: Use flags to store '<' check results

Instead of abusing the LSB of the "checked" member, store the result
of testing for occurrence of '<' character in "flags".

Also use the flags in xmlParseStringEntityRef instead of rescanning
every time.
This commit is contained in:
Nick Wellnhofer 2022-12-19 15:59:49 +01:00
parent 481d79d44c
commit 7e3f469be9
2 changed files with 32 additions and 38 deletions

View File

@ -11,6 +11,8 @@
* content. * content.
*/ */
#define XML_ENT_PARSED (1<<0) #define XML_ENT_PARSED (1<<0)
#define XML_ENT_CHECKED_LT (1<<1)
#define XML_ENT_CONTAINS_LT (1<<2)
XML_HIDDEN xmlChar * XML_HIDDEN xmlChar *
xmlEncodeAttributeEntities(xmlDocPtr doc, const xmlChar *input); xmlEncodeAttributeEntities(xmlDocPtr doc, const xmlChar *input);

View File

@ -158,7 +158,7 @@ xmlParserEntityCheck(xmlParserCtxtPtr ctxt, size_t size,
if ((ent != NULL) && (ent->etype != XML_INTERNAL_PREDEFINED_ENTITY) && if ((ent != NULL) && (ent->etype != XML_INTERNAL_PREDEFINED_ENTITY) &&
(ent->content != NULL) && (ent->checked == 0) && (ent->content != NULL) && (ent->checked == 0) &&
(ctxt->errNo != XML_ERR_ENTITY_LOOP)) { (ctxt->errNo != XML_ERR_ENTITY_LOOP)) {
unsigned long oldnbent = ctxt->nbentities, diff; unsigned long oldnbent = ctxt->nbentities;
xmlChar *rep; xmlChar *rep;
ent->checked = 1; ent->checked = 1;
@ -171,13 +171,8 @@ xmlParserEntityCheck(xmlParserCtxtPtr ctxt, size_t size,
ent->content[0] = 0; ent->content[0] = 0;
} }
diff = ctxt->nbentities - oldnbent + 1; ent->checked = ctxt->nbentities - oldnbent + 1;
if (diff > INT_MAX / 2)
diff = INT_MAX / 2;
ent->checked = diff * 2;
if (rep != NULL) { if (rep != NULL) {
if (xmlStrchr(rep, '<'))
ent->checked |= 1;
xmlFree(rep); xmlFree(rep);
rep = NULL; rep = NULL;
} }
@ -244,7 +239,7 @@ xmlParserEntityCheck(xmlParserCtxtPtr ctxt, size_t size,
/* /*
* use the number of parsed entities in the replacement * use the number of parsed entities in the replacement
*/ */
size = ent->checked / 2; size = ent->checked;
/* /*
* The amount of data parsed counting entities size only once * The amount of data parsed counting entities size only once
@ -2714,7 +2709,7 @@ xmlStringLenDecodeEntities(xmlParserCtxtPtr ctxt, const xmlChar *str, int len,
ent = xmlParseStringEntityRef(ctxt, &str); ent = xmlParseStringEntityRef(ctxt, &str);
xmlParserEntityCheck(ctxt, 0, ent, 0); xmlParserEntityCheck(ctxt, 0, ent, 0);
if (ent != NULL) if (ent != NULL)
ctxt->nbentities += ent->checked / 2; ctxt->nbentities += ent->checked;
if ((ent != NULL) && if ((ent != NULL) &&
(ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) { (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
if (ent->content != NULL) { if (ent->content != NULL) {
@ -2767,7 +2762,7 @@ xmlStringLenDecodeEntities(xmlParserCtxtPtr ctxt, const xmlChar *str, int len,
ent = xmlParseStringPEReference(ctxt, &str); ent = xmlParseStringPEReference(ctxt, &str);
xmlParserEntityCheck(ctxt, 0, ent, 0); xmlParserEntityCheck(ctxt, 0, ent, 0);
if (ent != NULL) if (ent != NULL)
ctxt->nbentities += ent->checked / 2; ctxt->nbentities += ent->checked;
if (ent != NULL) { if (ent != NULL) {
if (ent->content == NULL) { if (ent->content == NULL) {
/* /*
@ -4067,20 +4062,15 @@ xmlParseAttValueComplex(xmlParserCtxtPtr ctxt, int *attlen, int normalize) {
*/ */
if ((ent->etype != XML_INTERNAL_PREDEFINED_ENTITY) && if ((ent->etype != XML_INTERNAL_PREDEFINED_ENTITY) &&
(ent->content != NULL) && (ent->checked == 0)) { (ent->content != NULL) && (ent->checked == 0)) {
unsigned long oldnbent = ctxt->nbentities, diff; unsigned long oldnbent = ctxt->nbentities;
++ctxt->depth; ++ctxt->depth;
rep = xmlStringDecodeEntities(ctxt, ent->content, rep = xmlStringDecodeEntities(ctxt, ent->content,
XML_SUBSTITUTE_REF, 0, 0, 0); XML_SUBSTITUTE_REF, 0, 0, 0);
--ctxt->depth; --ctxt->depth;
diff = ctxt->nbentities - oldnbent + 1; ent->checked = ctxt->nbentities - oldnbent + 1;
if (diff > INT_MAX / 2)
diff = INT_MAX / 2;
ent->checked = diff * 2;
if (rep != NULL) { if (rep != NULL) {
if (xmlStrchr(rep, '<'))
ent->checked |= 1;
xmlFree(rep); xmlFree(rep);
rep = NULL; rep = NULL;
} else { } else {
@ -7233,7 +7223,7 @@ xmlParseReference(xmlParserCtxtPtr ctxt) {
if (((ent->flags & XML_ENT_PARSED) == 0) && if (((ent->flags & XML_ENT_PARSED) == 0) &&
((ent->etype != XML_EXTERNAL_GENERAL_PARSED_ENTITY) || ((ent->etype != XML_EXTERNAL_GENERAL_PARSED_ENTITY) ||
(ctxt->options & (XML_PARSE_NOENT | XML_PARSE_DTDVALID)))) { (ctxt->options & (XML_PARSE_NOENT | XML_PARSE_DTDVALID)))) {
unsigned long oldnbent = ctxt->nbentities, diff; unsigned long oldnbent = ctxt->nbentities;
/* /*
* This is a bit hackish but this seems the best * This is a bit hackish but this seems the best
@ -7275,12 +7265,7 @@ xmlParseReference(xmlParserCtxtPtr ctxt) {
* Store the number of entities needing parsing for this entity * Store the number of entities needing parsing for this entity
* content and do checkings * content and do checkings
*/ */
diff = ctxt->nbentities - oldnbent + 1; ent->checked = ctxt->nbentities - oldnbent + 1;
if (diff > INT_MAX / 2)
diff = INT_MAX / 2;
ent->checked = diff * 2;
if ((ent->content != NULL) && (xmlStrchr(ent->content, '<')))
ent->checked |= 1;
if (ret == XML_ERR_ENTITY_LOOP) { if (ret == XML_ERR_ENTITY_LOOP) {
xmlFatalErr(ctxt, XML_ERR_ENTITY_LOOP, NULL); xmlFatalErr(ctxt, XML_ERR_ENTITY_LOOP, NULL);
xmlHaltParser(ctxt); xmlHaltParser(ctxt);
@ -7345,12 +7330,12 @@ xmlParseReference(xmlParserCtxtPtr ctxt) {
list = NULL; list = NULL;
} }
if (ent->checked == 0) if (ent->checked == 0)
ent->checked = 2; ent->checked = 1;
/* Prevent entity from being parsed and expanded twice (Bug 760367). */ /* Prevent entity from being parsed and expanded twice (Bug 760367). */
was_checked = 0; was_checked = 0;
} else if (ent->checked != 1) { } else {
ctxt->nbentities += ent->checked / 2; ctxt->nbentities += ent->checked;
} }
/* /*
@ -7716,13 +7701,16 @@ xmlParseEntityRef(xmlParserCtxtPtr ctxt) {
* not contain a <. * not contain a <.
*/ */
else if ((ctxt->instate == XML_PARSER_ATTRIBUTE_VALUE) && else if ((ctxt->instate == XML_PARSER_ATTRIBUTE_VALUE) &&
(ent != NULL) &&
(ent->etype != XML_INTERNAL_PREDEFINED_ENTITY)) { (ent->etype != XML_INTERNAL_PREDEFINED_ENTITY)) {
if (((ent->checked & 1) || (ent->checked == 0)) && if ((ent->flags & XML_ENT_CHECKED_LT) == 0) {
(ent->content != NULL) && (xmlStrchr(ent->content, '<'))) { if ((ent->content != NULL) && (xmlStrchr(ent->content, '<')))
xmlFatalErrMsgStr(ctxt, XML_ERR_LT_IN_ATTRIBUTE, ent->flags |= XML_ENT_CONTAINS_LT;
"'<' in entity '%s' is not allowed in attributes values\n", name); ent->flags |= XML_ENT_CHECKED_LT;
} }
if (ent->flags & XML_ENT_CONTAINS_LT)
xmlFatalErrMsgStr(ctxt, XML_ERR_LT_IN_ATTRIBUTE,
"'<' in entity '%s' is not allowed in attributes "
"values\n", name);
} }
/* /*
@ -7910,12 +7898,16 @@ xmlParseStringEntityRef(xmlParserCtxtPtr ctxt, const xmlChar ** str) {
* not contain a <. * not contain a <.
*/ */
else if ((ctxt->instate == XML_PARSER_ATTRIBUTE_VALUE) && else if ((ctxt->instate == XML_PARSER_ATTRIBUTE_VALUE) &&
(ent != NULL) && (ent->content != NULL) && (ent->etype != XML_INTERNAL_PREDEFINED_ENTITY)) {
(ent->etype != XML_INTERNAL_PREDEFINED_ENTITY) && if ((ent->flags & XML_ENT_CHECKED_LT) == 0) {
(xmlStrchr(ent->content, '<'))) { if ((ent->content != NULL) && (xmlStrchr(ent->content, '<')))
xmlFatalErrMsgStr(ctxt, XML_ERR_LT_IN_ATTRIBUTE, ent->flags |= XML_ENT_CONTAINS_LT;
"'<' in entity '%s' is not allowed in attributes values\n", ent->flags |= XML_ENT_CHECKED_LT;
name); }
if (ent->flags & XML_ENT_CONTAINS_LT)
xmlFatalErrMsgStr(ctxt, XML_ERR_LT_IN_ATTRIBUTE,
"'<' in entity '%s' is not allowed in attributes "
"values\n", name);
} }
/* /*