Bug #3200
closedStackOverflow (infinite recursion in optimizer)
100%
Description
The XSLT looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs"
version="2.0">
<xsl:template match="/">
<results>
<xsl:for-each select="1 to 3">
<xsl:variable name="pos" select="position()"/>
<xsl:for-each select="7 to 9">
<xsl:element name="test">
<xsl:attribute name="xml:id" select="concat('hi', string($pos))"/>
</xsl:element>
</xsl:for-each>
</xsl:for-each>
</results>
</xsl:template>
</xsl:stylesheet>
and if it is applied to any XML you get this:
java.lang.StackOverflowError
at java.util.AbstractList.iterator(Unknown Source)
at net.sf.saxon.expr.Expression.optimizeChildren(Expression.java:514)
at net.sf.saxon.expr.FunctionCall.optimize(FunctionCall.java:248)
at net.sf.saxon.expr.SystemFunctionCall.optimize(SystemFunctionCall.java:158)
at net.sf.saxon.expr.Operand.optimize(Operand.java:200)
at net.sf.saxon.expr.Expression.optimizeChildren(Expression.java:515)
at net.sf.saxon.expr.instruct.SimpleNodeConstructor.optimize(SimpleNodeConstructor.java:163)
at net.sf.saxon.expr.Operand.optimize(Operand.java:200)
at net.sf.saxon.expr.Expression.optimizeChildren(Expression.java:515)
at net.sf.saxon.expr.instruct.ParentNodeConstructor.optimize(ParentNodeConstructor.java:206)
at net.sf.saxon.expr.instruct.FixedElement.optimize(FixedElement.java:108)
at net.sf.saxon.expr.Operand.optimize(Operand.java:200)
at net.sf.saxon.expr.instruct.ForEach.optimize(ForEach.java:248)
at net.sf.saxon.expr.Operand.optimize(Operand.java:200)
at net.sf.saxon.expr.LetExpression.optimize(LetExpression.java:311)
at net.sf.saxon.expr.instruct.ForEach.optimize(ForEach.java:273)
at net.sf.saxon.expr.Operand.optimize(Operand.java:200)
at net.sf.saxon.expr.LetExpression.optimize(LetExpression.java:311)
at net.sf.saxon.expr.instruct.ForEach.optimize(ForEach.java:273)
at net.sf.saxon.expr.Operand.optimize(Operand.java:200)
at net.sf.saxon.expr.LetExpression.optimize(LetExpression.java:311)
at net.sf.saxon.expr.instruct.ForEach.optimize(ForEach.java:273)
at net.sf.saxon.expr.Operand.optimize(Operand.java:200)
at net.sf.saxon.expr.LetExpression.optimize(LetExpression.java:311)
at net.sf.saxon.expr.instruct.ForEach.optimize(ForEach.java:273)
at net.sf.saxon.expr.Operand.optimize(Operand.java:200)
at net.sf.saxon.expr.LetExpression.optimize(LetExpression.java:311)
at net.sf.saxon.expr.instruct.ForEach.optimize(ForEach.java:273)
at net.sf.saxon.expr.Operand.optimize(Operand.java:200)
at net.sf.saxon.expr.LetExpression.optimize(LetExpression.java:311)
at net.sf.saxon.expr.instruct.ForEach.optimize(ForEach.java:273)
at net.sf.saxon.expr.Operand.optimize(Operand.java:200)
at net.sf.saxon.expr.LetExpression.optimize(LetExpression.java:311)
at net.sf.saxon.expr.instruct.ForEach.optimize(ForEach.java:273)
at net.sf.saxon.expr.Operand.optimize(Operand.java:200)
at net.sf.saxon.expr.LetExpression.optimize(LetExpression.java:311)
at net.sf.saxon.expr.instruct.ForEach.optimize(ForEach.java:273)
at net.sf.saxon.expr.Operand.optimize(Operand.java:200)
at net.sf.saxon.expr.LetExpression.optimize(LetExpression.java:311)
at net.sf.saxon.expr.instruct.ForEach.optimize(ForEach.java:273)
at net.sf.saxon.expr.Operand.optimize(Operand.java:200)
Updated by Radu Coravu about 7 years ago
Adding link to Oxygen forum where this was first reported:
Updated by Michael Kay about 7 years ago
- Subject changed from StackOverflow to StackOverflow (infinite recursion in optimizer)
- Category set to Internals
- Assignee set to Michael Kay
Updated by Michael Kay about 7 years ago
- Applies to branch 9.7 added
Applies to 9.7 only: the problem is in the loop-lifting optimization which has been rewritten for 9.8
Updated by Radu Coravu about 7 years ago
Thanks for looking into this. Any hint how I could patch this for the Saxon 9.7 bundled with Oxygen 19.0? Any particular class containing the particular fix that I could use as a patch.
Also I'm not sure if you saw that but I also requested this issue to be reopened:
https://saxonica.plan.io/issues/3068
as it produces some invalid XML docs when having attributes like xml:space set as default attributes in the XML Schema..
Updated by Michael Kay about 7 years ago
The problem is in FixedAttribute.setSelect() and is specific to the case where the attribute name is xml:id; the code is wrapping a call of normalize-space() around the select expression; if the select expression XX is focus-independent it then attempts to loop-lift the call of normalize-space(XX), and this attempt has the side-effect of wrapping another call of normalize-space() around the new select expression, ad infinitum.
Updated by Michael Kay about 7 years ago
The problem can be fixed by moving the code that adds the call on normalize-space() from the FixedAttribute.setSelect() method to FixedAttribute.localTypeCheck(). Question is, does this have any unwanted side-effects?
Updated by Radu Coravu about 7 years ago
Well, we could unleash it on all the innocent Oxygen users and find out :)
I can initially make a fix on my side and then see what XSLT-related automated tests that we have fail tomorrow.
Could you run the tests that you have for Saxon with this change in place?
Updated by Radu Coravu about 7 years ago
So the code at the end of "net.sf.saxon.expr.instruct.FixedAttribute.localTypeCheck(ExpressionVisitor, ContextItemStaticInfo)" would change to something like this:
Expression select = getSelect();
if (select instanceof StringLiteral) {
boolean special = false;
// If attribute name is xml:id, add whitespace normalization
if (nodeName.equals(StandardNames.XML_ID_NAME)) {
select = SystemFunction.makeCall("normalize-space", getRetainedStaticContext(), select);
}
CharSequence val = ((StringLiteral) select).getStringValue();
for (int k = 0; k < val.length(); k++) {
char c = val.charAt(k);
if ((int) c < 33 || (int) c > 126 ||
c == '<' || c == '>' || c == '&' || c == '\"') {
special = true;
break;
}
}
if (!special) {
setNoSpecialChars();
}
}
right?
ADDED BY MHK: No, I don't think it's correct to do this only when the value is a literal. Please see the patch I'm committing.
Updated by Michael Kay about 7 years ago
- Status changed from In Progress to Resolved
- Fix Committed on Branch 9.7, 9.8 added
The fix seems to be OK as far as I can tell - there will be more regression testing when we do a maintenance release build.
Committing on the 9.7 and 9.8 branches even though the problem manifests itself only on 9.7.
Updated by Radu Coravu about 7 years ago
Ok, I'll report back here if I find anything wrong with the fix in our automated tests...
Updated by O'Neil Delpratt almost 7 years ago
- Fix Committed on Branch trunk added
- Fix Committed on Branch deleted (
9.8)
Updated by O'Neil Delpratt almost 7 years ago
- Status changed from Resolved to Closed
- % Done changed from 0 to 100
- Fixed in Maintenance Release 9.7.0.19 added
Bug fix applied in the 9.7.0.19 maintenance release.
Please register to edit this issue