Handling infinite recursion XSL in Saxon
Asked Answered
M

2

8

I understand this question might be beyond Saxon and more related to the architecture of the application using it for transformations, but just wanted to give a try. Consider the following files-

XML

<?xml version="1.0" encoding="UTF-8"?>
<document>
    string
</document>

XSL

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="3.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="xsl xs">

    <xsl:template match="/"> 
       <xsl:apply-templates/>
    </xsl:template>

    <xsl:template match="node()">
        <xsl:apply-templates select="."/>
    </xsl:template>

</xsl:stylesheet>

The XSL will go into an infinite recursion during the transformation aka stack overflow. My question is- Is there a way to stop or prevent this type of transformation from going into an infinite recursion? Any parameters that can be added to the command-line that can trigger a warning and gracefully stop?

Midriff answered 21/4, 2016 at 0:41 Comment(6)
My favoured xslt processor xsltproc has: --maxdepth value Adjust the maximum depth of the template stack before libxslt concludes it is in an infinite loop. The default is 500Clout
You'll want to look at the -quit:(on|off) option, which determines whether Saxon quits the JVM or raises a runtime exception in case of failure. The latter is helpful if Saxon is being called from Java. If there were a way to detect infinite recursion statically, or prevent it, computer science would be very different. (By which I mean: no, Saxon doesn't have it, because Turing proved that it cannot be had.)Geosyncline
The Java VM detects stack overflow, and Saxon intercepts the exception and tries to explain it in terms of recursive template invocation if it can. But stack overflow and infinite recursion aren't quite the same thing. In this particular example, Saxon uses a technique called tail call optimization, which converts recursion into looping; this is deliberately designed to enable arbitrarily deep recursion without exhausting the stack space available, which has the consequence that instead of throwing a stack overflow exception, this program runs for ever. Which is of course undetectable.Jobie
@Clout Thanks! That setting is similar to what I'm looking for. Most of the XSLs I'm using are version 3.0, which I believe is not supported by xsltprocMidriff
Did you find a way how to prevent Saxon from stackoverflow for infitit xslt documents? In case of misconfiguration my XSLT is cycling around net.sf.saxon.instruct.ApplyTemplates.applyTemplates(ApplyTemplates.java:327) at net.sf.saxon.instruct.ApplyTemplates.defaultAction(ApplyTemplates.java:376)Superstar
@Superstar Nope..still a problem :(Midriff
L
1

Instead of relying on existing settings to address this sort of thing, you might just want to create your own.

Consider the following XSL run against the very simple XML you gave:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="3.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="xsl xs">

    <xsl:variable name="recursion.limit" select="500" as="xs:integer"/>
    <xsl:variable name="new.line" select="'&#x0A;'" as="xs:string"/>

    <xsl:template match="/">
        <xsl:value-of select="$new.line"/>
        <xsl:apply-templates/>
    </xsl:template>

    <xsl:template match="node()">
        <xsl:param name="recursion.count" select="1" as="xs:integer"/>

        <xsl:choose>
            <xsl:when test="$recursion.count &lt;= $recursion.limit">
                <xsl:value-of select="'&lt;' || name() || '&gt;' || ':' || $recursion.count || $new.line" disable-output-escaping="yes"/>
                <xsl:apply-templates select=".">
                    <xsl:with-param name="recursion.count" select="$recursion.count + 1" as="xs:integer"/>
                </xsl:apply-templates>
            </xsl:when>
            <xsl:otherwise>
                <xsl:message>
                    <xsl:value-of select="'Recursion limit of ' || $recursion.limit|| ' hit.'"/>
                </xsl:message>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>

</xsl:stylesheet>

This would certainly stop or prevent this type of transformation from going into an infinite recursion, but it's of course not automatic. You have to set it up in code. But if done, this can function as a home-brew max-depth setting. All you would have to do at this point is parameterize the sheet to take such a value instead of baking it in as I did, and there's your setting. And that takes care of your desire for parameters that can be added to the command line that can trigger some sort of warning and/or gracefully stop. It's pure XSL, and as such, ought to be engine-independent, provided the XSL spec is being properly met by your engine of choice (which I really do hope is Saxon).

Lux answered 18/12, 2019 at 9:34 Comment(0)
S
0

Did you try -opt:0 to disable optimizations ?

Subequatorial answered 12/8, 2016 at 23:33 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.