JDK-8370522 : SIGSEGV in JvmtiTagMapTable::find(oop)
  • Type: Bug
  • Component: hotspot
  • Sub-Component: runtime
  • Affected Version: 26
  • Priority: P2
  • Status: Open
  • Resolution: Unresolved
  • Submitted: 2025-10-24
  • Updated: 2025-11-03
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 26
26Unresolved
Related Reports
Relates :  
Description
vmTestbase/nsk/jvmti/scenarios/capability/CM02/cm02t001/TestDescription.java crashed with
#  SIGSEGV (0xb) at pc=0x00007f9734f77101, pid=1151933, tid=1152015
#
# JRE version: Java(TM) SE Runtime Environment (26.0) (fastdebug build 26-internal-2025-10-22-1941258.ekaterina.pavlova.jdk.jep516)
# Java VM: Java HotSpot(TM) 64-Bit Server VM (fastdebug 26-internal-2025-10-22-1941258.ekaterina.pavlova.jdk.jep516, mixed mode, sharing, tiered, compressed class ptrs, g1 gc, linux-amd64)

V  [libjvm.so+0x14aa101]  JvmtiTagMapTable::find(oop)+0x41  (atomicAccess.hpp:553)
V  [libjvm.so+0x14a0f35]  CallbackWrapper::CallbackWrapper(JvmtiTagMap*, oop)+0x335  (jvmtiTagMap.cpp:173)
V  [libjvm.so+0x14a342d]  CallbackInvoker::invoke_basic_object_reference_callback(jvmtiObjectReferenceKind, oop, oop, int)+0xfd  (jvmtiTagMap.cpp:1661)
V  [libjvm.so+0x14a61e2]  VM_HeapWalkOperation::visit(oop)+0xb22  (jvmtiTagMap.cpp:2128)
V  [libjvm.so+0x149fead]  VM_HeapWalkOperation::doit()+0x42d  (jvmtiTagMap.cpp:2984)
V  [libjvm.so+0x1c85086]  VM_Operation::evaluate()+0x196  (vmOperations.cpp:74)
V  [libjvm.so+0x1ca0d88]  VMThread::evaluate_operation(VM_Operation*)+0x318  (vmThread.cpp:284)
V  [libjvm.so+0x1ca1aff]  VMThread::inner_execute(VM_Operation*)+0x42f  (vmThread.cpp:421)
V  [libjvm.so+0x1ca1c94]  VMThread::loop()+0x84  (vmThread.cpp:487)
V  [libjvm.so+0x1ca1da4]  VMThread::run()+0x94  (vmThread.cpp:177)
V  [libjvm.so+0x1b831a6]  Thread::call_run()+0xb6  (thread.cpp:243)
V  [libjvm.so+0x17efd48]  thread_native_entry(Thread*)+0x128  (os_linux.cpp:883)
as part of jep516 testing.

The crash occurred when running with AOT cache and "-XX:-AOTClassLinking -XX:-UseCompressedOops -XX:+UseG1GC" flags.

Steps to run the test:

> bash jib.sh make -- run-test TEST="vmTestbase/nsk/jvmti/scenarios/capability/CM02/cm02t001/TestDescription.java" 
  JTREG_AOT_JDK=onestep
  TEST_VM_OPTS="-XX:-AOTClassLinking -XX:-UseCompressedOops -XX:+UseG1GC" JTREG_AOT_JDK=onestep

I tried to reproduce it but no luck.


Erik also confirmed that he also saw similar crash during his testing
"
Looks like JVMTI heap walking found an object with a class with a null mirror. I found that I seem to have run into the same failure mode last week in the same test. That time it was running less interesting JVM options (no special GC, no AOT cache, no -compressed oops). That run seems to have run plan vanilla G1 with compressed oops and crashed the exact same way. I guess we would in that case have used the default CDS archive that the JDK ships with, which would have resulted in using the mapping loader with G1."



Comments
Reopened and reassigned this bug. This is perceived to be a pre-existing bug even with the "mapped" solutions. This needs to be further investigated before being closed. The affects version should probably be before JDK 26.
03-11-2025

