Project

Profile

Help

Bug #3691

closed

Bad parent pointer error message

Added by Rob Brown about 6 years ago. Updated about 6 years ago.

Status:
Closed
Priority:
Normal
Assignee:
Category:
Internals
Sprint/Milestone:
-
Start date:
2018-02-20
Due date:
% Done:

100%

Estimated time:
Legacy ID:
Applies to branch:
9.8, trunk
Fix Committed on Branch:
9.8, trunk
Fixed in Maintenance Release:
Platforms:

Description

I just upgraded from 9.4.0.6 to 9.8.0.8 and I'm getting an error now that didn't occur before.

Here is the error message:

  • Bad parent pointer found in expression root / data / vineland2COM at file:/C:/saxonIssue/vineland2.xsl#17 *

The output seems OK, which makes sense as explained in posts like:

https://saxonica.plan.io/boards/3/topics/6838?r=6841#message-6841 and

https://saxonica.plan.io/issues/2555

I have appended a test case below that causes the error.

xsl:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"

            xmlns:xs="http://www.w3.org/2001/XMLSchema"

            version="2.0">

<xsl:variable name="medianAllDomains">

  <xsl:call-template name="calcMedian">

     <xsl:with-param name="values" select="(/data/test/vineland2/vineland2COM,

              /data/test/vineland2/vineland2DLS, 

              /data/test/vineland2/vineland2SOC,

              /data/test/vineland2/vineland2MOT)"/>

  </xsl:call-template>

</xsl:variable>

<xsl:template name="calcMedian">

  <xsl:param name="values" as="xs:double*" required="yes"/>

  <xsl:variable name="sortedValues" as="item()*">

     <xsl:perform-sort select="$values">

        <xsl:sort/>

     </xsl:perform-sort>

  </xsl:variable>

  <xsl:variable name="count" select="count($sortedValues)"/>

  <xsl:choose>

     <xsl:when test="($count mod 2) = 0">

        <xsl:variable name="midPos" select="$count div 2"/>

        <xsl:value-of select="

              avg(($sortedValues[$midPos], $sortedValues[$midPos + 1]))"/>

     </xsl:when>

     <xsl:otherwise>

        <xsl:value-of select="$sortedValues[($count+1) div 2]"/>

     </xsl:otherwise>

  </xsl:choose>

</xsl:template>

</xsl:stylesheet>

java:

	SAXSource saxSource = new SAXSource();

	saxSource.setInputSource(new InputSource(

			"file:/c:/saxonIssue/vineland2.xsl"));

	try {

		XsltCompiler compiler = new Processor(false).newXsltCompiler();

		compiler.compile(saxSource);

	} catch (SaxonApiException e) {

		Logger.getAnonymousLogger().log(Level.SEVERE, "an error occurred while processing xslt: " + e.getMessage(), e);

	}

Related issues

Related to Saxon - Bug #3722: XPST0008 on 9.8.0.10: failure to resolve a forwards reference to a global variable in the select expression of a template xsl:paramClosedMichael Kay2018-03-17

Actions
Actions #1

Updated by Michael Kay about 6 years ago

Thanks for reporting it. On my first attempts, I can't reproduce it. I will need to set up a configuration that tries to match yours as closely as possible.

Actions #3

Updated by Michael Kay about 6 years ago

Now reproduced.

Actions #4

Updated by Michael Kay about 6 years ago

The problem is in the xsl:with-param/@select expression. The expression verifies on exit from WithParam.optimize(), and it fails to verify on entry to checkAgainstRequiredType() as called from XSLCallTemplate. The expression is the same object; it's not clear what has changed in between.

After optimize(), the expression looks like this:

convertUntyped(Block(data(((((/)/child::element(Q{}data))/child::element(Q{}test))/child::element(Q{}vineland2))/child::element(Q{}vineland2COM)), data(((((/)/child::element(Q{}data))/child::element(Q{}test))/child::element(Q{}vineland2))/child::element(Q{}vineland2DLS)), data(((((/)/child::element(Q{}data))/child::element(Q{}test))/child::element(Q{}vineland2))/child::element(Q{}vineland2SOC)), data(((((/)/child::element(Q{}data))/child::element(Q{}test))/child::element(Q{}vineland2))/child::element(Q{}vineland2MOT))))

