Peter Hofer reported the following output with -Xcheck:jni when using a JVM TI agent:
FATAL ERROR in native method: Wrong object class or methodID passed to JNI call
at jdk.internal.vm.Continuation.run(java.base/Continuation.java:260)
at java.lang.VirtualThread.runContinuation(java.base/VirtualThread.java:213)
at java.lang.VirtualThread$$Lambda$44/0x00000008000a2490.run(java.base/Unknown Source)
at java.util.concurrent.ForkJoinTask$RunnableExecuteAction.exec(java.base/ForkJoinTask.java:1423)
at java.util.concurrent.ForkJoinTask.doExec(java.base/ForkJoinTask.java:387)
at java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(java.base/ForkJoinPool.java:1311)
at java.util.concurrent.ForkJoinPool.scan(java.base/ForkJoinPool.java:1840)
at java.util.concurrent.ForkJoinPool.runWorker(java.base/ForkJoinPool.java:1806)
at java.util.concurrent.ForkJoinWorkerThread.run(java.base/ForkJoinWorkerThread.java:177)
The issue here is not the crash or the reasons for it, but that the stack trace printed by ReportJNIFatalError is not very useful when there are virtual thread frames on the stack and the thread identity has temporarily switched to the carrier thread. The thread stack printing supports just the carrier stack frames or just the virtual thread stack frames but the scenario where the thread identity has to temporarily switch to the carrier is complicated and we should except a stack trace like this:
at java.lang.Class.isArray()
at java.lang.invoke.MethodHandles$Lookup.isClassAccessible
at java.lang.invoke.MethodHandles$Lookup.checkSymbolicClass
at java.lang.invoke.MethodHandles$Lookup.resolveOrFail
at java.lang.invoke.MethodHandles$Lookup.findVarHandle
at java.lang.invoke.MethodHandles$Lookup.findVarHandle
at java.util.concurrent.FutureTask.<clinit>
at java.util.concurrent.ScheduledThreadPoolExecutor.schedule
at java.lang.VirtualThread.scheduleUnpark. <=== thread identity changes to the carrier thread here
at java.lang.VirtualThread.parkNanos
at java.lang.VirtualThread.doSleepNanos
at java.lang.VirtualThread.sleepNanos
at java.lang.Thread.sleep
at gameoflife.GameOfLife.sleep
at gameoflife.GameOfLife.run
at jdk.internal.vm.Continuation.enterSpecial
at jdk.internal.vm.Continuation.run(java.base/Continuation.java:260)
at java.lang.VirtualThread.runContinuation(java.base/VirtualThread.java:213)
at java.lang.VirtualThread$$Lambda$44/0x00000008000a2490.run(java.base/Unknown Source)
at java.util.concurrent.ForkJoinTask$RunnableExecuteAction.exec(java.base/ForkJoinTask.java:1423)
at java.util.concurrent.ForkJoinTask.doExec(java.base/ForkJoinTask.java:387)
at java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(java.base/ForkJoinPool.java:1311)
at java.util.concurrent.ForkJoinPool.scan(java.base/ForkJoinPool.java:1840)
at java.util.concurrent.ForkJoinPool.runWorker(java.base/ForkJoinPool.java:1806)
at java.util.concurrent.ForkJoinWorkerThread.run(java.base/ForkJoinWorkerThread.java:177)
For JNI fatal errors then I think the simplest is to print all stack frames (there are flags for that).
FATAL ERROR in native method: Wrong object class or methodID passed to JNI call
at jdk.internal.vm.Continuation.run(java.base/Continuation.java:260)
at java.lang.VirtualThread.runContinuation(java.base/VirtualThread.java:213)
at java.lang.VirtualThread$$Lambda$44/0x00000008000a2490.run(java.base/Unknown Source)
at java.util.concurrent.ForkJoinTask$RunnableExecuteAction.exec(java.base/ForkJoinTask.java:1423)
at java.util.concurrent.ForkJoinTask.doExec(java.base/ForkJoinTask.java:387)
at java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(java.base/ForkJoinPool.java:1311)
at java.util.concurrent.ForkJoinPool.scan(java.base/ForkJoinPool.java:1840)
at java.util.concurrent.ForkJoinPool.runWorker(java.base/ForkJoinPool.java:1806)
at java.util.concurrent.ForkJoinWorkerThread.run(java.base/ForkJoinWorkerThread.java:177)
The issue here is not the crash or the reasons for it, but that the stack trace printed by ReportJNIFatalError is not very useful when there are virtual thread frames on the stack and the thread identity has temporarily switched to the carrier thread. The thread stack printing supports just the carrier stack frames or just the virtual thread stack frames but the scenario where the thread identity has to temporarily switch to the carrier is complicated and we should except a stack trace like this:
at java.lang.Class.isArray()
at java.lang.invoke.MethodHandles$Lookup.isClassAccessible
at java.lang.invoke.MethodHandles$Lookup.checkSymbolicClass
at java.lang.invoke.MethodHandles$Lookup.resolveOrFail
at java.lang.invoke.MethodHandles$Lookup.findVarHandle
at java.lang.invoke.MethodHandles$Lookup.findVarHandle
at java.util.concurrent.FutureTask.<clinit>
at java.util.concurrent.ScheduledThreadPoolExecutor.schedule
at java.lang.VirtualThread.scheduleUnpark. <=== thread identity changes to the carrier thread here
at java.lang.VirtualThread.parkNanos
at java.lang.VirtualThread.doSleepNanos
at java.lang.VirtualThread.sleepNanos
at java.lang.Thread.sleep
at gameoflife.GameOfLife.sleep
at gameoflife.GameOfLife.run
at jdk.internal.vm.Continuation.enterSpecial
at jdk.internal.vm.Continuation.run(java.base/Continuation.java:260)
at java.lang.VirtualThread.runContinuation(java.base/VirtualThread.java:213)
at java.lang.VirtualThread$$Lambda$44/0x00000008000a2490.run(java.base/Unknown Source)
at java.util.concurrent.ForkJoinTask$RunnableExecuteAction.exec(java.base/ForkJoinTask.java:1423)
at java.util.concurrent.ForkJoinTask.doExec(java.base/ForkJoinTask.java:387)
at java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(java.base/ForkJoinPool.java:1311)
at java.util.concurrent.ForkJoinPool.scan(java.base/ForkJoinPool.java:1840)
at java.util.concurrent.ForkJoinPool.runWorker(java.base/ForkJoinPool.java:1806)
at java.util.concurrent.ForkJoinWorkerThread.run(java.base/ForkJoinWorkerThread.java:177)
For JNI fatal errors then I think the simplest is to print all stack frames (there are flags for that).
- relates to
-
JDK-8293613 need to properly handle and hide tmp VTMS transitions
-
- Resolved
-
-
JDK-8298081 DiagnoseSyncOnValueBasedClasses doesn't report useful information for virtual threads
-
- Resolved
-