Bug #4478
closedjava.lang.NullPointerException: while trying to invoke the method net.sf.saxon.om.Sequence.head() of a null object loaded from local variable 'actual'
100%
Description
Hi Colleagues,
While consuming SaxonEE 9.9.1.6 version in SAP, our customer is facing issues while XSLT processing. I've attached the payload and the xslt file, along with the detailed error traces.
FYI: We are noticing this issue in 9.9.1.6 version only, previously we were using 9.9.1.3 and this issue was not coming.
Customer scenarios are blocked due to this issue and its a production down for them. It would be really helpful in case you can suggest a quick workaround for our customers so that we can unblock them temporarily.
Could you please check this issue on priority.
Thanks and Regards Pranay Deshpande SAP Labs
Files
Updated by Pranay Deshpande over 4 years ago
- File StackTraces.txt StackTraces.txt added
Updated by Michael Kay over 4 years ago
Thanks for reporting it. I have reproduced the error under 9.9 1.7.
I've also established that it goes away if you disable optimization, so for a quick workaround, you can switch optimization off: use -opt:0 on the command line, or set the configuration property OPTIMIZATION_LEVEL to the value "0".
Updated by Michael Kay over 4 years ago
- Category set to Internals
- Status changed from New to In Progress
- Assignee set to Michael Kay
- Priority changed from High to Normal
- Applies to branch 9.9, trunk added
The problem is with the variable $altova:nodeTable
on line 1231.
The function altova:GetGridRowNumForCell
has been inlined at the point of the call from altova:col-position()
on line 1077. Running with function inlining suppressed (-opt:-f
) makes the problem go away. The regression from earlier releases is probably because (after conducting experiments) we changed the threshold for the size of functions that are eligible for inlining.
Updated by Pranay Deshpande over 4 years ago
Hi Michael,
Thanks for providing the quick workaround.
I wanted to know is there something we can change in the XSLT file and resolve this issue temporarily?
Also, could you please confirm, once the issue is fixed from your end, could you downport it to 9.9.1.6 version?
Regards Pranay
Updated by Michael Kay over 4 years ago
There's no direct way to switch optimizations off from within the XSLT file itself, it has to be done from the calling application or shell script.
However, it's possible to rewrite the function in such a way that it doesn't get inlined. The simplest way is probably to make the function recursive: in the xsl:choose at line 1233, add a never-executed branch
<xsl:when test="$altova:sTableSection eq 'something-impossible'">
<xsl:sequence select="altova:GetGridRowNumForCell($altova:nodeTableCell)"/>
</xsl:when>
I tried that and it seems to work.
The eventual fix will be in a new maintenance release, likely to be numbered 9.9.1.8.
Updated by Michael Kay over 4 years ago
The -explain output shows:
At line 1077 of file:/Users/mike/bugs/2020/4478-Deshpande/problem.xsl
OPT : Moved function altova:GetGridRowNumForCell inline:
OPT : Expression after rewrite:
let $Q{http://www.altova.com}nodeTableCell := $Q{http://www.altova.com}Cell
return (bytecode(
let $Q{http://www.altova.com}nodeTableRow := exactly-one($Q{http://www.altova.com}nodeTableCell/parent::(document-node()|element()))
return (
let $Q{http://www.altova.com}nodeTableSection := exactly-one($Q{http://www.altova.com}nodeTableRow/parent::(document-node()|element()))
return (
let $Q{http://www.altova.com}nodeTable := exactly-one($Q{http://www.altova.com}nodeTableSection/parent::(document-node()|element())) return (let $Q{http://www.altova.com}nRowNumInSection := (count($Q{http://www.altova.com}nodeTableRow/preceding-sibling::element(Q{}tr))) + 1
return (SwitchExpression(local-name($Q{http://www.altova.com}nodeTableSection)....)
At this stage things look OK.
But we then see:
Eliminated unused variable altova:nodeTable
OPT : Expression after rewrite: SwitchExpression(local-name($Q{http://www.altova.com}nodeTableSection), ....
and this is clearly wrong, because the variable is not unused; we are left with references to a variable that has no binding.
Updated by Michael Kay over 4 years ago
At some point in the optimization process the LetExpression
binding $altova:nodeTable
at @8515 has been replaced by a new LetExpression
@11184, but the variable references in its action part have not been rebound to the new LetExpression
.
This is happening when the expression is copied during function inlining.
The code for SwitchExpression.copy()
is not performing a deep copy of its operands, so the variable references retain their old bindings. (A SwitchExpression
is the optimized form of an xsl:choose
where all the branches are equality tests on the same subexpression).
Fixed by changing SwitchExpression
to deep-copy the action operands.
Updated by Michael Kay over 4 years ago
- Status changed from In Progress to Resolved
- Fix Committed on Branch 9.9, trunk added
Updated by O'Neil Delpratt over 4 years ago
- Fixed in Maintenance Release 10.0 added
Bug fix applied in the Saxon 10 major release.
Updated by O'Neil Delpratt about 4 years ago
- Status changed from Resolved to Closed
- % Done changed from 0 to 100
- Fixed in Maintenance Release 9.9.1.8 added
Bug fix applied on the Saxon 9.9.1.8 maintenance release.
Please register to edit this issue