|
|
4607f9 |
From 7d81bd62d5788a9e2931c20a3d0a6be7e703c608 Mon Sep 17 00:00:00 2001
|
|
|
4607f9 |
From: Nick Wellnhofer <wellnhofer@aevum.de>
|
|
|
4607f9 |
Date: Mon, 23 Jul 2018 22:52:12 +0200
|
|
|
4607f9 |
Subject: [PATCH] Fix EXSLT functions returning RVTs from outer scopes
|
|
|
4607f9 |
|
|
|
4607f9 |
The RVTs referenced from function results must not be blindly registered
|
|
|
4607f9 |
as local, as they might be part of variables from an outer scope. Remove
|
|
|
4607f9 |
LOCAL/VARIABLE distinction for RVTs. Don't register as local RVT
|
|
|
4607f9 |
unconditionally when reflagging as LOCAL. Instead, register function
|
|
|
4607f9 |
result RVTs from inner variables as local RVTs when they're released in
|
|
|
4607f9 |
xsltFreeStackElem. Keep local function result RVTs xsltReleaseLocalRVTs
|
|
|
4607f9 |
instead of reregistering.
|
|
|
4607f9 |
|
|
|
4607f9 |
Closes: https://gitlab.gnome.org/GNOME/libxslt/issues/2
|
|
|
4607f9 |
|
|
|
4607f9 |
Thanks to Daniel Mendler and Martin Gieseking for the reports.
|
|
|
4607f9 |
---
|
|
|
4607f9 |
libexslt/functions.c | 11 ++++++++++-
|
|
|
4607f9 |
libxslt/transform.c | 17 ++++++++++++++---
|
|
|
4607f9 |
libxslt/variables.c | 27 +++++++++++----------------
|
|
|
4607f9 |
libxslt/variables.h | 12 ++----------
|
|
|
4607f9 |
tests/docs/bug-210.xml | 1 +
|
|
|
4607f9 |
tests/docs/bug-211.xml | 1 +
|
|
|
4607f9 |
tests/general/bug-210.out | 2 ++
|
|
|
4607f9 |
tests/general/bug-210.xsl | 20 ++++++++++++++++++++
|
|
|
4607f9 |
tests/general/bug-211.out | 2 ++
|
|
|
4607f9 |
tests/general/bug-211.xsl | 26 ++++++++++++++++++++++++++
|
|
|
4607f9 |
10 files changed, 89 insertions(+), 30 deletions(-)
|
|
|
4607f9 |
create mode 100644 tests/docs/bug-210.xml
|
|
|
4607f9 |
create mode 100644 tests/docs/bug-211.xml
|
|
|
4607f9 |
create mode 100644 tests/general/bug-210.out
|
|
|
4607f9 |
create mode 100644 tests/general/bug-210.xsl
|
|
|
4607f9 |
create mode 100644 tests/general/bug-211.out
|
|
|
4607f9 |
create mode 100644 tests/general/bug-211.xsl
|
|
|
4607f9 |
|
|
|
4607f9 |
diff --git a/libexslt/functions.c b/libexslt/functions.c
|
|
|
4607f9 |
index 2b83ca34..b7b968f8 100644
|
|
|
4607f9 |
--- a/libexslt/functions.c
|
|
|
4607f9 |
+++ b/libexslt/functions.c
|
|
|
4607f9 |
@@ -426,7 +426,15 @@ exsltFuncFunctionFunction (xmlXPathParserContextPtr ctxt, int nargs) {
|
|
|
4607f9 |
}
|
|
|
4607f9 |
}
|
|
|
4607f9 |
/*
|
|
|
4607f9 |
- * actual processing
|
|
|
4607f9 |
+ * Actual processing. Note that contextVariable is set to NULL which
|
|
|
4607f9 |
+ * means that RVTs returned from functions always end up as local RVTs,
|
|
|
4607f9 |
+ * not as variable fragments if the function is called in the select
|
|
|
4607f9 |
+ * expression of an xsl:variable. This is a hack that only works because
|
|
|
4607f9 |
+ * xsltReleaseLocalRVTs isn't called after processing xsl:variable.
|
|
|
4607f9 |
+ *
|
|
|
4607f9 |
+ * It would probably be better to remove the fragile contextVariable
|
|
|
4607f9 |
+ * logic and make xsltEvalVariable move the required RVTs into the
|
|
|
4607f9 |
+ * variable manually.
|
|
|
4607f9 |
*/
|
|
|
4607f9 |
fake = xmlNewDocNode(tctxt->output, NULL,
|
|
|
4607f9 |
(const xmlChar *)"fake", NULL);
|
|
|
4607f9 |
@@ -766,6 +774,7 @@ exsltFuncResultElem (xsltTransformContextPtr ctxt,
|
|
|
4607f9 |
return;
|
|
|
4607f9 |
}
|
|
|
4607f9 |
/* Mark as function result. */
|
|
|
4607f9 |
+ xsltRegisterLocalRVT(ctxt, container);
|
|
|
4607f9 |
container->psvi = XSLT_RVT_FUNC_RESULT;
|
|
|
4607f9 |
|
|
|
4607f9 |
oldInsert = ctxt->insert;
|
|
|
4607f9 |
diff --git a/libxslt/transform.c b/libxslt/transform.c
|
|
|
4607f9 |
index 90d2731d..d7af31f1 100644
|
|
|
4607f9 |
--- a/libxslt/transform.c
|
|
|
4607f9 |
+++ b/libxslt/transform.c
|
|
|
4607f9 |
@@ -2295,6 +2295,7 @@ static void
|
|
|
4607f9 |
xsltReleaseLocalRVTs(xsltTransformContextPtr ctxt, xmlDocPtr base)
|
|
|
4607f9 |
{
|
|
|
4607f9 |
xmlDocPtr cur = ctxt->localRVT, tmp;
|
|
|
4607f9 |
+ xmlDocPtr prev = NULL;
|
|
|
4607f9 |
|
|
|
4607f9 |
if (cur == base)
|
|
|
4607f9 |
return;
|
|
|
4607f9 |
@@ -2308,16 +2309,26 @@ xsltReleaseLocalRVTs(xsltTransformContextPtr ctxt, xmlDocPtr base)
|
|
|
4607f9 |
xsltReleaseRVT(ctxt, tmp);
|
|
|
4607f9 |
} else if (tmp->psvi == XSLT_RVT_GLOBAL) {
|
|
|
4607f9 |
xsltRegisterPersistRVT(ctxt, tmp);
|
|
|
4607f9 |
- } else if (tmp->psvi != XSLT_RVT_FUNC_RESULT) {
|
|
|
4607f9 |
+ } else if (tmp->psvi == XSLT_RVT_FUNC_RESULT) {
|
|
|
4607f9 |
+ if (prev == NULL)
|
|
|
4607f9 |
+ ctxt->localRVT = tmp;
|
|
|
4607f9 |
+ else
|
|
|
4607f9 |
+ prev->next = (xmlNodePtr) tmp;
|
|
|
4607f9 |
+ tmp->prev = (xmlNodePtr) prev;
|
|
|
4607f9 |
+ prev = tmp;
|
|
|
4607f9 |
+ } else {
|
|
|
4607f9 |
xmlGenericError(xmlGenericErrorContext,
|
|
|
4607f9 |
"xsltReleaseLocalRVTs: Unexpected RVT flag %p\n",
|
|
|
4607f9 |
tmp->psvi);
|
|
|
4607f9 |
}
|
|
|
4607f9 |
} while (cur != base);
|
|
|
4607f9 |
|
|
|
4607f9 |
+ if (prev == NULL)
|
|
|
4607f9 |
+ ctxt->localRVT = base;
|
|
|
4607f9 |
+ else
|
|
|
4607f9 |
+ prev->next = (xmlNodePtr) base;
|
|
|
4607f9 |
if (base != NULL)
|
|
|
4607f9 |
- base->prev = NULL;
|
|
|
4607f9 |
- ctxt->localRVT = base;
|
|
|
4607f9 |
+ base->prev = (xmlNodePtr) prev;
|
|
|
4607f9 |
}
|
|
|
4607f9 |
|
|
|
4607f9 |
/**
|
|
|
4607f9 |
diff --git a/libxslt/variables.c b/libxslt/variables.c
|
|
|
4607f9 |
index fe6f299c..8f88e573 100644
|
|
|
4607f9 |
--- a/libxslt/variables.c
|
|
|
4607f9 |
+++ b/libxslt/variables.c
|
|
|
4607f9 |
@@ -123,7 +123,7 @@ xsltRegisterTmpRVT(xsltTransformContextPtr ctxt, xmlDocPtr RVT)
|
|
|
4607f9 |
return(-1);
|
|
|
4607f9 |
|
|
|
4607f9 |
RVT->prev = NULL;
|
|
|
4607f9 |
- RVT->psvi = XSLT_RVT_VARIABLE;
|
|
|
4607f9 |
+ RVT->psvi = XSLT_RVT_LOCAL;
|
|
|
4607f9 |
|
|
|
4607f9 |
/*
|
|
|
4607f9 |
* We'll restrict the lifetime of user-created fragments
|
|
|
4607f9 |
@@ -163,6 +163,7 @@ xsltRegisterLocalRVT(xsltTransformContextPtr ctxt,
|
|
|
4607f9 |
return(-1);
|
|
|
4607f9 |
|
|
|
4607f9 |
RVT->prev = NULL;
|
|
|
4607f9 |
+ RVT->psvi = XSLT_RVT_LOCAL;
|
|
|
4607f9 |
|
|
|
4607f9 |
/*
|
|
|
4607f9 |
* When evaluating "select" expressions of xsl:variable
|
|
|
4607f9 |
@@ -173,7 +174,6 @@ xsltRegisterLocalRVT(xsltTransformContextPtr ctxt,
|
|
|
4607f9 |
if ((ctxt->contextVariable != NULL) &&
|
|
|
4607f9 |
(XSLT_TCTXT_VARIABLE(ctxt)->flags & XSLT_VAR_IN_SELECT))
|
|
|
4607f9 |
{
|
|
|
4607f9 |
- RVT->psvi = XSLT_RVT_VARIABLE;
|
|
|
4607f9 |
RVT->next = (xmlNodePtr) XSLT_TCTXT_VARIABLE(ctxt)->fragment;
|
|
|
4607f9 |
XSLT_TCTXT_VARIABLE(ctxt)->fragment = RVT;
|
|
|
4607f9 |
return(0);
|
|
|
4607f9 |
@@ -183,7 +183,6 @@ xsltRegisterLocalRVT(xsltTransformContextPtr ctxt,
|
|
|
4607f9 |
* If not reference by a returning instruction (like EXSLT's function),
|
|
|
4607f9 |
* then this fragment will be freed, when the instruction exits.
|
|
|
4607f9 |
*/
|
|
|
4607f9 |
- RVT->psvi = XSLT_RVT_LOCAL;
|
|
|
4607f9 |
RVT->next = (xmlNodePtr) ctxt->localRVT;
|
|
|
4607f9 |
if (ctxt->localRVT != NULL)
|
|
|
4607f9 |
ctxt->localRVT->prev = (xmlNodePtr) RVT;
|
|
|
4607f9 |
@@ -314,14 +313,8 @@ xsltFlagRVTs(xsltTransformContextPtr ctxt, xmlXPathObjectPtr obj, void *val) {
|
|
|
4607f9 |
#endif
|
|
|
4607f9 |
|
|
|
4607f9 |
if (val == XSLT_RVT_LOCAL) {
|
|
|
4607f9 |
- if (doc->psvi != XSLT_RVT_FUNC_RESULT) {
|
|
|
4607f9 |
- xmlGenericError(xmlGenericErrorContext,
|
|
|
4607f9 |
- "xsltFlagRVTs: Invalid transition %p => LOCAL\n",
|
|
|
4607f9 |
- doc->psvi);
|
|
|
4607f9 |
- return(-1);
|
|
|
4607f9 |
- }
|
|
|
4607f9 |
-
|
|
|
4607f9 |
- xsltRegisterLocalRVT(ctxt, doc);
|
|
|
4607f9 |
+ if (doc->psvi == XSLT_RVT_FUNC_RESULT)
|
|
|
4607f9 |
+ doc->psvi = XSLT_RVT_LOCAL;
|
|
|
4607f9 |
} else if (val == XSLT_RVT_GLOBAL) {
|
|
|
4607f9 |
if (doc->psvi != XSLT_RVT_LOCAL) {
|
|
|
4607f9 |
xmlGenericError(xmlGenericErrorContext,
|
|
|
4607f9 |
@@ -585,10 +578,12 @@ xsltFreeStackElem(xsltStackElemPtr elem) {
|
|
|
4607f9 |
cur = elem->fragment;
|
|
|
4607f9 |
elem->fragment = (xmlDocPtr) cur->next;
|
|
|
4607f9 |
|
|
|
4607f9 |
- if (cur->psvi == XSLT_RVT_VARIABLE) {
|
|
|
4607f9 |
- xsltReleaseRVT((xsltTransformContextPtr) elem->context,
|
|
|
4607f9 |
- cur);
|
|
|
4607f9 |
- } else if (cur->psvi != XSLT_RVT_FUNC_RESULT) {
|
|
|
4607f9 |
+ if (cur->psvi == XSLT_RVT_LOCAL) {
|
|
|
4607f9 |
+ xsltReleaseRVT(elem->context, cur);
|
|
|
4607f9 |
+ } else if (cur->psvi == XSLT_RVT_FUNC_RESULT) {
|
|
|
4607f9 |
+ xsltRegisterLocalRVT(elem->context, cur);
|
|
|
4607f9 |
+ cur->psvi = XSLT_RVT_FUNC_RESULT;
|
|
|
4607f9 |
+ } else {
|
|
|
4607f9 |
xmlGenericError(xmlGenericErrorContext,
|
|
|
4607f9 |
"xsltFreeStackElem: Unexpected RVT flag %p\n",
|
|
|
4607f9 |
cur->psvi);
|
|
|
4607f9 |
@@ -992,7 +987,7 @@ xsltEvalVariable(xsltTransformContextPtr ctxt, xsltStackElemPtr variable,
|
|
|
4607f9 |
* the Result Tree Fragment.
|
|
|
4607f9 |
*/
|
|
|
4607f9 |
variable->fragment = container;
|
|
|
4607f9 |
- container->psvi = XSLT_RVT_VARIABLE;
|
|
|
4607f9 |
+ container->psvi = XSLT_RVT_LOCAL;
|
|
|
4607f9 |
|
|
|
4607f9 |
oldOutput = ctxt->output;
|
|
|
4607f9 |
oldInsert = ctxt->insert;
|
|
|
4607f9 |
diff --git a/libxslt/variables.h b/libxslt/variables.h
|
|
|
4607f9 |
index 24acf8d1..039288fb 100644
|
|
|
4607f9 |
--- a/libxslt/variables.h
|
|
|
4607f9 |
+++ b/libxslt/variables.h
|
|
|
4607f9 |
@@ -45,14 +45,6 @@ extern "C" {
|
|
|
4607f9 |
*/
|
|
|
4607f9 |
#define XSLT_RVT_LOCAL ((void *)1)
|
|
|
4607f9 |
|
|
|
4607f9 |
-/**
|
|
|
4607f9 |
- * XSLT_RVT_VARIABLE:
|
|
|
4607f9 |
- *
|
|
|
4607f9 |
- * RVT is part of a local variable and destroyed after the variable goes out
|
|
|
4607f9 |
- * of scope.
|
|
|
4607f9 |
- */
|
|
|
4607f9 |
-#define XSLT_RVT_VARIABLE ((void *)2)
|
|
|
4607f9 |
-
|
|
|
4607f9 |
/**
|
|
|
4607f9 |
* XSLT_RVT_FUNC_RESULT:
|
|
|
4607f9 |
*
|
|
|
4607f9 |
@@ -60,14 +52,14 @@ extern "C" {
|
|
|
4607f9 |
* destroyed after exiting a template and will be reset to XSLT_RVT_LOCAL or
|
|
|
4607f9 |
* XSLT_RVT_VARIABLE in the template that receives the return value.
|
|
|
4607f9 |
*/
|
|
|
4607f9 |
-#define XSLT_RVT_FUNC_RESULT ((void *)3)
|
|
|
4607f9 |
+#define XSLT_RVT_FUNC_RESULT ((void *)2)
|
|
|
4607f9 |
|
|
|
4607f9 |
/**
|
|
|
4607f9 |
* XSLT_RVT_GLOBAL:
|
|
|
4607f9 |
*
|
|
|
4607f9 |
* RVT is part of a global variable.
|
|
|
4607f9 |
*/
|
|
|
4607f9 |
-#define XSLT_RVT_GLOBAL ((void *)4)
|
|
|
4607f9 |
+#define XSLT_RVT_GLOBAL ((void *)3)
|
|
|
4607f9 |
|
|
|
4607f9 |
/*
|
|
|
4607f9 |
* Interfaces for the variable module.
|
|
|
4607f9 |
diff --git a/tests/docs/bug-210.xml b/tests/docs/bug-210.xml
|
|
|
4607f9 |
new file mode 100644
|
|
|
4607f9 |
index 00000000..69d62f2c
|
|
|
4607f9 |
--- /dev/null
|
|
|
4607f9 |
+++ b/tests/docs/bug-210.xml
|
|
|
4607f9 |
@@ -0,0 +1 @@
|
|
|
4607f9 |
+<doc/>
|
|
|
4607f9 |
diff --git a/tests/docs/bug-211.xml b/tests/docs/bug-211.xml
|
|
|
4607f9 |
new file mode 100644
|
|
|
4607f9 |
index 00000000..69d62f2c
|
|
|
4607f9 |
--- /dev/null
|
|
|
4607f9 |
+++ b/tests/docs/bug-211.xml
|
|
|
4607f9 |
@@ -0,0 +1 @@
|
|
|
4607f9 |
+<doc/>
|
|
|
4607f9 |
diff --git a/tests/general/bug-210.out b/tests/general/bug-210.out
|
|
|
4607f9 |
new file mode 100644
|
|
|
4607f9 |
index 00000000..445906d6
|
|
|
4607f9 |
--- /dev/null
|
|
|
4607f9 |
+++ b/tests/general/bug-210.out
|
|
|
4607f9 |
@@ -0,0 +1,2 @@
|
|
|
4607f9 |
+
|
|
|
4607f9 |
+value
|
|
|
4607f9 |
diff --git a/tests/general/bug-210.xsl b/tests/general/bug-210.xsl
|
|
|
4607f9 |
new file mode 100644
|
|
|
4607f9 |
index 00000000..1915171d
|
|
|
4607f9 |
--- /dev/null
|
|
|
4607f9 |
+++ b/tests/general/bug-210.xsl
|
|
|
4607f9 |
@@ -0,0 +1,20 @@
|
|
|
4607f9 |
+
|
|
|
4607f9 |
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
|
|
4607f9 |
+ xmlns:exsl="http://exslt.org/common"
|
|
|
4607f9 |
+ xmlns:func="http://exslt.org/functions"
|
|
|
4607f9 |
+ xmlns:my="my-namespace"
|
|
|
4607f9 |
+ extension-element-prefixes="exsl func">
|
|
|
4607f9 |
+
|
|
|
4607f9 |
+<xsl:template match="/">
|
|
|
4607f9 |
+ <xsl:variable name="var">
|
|
|
4607f9 |
+ value
|
|
|
4607f9 |
+ </xsl:variable>
|
|
|
4607f9 |
+ <xsl:copy-of select="my:func($var)"/>
|
|
|
4607f9 |
+</xsl:template>
|
|
|
4607f9 |
+
|
|
|
4607f9 |
+<func:function name="my:func">
|
|
|
4607f9 |
+ <xsl:param name="var"/>
|
|
|
4607f9 |
+ <func:result select="$var"/>
|
|
|
4607f9 |
+</func:function>
|
|
|
4607f9 |
+
|
|
|
4607f9 |
+</xsl:stylesheet>
|
|
|
4607f9 |
diff --git a/tests/general/bug-211.out b/tests/general/bug-211.out
|
|
|
4607f9 |
new file mode 100644
|
|
|
4607f9 |
index 00000000..7b3cf11c
|
|
|
4607f9 |
--- /dev/null
|
|
|
4607f9 |
+++ b/tests/general/bug-211.out
|
|
|
4607f9 |
@@ -0,0 +1,2 @@
|
|
|
4607f9 |
+
|
|
|
4607f9 |
+__
|
|
|
4607f9 |
diff --git a/tests/general/bug-211.xsl b/tests/general/bug-211.xsl
|
|
|
4607f9 |
new file mode 100644
|
|
|
4607f9 |
index 00000000..557f5fb3
|
|
|
4607f9 |
--- /dev/null
|
|
|
4607f9 |
+++ b/tests/general/bug-211.xsl
|
|
|
4607f9 |
@@ -0,0 +1,26 @@
|
|
|
4607f9 |
+
|
|
|
4607f9 |
+
|
|
|
4607f9 |
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
|
|
4607f9 |
+ xmlns:str="http://exslt.org/strings"
|
|
|
4607f9 |
+ xmlns:fn="http://exslt.org/functions"
|
|
|
4607f9 |
+ xmlns:adoc="http://asciidoc.org/"
|
|
|
4607f9 |
+ extension-element-prefixes="fn">
|
|
|
4607f9 |
+
|
|
|
4607f9 |
+ <fn:function name="adoc:sanitize">
|
|
|
4607f9 |
+ <xsl:param name="id"/>
|
|
|
4607f9 |
+ <xsl:variable name="tmp" select="str:replace($id, '__', '_')"/>
|
|
|
4607f9 |
+ <xsl:choose>
|
|
|
4607f9 |
+ <xsl:when test="contains($tmp, '__')">
|
|
|
4607f9 |
+ <fn:result select="adoc:sanitize($tmp)"/>
|
|
|
4607f9 |
+ </xsl:when>
|
|
|
4607f9 |
+ <xsl:otherwise>
|
|
|
4607f9 |
+ <fn:result select="$id"/>
|
|
|
4607f9 |
+ </xsl:otherwise>
|
|
|
4607f9 |
+ </xsl:choose>
|
|
|
4607f9 |
+ </fn:function>
|
|
|
4607f9 |
+
|
|
|
4607f9 |
+ <xsl:template match="*">
|
|
|
4607f9 |
+ <xsl:value-of select="adoc:sanitize('________')"/>
|
|
|
4607f9 |
+ </xsl:template>
|
|
|
4607f9 |
+
|
|
|
4607f9 |
+</xsl:stylesheet>
|
|
|
4607f9 |
--
|
|
|
4607f9 |
GitLab
|
|
|
4607f9 |
|