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

entities: Report malloc failures

Fix places where malloc failures aren't reported.

Introduce new API function xmlAddEntity that returns separate error
codes.

Don't invoke global error handler for low-level errors which should be
handled by higher layers.

Invalid redelcaration warnings will be fixed later.
This commit is contained in:
Nick Wellnhofer 2023-12-10 15:25:42 +01:00
parent 2e5d273beb
commit a1f7ecaef8
5 changed files with 138 additions and 211 deletions

View File

@ -68,48 +68,6 @@ static xmlEntity xmlEntityApos = {
NULL, NULL, NULL, NULL, 0, 0, 0
};
/**
* xmlEntitiesErrMemory:
* @extra: extra information
*
* Handle an out of memory condition
*/
static void
xmlEntitiesErrMemory(const char *extra)
{
__xmlSimpleError(XML_FROM_TREE, XML_ERR_NO_MEMORY, NULL, NULL, extra);
}
/**
* xmlEntitiesErr:
* @code: the error code
* @msg: the message
*
* Raise an error.
*/
static void LIBXML_ATTR_FORMAT(2,0)
xmlEntitiesErr(xmlParserErrors code, const char *msg)
{
__xmlSimpleError(XML_FROM_TREE, code, NULL, msg, NULL);
}
/**
* xmlEntitiesWarn:
* @code: the error code
* @msg: the message
*
* Raise a warning.
*/
static void LIBXML_ATTR_FORMAT(2,0)
xmlEntitiesWarn(xmlParserErrors code, const char *msg, const xmlChar *str1)
{
__xmlRaiseError(NULL, NULL, NULL,
NULL, NULL, XML_FROM_TREE, code,
XML_ERR_WARNING, NULL, 0,
(const char *)str1, NULL, NULL, 0, 0,
msg, (const char *)str1, NULL);
}
/*
* xmlFreeEntity : clean-up an entity record.
*/
@ -150,37 +108,43 @@ xmlFreeEntity(xmlEntityPtr entity)
* internal routine doing the entity node structures allocations
*/
static xmlEntityPtr
xmlCreateEntity(xmlDictPtr dict, const xmlChar *name, int type,
xmlCreateEntity(xmlDocPtr doc, const xmlChar *name, int type,
const xmlChar *ExternalID, const xmlChar *SystemID,
const xmlChar *content) {
xmlEntityPtr ret;
ret = (xmlEntityPtr) xmlMalloc(sizeof(xmlEntity));
if (ret == NULL) {
xmlEntitiesErrMemory("xmlCreateEntity: malloc failed");
if (ret == NULL)
return(NULL);
}
memset(ret, 0, sizeof(xmlEntity));
ret->doc = doc;
ret->type = XML_ENTITY_DECL;
/*
* fill the structure.
*/
ret->etype = (xmlEntityType) type;
if (dict == NULL) {
if ((doc == NULL) || (doc->dict == NULL))
ret->name = xmlStrdup(name);
if (ExternalID != NULL)
ret->ExternalID = xmlStrdup(ExternalID);
if (SystemID != NULL)
ret->SystemID = xmlStrdup(SystemID);
} else {
ret->name = xmlDictLookup(dict, name, -1);
ret->ExternalID = xmlStrdup(ExternalID);
ret->SystemID = xmlStrdup(SystemID);
else
ret->name = xmlDictLookup(doc->dict, name, -1);
if (ret->name == NULL)
goto error;
if (ExternalID != NULL) {
ret->ExternalID = xmlStrdup(ExternalID);
if (ret->ExternalID == NULL)
goto error;
}
if (SystemID != NULL) {
ret->SystemID = xmlStrdup(SystemID);
if (ret->SystemID == NULL)
goto error;
}
if (content != NULL) {
ret->length = xmlStrlen(content);
ret->content = xmlStrndup(content, ret->length);
if (ret->content == NULL)
goto error;
} else {
ret->length = 0;
ret->content = NULL;
@ -191,25 +155,49 @@ xmlCreateEntity(xmlDictPtr dict, const xmlChar *name, int type,
ret->owner = 0;
return(ret);
error:
xmlFreeEntity(ret);
return(NULL);
}
/*
* xmlAddEntity : register a new entity for an entities table.
/**
* xmlAddEntity:
* @doc: the document
* @extSubset: add to the external or internal subset
* @name: the entity name
* @type: the entity type XML_xxx_yyy_ENTITY
* @ExternalID: the entity external ID if available
* @SystemID: the entity system ID if available
* @content: the entity content
* @out: pointer to resulting entity (optional)
*
* Register a new entity for this document.
*
* Returns an xmlParserErrors error code.
*/
static xmlEntityPtr
xmlAddEntity(xmlDtdPtr dtd, const xmlChar *name, int type,
int
xmlAddEntity(xmlDocPtr doc, int extSubset, const xmlChar *name, int type,
const xmlChar *ExternalID, const xmlChar *SystemID,
const xmlChar *content) {
const xmlChar *content, xmlEntityPtr *out) {
xmlDtdPtr dtd;
xmlDictPtr dict = NULL;
xmlEntitiesTablePtr table = NULL;
xmlEntityPtr ret, predef;
int res;
if (name == NULL)
return(NULL);
if (out != NULL)
*out = NULL;
if ((doc == NULL) || (name == NULL))
return(XML_ERR_ARGUMENT);
dict = doc->dict;
if (extSubset)
dtd = doc->extSubset;
else
dtd = doc->intSubset;
if (dtd == NULL)
return(NULL);
if (dtd->doc != NULL)
dict = dtd->doc->dict;
return(XML_DTD_NO_DTD);
switch (type) {
case XML_INTERNAL_GENERAL_ENTITY:
@ -246,41 +234,59 @@ xmlAddEntity(xmlDtdPtr dtd, const xmlChar *name, int type,
}
}
}
if (!valid) {
xmlEntitiesWarn(XML_ERR_ENTITY_PROCESSING,
"xmlAddEntity: invalid redeclaration of predefined"
" entity '%s'", name);
return(NULL);
}
if (!valid)
return(XML_ERR_REDECL_PREDEF_ENTITY);
}
if (dtd->entities == NULL)
if (dtd->entities == NULL) {
dtd->entities = xmlHashCreateDict(0, dict);
if (dtd->entities == NULL)
return(XML_ERR_NO_MEMORY);
}
table = dtd->entities;
break;
case XML_INTERNAL_PARAMETER_ENTITY:
case XML_EXTERNAL_PARAMETER_ENTITY:
if (dtd->pentities == NULL)
if (dtd->pentities == NULL) {
dtd->pentities = xmlHashCreateDict(0, dict);
if (dtd->pentities == NULL)
return(XML_ERR_NO_MEMORY);
}
table = dtd->pentities;
break;
case XML_INTERNAL_PREDEFINED_ENTITY:
return(NULL);
return(XML_ERR_ARGUMENT);
}
if (table == NULL)
return(NULL);
ret = xmlCreateEntity(dict, name, type, ExternalID, SystemID, content);
ret = xmlCreateEntity(dtd->doc, name, type, ExternalID, SystemID, content);
if (ret == NULL)
return(NULL);
ret->doc = dtd->doc;
return(XML_ERR_NO_MEMORY);
if (xmlHashAddEntry(table, name, ret)) {
res = xmlHashAdd(table, name, ret);
if (res < 0) {
xmlFreeEntity(ret);
return(XML_ERR_NO_MEMORY);
} else if (res == 0) {
/*
* entity was already defined at another level.
*/
xmlFreeEntity(ret);
return(NULL);
return(XML_WAR_ENTITY_REDEFINED);
}
return(ret);
/*
* Link it to the DTD
*/
ret->parent = dtd;
ret->doc = dtd->doc;
if (dtd->last == NULL) {
dtd->children = dtd->last = (xmlNodePtr) ret;
} else {
dtd->last->next = (xmlNodePtr) ret;
ret->prev = dtd->last;
dtd->last = (xmlNodePtr) ret;
}
*out = ret;
return(0);
}
/**
@ -337,34 +343,8 @@ xmlAddDtdEntity(xmlDocPtr doc, const xmlChar *name, int type,
const xmlChar *ExternalID, const xmlChar *SystemID,
const xmlChar *content) {
xmlEntityPtr ret;
xmlDtdPtr dtd;
if (doc == NULL) {
xmlEntitiesErr(XML_DTD_NO_DOC,
"xmlAddDtdEntity: document is NULL");
return(NULL);
}
if (doc->extSubset == NULL) {
xmlEntitiesErr(XML_DTD_NO_DTD,
"xmlAddDtdEntity: document without external subset");
return(NULL);
}
dtd = doc->extSubset;
ret = xmlAddEntity(dtd, name, type, ExternalID, SystemID, content);
if (ret == NULL) return(NULL);
/*
* Link it to the DTD
*/
ret->parent = dtd;
ret->doc = dtd->doc;
if (dtd->last == NULL) {
dtd->children = dtd->last = (xmlNodePtr) ret;
} else {
dtd->last->next = (xmlNodePtr) ret;
ret->prev = dtd->last;
dtd->last = (xmlNodePtr) ret;
}
xmlAddEntity(doc, 1, name, type, ExternalID, SystemID, content, &ret);
return(ret);
}
@ -386,34 +366,8 @@ xmlAddDocEntity(xmlDocPtr doc, const xmlChar *name, int type,
const xmlChar *ExternalID, const xmlChar *SystemID,
const xmlChar *content) {
xmlEntityPtr ret;
xmlDtdPtr dtd;
if (doc == NULL) {
xmlEntitiesErr(XML_DTD_NO_DOC,
"xmlAddDocEntity: document is NULL");
return(NULL);
}
if (doc->intSubset == NULL) {
xmlEntitiesErr(XML_DTD_NO_DTD,
"xmlAddDocEntity: document without internal subset");
return(NULL);
}
dtd = doc->intSubset;
ret = xmlAddEntity(dtd, name, type, ExternalID, SystemID, content);
if (ret == NULL) return(NULL);
/*
* Link it to the DTD
*/
ret->parent = dtd;
ret->doc = dtd->doc;
if (dtd->last == NULL) {
dtd->children = dtd->last = (xmlNodePtr) ret;
} else {
dtd->last->next = (xmlNodePtr) ret;
ret->prev = dtd->last;
dtd->last = (xmlNodePtr) ret;
}
xmlAddEntity(doc, 0, name, type, ExternalID, SystemID, content, &ret);
return(ret);
}
@ -438,21 +392,10 @@ xmlEntityPtr
xmlNewEntity(xmlDocPtr doc, const xmlChar *name, int type,
const xmlChar *ExternalID, const xmlChar *SystemID,
const xmlChar *content) {
xmlEntityPtr ret;
xmlDictPtr dict;
if ((doc != NULL) && (doc->intSubset != NULL)) {
return(xmlAddDocEntity(doc, name, type, ExternalID, SystemID, content));
}
if (doc != NULL)
dict = doc->dict;
else
dict = NULL;
ret = xmlCreateEntity(dict, name, type, ExternalID, SystemID, content);
if (ret == NULL)
return(NULL);
ret->doc = doc;
return(ret);
return(xmlCreateEntity(doc, name, type, ExternalID, SystemID, content));
}
/**
@ -604,10 +547,8 @@ xmlEncodeEntitiesInternal(xmlDocPtr doc, const xmlChar *input, int attr) {
*/
buffer_size = 1000;
buffer = (xmlChar *) xmlMalloc(buffer_size);
if (buffer == NULL) {
xmlEntitiesErrMemory("xmlEncodeEntities: malloc failed");
if (buffer == NULL)
return(NULL);
}
out = buffer;
while (*cur != '\0') {
@ -707,47 +648,12 @@ xmlEncodeEntitiesInternal(xmlDocPtr doc, const xmlChar *input, int attr) {
* cur[3] is 10xxxxxx if cur[0] is 1111xxxx
* cur[0] is not 11111xxx
*/
char buf[11], *ptr;
int val = 0, l = 1;
char buf[13], *ptr;
int val, l;
if (((cur[0] & 0xC0) != 0xC0) ||
((cur[1] & 0xC0) != 0x80) ||
(((cur[0] & 0xE0) == 0xE0) && ((cur[2] & 0xC0) != 0x80)) ||
(((cur[0] & 0xF0) == 0xF0) && ((cur[3] & 0xC0) != 0x80)) ||
(((cur[0] & 0xF8) == 0xF8))) {
xmlEntitiesErr(XML_CHECK_NOT_UTF8,
"xmlEncodeEntities: input not UTF-8");
snprintf(buf, sizeof(buf), "&#%d;", *cur);
buf[sizeof(buf) - 1] = 0;
ptr = buf;
while (*ptr != 0) *out++ = *ptr++;
cur++;
continue;
} else if (*cur < 0xE0) {
val = (cur[0]) & 0x1F;
val <<= 6;
val |= (cur[1]) & 0x3F;
l = 2;
} else if (*cur < 0xF0) {
val = (cur[0]) & 0x0F;
val <<= 6;
val |= (cur[1]) & 0x3F;
val <<= 6;
val |= (cur[2]) & 0x3F;
l = 3;
} else if (*cur < 0xF8) {
val = (cur[0]) & 0x07;
val <<= 6;
val |= (cur[1]) & 0x3F;
val <<= 6;
val |= (cur[2]) & 0x3F;
val <<= 6;
val |= (cur[3]) & 0x3F;
l = 4;
}
if ((l == 1) || (!IS_CHAR(val))) {
xmlEntitiesErr(XML_ERR_INVALID_CHAR,
"xmlEncodeEntities: char out of range\n");
l = 4;
val = xmlGetUTF8Char(cur, &l);
if ((val < 0) || (!IS_CHAR(val))) {
snprintf(buf, sizeof(buf), "&#%d;", *cur);
buf[sizeof(buf) - 1] = 0;
ptr = buf;
@ -779,7 +685,6 @@ xmlEncodeEntitiesInternal(xmlDocPtr doc, const xmlChar *input, int attr) {
return(buffer);
mem_error:
xmlEntitiesErrMemory("xmlEncodeEntities: realloc failed");
xmlFree(buffer);
return(NULL);
}
@ -840,10 +745,8 @@ xmlEncodeSpecialChars(const xmlDoc *doc ATTRIBUTE_UNUSED, const xmlChar *input)
*/
buffer_size = 1000;
buffer = (xmlChar *) xmlMalloc(buffer_size);
if (buffer == NULL) {
xmlEntitiesErrMemory("xmlEncodeSpecialChars: malloc failed");
if (buffer == NULL)
return(NULL);
}
out = buffer;
while (*cur != '\0') {
@ -899,7 +802,6 @@ xmlEncodeSpecialChars(const xmlDoc *doc ATTRIBUTE_UNUSED, const xmlChar *input)
return(buffer);
mem_error:
xmlEntitiesErrMemory("xmlEncodeSpecialChars: realloc failed");
xmlFree(buffer);
return(NULL);
}
@ -956,27 +858,47 @@ xmlCopyEntity(void *payload, const xmlChar *name ATTRIBUTE_UNUSED) {
xmlEntityPtr cur;
cur = (xmlEntityPtr) xmlMalloc(sizeof(xmlEntity));
if (cur == NULL) {
xmlEntitiesErrMemory("xmlCopyEntity:: malloc failed");
if (cur == NULL)
return(NULL);
}
memset(cur, 0, sizeof(xmlEntity));
cur->type = XML_ENTITY_DECL;
cur->etype = ent->etype;
if (ent->name != NULL)
if (ent->name != NULL) {
cur->name = xmlStrdup(ent->name);
if (ent->ExternalID != NULL)
if (cur->name == NULL)
goto error;
}
if (ent->ExternalID != NULL) {
cur->ExternalID = xmlStrdup(ent->ExternalID);
if (ent->SystemID != NULL)
if (cur->ExternalID == NULL)
goto error;
}
if (ent->SystemID != NULL) {
cur->SystemID = xmlStrdup(ent->SystemID);
if (ent->content != NULL)
if (cur->SystemID == NULL)
goto error;
}
if (ent->content != NULL) {
cur->content = xmlStrdup(ent->content);
if (ent->orig != NULL)
if (cur->content == NULL)
goto error;
}
if (ent->orig != NULL) {
cur->orig = xmlStrdup(ent->orig);
if (ent->URI != NULL)
if (cur->orig == NULL)
goto error;
}
if (ent->URI != NULL) {
cur->URI = xmlStrdup(ent->URI);
if (cur->URI == NULL)
goto error;
}
return(cur);
error:
xmlFreeEntity(cur);
return(NULL);
}
/**
@ -989,7 +911,7 @@ xmlCopyEntity(void *payload, const xmlChar *name ATTRIBUTE_UNUSED) {
*/
xmlEntitiesTablePtr
xmlCopyEntitiesTable(xmlEntitiesTablePtr table) {
return(xmlHashCopy(table, xmlCopyEntity));
return(xmlHashCopySafe(table, xmlCopyEntity, xmlFreeEntityWrapper));
}
#endif /* LIBXML_TREE_ENABLED */
@ -1116,8 +1038,7 @@ xmlDumpEntityDecl(xmlBufferPtr buf, xmlEntityPtr ent) {
xmlBufferWriteChar(buf, ">\n");
break;
default:
xmlEntitiesErr(XML_DTD_UNKNOWN_ENTITY,
"xmlDumpEntitiesDecl: internal: unknown type entity type");
break;
}
}

View File

@ -87,6 +87,15 @@ XMLPUBFUN xmlEntityPtr
const xmlChar *content);
XMLPUBFUN void
xmlFreeEntity (xmlEntityPtr entity);
XMLPUBFUN int
xmlAddEntity (xmlDocPtr doc,
int extSubset,
const xmlChar *name,
int type,
const xmlChar *ExternalID,
const xmlChar *SystemID,
const xmlChar *content,
xmlEntityPtr *out);
XMLPUBFUN xmlEntityPtr
xmlAddDocEntity (xmlDocPtr doc,
const xmlChar *name,

View File

@ -1 +0,0 @@
warning : xmlAddEntity: invalid redeclaration of predefined entity 'lt'

View File

@ -1 +0,0 @@
warning : xmlAddEntity: invalid redeclaration of predefined entity 'lt'

View File

@ -1 +0,0 @@
warning : xmlAddEntity: invalid redeclaration of predefined entity 'lt'