Skip to content

Crash when opening custom cube dialog #9504

@vkordic

Description

@vkordic

Describe the bug
When trying to start a Custom Cube draft, the program crashes and needs to be killed through Task Manager.
It does not happen every time.

This is the stack trace:

Language 'en-US' loaded successfully.
(ThreadUtil first call): Running on a machine with 16 cpu core(s)
Firdoch Core has neither ManaCost nor Color
Read cards: 32158 archived files in 1 ms (25 parts) using thread pool
Upcoming set Marvel Super Heroes (MSH) dated in the future. All `upcoming` cards will be added to this set with unknown rarity.
The card A-Baba Lysaga, Night Witch was not assigned to any set. Adding it to UNKNOWN set... to fix see res/editions/ folder. 
The card A-Divide by Zero was not assigned to any set. Adding it to UNKNOWN set... to fix see res/editions/ folder. 
The card A-Esika's Chariot was not assigned to any set. Adding it to UNKNOWN set... to fix see res/editions/ folder. 
The card A-Faceless Haven was not assigned to any set. Adding it to UNKNOWN set... to fix see res/editions/ folder. 
The card A-Fires of Invention was not assigned to any set. Adding it to UNKNOWN set... to fix see res/editions/ folder. 
The card A-Goldspan Dragon was not assigned to any set. Adding it to UNKNOWN set... to fix see res/editions/ folder. 
The card A-Hullbreaker Horror was not assigned to any set. Adding it to UNKNOWN set... to fix see res/editions/ folder. 
The card A-Kumano Faces Kakkazan was not assigned to any set. Adding it to UNKNOWN set... to fix see res/editions/ folder. 
The card A-Luminarch Aspirant was not assigned to any set. Adding it to UNKNOWN set... to fix see res/editions/ folder. 
The card A-Monster Manual was not assigned to any set. Adding it to UNKNOWN set... to fix see res/editions/ folder. 
The card A-The Meathook Massacre was not assigned to any set. Adding it to UNKNOWN set... to fix see res/editions/ folder. 
The card Blinding Radiance was not assigned to any set. Adding it to UNKNOWN set... to fix see res/editions/ folder. 
The card Goblin Bruiser was not assigned to any set. Adding it to UNKNOWN set... to fix see res/editions/ folder. 
The card Ogre Painbringer was not assigned to any set. Adding it to UNKNOWN set... to fix see res/editions/ folder. 
The card Titanic Pelagosaur was not assigned to any set. Adding it to UNKNOWN set... to fix see res/editions/ folder. 
The card Treetop Recluse was not assigned to any set. Adding it to UNKNOWN set... to fix see res/editions/ folder. 
Upcoming set Marvel Super Heroes (MSH) dated in the future. All `upcoming` cards will be added to this set with unknown rarity.
Read cards: 789 files in 0 ms (7 parts) using thread pool
java.util.concurrent.CompletionException: java.lang.NullPointerException: Cannot read field "left" because "r" is null
	at java.base/java.util.concurrent.CompletableFuture.encodeThrowable(CompletableFuture.java:315)
	at java.base/java.util.concurrent.CompletableFuture.completeThrowable(CompletableFuture.java:320)
	at java.base/java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1770)
	at java.base/java.util.concurrent.CompletableFuture$AsyncSupply.exec(CompletableFuture.java:1760)
	at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:373)
	at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1182)
	at java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1655)
	at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1622)
	at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:165)
Caused by: java.lang.NullPointerException: Cannot read field "left" because "r" is null
	at java.base/java.util.TreeMap.rotateLeft(TreeMap.java:2543)
	at java.base/java.util.TreeMap.fixAfterInsertion(TreeMap.java:2610)
	at java.base/java.util.TreeMap.addEntry(TreeMap.java:770)
	at java.base/java.util.TreeMap.put(TreeMap.java:828)
	at java.base/java.util.TreeMap.put(TreeMap.java:534)
	at com.google.common.collect.AbstractMapBasedMultimap.put(AbstractMapBasedMultimap.java:191)
	at com.google.common.collect.AbstractListMultimap.put(AbstractListMultimap.java:118)
	at forge.card.CardEdition.getCardInSet(CardEdition.java:437)
	at forge.card.CardEdition.hasBasicLands(CardEdition.java:1083)
	at forge.card.CardEdition$Predicates.lambda$static$3(CardEdition.java:1062)
	at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:178)
	at java.base/java.util.Spliterators$IteratorSpliterator.tryAdvance(Spliterators.java:1856)
	at java.base/java.util.stream.StreamSpliterators$WrappingSpliterator.lambda$initPartialTraversalState$0(StreamSpliterators.java:292)
	at java.base/java.util.stream.StreamSpliterators$AbstractWrappingSpliterator.fillBuffer(StreamSpliterators.java:206)
	at java.base/java.util.stream.StreamSpliterators$AbstractWrappingSpliterator.doAdvance(StreamSpliterators.java:161)
	at java.base/java.util.stream.StreamSpliterators$WrappingSpliterator.tryAdvance(StreamSpliterators.java:298)
	at java.base/java.util.Spliterators$1Adapter.hasNext(Spliterators.java:681)
	at forge.util.Aggregates.random(Aggregates.java:145)
	at forge.card.CardEdition$Predicates.getRandomSetWithAllBasicLands(CardEdition.java:1031)
	at forge.gamemodes.limited.CustomLimited.<init>(CustomLimited.java:57)
	at forge.gamemodes.limited.CustomLimited.parse(CustomLimited.java:115)
	at forge.gamemodes.limited.BoosterDraft.lambda$loadCustomDrafts$1(BoosterDraft.java:432)
	at java.base/java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1768)
	... 6 more
