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