While it is true that the error mode reported and found by this test was only found in the JEP work (and has now been fixed), it still seems to me that if JVMTI heap walking is triggered before the invalid object subgraph is cleared when resolving classes, then we can install bad objects i to the JVMTI tag map and crash later, when using the mapping mode. After fixing this in the streaming mode, the objects are never loaded into the heap - hence the objects are never reachable or iteratively discoverable from JVMTI. The mapping mode, however, has these objects reachable from when the archive is mapped in. Then, the roots are cleared later on when resolving classes making the bad objects no longer reachable. If JVMTI heap walking is triggered between those two points, we will eventually crash the JVM. While this might not be exercised by the particular test that discovered the closely related problem with streaming, I still think there is an existing bug for the mapping mode, unless there is some code somewhere to prevent JVMTI heap walking this early, which I don’t think there is. In other words, we don’t have a crash report for the mapping mode right now, but I can’t see how this wouldn’t cause a crash in the described scenario. I’m happy to be wrong though.
02-11-2025

This is a JEP 516 specific issue as the last comment by [~iklam] indicates, so closing this out.
01-11-2025

Regarding the G1 crash, I extracted the specific build and source code from Mach5. The default CDS archive has object_streaming_mode==1, so the crash in G1 is most likely caused by the same reason as the ZGC crash -- eager materialization of archived oops. $ tar zxf jdk-26-internal_linux-x64_bin-debug.tar.gz $ ./jdk-26/fastdebug/bin/java --version java 26-internal 2026-03-17 Java(TM) SE Runtime Environment (fastdebug build 26-internal-2025-10-16-1612271.erik.osterlund.jdk-jdk.git) Java HotSpot(TM) 64-Bit Server VM (fastdebug build 26-internal-2025-10-16-1612271.erik.osterlund.jdk-jdk.git, mixed mode, sharing) $ ./jdk-26/fastdebug/bin/java -Xlog:aot+map --version | grep object_streaming_mode [0.031s][info][aot,map] - object_streaming_mode: 1 From the source code, it looks like the bug was caused by this line in 26-internal-2025-10-16-1612271: void HeapShared::initialize_writing_mode() { if (FLAG_IS_DEFAULT(AOTStreamableObjects)) { FLAG_SET_DEFAULT(AOTStreamableObjects, UseCompressedOops); <<<< In Erik's latest JEP 516 PR, the above line has been fixed: FLAG_SET_DEFAULT(AOTStreamableObjects, !UseCompressedOops); ****** In conclusion -- the G1 crash doesn't affect the mainline, and has been fixed in the latest JEP 516 PR.
31-10-2025

[~iklam] While it is true that this failure did occur with the streaming approach and it did eagerly materialize objects, I have since stopped doing that when JVMTI CFLH is on. Neither the objects nor classes are injected to the JVM, so this mode of failure should be solved already. What concerns me though is that I have seen a failure from before with what appears to have been the mapping mode. Seemed to use G1 without strange flags that would make it stream.
31-10-2025

The new failure seems to suggest that we have eagerly materialized an object before its class has been loaded. This problem is not limited to JVMTI. If a GC happens before that class is loaded, it will also find that the ClassLoaderData of the class is null. If this is the case, we need to disable eager class loading when CDSConfig::has_aot_linked_classes() == false. For (has_aot_linked_classes() == false), all classes of all archived oops will be loaded before any GC could happen, so it should be OK to eagerly materialize archived oops. *** crash because "this" is null. V [libjvm.so+0x951ed0] ClassLoaderData::oops_do(OopClosure*, int, bool)+0x24 (atomicAccess.hpp:553) V [libjvm.so+0x1a149ac] void ZIterator::oop_iterate<ZHeapIteratorOopClosure<true> >(oop, ZHeapIteratorOopClosure<true>*)+0xac (iterator.inline.hpp:294) V [libjvm.so+0x1a14cf4] void ZHeapIterator::visit_and_follow<true>(ZHeapIteratorContext const&, oop)+0x174 (zHeapIterator.cpp:433) V [libjvm.so+0x1a14f68] void ZHeapIterator::drain<true>(ZHeapIteratorContext const&)+0x108 (zHeapIterator.cpp:488) V [libjvm.so+0x1a0e40c] ZHeapIterator::object_and_field_iterate(ObjectClosure*, OopFieldClosure*, unsigned int)+0xa4 (zHeapIterator.cpp:520) V [libjvm.so+0x1a09a24] ZHeap::object_iterate(ObjectClosure*, bool)+0x1a4 (zHeap.cpp:331) V [libjvm.so+0x123f4fc] VM_HeapIterateOperation::doit()+0x7c (jvmtiTagMap.cpp:897) V [libjvm.so+0x195ccf0] VM_Operation::evaluate()+0x148 (vmOperations.cpp:74) V [libjvm.so+0x197ef18] VMThread::evaluate_operation(VM_Operation*)+0x2b8 (vmThread.cpp:284) V [libjvm.so+0x197fb8c] VMThread::inner_execute(VM_Operation*)+0x3ec (vmThread.cpp:421) V [libjvm.so+0x197fdf0] VMThread::loop()+0x88 (vmThread.cpp:487) V [libjvm.so+0x197ff24] VMThread::run()+0xa4 (vmThread.cpp:177) V [libjvm.so+0x1865d1c] Thread::call_run()+0xac (thread.cpp:243) V [libjvm.so+0x154383c] thread_native_entry(Thread*)+0x12c (os_linux.cpp:883)
30-10-2025

The mainline seems to be safe: [1] HeapShared::resolve_classes() is called while is_init_completed()==false. This means no GC can happen yet. At this point, we will (a) clear the roots of all unusable object graphs, and (b) load the classes of all the objects reachable from the useable object graphs. So all future GC will never see a live object whose class is not loaded. Note that we have removed the following null check for ClassLoaderData in JDK-8350550. If the GC could ever reach an object whose class is not yet loaded, the VM would have crashed. But we have seen no such crashes since JDK-8350550. https://github.com/openjdk/jdk/blame/61acdf6512c6ea3123edb9017ef99d851c917b90/src/hotspot/share/memory/iterator.inline.hpp#L55-L59 [2] we have the "skipped dormant archived object" code IterateOverHeapObjectClosure::do_object() that skip over the dead objects. I am assigning this bug to [~eosterlund] for fixing the problem in JEP 516,
30-10-2025

In the mainline, when the subgraph of class k is not loaded, HeapShared::clear_archived_roots_of(k) will be called, so the subgraph will no longer be referenced, so objects in this graph will become garbage, However, jvmti can still see these objects (in some GCs?). For example, with G1: 0 IterateOverHeapObjectClosure::do_object 1 G1HeapRegion::object_iterate 2 IterateObjectClosureRegionClosure::do_heap_region 3 G1HeapRegionManager::iterate 4 G1CollectedHeap::heap_region_iterate 5 G1CollectedHeap::object_iterate 6 VM_HeapIterateOperation::doit This will iterate over dead objects. To handle this case, we have this code in jvmtiTagMap.cpp: // skip if object is a dormant shared object whose mirror hasn't been loaded if (o->klass()->java_mirror() == nullptr) { log_debug(aot, heap)("skipped dormant archived object " INTPTR_FORMAT " (%s)", p2i(o), o->klass()->external_name()); return; }
30-10-2025

[~eosterlund] do you have a reproducer for the mainline?
30-10-2025

Thank you [~epavlova]. The new failure mode does still use the JDK default AOT cache which also includes objects now, and hence leaves us susceptible to the same problem. In this case though, the GC crashed into the illegal instances before the JVMTI heap walker.
27-10-2025

The test crashed differently in jep516 PIT: # A fatal error has been detected by the Java Runtime Environment: # # SIGSEGV (0xb) at pc=0x0000ffff9a06ded0, pid=1488866, tid=1488905 # # JRE version: Java(TM) SE Runtime Environment (26.0) (fastdebug build 26-internal-2025-10-24-1959100.erik.osterlund.jdk-jdk.git) # Java VM: Java HotSpot(TM) 64-Bit Server VM (fastdebug 26-internal-2025-10-24-1959100.erik.osterlund.jdk-jdk.git, mixed mode, sharing, compressed class ptrs, z gc, linux-aarch64) # Problematic frame: # V [libjvm.so+0x951ed0] ClassLoaderData::oops_do(OopClosure*, int, bool)+0x24 The test crashed with " -XX:+UseZGC -XX:-TieredCompilation" flags, no AOT cache was used in this case.
27-10-2025

The archivedCaches subgraph recorded for jdk/internal/math/FDBigInteger becomes invalid because there is a JVMTI class file load hook. This means that the klasses for the subgraph are not set up appropriately. However, the root is not cleared, and the JVMTI heap walker finds objects with klasses in an invalid state. It looks like this must be a mainline bug. In the JEP code, it reproduces both with the old mapping loader as well as the new streaming loader.
24-10-2025

Could JDK-8369742 be related?
24-10-2025