Carpet

Carpet

2M Downloads

`script run global_x = 'script run run(global_x)'; run(global_x)` crashes the game

James103 opened this issue ยท 1 comments

commented

When running script run global_x = 'script run run(global_x)'; run(global_x) in Carpet mod versions 1.4.47 through 1.4.50+ and Minecraft 1.17.1, the command can crash the game with the following error:

java.lang.NoClassDefFoundError: carpet.script.exception.ExpressionException (initialization failure)
	at java.base/java.lang.J9VMInternals.initializationAlreadyFailed(J9VMInternals.java:134)
	at carpet.script.Expression.evalValue(Expression.java:950)
	at carpet.script.Expression.eval(Expression.java:931)
	at carpet.script.CarpetExpression.lambda$scriptRunCommand$13(CarpetExpression.java:112)
	at carpet.script.CarpetExpression$$Lambda$5050/0x00000000975b90b0.get(Unknown Source)
	at carpet.script.utils.GlocalFlag.whileValueReturn(GlocalFlag.java:42)
	at carpet.script.utils.GlocalFlag.getWhileDisabled(GlocalFlag.java:28)
	at carpet.script.CarpetExpression.scriptRunCommand(CarpetExpression.java:112)
	at carpet.commands.ScriptCommand.lambda$compute$69(ScriptCommand.java:507)
	at carpet.commands.ScriptCommand$$Lambda$5434/0x00000000977f3108.get(Unknown Source)
	at carpet.commands.ScriptCommand.handleCall(ScriptCommand.java:439)
	at carpet.commands.ScriptCommand.compute(ScriptCommand.java:505)
	at carpet.commands.ScriptCommand.lambda$register$17(ScriptCommand.java:144)
	at carpet.commands.ScriptCommand$$Lambda$4310/0x00000000964b0da0.run(Unknown Source)
	at com.mojang.brigadier.CommandDispatcher.execute(CommandDispatcher.java:263)
	at com.mojang.brigadier.CommandDispatcher.execute(CommandDispatcher.java:177)
	at net.minecraft.class_2170.method_9249(class_2170.java:251)
	at carpet.script.api.Auxiliary.lambda$apply$25(Auxiliary.java:629)
	at carpet.script.api.Auxiliary$$Lambda$4259/0x0000000095770c30.apply(Unknown Source)
	at carpet.script.Expression$17.lazyEval(Expression.java:597)
	at carpet.script.Expression.lambda$extractOp$19(Expression.java:1344)
	at carpet.script.Expression$$Lambda$5068/0x00000000975bf1e0.evalValue(Unknown Source)
	at carpet.script.Expression.evalValue(Expression.java:938)
	at carpet.script.Expression.eval(Expression.java:931)
	at carpet.script.CarpetExpression.lambda$scriptRunCommand$13(CarpetExpression.java:112)
	at carpet.script.CarpetExpression$$Lambda$5050/0x00000000975b90b0.get(Unknown Source)
	at carpet.script.utils.GlocalFlag.whileValueReturn(GlocalFlag.java:42)
	at carpet.script.utils.GlocalFlag.getWhileDisabled(GlocalFlag.java:28)
	at carpet.script.CarpetExpression.scriptRunCommand(CarpetExpression.java:112)
	at carpet.commands.ScriptCommand.lambda$compute$69(ScriptCommand.java:507)
	at carpet.commands.ScriptCommand$$Lambda$5434/0x00000000977f3108.get(Unknown Source)
	at carpet.commands.ScriptCommand.handleCall(ScriptCommand.java:439)
	at carpet.commands.ScriptCommand.compute(ScriptCommand.java:505)
	at carpet.commands.ScriptCommand.lambda$register$17(ScriptCommand.java:144)
	at carpet.commands.ScriptCommand$$Lambda$4310/0x00000000964b0da0.run(Unknown Source)
... thousands more
Caused by: java.lang.StackOverflowError
	at java.base/java.lang.J9VMInternals.fastIdentityHashCode(J9VMInternals.java:406)
	at java.base/java.lang.Object.hashCode(Object.java:122)
	at java.base/java.lang.invoke.MethodType.hashCode(MethodType.java:433)
	at java.base/java.util.WeakHashMap.hash(WeakHashMap.java:303)
	at java.base/java.util.WeakHashMap.get(WeakHashMap.java:402)
	at java.base/java.util.Collections$SynchronizedMap.get(Collections.java:2634)
	at java.base/java.lang.invoke.MethodType.probeTable(MethodType.java:623)
	at java.base/java.lang.invoke.MethodType.intern(MethodType.java:578)
	at java.base/java.lang.invoke.MethodType.methodType(MethodType.java:567)
	at java.base/java.lang.invoke.MethodType.methodType(MethodType.java:557)
	at java.base/java.lang.invoke.ThunkKey.computeThunkableType(MethodHandle.java:1144)
	at java.base/java.lang.invoke.ThunkKey.computeThunkableType(MethodHandle.java:1133)
	at java.base/java.lang.invoke.ThunkKey.computeThunkableType(MethodHandle.java:1130)
	at java.base/java.lang.invoke.MethodHandle.computeThunks(MethodHandle.java:180)
	at java.base/java.lang.invoke.MethodHandle.<init>(MethodHandle.java:233)
	at java.base/java.lang.invoke.PrimitiveHandle.<init>(PrimitiveHandle.java:62)
	at java.base/java.lang.invoke.PrimitiveHandle.<init>(PrimitiveHandle.java:70)
	at java.base/java.lang.invoke.DirectHandle.<init>(DirectHandle.java:47)
	at java.base/java.lang.invoke.DirectHandle.<init>(DirectHandle.java:43)
	at java.base/java.lang.invoke.MethodHandles$Lookup.findStatic(MethodHandles.java:697)
	at java.base/java.lang.invoke.MethodHandleResolver.sendResolveMethodHandle(MethodHandleResolver.java:312)
	at java.base/java.lang.invoke.MethodHandleResolver.getCPMethodHandleAt(Native Method)
	at java.base/java.lang.invoke.MethodHandleResolver.resolveInvokeDynamic(MethodHandleResolver.java:215)
... thousands more

If this crash occurs in the integrated server when NotEnoughCrashes is installed, then any further Scarpet exceptions will always crash the whole server for similar reasons until the whole instance process is restarted.

The crash is likely because Scarpet code runs into a StackOverflowError (which should be catched and rethrown as an Expression Exception that prints as "Your thoughts are too deep"), but it fails at initializing carpet.script.exception.ExpressionException. When the game is restarted, that class is still not fully initialized (as it failed to do so before), leading to subsequent crashes on any Scarpet exception.

commented

Scarpet doesn't throw the StackOverflowException, Java does. And the jvm state after recovering from a StackOverflow can be quite bad. In this case, Scarpet is trying to throw an ExpressionException (after catching the StackOverflow, so it can present a better error message), but since it isn't initialized yet, Java tries to initialize but runs into a new StackOverflow (we already had only a few frames available). And the behaviour of Java after failing to load a class because an exception was thrown during its initialization is to not retry, so it throws ClassDefNotFoundError in there (because the next frame down the stack is also trying to access ExpressionException I assume). Errors aren't caught because, other than StackOverflow, they should not happen.

Possible solutions are to noop ExpressionException at startup so it is always properly loaded, but then the error could just come from somewhere else trying to do something slightly complex with almost no stack frames available...