on entry to checkAgainstRequiredType it looks like this:

Block(((((/)/child::element(Q{}data))/child::element(Q{}test))/child::element(Q{}vineland2))/child::element(Q{}vineland2COM), ((((/)/child::element(Q{}data))/child::element(Q{}test))/child::element(Q{}vineland2))/child::element(Q{}vineland2DLS), ((((/)/child::element(Q{}data))/child::element(Q{}test))/child::element(Q{}vineland2))/child::element(Q{}vineland2SOC), ((((/)/child::element(Q{}data))/child::element(Q{}test))/child::element(Q{}vineland2))/child::element(Q{}vineland2MOT))

which is the original expression before atomization was applied.

The call on checkAgainstRequiredType uses the SourceBinding object, which is in the XSLT source tree, and has not been updated to point to the modified expression; but some of its component expressions have been changed in situ (rather than being copied) and so point to a new parent.

The checkAgainstRequiredType call is happening during the completionActions on the stylesheet module. Although the "completionActions" mechanism is completely general, this appears to be the only situation where it is used: checking of the expressions used in xsl:with-param on a call-template instruction against the declared types of the parameters on the named XSLTemplate.

The current code appears to have been introduced in 9.6 - until then, it seems there was no attempt to do static checking of call-template parameters against the declared parameters of the target template in the case where the call is a forwards reference. Apart from the bad parent pointers, it probably works reasonably well, in that we're only using the template body to find the LocalParam objects, and looking for these in the old (corrupt) tree rather than the new tree isn't going to cause any trouble. However, the logic seems strange. It's not clear why we have to look inside the compiled template body for the LocalParam objects, we can equally well get the declared types from the source-level XSLParam elements.

Actions #5

Updated by Michael Kay about 6 years ago

The reason we're looking at the LocalParam objects in the compiled template body, rather than at the XSLLocalParam element nodes in the source stylesheet tree, is because XSLCallTemplate has a reference to the compiled form of the target template and not the source. That's because the process of finding the target template (taking into account import precedences etc) works with the compiled objects: and of course in the pre-packaging XSLT 1.0 model there's no requirement that two named templates with different precedence have compatible parameters. Also relevant is the design principle that we don't link back from compiled code to the source tree - this is probably legacy these days, it was done to ensure the source tree is eligible for garbage collection. With JIT compilation of template rules though, it ceases to have much point.

The key here appears to be PreparedStylesheetModule.indexNamedTemplate(): this method has access to both the source XSLTemplate and the compiled NamedTemplate object, and it is here that the import precedences are sorted out. At this point we could register the names and declared types of the named template with the NamedTemplate object, which would then be accessible without searching the template body for the LocalParam objects.

Actions #6

Updated by Michael Kay about 6 years ago

  • Category set to Internals
  • Assignee set to Michael Kay
  • Priority changed from Low to Normal

Ended up being a bit radical.

The indexedNamedTemplates() method now constructs a list of LocalParamInfo objects containing basic details of the declared parameters, and saves this with the NamedTemplate object. This makes it available to XSLCallTemplate.checkParam(), which can now be done immediately rather than being deferred until the named template body has been compiled. Forwards references no longer need to be handled specially, and the "completionAction" mechanism becomes obsolete.

Actions #7

Updated by Michael Kay about 6 years ago

  • Status changed from New to Resolved
  • Applies to branch 9.8, trunk added
  • Fix Committed on Branch 9.8, trunk added

This didn't quite work: a couple of regression tests failed (tunnel-0109 and tunnel-0110). The failures were because we were looking at the properties of XSLLocalParam objects before these had been fully initialized. Was able to solve this by initialising the properties earlier.

Actions #8

Updated by O'Neil Delpratt about 6 years ago

  • Status changed from Resolved to Closed
  • % Done changed from 0 to 100
  • Fixed in Maintenance Release 9.8.0.10 added

Bug fix applied in the Saxon 9.8.0.10 maintenance release.

Actions #9

Updated by Michael Kay about 6 years ago

  • Related to Bug #3722: XPST0008 on 9.8.0.10: failure to resolve a forwards reference to a global variable in the select expression of a template xsl:param added

Please register to edit this issue

Also available in: Atom PDF