ConcurrentModificationException on SimpleTerminableRegistry.close()

Summary

The implementation of SimpleTerminableRegistry.close() cause ConcurrentModificationException in multi threads context.

Steps to reproduce

This bug occurs randomly when casting some aura and can not be reproduced stablely. I have checked the source and found out the cause.

Here is the stacktrace:

java.util.ConcurrentModificationException
	at java.base/java.util.ArrayList$Itr.checkForComodification(ArrayList.java:1095)
	at java.base/java.util.ArrayList$ListItr.previous(ArrayList.java:1122)
	at com.google.common.collect.Lists$ReverseList$1.next(Lists.java:935)
	at java.base/java.lang.Iterable.forEach(Iterable.java:74)
	at MythicMobs-5.7.2.jar//io.lumine.mythic.bukkit.utils.terminable.SimpleTerminableRegistry.close(SimpleTerminableRegistry.java:31)
	at MythicMobs-5.7.2.jar//io.lumine.mythic.bukkit.utils.terminable.Terminable.closeAndReportException(Terminable.java:61)
	at MythicMobs-5.7.2.jar//io.lumine.mythic.bukkit.utils.terminable.Terminable.terminate(Terminable.java:18)
	at MythicMobs-5.7.2.jar//io.lumine.mythic.core.skills.auras.Aura$AuraTracker.close(Aura.java:634)
	at MythicMobs-5.7.2.jar//io.lumine.mythic.bukkit.utils.terminable.Terminable.closeAndReportException(Terminable.java:61)
	at MythicMobs-5.7.2.jar//io.lumine.mythic.bukkit.utils.terminable.Terminable.terminate(Terminable.java:18)
	at MythicMobs-5.7.2.jar//io.lumine.mythic.core.skills.auras.Aura$AuraTracker.run(Aura.java:568)
	at MythicMobs-5.7.2.jar//io.lumine.mythic.bukkit.utils.Delegates$RunnableToConsumer.accept(Delegates.java:93)
	at MythicMobs-5.7.2.jar//io.lumine.mythic.bukkit.utils.Schedulers$LumineTask.run(Schedulers.java:184)
	at org.bukkit.craftbukkit.scheduler.CraftTask.run(CraftTask.java:86)
	at org.bukkit.craftbukkit.scheduler.CraftAsyncTask.run(CraftAsyncTask.java:57)
	at com.destroystokyo.paper.ServerSchedulerReportingWrapper.run(ServerSchedulerReportingWrapper.java:22)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642)
	at java.base/java.lang.Thread.run(Thread.java:1583)

The SimpleTerminableRegistry.close() method will iterate the termibales#List field in multi threads context. The list has been synchronized through Collections.synchronizedList() method. Howerver, the Collections#SynchronizedList.iterator()
method is not synced and needs to be synced manually but not in the code. The List.forEach() method will invoke the unsynced List.iterator() method, causing ConcurrentModificationException.

image

Proposed fixes

Sync the iteration in some way.

I have checked the source and this bug still exists in MM-5.8.0. But have not gotten it reproduced yet because of randomness.

Edited Jan 16, 2025 by Windmill1055
Assignee Loading
Time tracking Loading