Project

Profile

Help

Bug #4227

java.lang.NullPointerException when using xsl:catch with @error on undefined errors

Added by Jan Pertermann 4 months ago. Updated 12 days ago.

Status:
Closed
Priority:
Normal
Assignee:
Category:
Diagnostics
Sprint/Milestone:
-
Start date:
2019-05-24
Due date:
% Done:

100%

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

Description

I get a java.lang.NullPointerException when trying to catch an undefined error in XSLT such as a java.io.FileNotFoundException.

                <xsl:try>
                    <xsl:result-document href="{resolve-uri('example')}">
                        <root></root>
                    </xsl:result-document>
                    <xsl:catch errors="err:*">
                    </xsl:catch>
                    <xsl:catch>
                    </xsl:catch>
                </xsl:try>

Prerequisite for this to (not) work is that there is a directory with same path example.

Please have a look at the test.xsl attachement to reproduce. I guess saxon tries to compare the error QName, which in this case does not exist ...

  • OS: Win 10
  • Saxon: PE 9.8.0.15 .Net / 9.8.0.12 Java
test.xsl (2.79 KB) Jan Pertermann, 2019-05-24 13:02 test.xsl

History

#1 Updated by Jan Pertermann 4 months ago

#2 Updated by Michael Kay 4 months ago

We haven't been able to reproduce this, either on Mac or Windows, Java or .NET, 9.8 or 9.9.

Is there a stack trace available?

Saxon of course should be setting an error code on this exception, and shouldn't be failing if there isn't one.

