Package: xsltproc
Version: 1.1.17-3

(Reported upstream as http://bugzilla.gnome.org/show_bug.cgi?id=350085)

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

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


"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.

- Josh Triplett

Attachment: signature.asc
Description: OpenPGP digital signature

Reply via email to