[libxslt] Reuse XPath context when compiling stylesheets
- From: Nick Wellnhofer <nwellnhof src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [libxslt] Reuse XPath context when compiling stylesheets
- Date: Mon, 22 Apr 2019 16:01:39 +0000 (UTC)
commit 4cefab0663a77791f4daba1b0700ac8ad74a150d
Author: Nick Wellnhofer <wellnhofer aevum de>
Date: Mon Apr 22 17:05:29 2019 +0200
Reuse XPath context when compiling stylesheets
Also introduce xsltParseStylesheetUser to parse a stylesheet using
a custom xsltStylesheet struct.
Set XPath resource limits when fuzzing stylesheets.
libxslt/pattern.c | 14 +--
libxslt/xslt.c | 226 ++++++++++++++++++++++++------------------------
libxslt/xsltInternals.h | 16 ++--
libxslt/xsltutils.c | 26 +-----
tests/fuzz/xslt.c | 22 +++--
5 files changed, 142 insertions(+), 162 deletions(-)
---
diff --git a/libxslt/pattern.c b/libxslt/pattern.c
index 55778774..32de1b48 100644
--- a/libxslt/pattern.c
+++ b/libxslt/pattern.c
@@ -342,20 +342,14 @@ xsltCompMatchAdd(xsltParserContextPtr ctxt, xsltCompMatchPtr comp,
xsltAllocateExtra(ctxt->style);
}
if (op == XSLT_OP_PREDICATE) {
- xmlXPathContextPtr xctxt;
+ int flags = 0;
- if (ctxt->style != NULL)
- xctxt = xmlXPathNewContext(ctxt->style->doc);
- else
- xctxt = xmlXPathNewContext(NULL);
#ifdef XML_XPATH_NOVAR
if (novar != 0)
- xctxt->flags = XML_XPATH_NOVAR;
+ flags = XML_XPATH_NOVAR;
#endif
- if (ctxt->style != NULL)
- xctxt->dict = ctxt->style->dict;
- comp->steps[comp->nbStep].comp = xmlXPathCtxtCompile(xctxt, value);
- xmlXPathFreeContext(xctxt);
+ comp->steps[comp->nbStep].comp = xsltXPathCompileFlags(ctxt->style,
+ value, flags);
if (comp->steps[comp->nbStep].comp == NULL) {
xsltTransformError(NULL, ctxt->style, ctxt->elem,
"Failed to compile predicate\n");
diff --git a/libxslt/xslt.c b/libxslt/xslt.c
index 5fda7604..53d43c38 100644
--- a/libxslt/xslt.c
+++ b/libxslt/xslt.c
@@ -592,10 +592,6 @@ xsltCompilationCtxtFree(xsltCompilerCtxtPtr cctxt)
}
if (cctxt->tmpList != NULL)
xsltPointerListFree(cctxt->tmpList);
-#ifdef XSLT_REFACTORED_XPATHCOMP
- if (cctxt->xpathCtxt != NULL)
- xmlXPathFreeContext(cctxt->xpathCtxt);
-#endif
if (cctxt->nsAliases != NULL)
xsltFreeNsAliasList(cctxt->nsAliases);
@@ -631,15 +627,6 @@ xsltCompilationCtxtCreate(xsltStylesheetPtr style) {
if (ret->tmpList == NULL) {
goto internal_err;
}
-#ifdef XSLT_REFACTORED_XPATHCOMP
- /*
- * Create the XPath compilation context in order
- * to speed up precompilation of XPath expressions.
- */
- ret->xpathCtxt = xmlXPathNewContext(NULL);
- if (ret->xpathCtxt == NULL)
- goto internal_err;
-#endif
return(ret);
@@ -761,14 +748,15 @@ internal_err:
#endif
/**
- * xsltNewStylesheet:
+ * xsltNewStylesheetInternal:
+ * @parent: the parent stylesheet or NULL
*
* Create a new XSLT Stylesheet
*
* Returns the newly allocated xsltStylesheetPtr or NULL in case of error
*/
-xsltStylesheetPtr
-xsltNewStylesheet(void) {
+static xsltStylesheetPtr
+xsltNewStylesheetInternal(xsltStylesheetPtr parent) {
xsltStylesheetPtr ret = NULL;
ret = (xsltStylesheetPtr) xmlMalloc(sizeof(xsltStylesheet));
@@ -779,6 +767,7 @@ xsltNewStylesheet(void) {
}
memset(ret, 0, sizeof(xsltStylesheet));
+ ret->parent = parent;
ret->omitXmlDeclaration = -1;
ret->standalone = -1;
ret->decimalFormat = xsltNewDecimalFormat(NULL, NULL);
@@ -799,6 +788,21 @@ xsltNewStylesheet(void) {
"creating dictionary for stylesheet\n");
#endif
+ if (parent == NULL) {
+ ret->principal = ret;
+
+ ret->xpathCtxt = xmlXPathNewContext(NULL);
+ if (ret->xpathCtxt == NULL) {
+ xsltTransformError(NULL, NULL, NULL,
+ "xsltNewStylesheet: xmlXPathNewContext failed\n");
+ goto internal_err;
+ }
+ if (xmlXPathContextSetCache(ret->xpathCtxt, 1, -1, 0) == -1)
+ goto internal_err;
+ } else {
+ ret->principal = parent->principal;
+ }
+
xsltInit();
return(ret);
@@ -809,6 +813,18 @@ internal_err:
return(NULL);
}
+/**
+ * xsltNewStylesheet:
+ *
+ * Create a new XSLT Stylesheet
+ *
+ * Returns the newly allocated xsltStylesheetPtr or NULL in case of error
+ */
+xsltStylesheetPtr
+xsltNewStylesheet(void) {
+ return xsltNewStylesheetInternal(NULL);
+}
+
/**
* xsltAllocateExtra:
* @style: an XSLT stylesheet
@@ -1065,6 +1081,9 @@ xsltFreeStylesheet(xsltStylesheetPtr style)
#endif
xmlDictFree(style->dict);
+ if (style->xpathCtxt != NULL)
+ xmlXPathFreeContext(style->xpathCtxt);
+
memset(style, -1, sizeof(xsltStylesheet));
xmlFree(style);
}
@@ -6532,54 +6551,68 @@ xsltParseStylesheetImportedDoc(xmlDocPtr doc,
if (doc == NULL)
return(NULL);
- retStyle = xsltNewStylesheet();
+ retStyle = xsltNewStylesheetInternal(parentStyle);
if (retStyle == NULL)
return(NULL);
- /*
- * Set the importing stylesheet module; also used to detect recursion.
- */
- retStyle->parent = parentStyle;
+
+ if (xsltParseStylesheetUser(retStyle, doc) != 0) {
+ xsltFreeStylesheet(retStyle);
+ return(NULL);
+ }
+
+ return(retStyle);
+}
+
+/**
+ * xsltParseStylesheetUser:
+ * @doc: an xmlDoc parsed XML
+ * @style: pointer to the stylesheet
+ * @parentStyle: pointer to the parent stylesheet (if it exists)
+ *
+ * Parse an XSLT stylesheet with a user-provided stylesheet struct.
+ *
+ * Returns 0 if successful, -1 in case of error.
+ */
+int
+xsltParseStylesheetUser(xsltStylesheetPtr style, xmlDocPtr doc) {
+ if ((style == NULL) || (doc == NULL))
+ return(-1);
+
/*
* Adjust the string dict.
*/
if (doc->dict != NULL) {
- xmlDictFree(retStyle->dict);
- retStyle->dict = doc->dict;
+ xmlDictFree(style->dict);
+ style->dict = doc->dict;
#ifdef WITH_XSLT_DEBUG
xsltGenericDebug(xsltGenericDebugContext,
"reusing dictionary from %s for stylesheet\n",
doc->URL);
#endif
- xmlDictReference(retStyle->dict);
+ xmlDictReference(style->dict);
}
/*
* TODO: Eliminate xsltGatherNamespaces(); we must not restrict
* the stylesheet to containt distinct namespace prefixes.
*/
- xsltGatherNamespaces(retStyle);
+ xsltGatherNamespaces(style);
#ifdef XSLT_REFACTORED
{
xsltCompilerCtxtPtr cctxt;
xsltStylesheetPtr oldCurSheet;
- if (parentStyle == NULL) {
+ if (style->parent == NULL) {
xsltPrincipalStylesheetDataPtr principalData;
/*
- * Principal stylesheet
- * --------------------
- */
- retStyle->principal = retStyle;
- /*
* Create extra data for the principal stylesheet.
*/
principalData = xsltNewPrincipalStylesheetData();
if (principalData == NULL) {
- xsltFreeStylesheet(retStyle);
- return(NULL);
+ return(-1);
}
- retStyle->principalData = principalData;
+ style->principalData = principalData;
/*
* Create the compilation context
* ------------------------------
@@ -6587,14 +6620,13 @@ xsltParseStylesheetImportedDoc(xmlDocPtr doc,
* This is currently the only function where the
* compilation context is created.
*/
- cctxt = xsltCompilationCtxtCreate(retStyle);
+ cctxt = xsltCompilationCtxtCreate(style);
if (cctxt == NULL) {
- xsltFreeStylesheet(retStyle);
- return(NULL);
+ return(-1);
}
- retStyle->compCtxt = (void *) cctxt;
- cctxt->style = retStyle;
- cctxt->dict = retStyle->dict;
+ style->compCtxt = (void *) cctxt;
+ cctxt->style = style;
+ cctxt->dict = style->dict;
cctxt->psData = principalData;
/*
* Push initial dummy node info.
@@ -6605,22 +6637,21 @@ xsltParseStylesheetImportedDoc(xmlDocPtr doc,
/*
* Imported stylesheet.
*/
- retStyle->principal = parentStyle->principal;
- cctxt = parentStyle->compCtxt;
- retStyle->compCtxt = cctxt;
+ cctxt = style->parent->compCtxt;
+ style->compCtxt = cctxt;
}
/*
* Save the old and set the current stylesheet structure in the
* compilation context.
*/
oldCurSheet = cctxt->style;
- cctxt->style = retStyle;
+ cctxt->style = style;
- retStyle->doc = doc;
- xsltParseStylesheetProcess(retStyle, doc);
+ style->doc = doc;
+ xsltParseStylesheetProcess(style, doc);
cctxt->style = oldCurSheet;
- if (parentStyle == NULL) {
+ if (style->parent == NULL) {
/*
* Pop the initial dummy node info.
*/
@@ -6631,65 +6662,54 @@ xsltParseStylesheetImportedDoc(xmlDocPtr doc,
* stylesheets.
* TODO: really?
*/
- /* retStyle->compCtxt = NULL; */
+ /* style->compCtxt = NULL; */
}
- /*
- * Free the stylesheet if there were errors.
- */
- if (retStyle != NULL) {
- if (retStyle->errors != 0) {
+
#ifdef XSLT_REFACTORED_XSLT_NSCOMP
- /*
- * Restore all changes made to namespace URIs of ns-decls.
- */
- if (cctxt->psData->nsMap)
- xsltRestoreDocumentNamespaces(cctxt->psData->nsMap, doc);
+ if (style->errors != 0) {
+ /*
+ * Restore all changes made to namespace URIs of ns-decls.
+ */
+ if (cctxt->psData->nsMap)
+ xsltRestoreDocumentNamespaces(cctxt->psData->nsMap, doc);
+ }
#endif
- /*
- * Detach the doc from the stylesheet; otherwise the doc
- * will be freed in xsltFreeStylesheet().
- */
- retStyle->doc = NULL;
- /*
- * Cleanup the doc if its the main stylesheet.
- */
- if (parentStyle == NULL) {
- xsltCleanupStylesheetTree(doc, xmlDocGetRootElement(doc));
- if (retStyle->compCtxt != NULL) {
- xsltCompilationCtxtFree(retStyle->compCtxt);
- retStyle->compCtxt = NULL;
- }
- }
- xsltFreeStylesheet(retStyle);
- retStyle = NULL;
- }
- }
+ if (style->parent == NULL) {
+ xsltCompilationCtxtFree(style->compCtxt);
+ style->compCtxt = NULL;
+ }
}
#else /* XSLT_REFACTORED */
/*
* Old behaviour.
*/
- retStyle->doc = doc;
- if (xsltParseStylesheetProcess(retStyle, doc) == NULL) {
- retStyle->doc = NULL;
- xsltFreeStylesheet(retStyle);
- retStyle = NULL;
- }
- if (retStyle != NULL) {
- if (retStyle->errors != 0) {
- retStyle->doc = NULL;
- if (parentStyle == NULL)
- xsltCleanupStylesheetTree(doc,
- xmlDocGetRootElement(doc));
- xsltFreeStylesheet(retStyle);
- retStyle = NULL;
- }
+ style->doc = doc;
+ if (xsltParseStylesheetProcess(style, doc) == NULL) {
+ style->doc = NULL;
+ return(-1);
}
#endif /* else of XSLT_REFACTORED */
- return(retStyle);
+ if (style->errors != 0) {
+ /*
+ * Detach the doc from the stylesheet; otherwise the doc
+ * will be freed in xsltFreeStylesheet().
+ */
+ style->doc = NULL;
+ /*
+ * Cleanup the doc if its the main stylesheet.
+ */
+ if (style->parent == NULL)
+ xsltCleanupStylesheetTree(doc, xmlDocGetRootElement(doc));
+ return(-1);
+ }
+
+ if (style->parent == NULL)
+ xsltResolveStylesheetAttributeSet(style);
+
+ return(0);
}
/**
@@ -6707,27 +6727,9 @@ xsltParseStylesheetImportedDoc(xmlDocPtr doc,
xsltStylesheetPtr
xsltParseStylesheetDoc(xmlDocPtr doc) {
- xsltStylesheetPtr ret;
-
xsltInitGlobals();
- ret = xsltParseStylesheetImportedDoc(doc, NULL);
- if (ret == NULL)
- return(NULL);
-
- xsltResolveStylesheetAttributeSet(ret);
-#ifdef XSLT_REFACTORED
- /*
- * Free the compilation context.
- * TODO: Check if it's better to move this cleanup to
- * xsltParseStylesheetImportedDoc().
- */
- if (ret->compCtxt != NULL) {
- xsltCompilationCtxtFree(XSLT_CCTXT(ret));
- ret->compCtxt = NULL;
- }
-#endif
- return(ret);
+ return(xsltParseStylesheetImportedDoc(doc, NULL));
}
/**
diff --git a/libxslt/xsltInternals.h b/libxslt/xsltInternals.h
index f9066adc..464c5cd9 100644
--- a/libxslt/xsltInternals.h
+++ b/libxslt/xsltInternals.h
@@ -105,14 +105,6 @@ extern const xmlChar *xsltXSLTAttrMarker;
*/
/* #define XSLT_REFACTORED_XSLT_NSCOMP */
-/**
- * XSLT_REFACTORED_XPATHCOMP:
- *
- * Internal define to enable the optimization of the
- * compilation of XPath expressions.
- */
-#define XSLT_REFACTORED_XPATHCOMP
-
#ifdef XSLT_REFACTORED_XSLT_NSCOMP
extern const xmlChar *xsltConstNamespaceNameXSLT;
@@ -1346,9 +1338,6 @@ struct _xsltCompilerCtxt {
*/
int strict;
xsltPrincipalStylesheetDataPtr psData;
-#ifdef XSLT_REFACTORED_XPATHCOMP
- xmlXPathContextPtr xpathCtxt;
-#endif
xsltStyleItemUknownPtr unknownItem;
int hasNsAliases; /* Indicator if there was an xsl:namespace-alias. */
xsltNsAliasPtr nsAliases;
@@ -1642,6 +1631,8 @@ struct _xsltStylesheet {
int forwards_compatible;
xmlHashTablePtr namedTemplates; /* hash table of named templates */
+
+ xmlXPathContextPtr xpathCtxt;
};
typedef struct _xsltTransformCache xsltTransformCache;
@@ -1871,6 +1862,9 @@ XSLTPUBFUN xsltStylesheetPtr XSLTCALL
XSLTPUBFUN xsltStylesheetPtr XSLTCALL
xsltParseStylesheetImportedDoc(xmlDocPtr doc,
xsltStylesheetPtr style);
+XSLTPUBFUN int XSLTCALL
+ xsltParseStylesheetUser(xsltStylesheetPtr style,
+ xmlDocPtr doc);
XSLTPUBFUN xsltStylesheetPtr XSLTCALL
xsltLoadStylesheetPI (xmlDocPtr doc);
XSLTPUBFUN void XSLTCALL
diff --git a/libxslt/xsltutils.c b/libxslt/xsltutils.c
index adefde98..61f5c25d 100644
--- a/libxslt/xsltutils.c
+++ b/libxslt/xsltutils.c
@@ -2288,25 +2288,7 @@ xsltXPathCompileFlags(xsltStylesheetPtr style, const xmlChar *str, int flags) {
xmlXPathCompExprPtr ret;
if (style != NULL) {
-#ifdef XSLT_REFACTORED_XPATHCOMP
- if (XSLT_CCTXT(style)) {
- /*
- * Proposed by Jerome Pesenti
- * --------------------------
- * For better efficiency we'll reuse the compilation
- * context's XPath context. For the common stylesheet using
- * XPath expressions this will reduce compilation time to
- * about 50%.
- *
- * See http://mail.gnome.org/archives/xslt/2006-April/msg00037.html
- */
- xpathCtxt = XSLT_CCTXT(style)->xpathCtxt;
- xpathCtxt->doc = style->doc;
- } else
- xpathCtxt = xmlXPathNewContext(style->doc);
-#else
- xpathCtxt = xmlXPathNewContext(style->doc);
-#endif
+ xpathCtxt = style->principal->xpathCtxt;
if (xpathCtxt == NULL)
return NULL;
xpathCtxt->dict = style->dict;
@@ -2322,13 +2304,9 @@ xsltXPathCompileFlags(xsltStylesheetPtr style, const xmlChar *str, int flags) {
*/
ret = xmlXPathCtxtCompile(xpathCtxt, str);
-#ifdef XSLT_REFACTORED_XPATHCOMP
- if ((style == NULL) || (! XSLT_CCTXT(style))) {
+ if (style == NULL) {
xmlXPathFreeContext(xpathCtxt);
}
-#else
- xmlXPathFreeContext(xpathCtxt);
-#endif
/*
* TODO: there is a lot of optimizations which should be possible
* like variable slot precomputations, function precomputations, etc.
diff --git a/tests/fuzz/xslt.c b/tests/fuzz/xslt.c
index db3d45ca..0520550d 100644
--- a/tests/fuzz/xslt.c
+++ b/tests/fuzz/xslt.c
@@ -79,6 +79,13 @@ LLVMFuzzerInitialize(int *argc_p ATTRIBUTE_UNUSED,
return 0;
}
+static void
+xsltSetXPathResourceLimits(xmlXPathContextPtr ctxt) {
+ ctxt->maxParserDepth = 15;
+ ctxt->maxDepth = 100;
+ ctxt->opLimit = 100000;
+}
+
int
LLVMFuzzerTestOneInput(const char *data, size_t size) {
xmlDocPtr xsltDoc;
@@ -101,19 +108,24 @@ LLVMFuzzerTestOneInput(const char *data, size_t size) {
xmlNewNs(xsltRoot, EXSLT_STRINGS_NAMESPACE, BAD_CAST "str");
xmlNewNs(xsltRoot, SAXON_NAMESPACE, BAD_CAST "saxon");
- sheet = xsltParseStylesheetDoc(xsltDoc);
+ sheet = xsltNewStylesheet();
if (sheet == NULL) {
xmlFreeDoc(xsltDoc);
return 0;
}
+ xsltSetXPathResourceLimits(sheet->xpathCtxt);
+ sheet->xpathCtxt->opCount = 0;
+ if (xsltParseStylesheetUser(sheet, xsltDoc) != 0) {
+ xsltFreeStylesheet(sheet);
+ xmlFreeDoc(xsltDoc);
+ return 0;
+ }
ctxt = xsltNewTransformContext(sheet, doc);
xsltSetCtxtSecurityPrefs(sec, ctxt);
ctxt->maxTemplateDepth = 100;
- ctxt->xpathCtxt->maxParserDepth = 15;
- ctxt->xpathCtxt->maxDepth = 100;
- ctxt->xpathCtxt->opCount = 0;
- ctxt->xpathCtxt->opLimit = 100000;
+ xsltSetXPathResourceLimits(ctxt->xpathCtxt);
+ ctxt->xpathCtxt->opCount = sheet->xpathCtxt->opCount;
result = xsltApplyStylesheetUser(sheet, doc, NULL, NULL, NULL, ctxt);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]