Looking at the code for try/catch, I see that evaluateItem() has logic to explicitly test if the error code is missing, while iterate() has no such logic. For the development branch I will add the logic to both methods; but I'm reluctant to make any change on the 9.8 branch that I can't test, because 9.8 is a stable release so the bar for making changes is very high (indeed, it's quite likely there will be no more maintenance releases on that branch unless something very serious crops up).

#3 Updated by Michael Kay 4 months ago

The failure to set an error code is in Emitter.makeOutputStream(). I guess the reason it isn't doing so is that there's no obvious error code that fits; no error code that means "the URI in the href attribute of xsl:result-document is a valid URI, but refers to a resource that isn't writable". And indeed, when we detect the error, we don't really know that there's anything wrong with the URI; we detect it on the first attempt to create content for the result document (which can be significantly deferred because of buffering) and all we have to go on is an IOException from the attempt to create an output stream. Our normal policy in such situations is to use a Saxon-defined error code.

#4 Updated by Jan Pertermann 4 months ago

Hi Michael,

thanks for your feedback. Here is the stack trace from the commandline (9.8.0.15 .Net):

java.lang.NullPointerException
        at net.sf.saxon.pattern.NamespaceTest.matches(NamespaceTest.java:118)
        at net.sf.saxon.expr.TryCatch.iterate(TryCatch.java:276)
        at net.sf.saxon.expr.Expression.process(Expression.java:936)
        at net.sf.saxon.expr.instruct.Choose.processLeavingTail(Choose.java:881)
        at net.sf.saxon.expr.instruct.Block.processLeavingTail(Block.java:687)
        at net.sf.saxon.expr.instruct.NamedTemplate.expand(NamedTemplate.java:263)
        at net.sf.saxon.Controller.callTemplate(Controller.java:2559)
        at net.sf.saxon.s9api.Xslt30Transformer.callTemplate(Xslt30Transformer.java:749)
        at net.sf.saxon.Transform.processFile(Transform.java:1253)
        at net.sf.saxon.Transform.doTransform(Transform.java:783)
        at cli.Saxon.Cmd.DotNetTransform.Main(Unknown Source)
Fatal error during transformation: java.lang.NullPointerException:  (no message)

I'm wondering why you cannot reproduce this. Maybe you can provoke another type of "undefined" error? Anyway it is kind of serious issue, when the process totally dies. As the trace shows, error seems - as you mentioned - to lie in iterate().

Regards Jan

#5 Updated by Jan Pertermann 4 months ago

I did a comparison with latest Saxon 9.8 and 9.9 .Net versions on the commandline - here is my output:

PS C:\tmp\test\2019-05-22-saxon-result-doc-bug> dir


    Verzeichnis: C:\tmp\test\2019-05-22-saxon-result-doc-bug


Mode                LastWriteTime         Length Name
----                -------------         ------ ----
d-----       22.05.2019     13:35                example
-a----       24.05.2019     12:49           2862 test.xsl


PS C:\tmp\test\2019-05-22-saxon-result-doc-bug> & 'C:\Program Files\Saxonica\SaxonPE9.8N\bin\Transform.exe' -it:main -xsl:test.xsl test=1
Running 1
Error in xsl:when/@test on line 31 column 41 of test.xsl:
  java.io.FileNotFoundException: Der Zugriff auf den Pfad
  "C:\tmp\test\2019-05-22-saxon-result-doc-bug\example" wurde verweigert.
java.io.FileNotFoundException: Der Zugriff auf den Pfad "C:\tmp\test\2019-05-22-saxon-result-doc-bug\example" wurde verweigert.



PS C:\tmp\test\2019-05-22-saxon-result-doc-bug> & 'C:\Program Files\Saxonica\SaxonPE9.9N\bin\Transform.exe' -it:main -xsl:test.xsl test=1
Running 1
Error in xsl:when/@test on line 31 column 41 of test.xsl:
  java.io.FileNotFoundException: C:\tmp\test\2019-05-22-saxon-result-doc-bug\example (Access
  is denied)
at template main on line 7 of test.xsl:
     invoked by unknown caller (null)
java.io.FileNotFoundException: C:\tmp\test\2019-05-22-saxon-result-doc-bug\example (Access is denied)



PS C:\tmp\test\2019-05-22-saxon-result-doc-bug> & 'C:\Program Files\Saxonica\SaxonPE9.8N\bin\Transform.exe' -it:main -xsl:test.xsl test=2
Running 2



PS C:\tmp\test\2019-05-22-saxon-result-doc-bug> & 'C:\Program Files\Saxonica\SaxonPE9.9N\bin\Transform.exe' -it:main -xsl:test.xsl test=2
Running 2



PS C:\tmp\test\2019-05-22-saxon-result-doc-bug> & 'C:\Program Files\Saxonica\SaxonPE9.8N\bin\Transform.exe' -it:main -xsl:test.xsl test=3
Running 3
java.lang.NullPointerException
        at net.sf.saxon.pattern.NamespaceTest.matches(NamespaceTest.java:118)
        at net.sf.saxon.expr.TryCatch.iterate(TryCatch.java:276)
        at net.sf.saxon.expr.Expression.process(Expression.java:936)
        at net.sf.saxon.expr.instruct.Choose.processLeavingTail(Choose.java:881)
        at net.sf.saxon.expr.instruct.Block.processLeavingTail(Block.java:687)
        at net.sf.saxon.expr.instruct.NamedTemplate.expand(NamedTemplate.java:263)
        at net.sf.saxon.Controller.callTemplate(Controller.java:2559)
        at net.sf.saxon.s9api.Xslt30Transformer.callTemplate(Xslt30Transformer.java:749)
        at net.sf.saxon.Transform.processFile(Transform.java:1253)
        at net.sf.saxon.Transform.doTransform(Transform.java:783)
        at cli.Saxon.Cmd.DotNetTransform.Main(Unknown Source)
Fatal error during transformation: java.lang.NullPointerException:  (no message)



PS C:\tmp\test\2019-05-22-saxon-result-doc-bug> & 'C:\Program Files\Saxonica\SaxonPE9.9N\bin\Transform.exe' -it:main -xsl:test.xsl test=3
Running 3



PS C:\tmp\test\2019-05-22-saxon-result-doc-bug> & 'C:\Program Files\Saxonica\SaxonPE9.8N\bin\Transform.exe' -it:main -xsl:test.xsl test=4
Running 4
<?xml version="1.0" encoding="UTF-8"?>



PS C:\tmp\test\2019-05-22-saxon-result-doc-bug> & 'C:\Program Files\Saxonica\SaxonPE9.9N\bin\Transform.exe' -it:main -xsl:test.xsl test=4
Running 4


Conclusion:

9.9 seems to fix all the issues of 9.8

  • Now there's an error code ("saxon:XXXX9999"; I checked that separately)
  • No NullPointerException and correct matching the catch alternatives (I checked that separately)
  • In "test 4": I don't know why in 9.8 there is an XML prologue in the ouput ...

Having talked with the team, we will then go for the 9.9 Release.

Regards

Jan

#6 Updated by Michael Kay 4 months ago

Now reproduced (under 9.8). I hadn't appreciated the need to set test=3 on the command line.

I'm going to make the following changes:

(a) In 9.8, just in case we produce another maintenance release, make try/catch resilient to there being no error code in the exception object

(b) In 9.9 and trunk, ensure that this kind of error (an I/O error in Emitter.openConnection()) contains some kind of error code: it will probably be a Saxon-specific one since there's no obvious error code in the spec that covers this case.

(c) I might also consider adding a specific check to xsl:result-document for cases where we can detect without opening the file that it is actually a directory and therefore ineligible. This would tie the error more specifically to the xsl:result-document instruction which makes the diagnostics cleaner.

#7 Updated by Michael Kay 4 months ago

In trying to improve the diagnostics, I hit another little glitch: xsl:result-document has a "finally" block which tries to close the output file, and if this fails we report the secondary failure rather than the original one, which loses location information. Changes ResultDocument.processInstruction().

Allocated error code SXRD0004 for these conditions.

#8 Updated by Michael Kay 4 months ago

  • Category set to Diagnostics
  • Status changed from New to Resolved
  • Assignee set to Michael Kay
  • Priority changed from Low to Normal
  • Applies to branch 9.8, 9.9, trunk added
  • Fix Committed on Branch 9.8, 9.9, trunk added

#9 Updated by Jan Pertermann 4 months ago

Of course we appreciate an accurate error code and message - thanks for the resolution!

Can you estimate a date for the next maintenance release of 9.9?

Jan

#10 Updated by Michael Kay 4 months ago

At this stage of maturity in a release cycle, we generally produce a maintenance release every 8 weeks or so. But it can be sooner if an urgent problem is found, or longer if the bug traffic is very quiet.

#11 Updated by Michael Kay 3 months ago

  • Status changed from Resolved to In Progress

During testing of the maintenance release we found a regression caused by the change to StandardResultDocumentResolver.java - outputFile.canWrite() is returning false in the case where the path contains a non-existent directory. But later on we detect that and recover from it by creating the directory.

The logic for creating the directory is in XmlEmitter.makeOutputStream(), duplicated in ExpandedStreamResult, which is used by the JSON and Adaptive output methods (it could also be used by the older output methods, but we never got around to doing that).

I have extracted the duplicate code into a new static method ExpandedOutputStream.makeWriteableOutputFile().

#12 Updated by Michael Kay 3 months ago

  • Status changed from In Progress to Resolved

Also needed a tweak to the finally block in ResultDocument.processInstruction() - an error during out.close() wasn't being thrown as an exception, leading to test error-1555b failing.

#13 Updated by O'Neil Delpratt 3 months ago

  • % Done changed from 0 to 100
  • Fixed in Maintenance Release 9.9.1.4 added

Bug fix applied in the Saxon 9.9.1.4 maintenance release.

#14 Updated by O'Neil Delpratt 12 days ago

  • Status changed from Resolved to Closed
  • Fixed in Maintenance Release 9.9.1.5 added
  • Fixed in Maintenance Release deleted (9.9.1.4)

Bug fix applied in the Saxon 9.9.1.5 maintenance release.

Please register to edit this issue

Also available in: Atom PDF