Bug #6161
closed![Author: Johan Gheys](https://www.gravatar.com/avatar/488363e2a5858062d4459679a5d97e66?rating=PG&size=50&default=https%3A%2F%2Fassets.plan.io%2Fimages%2Fdefault_avatar.png)
![Assignee: Michael Kay](https://www.gravatar.com/avatar/db6526d63053f09b62e52c2da8b2230a?rating=PG&size=22&default=https%3A%2F%2Fassets.plan.io%2Fimages%2Fdefault_avatar.png)
net.sf.saxon.tree.iter.ReportingSingletonIterator.next throws NullPointerException - race condition
100%
Description
In our test environment, we recently started using Saxon-EE 12.3. During one of our transformations, we got the following error message:
2023-08-08 17:12:36 [main] Launching /tph/delete-obsolete-trains.xslt
2023-08-08 17:12:36 [main] parameter new-file=/var/opt/app/arte2/envs/u00t/interfac/exporter/tph/train.xml
2023-08-08 17:12:36 [main] parameter old-file=/var/opt/app/arte2/envs/u00t/interfac/exporter/tph/previous/train.xml
2023-08-08 17:12:36 [main] parameter output-folder=/var/opt/app/arte2/envs/u00t/interfac/exporter/tph/run/train-to-delete/
2023-08-08 17:12:36 [main] parameter working-folder=/var/opt/app/arte2/envs/u00t/interfac/exporter/tph/train/
2023-08-08 17:12:36 [main] Deleting /var/opt/app/arte2/envs/u00t/interfac/exporter/tph/train/train_EM_2411.xml
2023-08-08 17:12:36 [main] Deleting /var/opt/app/arte2/envs/u00t/interfac/exporter/tph/train/train_ME_2432.xml
2023-08-08 17:12:36 [main] Deleting /var/opt/app/arte2/envs/u00t/interfac/exporter/tph/train/train_EL_2613.xml
...
2023-08-08 17:12:36 [main] Deleting /var/opt/app/arte2/envs/u00t/interfac/exporter/tph/train/train_ZL_42843.xml
java.lang.NullPointerException
at net.sf.saxon.tree.iter.ReportingSingletonIterator.next(ReportingSingletonIterator.java:42)
at net.sf.saxon.expr.Atomizer.getAtomizingIterator(Atomizer.java:596)
at net.sf.saxon.expr.Atomizer$AtomizerElaborator.lambda$elaborateForPull$0(Atomizer.java:677)
at net.sf.saxon.expr.UntypedSequenceConverter$UntypedSequenceConverterElaborator.lambda$elaborateForPull$0(UntypedSequenceConverter.java:304)
at net.sf.saxon.expr.CardinalityChecker$CardinalityCheckerElaborator.lambda$elaborateForPull$0(CardinalityChecker.java:502)
at net.sf.saxon.expr.elab.SharedAppendEvaluator.lambda$new$1(SharedAppendEvaluator.java:42)
at net.sf.saxon.expr.elab.SharedAppendEvaluator.evaluate(SharedAppendEvaluator.java:63)
at net.sf.saxon.expr.SystemFunctionCall$SystemFunctionCallElaborator.lambda$elaborateForPull$1(SystemFunctionCall.java:605)
at net.sf.saxon.value.SingletonClosure.asItem(SingletonClosure.java:111)
at net.sf.saxon.value.SingletonClosure.materialize(SingletonClosure.java:162)
at net.sf.saxon.expr.elab.LocalVariableEvaluator.evaluate(LocalVariableEvaluator.java:31)
at net.sf.saxon.expr.SystemFunctionCall$SystemFunctionCallElaborator.lambda$elaborateForItem$5(SystemFunctionCall.java:652)
at net.sf.saxon.expr.AtomicSequenceConverter$AtomicSequenceConverterElaborator.lambda$elaborateForItem$1(AtomicSequenceConverter.java:534)
at net.sf.saxon.expr.LetExpression$LetExprElaborator.lambda$elaborateForItem$7(LetExpression.java:957)
at net.sf.saxon.expr.elab.PullElaborator.lambda$elaborateForUnicodeString$3(PullElaborator.java:76)
at net.sf.saxon.expr.instruct.ResultDocument.processLeft(ResultDocument.java:461)
at net.sf.saxon.expr.instruct.ResultDocument.processInstruction(ResultDocument.java:400)
at com.saxonica.config.EnterpriseConfiguration.lambda$processResultDocument$1(EnterpriseConfiguration.java:1926)
at java.util.concurrent.FutureTask.run(FutureTask.java:277)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:522)
at java.util.concurrent.FutureTask.run(FutureTask.java:277)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1160)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
at java.lang.Thread.run(Thread.java:825)
Please find attached the transformation in question. Note that a 2nd run gave no problems. Hopefully the above logging can help improve your code.
Files
Updated by Michael Kay 11 months ago
Thanks for reporting it. This is part of the new mechanism for learning whether a particular expression should be evaluated eagerly or lazily, and guess there could well be a thread-safety issue with it.
Updated by Michael Kay 11 months ago
- Tracker changed from Support to Bug
- Category set to Multithreading
- Status changed from New to In Progress
- Assignee set to Michael Kay
- Priority changed from Low to Normal
- Applies to branch 12, trunk added
- Platforms .NET, Java added
Updated by Michael Kay 11 months ago
- Status changed from In Progress to Resolved
I haven't been able to construct a repro, but from studying the code, I think that synchronizing SingletonClosure.asItem()
should be sufficient.
The method wasn't synchronized in 11.x, but I think the worst that could happen then would be that the value of a variable would be evaluated twice, which would normally be symptomless. We could synchronise a smaller block of code in 12.x to retain that behaviour, but I think that synchronizing the whole method makes more sense.
I'm puzzled by another aspect of the code, namely why do we give the SingletonClosure
a PullEvaluator
rather than an ItemEvaluator
over the input expression? The only justification seems to be that it enables inheritance from the abstract class Closure
and therefore a small amount of code reuse. Let's leave well alone on that one.
Updated by O'Neil Delpratt 8 months ago
- Status changed from Resolved to Closed
- % Done changed from 0 to 100
- Fixed in Maintenance Release 12.4 added
Bug fix applied in the Saxon 12.4 maintenance release
Please register to edit this issue