apache / apache/logging-log4j2
When logging exceptions, the exception stack traces include dynamically generated class names, which leads to a memory leak.
- Dominant language
- Java
- Stars
- 3.6k
- Forks
- 1.7k
- Avg merge
- 21h 30m
- Merged PRs (30d)
- 27
Description
## Description
When using the Nashorn JavaScript engine, if an exception is thrown internally within the JavaScript code and this exception is logged using a logger, it results in a memory leak. Tracing the log4j source code reveals that log4j uses `ThrowableProxy` when handling exception parameters. `ThrowableProxy` calls `loadClass`. Because Nashorn dynamically generates some classes, the exception stack trace includes dynamically generated class names, which are not cached. This causes loadClass to add these class names to the `parallelLockMap` inside the ClassLoader, leading to a memory leak.
## Configuration
**Version:** 2.24.1
**Operating system:** Windows10
**JDK:** 1.8.0_331
## Logs
Below are some log fragments. Note the class names in the exception stack trace that follow the pattern `jdk.nashorn.internal.scripts.Script$Recompilation$19663$15$^eval_.test.` The numbers following Recompilation$ are incrementing.
```
a 2024-12-06 20:11:38,104 [main] ERROR c.l.t.l.TestJsEngine - Script execution exception
javax.script.ScriptException: Error: error in at line number 1 at column number 16
at jdk.nashorn.api.scripting.NashornScriptEngine.throwAsScriptException(NashornScriptEngine.java:470) ~[nashorn.jar:?]
at jdk.nashorn.api.scripting.NashornScriptEngine.invokeImpl(NashornScriptEngine.java:392) ~[nashorn.jar:?]
at jdk.nashorn.api.scripting.NashornScriptEngine.invokeFunction(NashornScriptEngine.java:190) ~[nashorn.jar:?]
at com.lt.test.log4j.TestJsEngine.main(TestJsEngine.java:33) [classes/:?]
Caused by: jdk.nashorn.internal.runtime.ECMAException: Error: error
at jdk.nashorn.internal.objects.NativeError.initException(NativeError.java:137) ~[nashorn.jar:?]
at jdk.nashorn.internal.objects.NativeError.(NativeError.java:102) ~[nashorn.jar:?]
at jdk.nashorn.internal.objects.NativeError.(NativeError.java:106) ~[nashorn.jar:?]
at jdk.nashorn.internal.objects.NativeError.(NativeError.java:110) ~[nashorn.jar:?]
at jdk.nashorn.internal.objects.NativeError.constructor(NativeError.java:129) ~[nashorn.jar:?]
at jdk.nashorn.internal.scripts.Script$Recompilation$19663$15$\^eval\_.test(:1) ~[?:?]
at jdk.nashorn.internal.runtime.ScriptFunctionData.invoke(ScriptFunctionData.java:637) ~[nashorn.jar:?]
at jdk.nashorn.internal.runtime.ScriptFunction.invoke(ScriptFunction.java:494) ~[nashorn.jar:?]
at jdk.nashorn.internal.runtime.ScriptRuntime.apply(ScriptRuntime.java:393) ~[nashorn.jar:?]
at jdk.nashorn.api.scripting.ScriptObjectMirror.callMember(ScriptObjectMirror.java:199) ~[nashorn.jar:?]
at jdk.nashorn.api.scripting.NashornScriptEngine.invokeImpl(NashornScriptEngine.java:386) ~[nashorn.jar:?]
... 2 more
aaaaa 2024-12-06 20:11:40,699 [main] ERROR c.l.t.l.TestJsEngine - Script execution exception
javax.script.ScriptException: Error: error in at line number 1 at column number 16
at jdk.nashorn.api.scripting.NashornScriptEngine.throwAsScriptException(NashornScriptEngine.java:470) ~[nashorn.jar:?]
at jdk.nashorn.api.scripting.NashornScriptEngine.invokeImpl(NashornScriptEngine.java:392) ~[nashorn.jar:?]
at jdk.nashorn.api.scripting.NashornScriptEngine.invokeFunction(NashornScriptEngine.java:190) ~[nashorn.jar:?]
at com.lt.test.log4j.TestJsEngine.main(TestJsEngine.java:33) [classes/:?]
Caused by: jdk.nashorn.internal.runtime.ECMAException: Error: error
at jdk.nashorn.internal.objects.NativeError.initException(NativeError.java:137) ~[nashorn.jar:?]
at jdk.nashorn.internal.objects.NativeError.(NativeError.java:102) ~[nashorn.jar:?]
at jdk.nashorn.internal.objects.NativeError.(NativeError.java:106) ~[nashorn.jar:?]
at jdk.nashorn.internal.objects.NativeError.(NativeError.java:110) ~[nashorn.jar:?]
at jdk.nashorn.internal.objects.NativeError.constructor(NativeError.java:129) ~[nashorn.jar:?]
at jdk.nashorn.internal.scripts.Script$Recompilation$19665$15$\^eval\_.test(:1) ~[?:?]
at jdk.nashorn.internal.runtime.ScriptFunctionData.invoke(ScriptFunctionData.java:637) ~[nashorn.jar:?]
at jdk.nashorn.internal.runtime.ScriptFunction.invoke(ScriptFunction.java:494) ~[nashorn.jar:?]
at jdk.nashorn.internal.runtime.ScriptRuntime.apply(ScriptRuntime.java:393) ~[nashorn.jar:?]
at jdk.nashorn.api.scripting.ScriptObjectMirror.callMember(ScriptObjectMirror.java:199) ~[nashorn.jar:?]
at jdk.nashorn.api.scripting.NashornScriptEngine.invokeImpl(NashornScriptEngine.java:386) ~[nashorn.jar:?]
... 2 more
*** java.lang.instrument ASSERTION FAILED ***: "!errorOutstanding" with message can't create byte arrau at JPLISAgent.c line: 813
Exception in thread "main" java.lang.InternalError: BMH.reinvoke=Lambda(a0:L/SpeciesData,a1:L)=>{
t2:L=BoundMethodHandle$Species_LIL.argL2(a0:L);
t3:I=BoundMethodHandle$Species_LIL.argI1(a0:L);
t4:L=BoundMethodHandle$Species_LIL.argL0(a0:L);
t5:L=MethodHandle.invokeBasic(t4:L,t2:L,a1:L,t3:I);t5:L}
at java.lang.invoke.MethodHandleStatics.newInternalError(MethodHandleStatics.java:127)
at java.lang.invoke.LambdaForm.compileToBytecode(LambdaForm.java:660)
at java.lang.invoke.LambdaForm.prepare(LambdaForm.java:635)
at java.lang.invoke.MethodHandle.(MethodHandle.java:461)
at java.lang.invoke.BoundMethodHandle.(BoundMethodHandle.java:58)
at java.lang.invoke.BoundMethodHandle$Species_LIL.(Species_LIL)
at java.lang.invoke.BoundMethodHandle$Species_LIL.make(Species_LIL)
at java.lang.invoke.BoundMethodHandle$Species_LI.copyWithExtendL(Species_LI)
at java.lang.invoke.LambdaFormEditor.bindArgumentL(LambdaFormEditor.java:404)
at java.lang.invoke.BoundMethodHandle.bindArgumentL(BoundMethodHandle.java:99)
at java.lang.invoke.MethodHandles.insertArguments(MethodHandles.java:2379)
at jdk.internal.dynalink.ChainedCallSite.makePruneAndInvokeMethod(ChainedCallSite.java:226)
at jdk.internal.dynalink.ChainedCallSite.relinkInternal(ChainedCallSite.java:184)
at jdk.internal.dynalink.ChainedCallSite.relink(ChainedCallSite.java:149)
at jdk.nashorn.internal.runtime.linker.LinkerCallSite.relink(LinkerCallSite.java:142)
at jdk.internal.dynalink.DynamicLinker.relink(DynamicLinker.java:285)
at jdk.nashorn.internal.scripts.Script$19666$\^eval\_.:program(:1)
at jdk.nashorn.internal.runtime.ScriptFunctionData.invoke(ScriptFunctionData.java:637)
at jdk.nashorn.internal.runtime.ScriptFunction.invoke(ScriptFunction.java:494)
at jdk.nashorn.internal.runtime.ScriptRuntime.apply(ScriptRuntime.java:393)
at jdk.nashorn.api.scripting.NashornScriptEngine.evalImpl(NashornScriptEngine.java:449)
at jdk.nashorn.api.scripting.NashornScriptEngine.evalImpl(NashornScriptEngine.java:406)
at jdk.nashorn.api.scripting.NashornScriptEngine.evalImpl(NashornScriptEngine.java:402)
at jdk.nashorn.api.scripting.NashornScriptEngine.eval(NashornScriptEngine.java:155)
at javax.script.AbstractScriptEngine.eval(AbstractScriptEngine.java:264)
at com.lt.test.log4j.TestJsEngine.main(TestJsEngine.java:27)
Caused by: java.lang.OutOfMemoryError: GC overhead limit exceeded
at jdk.internal.org.objectweb.asm.ClassWriter.newUTF8(ClassWriter.java:1122)
at jdk.internal.org.objectweb.asm.ClassWriter.newNameTypeItem(ClassWriter.java:1591)
at jdk.internal.org.objectweb.asm.ClassWriter.newNameType(ClassWriter.java:1574)
at jdk.internal.org.objectweb.asm.ClassWriter.newMethodItem(ClassWriter.java:1436)
at jdk.internal.org.objectweb.asm.MethodWriter.visitMethodInsn(MethodWriter.java:917)
at java.lang.invoke.InvokerBytecodeGenerator.emitStaticInvoke(InvokerBytecodeGenerator.java:867)
at java.lang.invoke.InvokerBytecodeGenerator.generateCustomizedCodeBytes(InvokerBytecodeGenerator.java:715)
at java.lang.invoke.InvokerBytecodeGenerator.generateCustomizedCode(InvokerBytecodeGenerator.java:618)
at java.lang.invoke.LambdaForm.compileToBytecode(LambdaForm.java:654)
at java.lang.invoke.LambdaForm.prepare(LambdaForm.java:635)
at java.lang.invoke.MethodHandle.(MethodHandle.java:461)
at java.lang.invoke.BoundMethodHandle.(BoundMethodHandle.java:58)
at java.lang.invoke.BoundMethodHandle$Species_LIL.(Species_LIL)
at java.lang.invoke.BoundMethodHandle$Species_LIL.make(Species_LIL)
at java.lang.invoke.LambdaForm$DMH/221634215.invokeStatic_L3IL_L(LambdaForm$DMH)
at java.lang.invoke.BoundMethodHandle$Species_LI.copyWithExtendL(Species_LI)
at java.lang.invoke.LambdaFormEditor.bindArgumentL(LambdaFormEditor.java:404)
at java.lang.invoke.BoundMethodHandle.bindArgumentL(BoundMethodHandle.java:99)
at java.lang.invoke.MethodHandles.insertArguments(MethodHandles.java:2379)
at jdk.internal.dynalink.ChainedCallSite.makePruneAndInvokeMethod(ChainedCallSite.java:226)
at jdk.internal.dynalink.ChainedCallSite.relinkInternal(ChainedCallSite.java:184)
at jdk.internal.dynalink.ChainedCallSite.relink(ChainedCallSite.java:149)
at jdk.nashorn.internal.runtime.linker.LinkerCallSite.relink(LinkerCallSite.java:142)
at jdk.internal.dynalink.DynamicLinker.relink(DynamicLinker.java:285)
at java.lang.invoke.LambdaForm$DMH/1976870338.invokeSpecial_LLIL_L(LambdaForm$DMH)
at java.lang.invoke.LambdaForm$BMH/645206471.reinvoke(LambdaForm$BMH)
at java.lang.invoke.LambdaForm$MH/480903748.exactInvoker(LambdaForm$MH)
at java.lang.invoke.LambdaForm$MH/756400524.linkToCallSite(LambdaForm$MH)
at jdk.nashorn.internal.scripts.Script$19666$\^eval\_.:program(:1)
at java.lang.invoke.LambdaForm$DMH/664223387.invokeStatic_LL_L(LambdaForm$DMH)
at java.lang.invoke.LambdaForm$MH/1278254413.invokeExact_MT(LambdaForm$MH)
at jdk.nashorn.internal.runtime.ScriptFunctionData.invoke(ScriptFunctionData.java:637)
```
## Reproduction
Below is my test case, with memory settings configured as -Xms10m -Xmx10m. The program runs for 2 minutes and 24 seconds before an OutOfMemoryError (OOM) occurs.
```java
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.script.Invocable;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
public class TestJsEngine {
private static final Logger LOGGER = LoggerFactory.getLogger(TestJsEngine.class);
public static void main(String[] args) {
//Set the class cache size to 0
System.setProperty("nashorn.option.class.cache.size", "0");
ScriptEngineManager engineManager = new ScriptEngineManager();
ScriptEngine engine = engineManager.getEngineByName("javascript");
String content = "function test(){" +
"throw new Error('error'); " +
"}";
while (true) {
try {
engine.eval(content);
} catch (ScriptException e) {
LOGGER.error("eval script exception", e);
}
Invocable in = (Invocable) engine;
try {
in.invokeFunction("test");
} catch (ScriptException e) {
LOGGER.error("Script execution exception", e);
} catch (NoSuchMethodException e) {
}
}
}
}
```
Contributor guide
No contributing guide indexed for this repository
Research direction
Start with the ThrowableProxy class and trace its handling of exception stack-trace class names. Run the supplied Nashorn reproduction with the stated JDK and memory settings, then compare behavior before and after a change. Done means repeated exception logging no longer leads to the reported memory exhaustion, with regression coverage for the scenario.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java
- Domain
- backend
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Needs clarification
- Newbie friendliness
- 35/100