Bug #4478

java.lang.NullPointerException: while trying to invoke the method of a null object loaded from local variable 'actual'

Added by Pranay Deshpande 11 months ago. Updated 3 months ago.

Start date:
Due date:
% Done:


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


Hi Colleagues,

While consuming SaxonEE 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 version only, previously we were using 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

payload.xml (5.22 KB) payload.xml Pranay Deshpande, 2020-03-11 08:33
StackTraces.txt (4.24 KB) StackTraces.txt Pranay Deshpande, 2020-03-11 08:33
problematicXSLTFile.txt (229 KB) problematicXSLTFile.txt Pranay Deshpande, 2020-03-11 08:33
StackTraces.txt (11.4 KB) StackTraces.txt This is the detailed stack trace Pranay Deshpande, 2020-03-11 09:14


#2 Updated by Michael Kay 11 months 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".

#3 Updated by Michael Kay 11 months 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.

#4 Updated by Pranay Deshpande 11 months 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 version?

Regards Pranay

#5 Updated by Michael Kay 11 months 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)"/>

I tried that and it seems to work.

The eventual fix will be in a new maintenance release, likely to be numbered

#6 Updated by Michael Kay 11 months 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{}nodeTableCell := $Q{}Cell 
return (bytecode(
  let $Q{}nodeTableRow := exactly-one($Q{}nodeTableCell/parent::(document-node()|element()))   
  return (
    let $Q{}nodeTableSection := exactly-one($Q{}nodeTableRow/parent::(document-node()|element())) 
    return (
       let $Q{}nodeTable := exactly-one($Q{}nodeTableSection/parent::(document-node()|element())) return (let $Q{}nRowNumInSection := (count($Q{}nodeTableRow/preceding-sibling::element(Q{}tr))) + 1 
      return (SwitchExpression(local-name($Q{}nodeTableSection)....)

At this stage things look OK.

But we then see:

Eliminated unused variable altova:nodeTable
OPT : Expression after rewrite: SwitchExpression(local-name($Q{}nodeTableSection), ....

and this is clearly wrong, because the variable is not unused; we are left with references to a variable that has no binding.

#7 Updated by Michael Kay 11 months 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.

#8 Updated by Michael Kay 11 months ago

  • Status changed from In Progress to Resolved
  • Fix Committed on Branch 9.9, trunk added

#9 Updated by O'Neil Delpratt 10 months ago

  • Fixed in Maintenance Release 10.0 added

Bug fix applied in the Saxon 10 major release.

#10 Updated by O'Neil Delpratt 3 months ago

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

Bug fix applied on the Saxon maintenance release.

Please register to edit this issue

Also available in: Atom PDF