summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNick Wellnhofer <wellnhofer@aevum.de>2018-09-26 23:20:48 +0200
committerNick Wellnhofer <wellnhofer@aevum.de>2018-09-26 23:20:48 +0200
commit5e16672db1188accbde737f0add01213ffed107e (patch)
tree241fdcd4dcef19291a231fcfbbe1b58ec8e8dddd
parentdfa1bdceaef73a404d1c6efe58c3618493b36afb (diff)
downloadlibxslt-5e16672db1188accbde737f0add01213ffed107e.tar.gz
Move function result RVTs to context variable
If a variable with a "select" expression calls an EXSLT func:function, the context variable must be restored before evaluating the function result. This makes sure that the RVTs in the result will be moved to the context variable's fragment list when they're released in xsltReleaseLocalRVTs or xsltReleaseLocalRVTs. Thanks to Nikolai Weibull for the report.
-rw-r--r--libexslt/functions.c23
-rw-r--r--libxslt/transform.c25
-rw-r--r--tests/docs/bug-212.xml1
-rw-r--r--tests/docs/bug-213.xml1
-rw-r--r--tests/general/bug-212.out1
-rw-r--r--tests/general/bug-212.xsl25
-rw-r--r--tests/general/bug-213.out1
-rw-r--r--tests/general/bug-213.xsl26
8 files changed, 78 insertions, 25 deletions
diff --git a/libexslt/functions.c b/libexslt/functions.c
index b7b968f8..60056717 100644
--- a/libexslt/functions.c
+++ b/libexslt/functions.c
@@ -34,6 +34,7 @@ typedef struct _exsltFuncData exsltFuncData;
struct _exsltFuncData {
xmlHashTablePtr funcs; /* pointer to the stylesheet module data */
xmlXPathObjectPtr result; /* returned by func:result */
+ xsltStackElemPtr ctxtVar; /* context variable */
int error; /* did an error occur? */
};
@@ -426,28 +427,23 @@ exsltFuncFunctionFunction (xmlXPathParserContextPtr ctxt, int nargs) {
}
}
/*
- * Actual processing. Note that contextVariable is set to NULL which
- * means that RVTs returned from functions always end up as local RVTs,
- * not as variable fragments if the function is called in the select
- * expression of an xsl:variable. This is a hack that only works because
- * xsltReleaseLocalRVTs isn't called after processing xsl:variable.
- *
- * It would probably be better to remove the fragile contextVariable
- * logic and make xsltEvalVariable move the required RVTs into the
- * variable manually.
+ * Actual processing. The context variable is cleared and restored
+ * when func:result is evaluated.
*/
fake = xmlNewDocNode(tctxt->output, NULL,
(const xmlChar *)"fake", NULL);
oldInsert = tctxt->insert;
- oldCtxtVar = tctxt->contextVariable;
+ oldCtxtVar = data->ctxtVar;
+ data->ctxtVar = tctxt->contextVariable;
tctxt->insert = fake;
tctxt->contextVariable = NULL;
xsltApplyOneTemplate (tctxt, tctxt->node,
func->content, NULL, NULL);
xsltLocalVariablePop(tctxt, tctxt->varsBase, -2);
tctxt->insert = oldInsert;
- tctxt->contextVariable = oldCtxtVar;
+ tctxt->contextVariable = data->ctxtVar;
tctxt->varsBase = oldBase; /* restore original scope */
+ data->ctxtVar = oldCtxtVar;
if (params != NULL)
xsltFreeStackElemList(params);
@@ -715,6 +711,11 @@ exsltFuncResultElem (xsltTransformContextPtr ctxt,
return;
}
/*
+ * Restore context variable, so that it will receive the function
+ * result RVTs.
+ */
+ ctxt->contextVariable = data->ctxtVar;
+ /*
* Processing
*/
if (comp->select != NULL) {
diff --git a/libxslt/transform.c b/libxslt/transform.c
index d7af31f1..ed5afacb 100644
--- a/libxslt/transform.c
+++ b/libxslt/transform.c
@@ -2295,13 +2295,17 @@ static void
xsltReleaseLocalRVTs(xsltTransformContextPtr ctxt, xmlDocPtr base)
{
xmlDocPtr cur = ctxt->localRVT, tmp;
- xmlDocPtr prev = NULL;
if (cur == base)
return;
if (cur->prev != NULL)
xsltTransformError(ctxt, NULL, NULL, "localRVT not head of list\n");
+ /* Reset localRVT early because some RVTs might be registered again. */
+ ctxt->localRVT = base;
+ if (base != NULL)
+ base->prev = NULL;
+
do {
tmp = cur;
cur = (xmlDocPtr) cur->next;
@@ -2310,25 +2314,18 @@ xsltReleaseLocalRVTs(xsltTransformContextPtr ctxt, xmlDocPtr base)
} else if (tmp->psvi == XSLT_RVT_GLOBAL) {
xsltRegisterPersistRVT(ctxt, tmp);
} else if (tmp->psvi == XSLT_RVT_FUNC_RESULT) {
- if (prev == NULL)
- ctxt->localRVT = tmp;
- else
- prev->next = (xmlNodePtr) tmp;
- tmp->prev = (xmlNodePtr) prev;
- prev = tmp;
+ /*
+ * This will either register the RVT again or move it to the
+ * context variable.
+ */
+ xsltRegisterLocalRVT(ctxt, tmp);
+ tmp->psvi = XSLT_RVT_FUNC_RESULT;
} else {
xmlGenericError(xmlGenericErrorContext,
"xsltReleaseLocalRVTs: Unexpected RVT flag %p\n",
tmp->psvi);
}
} while (cur != base);
-
- if (prev == NULL)
- ctxt->localRVT = base;
- else
- prev->next = (xmlNodePtr) base;
- if (base != NULL)
- base->prev = (xmlNodePtr) prev;
}
/**
diff --git a/tests/docs/bug-212.xml b/tests/docs/bug-212.xml
new file mode 100644
index 00000000..69d62f2c
--- /dev/null
+++ b/tests/docs/bug-212.xml
@@ -0,0 +1 @@
+<doc/>
diff --git a/tests/docs/bug-213.xml b/tests/docs/bug-213.xml
new file mode 100644
index 00000000..69d62f2c
--- /dev/null
+++ b/tests/docs/bug-213.xml
@@ -0,0 +1 @@
+<doc/>
diff --git a/tests/general/bug-212.out b/tests/general/bug-212.out
new file mode 100644
index 00000000..13d91365
--- /dev/null
+++ b/tests/general/bug-212.out
@@ -0,0 +1 @@
+a,a
diff --git a/tests/general/bug-212.xsl b/tests/general/bug-212.xsl
new file mode 100644
index 00000000..d8471c4e
--- /dev/null
+++ b/tests/general/bug-212.xsl
@@ -0,0 +1,25 @@
+<xsl:stylesheet version="1.0"
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:func="http://exslt.org/functions"
+ xmlns:a="a"
+ extension-element-prefixes="func">
+<xsl:output method="text" encoding="UTF-8"/>
+
+<func:function name="a:a">
+ <func:result>
+ <xsl:apply-templates mode="a"/>
+ </func:result>
+</func:function>
+
+<xsl:template mode="a" match="node()">
+ <xsl:text>a</xsl:text>
+</xsl:template>
+
+<xsl:template match="/">
+ <xsl:variable name="a" select="a:a()"/>
+ <xsl:value-of select="$a"/>
+ <xsl:text>,</xsl:text>
+ <xsl:value-of select="$a"/>
+ <xsl:text>&#x0a;</xsl:text>
+</xsl:template>
+</xsl:stylesheet>
diff --git a/tests/general/bug-213.out b/tests/general/bug-213.out
new file mode 100644
index 00000000..13d91365
--- /dev/null
+++ b/tests/general/bug-213.out
@@ -0,0 +1 @@
+a,a
diff --git a/tests/general/bug-213.xsl b/tests/general/bug-213.xsl
new file mode 100644
index 00000000..cfad3c51
--- /dev/null
+++ b/tests/general/bug-213.xsl
@@ -0,0 +1,26 @@
+<xsl:stylesheet version="1.0"
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:func="http://exslt.org/functions"
+ xmlns:a="a"
+ extension-element-prefixes="func">
+<xsl:output method="text" encoding="UTF-8"/>
+
+<func:function name="a:a">
+ <xsl:variable name="v">
+ <xsl:apply-templates mode="a"/>
+ </xsl:variable>
+ <func:result select="$v"/>
+</func:function>
+
+<xsl:template mode="a" match="node()">
+ <xsl:text>a</xsl:text>
+</xsl:template>
+
+<xsl:template match="/">
+ <xsl:variable name="a" select="a:a()"/>
+ <xsl:value-of select="$a"/>
+ <xsl:text>,</xsl:text>
+ <xsl:value-of select="$a"/>
+ <xsl:text>&#x0a;</xsl:text>
+</xsl:template>
+</xsl:stylesheet>