After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 350085 - xsl:variable changes value when using node-set for multipass processing
xsl:variable changes value when using node-set for multipass processing
Status: RESOLVED FIXED
Product: libxslt
Classification: Platform
Component: general
1.1.x
Other Linux
: Normal normal
: ---
Assigned To: Daniel Veillard
libxml QA maintainers
Depends on:
Blocks:
 
 
Reported: 2006-08-05 17:56 UTC by Josh Triplett
Modified: 2006-08-09 18:35 UTC
See Also:
GNOME target: ---
GNOME version: ---



Description Josh Triplett 2006-08-05 17:56:05 UTC
The following transform provides a minimal test case for a problem that arose in the XSLT-based C code generator for the XML-XCB project.  This transform performs multi-pass processing using the EXSLT node-set extension.  The bug arose when I attempted to define a variable in the stylesheet containing some fixed data and traverse it as part of the definition of one of the variables used for multi-pass processing; both variables consist of a result-tree-fragment subsequently passed to the node-set extension.  If you run this transform, the first access to the request-suffixes variable via xsl:for-each successfully iterates over the two elements it contains, but the second access sees no content in the variable.

test.xsl:
<?xml version="1.0" encoding="utf-8"?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
               version="1.0"
               xmlns:e="http://exslt.org/common"
               exclude-result-prefixes="e">
  <xsl:variable name="request-suffixes-rtf">
    <checked />
    <checked />
  </xsl:variable>
  <xsl:variable name="request-suffixes"
                select="e:node-set($request-suffixes-rtf)" />

  <xsl:template match="request" mode="pass1">
    <thing1>
    <xsl:for-each select="$request-suffixes/checked">
      <thing2 />
    </xsl:for-each>
    </thing1>
  </xsl:template>

  <xsl:variable name="pass1-rtf">
    <xsl:apply-templates select="/" mode="pass1" />
  </xsl:variable>
  <xsl:variable name="pass1" select="e:node-set($pass1-rtf)" />

  <xsl:template match="/">
    <root>
      <xsl:copy-of select="$pass1/*" />
    </root>
  </xsl:template>
</xsl:transform>

test.xml:
<?xml version="1.0" encoding="utf-8"?>
<xcb>
  <request />
  <request />
</xcb>

Run this example with: xsltproc test.xsl test.xml | xmllint --format -

Expected result:
<?xml version="1.0"?>
<root>
  <thing1>
    <thing2/>
    <thing2/>
  </thing1>
  <thing1>
    <thing2/>
    <thing2/>
  </thing1>
</root>

Actual result:
<?xml version="1.0"?>
<root>
  <thing1>
    <thing2/>
    <thing2/>
  </thing1>
  <thing1/>
</root>

Excerpts from the xsltproc -v debugging output:
[...]
xsltForEach: select $request-suffixes/checked
Lookup variable request-suffixes
Evaluating global variable request-suffixes
Lookup variable request-suffixes-rtf
Evaluating global variable request-suffixes-rtf
reusing transformation dict for RVT
xsltApplyOneTemplate: copy node checked
xsltApplyOneTemplate: copy node checked
Object is an XSLT value tree :
1  ELEMENT checked
  ELEMENT checked
found variable request-suffixes-rtf
Lookup function {http://exslt.org/common}node-set
found function node-set
Object is a Node Set :
Set contains 1 nodes:
1   /
found variable request-suffixes
xsltForEach: select evaluates to 2 nodes
xsltForEach: Changing document - context doc temp.xml, xpathdoc (null)
xsltApplyOneTemplate: copy node thing2
xsltApplyOneTemplate: copy node thing2
[...]
xsltForEach: select $request-suffixes/checked
Lookup variable request-suffixes
found variable request-suffixes
xsltForEach: select evaluates to 0 nodes
Comment 1 Josh Triplett 2006-08-05 17:56:55 UTC
xsltproc --version:
Using libxml 20626, libxslt 10117 and libexslt 813
xsltproc was compiled against libxml 20626, libxslt 10117 and libexslt 813
libxslt 10117 was compiled against libxml 20626
libexslt 813 was compiled against libxml 20626
Comment 2 Josh Triplett 2006-08-05 18:34:00 UTC
"valgrind xsltproc temp.xsl temp.xml" also seems rather informative; it indicates repeated accesses to freed memory:

==31926== Invalid read of size 4
==31926==    at 0x41415AA: xmlXPathNodeSetMerge (xpath.c:3708)
==31926==    by 0x4147653: xmlXPathObjectCopy (xpath.c:5062)
==31926==    by 0x40A5AED: xsltVariableLookup (variables.c:1401)
==31926==    by 0x40A5CA1: xsltXPathVariableLookup (variables.c:1727)
==31926==    by 0x414B19B: xmlXPathVariableLookup (xpath.c:4679)
==31926==    by 0x414C3CE: xmlXPathCompOpEval (xpath.c:12960)
==31926==    by 0x414BC3C: xmlXPathCompOpEval (xpath.c:12918)
==31926==    by 0x414B5AE: xmlXPathCompOpEval (xpath.c:13423)
==31926==    by 0x415149C: xmlXPathCompiledEval (xpath.c:14203)
==31926==    by 0x40B521E: xsltForEach (transform.c:4854)
==31926==    by 0x40B466E: xsltApplyOneTemplateInt (transform.c:2525)
==31926==    by 0x40B6707: xsltProcessOneNode (transform.c:1513)
==31926==  Address 0x43A89EC is 4 bytes inside a block of size 88 free'd
==31926==    at 0x401D139: free (vg_replace_malloc.c:233)
==31926==    by 0x4115DA6: xmlFreeDoc (tree.c:1179)
==31926==    by 0x40B4486: xsltApplyOneTemplateInt (transform.c:2790)
==31926==    by 0x40B6707: xsltProcessOneNode (transform.c:1513)
==31926==    by 0x40B6707: xsltProcessOneNode (transform.c:1513)
==31926==    by 0x40B6F2E: xsltApplyTemplates (transform.c:4501)
==31926==    by 0x40B466E: xsltApplyOneTemplateInt (transform.c:2525)
==31926==    by 0x40A5671: xsltEvalGlobalVariable (variables.c:723)
==31926==    by 0x40A5BED: xsltVariableLookup (variables.c:1363)
==31926==    by 0x40A5CA1: xsltXPathVariableLookup (variables.c:1727)
==31926==    by 0x414B19B: xmlXPathVariableLookup (xpath.c:4679)
==31926==    by 0x414C3CE: xmlXPathCompOpEval (xpath.c:12960)

The first backtrace (the invalid access) occurs during processing of the for-each, and the second (the free that has already occurred) looks like it occurred during the processing of the pass1/pass1-rtf variable.

Furthermore, when run under valgrind, the bug does not reproduce.  I also cannot reproduce the problem on an x86-64 machine running identical versions of xsltproc, libxml, libxslt, and libexslt.
Comment 3 William M. Brack 2006-08-09 18:35:34 UTC
The problem with the handling of node-set globals and the valgrind detected memory problems should now be fixed in CVS.  I have checked your above test files on both x86 and x64.

Please try the CVS code on your original data and confirm that all is now ok.  If there is any further problem, please re-open this bug.

Thanks for the informative and helpful report!