Abstract
Players and modpack developers sometimes find the game crashed with ConcurrentModificationExceptions
(CME) and IndexOutOfBoundsExceptions
(IOOBE), which only give stacktrace of current thread and are hard to trace which mod causes them. Here's one of the crashes which is caused by SimpleReloadInstance in 1.20.1 Forge:
So this is what the mod is developed for. Players who install this mod and add javaagent to JVM Argument correctly will receive a full log for modification history of a certain collection:
Usage
First, add this jar to mods folder.
Second, edit your Java Virtual Machine Argument in your launcher. Add -javaagent:mods/CMESuckMyDuck-<version>.jar=<class full name>;<field name>;<type>;<phase>
.
Finally, run the game, play and wait until the crash happens.
Usage for Other Java Projects
This mod can not only be used for Minecraft debugging, but also be utilized to debug other java projects. Similar to Minecraft. The only different step is that you should add gson and asm jar to classpath (-cp
) before javaagent, and add our CMESuckMyDuck-<version>.jar
to classpath after javaagent.
Arguments
<class full name>
A full name of the class, which has a container that you would like to monitor. Use \
instead of .
(a.k.a. the internal name of class).
<field name>
A field name of the container in target class, which you would like to monitor. For Forge, use SRG name. For Fabric, use intermediary name. For NeoForge, use official name.
<type>
Currently, we only support three containers: List
, Set
, Map
. This argument indicates the type of monitored container.
<phase>
static
or nonstatic
. This argument indicates the container is a static field or non-static field.
How to get <class full name> and <field name>
Let's start with an example.
First, take a look at the stacktrace of CME/IOOBE:
Second, read the source code of SoundEngine and confirm which container is facing this issue:
Now we know we should monitor map field_217942_m
(instanceToChannel
in SoundEngine
). Keep going.
Third, install this mod, and add "-javaagent:mods/CMESuckMyDuck-1.0.0.jar=net/minecraft/client/audio/SoundEngine;field_217942_m;Map;nonstatic
" to Java Virtual Machine Argument. Relaunch the game and wait for the next crash.
Finally, open CMESuckMyDuck.log
file and you will see which thread and which mod has concurrently modified the container.
Examples (JVM Arguments)
ConcurrentModificationException from SoundEngine in Forge 1.16.5 Environment
-javaagent:mods/CMESuckMyDuck-1.0.0.jar=net/minecraft/client/audio/SoundEngine;field_217942_m;Map;nonstatic
ConcurrentModificationException from PotionBrewing in Forge 1.20.1 Environment
-javaagent:mods/CMESuckMyDuck-1.0.0.jar=net/minecraft/world/item/alchemy/PotionBrewing;f_43494_;List;static
ArrayIndexOutOfBoundsException from Zeta mod
-javaagent:CMESuckMyDuck-1.0.0.jar=org/violetmoon/zetaimplforge/event/ForgeZetaEventBus;convertedHandlers;Map;nonstatic
Other options
Log Level
Use system property -Dcme_suck_my_duck.log_level=<level>
to set custom log level.
Default 1, which means no debug message will be logged.
Users can set it to 0 to output debug message, which is not recommended - query functions like Map#get, Set#containsAll will also be logged when set to 0, and make the file very very long.
Conclusion
I like eating peking duck. It's so delicious!
90% of ad revenue goes to creators
Support creators and Modrinth ad-free with Modrinth+