From 481d79d44cf8ed864ed3d74edbeb96e8cd9ed4a7 Mon Sep 17 00:00:00 2001 From: Nick Wellnhofer Date: Mon, 19 Dec 2022 15:26:46 +0100 Subject: [PATCH] entities: Add XML_ENT_PARSED flag To check whether an entity was already parsed, the code previously tested whether "checked" was non-zero or "children" was non-null. The "children" check could be unreliable because an empty entity also results in an empty (NULL) node list. Use a separate flag to make this check more reliable. --- include/private/entities.h | 8 ++++++++ parser.c | 12 ++++++------ tree.c | 8 ++++++-- 3 files changed, 20 insertions(+), 8 deletions(-) diff --git a/include/private/entities.h b/include/private/entities.h index 1118c6d0..eb187e81 100644 --- a/include/private/entities.h +++ b/include/private/entities.h @@ -4,6 +4,14 @@ #include #include +/* + * Entity flags + * + * XML_ENT_PARSED: The entity was parsed and `children` points to the + * content. + */ +#define XML_ENT_PARSED (1<<0) + XML_HIDDEN xmlChar * xmlEncodeAttributeEntities(xmlDocPtr doc, const xmlChar *input); diff --git a/parser.c b/parser.c index 9b98aeed..56f03a1f 100644 --- a/parser.c +++ b/parser.c @@ -78,6 +78,7 @@ #include "private/buf.h" #include "private/dict.h" #include "private/enc.h" +#include "private/entities.h" #include "private/error.h" #include "private/globals.h" #include "private/html.h" @@ -7203,7 +7204,7 @@ xmlParseReference(xmlParserCtxtPtr ctxt) { if (ent == NULL) return; if (!ctxt->wellFormed) return; - was_checked = ent->checked; + was_checked = ent->flags & XML_ENT_PARSED; /* special case of predefined entities */ if ((ent->name == NULL) || @@ -7229,8 +7230,7 @@ xmlParseReference(xmlParserCtxtPtr ctxt) { * far more secure as the parser will only process data coming from * the document entity by default. */ - if (((ent->checked == 0) || - ((ent->children == NULL) && (ctxt->options & XML_PARSE_NOENT))) && + 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; @@ -7270,6 +7270,7 @@ xmlParseReference(xmlParserCtxtPtr ctxt) { "invalid entity type found\n", NULL); } + ent->flags |= XML_ENT_PARSED; /* * Store the number of entities needing parsing for this entity * content and do checkings @@ -7292,9 +7293,8 @@ xmlParseReference(xmlParserCtxtPtr ctxt) { } if ((ret == XML_ERR_OK) && (list != NULL)) { - if (((ent->etype == XML_INTERNAL_GENERAL_ENTITY) || - (ent->etype == XML_EXTERNAL_GENERAL_PARSED_ENTITY))&& - (ent->children == NULL)) { + if ((ent->etype == XML_INTERNAL_GENERAL_ENTITY) || + (ent->etype == XML_EXTERNAL_GENERAL_PARSED_ENTITY)) { ent->children = list; /* * Prune it directly in the generated document diff --git a/tree.c b/tree.c index a7368a32..dd5b5709 100644 --- a/tree.c +++ b/tree.c @@ -1411,7 +1411,8 @@ xmlStringLenGetNodeList(const xmlDoc *doc, const xmlChar *value, int len) { if (val != NULL) xmlFree(val); goto out; } - else if ((ent != NULL) && (ent->children == NULL)) { + else if ((ent != NULL) && + ((ent->flags & XML_ENT_PARSED) == 0)) { xmlNodePtr temp; /* Set to non-NULL value to avoid recursion. */ @@ -1419,6 +1420,7 @@ xmlStringLenGetNodeList(const xmlDoc *doc, const xmlChar *value, int len) { ent->children = xmlStringGetNodeList(doc, (const xmlChar*)node->content); ent->owner = 1; + ent->flags |= XML_ENT_PARSED; temp = ent->children; while (temp) { temp->parent = (xmlNodePtr)ent; @@ -1607,7 +1609,8 @@ xmlStringGetNodeList(const xmlDoc *doc, const xmlChar *value) { node = xmlNewReference(doc, val); if (node == NULL) goto out; - if ((ent != NULL) && (ent->children == NULL)) { + if ((ent != NULL) && + ((ent->flags & XML_ENT_PARSED) == 0)) { xmlNodePtr temp; /* Set to non-NULL value to avoid recursion. */ @@ -1615,6 +1618,7 @@ xmlStringGetNodeList(const xmlDoc *doc, const xmlChar *value) { ent->children = xmlStringGetNodeList(doc, (const xmlChar*)node->content); ent->owner = 1; + ent->flags |= XML_ENT_PARSED; temp = ent->children; while (temp) { temp->parent = (xmlNodePtr)ent;