Note: this bug can be reproduced in JDK 17u only.
JDK 17u repo: https://github.com/openjdk/jdk17u
gcc version 10.3.0 (GCC)
For some reason, it's no longer reproducible in JDK mainline. For a simpler reproducer in the JDK mainline, see the second comment below.
The following patch causes a crash in the delete operation:
--- a/src/hotspot/share/classfile/systemDictionaryShared.cpp
+++ b/src/hotspot/share/classfile/systemDictionaryShared.cpp
@@ -1257,6 +1257,8 @@ DumpTimeSharedClassInfo* SystemDictionaryShared::find_or_allocate_info_for_locke
assert_lock_strong(DumpTimeTable_lock);
if (_dumptime_table == NULL) {
_dumptime_table = new (ResourceObj::C_HEAP, mtClass)DumpTimeSharedClassTable();
+ delete _dumptime_table;
+ _dumptime_table = new (ResourceObj::C_HEAP, mtClass)DumpTimeSharedClassTable();
}
return _dumptime_table->find_or_allocate_info_for(k, _dump_in_progress);
}
Gcc generates the following code:
0x00007ffff6681adc <+14>: mov $0x2,%esi
0x00007ffff6681ae1 <+19>: mov $0x1f0a8,%edi
0x00007ffff6681ae6 <+24>: callq 0x7ffff5a2e7dc <ResourceObj::operator new(unsigned long, ResourceObj::allocation_type, MEMFLAGS)>
0x00007ffff6681aeb <+29>: mov %rax,%rbx
0x00007ffff6681aee <+32>: test %rbx,%rbx
0x00007ffff6681af1 <+35>: je 0x7ffff6681b10 <foofoo()+66>
0x00007ffff6681af3 <+37>: mov %rbx,%rax
0x00007ffff6681af6 <+40>: mov $0x1f0a8,%edx
0x00007ffff6681afb <+45>: mov $0x0,%esi
0x00007ffff6681b00 <+50>: mov %rax,%rdi
>>>0x00007ffff6681b03 <+53>: callq 0x7ffff5827470 <memset@plt> <<<<<<<<<<<<<<<<< HERE
0x00007ffff6681b08 <+58>: mov %rbx,%rdi
0x00007ffff6681b0b <+61>: callq 0x7ffff6687db8 <DumpTimeSharedClassTable::DumpTimeSharedClassTable()>
ResourceObj::_allocation_t is initialized inside the new operator, and it gets trashed by the subsequent call to memset().
As a result, we get an assertion failure inside the destructor:
$ java -Xshare:dump
[....]
# Internal Error (/jdk2/mnd/open/src/hotspot/share/memory/allocation.cpp:190), pid=10343, tid=10344
# assert(~(_allocation_t[0] | allocation_mask) == (uintptr_t)this) failed: lost resource object
V [libjvm.so+0x4ebb89] ResourceObj::get_allocation_type() const+0x31
V [libjvm.so+0x4ec0e8] ResourceObj::allocated_on_C_heap() const+0x18
V [libjvm.so+0x4eb9f0] ResourceObj::operator delete(void*)+0x18
V [libjvm.so+0x113eb17] SystemDictionaryShared::find_or_allocate_info_for_locked(InstanceKlass*)+0x8b
However, adding a dummy constructor for DumpTimeSharedClassTable makes the problem goes away. The memset is no longer generated by gcc.
==================
--- a/src/hotspot/share/classfile/systemDictionaryShared.cpp
+++ b/src/hotspot/share/classfile/systemDictionaryShared.cpp
@@ -219,6 +219,7 @@ class DumpTimeSharedClassTable: public ResourceHashtable<
int _builtin_count;
int _unregistered_count;
public:
+ DumpTimeSharedClassTable(int dummy) {}
DumpTimeSharedClassInfo* find_or_allocate_info_for(InstanceKlass* k, bool dump_in_progress) {
bool created = false;
DumpTimeSharedClassInfo* p;
@@ -1256,7 +1257,9 @@ DumpTimeSharedClassInfo* SystemDictionaryShared::find_or_allocate_info_for(Insta
DumpTimeSharedClassInfo* SystemDictionaryShared::find_or_allocate_info_for_locked(InstanceKlass* k) {
assert_lock_strong(DumpTimeTable_lock);
if (_dumptime_table == NULL) {
- _dumptime_table = new (ResourceObj::C_HEAP, mtClass)DumpTimeSharedClassTable();
+ _dumptime_table = new (ResourceObj::C_HEAP, mtClass)DumpTimeSharedClassTable(0);
+ delete _dumptime_table;
+ _dumptime_table = new (ResourceObj::C_HEAP, mtClass)DumpTimeSharedClassTable(0);
}
return _dumptime_table->find_or_allocate_info_for(k, _dump_in_progress);
}