mirror of
https://gitlab.gnome.org/GNOME/libxml2.git
synced 2025-10-24 13:33:01 +03:00
Rework final handling of XPath results
Move cleanup of XPath stack to xmlXPathFreeParserContext. This avoids memory leaks if valuePop fails in some error cases. Found with libFuzzer and ASan. Rework handling of the final XPath result object in xmlXPathCompiledEvalInternal and xmlXPathEval to avoid useless error messages.
This commit is contained in:
92
xpath.c
92
xpath.c
@@ -6296,7 +6296,15 @@ xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
|
|||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
|
xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
|
||||||
|
int i;
|
||||||
|
|
||||||
if (ctxt->valueTab != NULL) {
|
if (ctxt->valueTab != NULL) {
|
||||||
|
for (i = 0; i < ctxt->valueNr; i++) {
|
||||||
|
if (ctxt->context)
|
||||||
|
xmlXPathReleaseObject(ctxt->context, ctxt->valueTab[i]);
|
||||||
|
else
|
||||||
|
xmlXPathFreeObject(ctxt->valueTab[i]);
|
||||||
|
}
|
||||||
xmlFree(ctxt->valueTab);
|
xmlFree(ctxt->valueTab);
|
||||||
}
|
}
|
||||||
if (ctxt->comp != NULL) {
|
if (ctxt->comp != NULL) {
|
||||||
@@ -14926,10 +14934,11 @@ xmlXPathCompile(const xmlChar *str) {
|
|||||||
static int
|
static int
|
||||||
xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
|
xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
|
||||||
xmlXPathContextPtr ctxt,
|
xmlXPathContextPtr ctxt,
|
||||||
xmlXPathObjectPtr *resObj,
|
xmlXPathObjectPtr *resObjPtr,
|
||||||
int toBool)
|
int toBool)
|
||||||
{
|
{
|
||||||
xmlXPathParserContextPtr pctxt;
|
xmlXPathParserContextPtr pctxt;
|
||||||
|
xmlXPathObjectPtr resObj;
|
||||||
#ifndef LIBXML_THREAD_ENABLED
|
#ifndef LIBXML_THREAD_ENABLED
|
||||||
static int reentance = 0;
|
static int reentance = 0;
|
||||||
#endif
|
#endif
|
||||||
@@ -14957,43 +14966,25 @@ xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
|
|||||||
pctxt = xmlXPathCompParserContext(comp, ctxt);
|
pctxt = xmlXPathCompParserContext(comp, ctxt);
|
||||||
res = xmlXPathRunEval(pctxt, toBool);
|
res = xmlXPathRunEval(pctxt, toBool);
|
||||||
|
|
||||||
if (resObj) {
|
if (pctxt->error != XPATH_EXPRESSION_OK) {
|
||||||
if (pctxt->value == NULL) {
|
resObj = NULL;
|
||||||
xmlGenericError(xmlGenericErrorContext,
|
} else {
|
||||||
"xmlXPathCompiledEval: evaluation failed\n");
|
resObj = valuePop(pctxt);
|
||||||
*resObj = NULL;
|
if (resObj == NULL) {
|
||||||
} else {
|
xmlGenericError(xmlGenericErrorContext,
|
||||||
*resObj = valuePop(pctxt);
|
"xmlXPathCompiledEval: No result on the stack.\n");
|
||||||
}
|
} else if (pctxt->valueNr > 0) {
|
||||||
|
xmlGenericError(xmlGenericErrorContext,
|
||||||
|
"xmlXPathCompiledEval: %d object(s) left on the stack.\n",
|
||||||
|
pctxt->valueNr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
if (resObjPtr)
|
||||||
* Pop all remaining objects from the stack.
|
*resObjPtr = resObj;
|
||||||
*/
|
else
|
||||||
if (pctxt->valueNr > 0) {
|
xmlXPathReleaseObject(ctxt, resObj);
|
||||||
xmlXPathObjectPtr tmp;
|
|
||||||
int stack = 0;
|
|
||||||
|
|
||||||
do {
|
|
||||||
tmp = valuePop(pctxt);
|
|
||||||
if (tmp != NULL) {
|
|
||||||
stack++;
|
|
||||||
xmlXPathReleaseObject(ctxt, tmp);
|
|
||||||
}
|
|
||||||
} while (tmp != NULL);
|
|
||||||
if ((stack != 0) &&
|
|
||||||
((toBool) || ((resObj) && (*resObj))))
|
|
||||||
{
|
|
||||||
xmlGenericError(xmlGenericErrorContext,
|
|
||||||
"xmlXPathCompiledEval: %d objects left on the stack.\n",
|
|
||||||
stack);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((pctxt->error != XPATH_EXPRESSION_OK) && (resObj) && (*resObj)) {
|
|
||||||
xmlXPathFreeObject(*resObj);
|
|
||||||
*resObj = NULL;
|
|
||||||
}
|
|
||||||
pctxt->comp = NULL;
|
pctxt->comp = NULL;
|
||||||
xmlXPathFreeParserContext(pctxt);
|
xmlXPathFreeParserContext(pctxt);
|
||||||
#ifndef LIBXML_THREAD_ENABLED
|
#ifndef LIBXML_THREAD_ENABLED
|
||||||
@@ -15093,8 +15084,7 @@ xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
|
|||||||
xmlXPathObjectPtr
|
xmlXPathObjectPtr
|
||||||
xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
|
xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
|
||||||
xmlXPathParserContextPtr ctxt;
|
xmlXPathParserContextPtr ctxt;
|
||||||
xmlXPathObjectPtr res, tmp, init = NULL;
|
xmlXPathObjectPtr res;
|
||||||
int stack = 0;
|
|
||||||
|
|
||||||
CHECK_CTXT(ctx)
|
CHECK_CTXT(ctx)
|
||||||
|
|
||||||
@@ -15105,9 +15095,7 @@ xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
|
|||||||
return NULL;
|
return NULL;
|
||||||
xmlXPathEvalExpr(ctxt);
|
xmlXPathEvalExpr(ctxt);
|
||||||
|
|
||||||
if (ctxt->value == NULL) {
|
if (ctxt->error != XPATH_EXPRESSION_OK) {
|
||||||
xmlGenericError(xmlGenericErrorContext,
|
|
||||||
"xmlXPathEval: evaluation failed\n");
|
|
||||||
res = NULL;
|
res = NULL;
|
||||||
} else if ((*ctxt->cur != 0) && (ctxt->comp != NULL)
|
} else if ((*ctxt->cur != 0) && (ctxt->comp != NULL)
|
||||||
#ifdef XPATH_STREAMING
|
#ifdef XPATH_STREAMING
|
||||||
@@ -15118,24 +15106,14 @@ xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
|
|||||||
res = NULL;
|
res = NULL;
|
||||||
} else {
|
} else {
|
||||||
res = valuePop(ctxt);
|
res = valuePop(ctxt);
|
||||||
}
|
if (res == NULL) {
|
||||||
|
xmlGenericError(xmlGenericErrorContext,
|
||||||
do {
|
"xmlXPathCompiledEval: No result on the stack.\n");
|
||||||
tmp = valuePop(ctxt);
|
} else if (ctxt->valueNr > 0) {
|
||||||
if (tmp != NULL) {
|
xmlGenericError(xmlGenericErrorContext,
|
||||||
if (tmp != init)
|
"xmlXPathCompiledEval: %d object(s) left on the stack.\n",
|
||||||
stack++;
|
ctxt->valueNr);
|
||||||
xmlXPathReleaseObject(ctx, tmp);
|
|
||||||
}
|
}
|
||||||
} while (tmp != NULL);
|
|
||||||
if ((stack != 0) && (res != NULL)) {
|
|
||||||
xmlGenericError(xmlGenericErrorContext,
|
|
||||||
"xmlXPathEval: %d object left on the stack\n",
|
|
||||||
stack);
|
|
||||||
}
|
|
||||||
if (ctxt->error != XPATH_EXPRESSION_OK) {
|
|
||||||
xmlXPathFreeObject(res);
|
|
||||||
res = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
xmlXPathFreeParserContext(ctxt);
|
xmlXPathFreeParserContext(ctxt);
|
||||||
|
|||||||
Reference in New Issue
Block a user