java.util.concurrent.CompletionException: java.lang.NullPointerException: Cannot read field "left" because "r" is null
	at java.base/java.util.concurrent.CompletableFuture.encodeThrowable(CompletableFuture.java:315)
	at java.base/java.util.concurrent.CompletableFuture.completeThrowable(CompletableFuture.java:320)
	at java.base/java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1770)
	at java.base/java.util.concurrent.CompletableFuture$AsyncSupply.exec(CompletableFuture.java:1760)
	at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:373)
	at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1182)
	at java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1655)
	at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1622)
	at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:165)
Caused by: java.lang.NullPointerException: Cannot read field "left" because "r" is null
	at java.base/java.util.TreeMap.rotateLeft(TreeMap.java:2543)
	at java.base/java.util.TreeMap.fixAfterInsertion(TreeMap.java:2610)
	at java.base/java.util.TreeMap.addEntry(TreeMap.java:770)
	at java.base/java.util.TreeMap.put(TreeMap.java:828)
	at java.base/java.util.TreeMap.put(TreeMap.java:534)
	at com.google.common.collect.AbstractMapBasedMultimap.put(AbstractMapBasedMultimap.java:191)
	at com.google.common.collect.AbstractListMultimap.put(AbstractListMultimap.java:118)
	at forge.card.CardEdition.getCardInSet(CardEdition.java:437)
	at forge.card.CardEdition.hasBasicLands(CardEdition.java:1083)
	at forge.card.CardEdition$Predicates.lambda$static$3(CardEdition.java:1062)
	at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:178)
	at java.base/java.util.Spliterators$IteratorSpliterator.tryAdvance(Spliterators.java:1856)
	at java.base/java.util.stream.StreamSpliterators$WrappingSpliterator.lambda$initPartialTraversalState$0(StreamSpliterators.java:292)
	at java.base/java.util.stream.StreamSpliterators$AbstractWrappingSpliterator.fillBuffer(StreamSpliterators.java:206)
	at java.base/java.util.stream.StreamSpliterators$AbstractWrappingSpliterator.doAdvance(StreamSpliterators.java:169)
	at java.base/java.util.stream.StreamSpliterators$WrappingSpliterator.tryAdvance(StreamSpliterators.java:298)
	at java.base/java.util.Spliterators$1Adapter.hasNext(Spliterators.java:681)
	at forge.util.Aggregates.random(Aggregates.java:145)
	at forge.card.CardEdition$Predicates.getRandomSetWithAllBasicLands(CardEdition.java:1031)
	at forge.gamemodes.limited.CustomLimited.<init>(CustomLimited.java:57)
	at forge.gamemodes.limited.CustomLimited.parse(CustomLimited.java:115)
	at forge.gamemodes.limited.BoosterDraft.lambda$loadCustomDrafts$1(BoosterDraft.java:432)
	at java.base/java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1768)
	... 6 more
java.util.concurrent.CompletionException: java.lang.NullPointerException: Cannot read field "left" because "r" is null
	at java.base/java.util.concurrent.CompletableFuture.encodeThrowable(CompletableFuture.java:315)
	at java.base/java.util.concurrent.CompletableFuture.completeThrowable(CompletableFuture.java:320)
	at java.base/java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1770)
	at java.base/java.util.concurrent.CompletableFuture$AsyncSupply.exec(CompletableFuture.java:1760)
	at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:373)
	at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1182)
... (162 lines left)

To Reproduce
Steps to reproduce the behavior:

  1. Start Forge
  2. Choose 'Booster Draft' under Sanctioned Formats
  3. Choose 'New Booster Draft Game'
  4. Choose 'Custom Cube'
  5. The program sometimes crashes and sometimes opens the expected dialog. If the dialog opened, restart Forge and retry.

Expected behavior
A dialog with a choice of different Cubes should open.

Desktop:

  • OS: Windows 10
  • Forge version: 2.0.09-SNAPSHOT-01.09

Possible cause

It seems to me that the issue might be caused by CardEdition.getCardInSet putting stuff into a ListMultimap which is not thread safe.

    at com.google.common.collect.AbstractListMultimap.put(AbstractListMultimap.java:118)
    at forge.card.CardEdition.getCardInSet(CardEdition.java:437)

I tried wrapping the map initialization into a SynchronizedListMultimap like the javadoc of Multimaps.newListMultimap suggests; after that I tried reproducing the error about ten times and it did not occur again:

    ListMultimap<String, EditionEntry> threadUnsafeMultimap = Multimaps.newListMultimap(new TreeMap<>(String.CASE_INSENSITIVE_ORDER), Lists::newArrayList);
    cardsInSetLookupMap = Multimaps.synchronizedListMultimap(threadUnsafeMultimap);

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions