Project

Profile

Help

Bug #6161

closed

net.sf.saxon.tree.iter.ReportingSingletonIterator.next throws NullPointerException - race condition

Added by Johan Gheys 9 months ago. Updated 5 months ago.

Status:
Closed
Priority:
Normal
Assignee:
Category:
Multithreading
Sprint/Milestone:
-
Start date:
2023-08-09
Due date:
% Done:

100%

Estimated time:
Legacy ID:
Applies to branch:
12, trunk
Fix Committed on Branch:
Fixed in Maintenance Release:
Platforms:
.NET, Java

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

delete-obsolete-trains.xslt (1.66 KB) delete-obsolete-trains.xslt Johan Gheys, 2023-08-09 09:17
Actions #1

Updated by Michael Kay 9 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.

Actions #2

Updated by Michael Kay 9 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
Actions #3

Updated by Michael Kay 9 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.

Actions #4

Updated by O'Neil Delpratt 5 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

Also available in: Atom PDF