JDK-8028096 : PrintSharedSpaces may crash when some blocks are freed and allocated again during -Xshare:dump
  • Type: Bug
  • Component: hotspot
  • Sub-Component: runtime
  • Affected Version: 9
  • Priority: P4
  • Status: Resolved
  • Resolution: Duplicate
  • Submitted: 2013-11-10
  • Updated: 2014-06-18
  • Resolved: 2014-06-18
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 9
9Resolved
Related Reports
Duplicate :  
Relates :  
Description
As of JDK8-b111, if -XX:+PrintSharedSpaces is specified during -Xshare:dump, in rare occasions, some arrays may be deallocated, and the space re-used later:

#1  0x00007ffff71a9444 in Metaspace::deallocate (this=0x7ffff0035ce8, ptr=0x800009500, word_size=95, 
    is_class=false) at /home/iklam/jdk/cds/src/share/vm/memory/metaspace.cpp:3176
#2  0x00007ffff6d6dadc in MetadataFactory::free_array<Method*> (loader_data=0x7ffff0035b88, data=0x800009500)
    at /home/iklam/jdk/cds/src/share/vm/memory/metadataFactory.hpp:70
#3  0x00007ffff6d6a8d5 in merge_in_new_methods (klass=0x80393ef10, new_methods=0x7ffff6715590, __the_thread__=
    0x7ffff000a000) at /home/iklam/jdk/cds/src/share/vm/classfile/defaultMethods.cpp:1092
#4  0x00007ffff6d6a2fd in create_overpasses (slots=0x7ffff0012b58, klass=0x80393ef10, 
    __the_thread__=0x7ffff000a000) at /home/iklam/jdk/cds/src/share/vm/classfile/defaultMethods.cpp:990
#5  0x00007ffff6d6966f in DefaultMethods::generate_default_methods (klass=0x80393ef10, mirandas=0x7ffff67158f0, 
    __the_thread__=0x7ffff000a000) at /home/iklam/jdk/cds/src/share/vm/classfile/defaultMethods.cpp:785
#6  0x00007ffff6c94be4 in ClassFileParser::parseClassFile (this=0x7ffff6715dd0, name=0x800000240, 
    loader_data=0x7ffff0035b88, protection_domain=..., host_klass=..., cp_patches=0x0, parsed_name=..., 
    verify=false, __the_thread__=0x7ffff000a000)
    at /home/iklam/jdk/cds/src/share/vm/classfile/classFileParser.cpp:4088
#7  0x00007ffff6ca27c3 in ClassFileParser::parseClassFile (this=0x7ffff6715dd0, name=0x800000240, 
    loader_data=0x7ffff0035b88, protection_domain=..., parsed_name=..., verify=false, 
    __the_thread__=0x7ffff000a000) at /home/iklam/jdk/cds/src/share/vm/classfile/classFileParser.hpp:468
#8  0x00007ffff6ca0457 in ClassLoader::load_classfile (h_name=0x800000240, __the_thread__=0x7ffff000a000)
    at /home/iklam/jdk/cds/src/share/vm/classfile/classLoader.cpp:941
#9  0x00007ffff736288d in SystemDictionary::load_instance_class (class_name=0x800000240, class_loader=..., 
    __the_thread__=0x7ffff000a000) at /home/iklam/jdk/cds/src/share/vm/classfile/systemDictionary.cpp:1335
#10 0x00007ffff736098c in SystemDictionary::resolve_instance_class_or_null (name=0x800000240, class_loader=..., 
    protection_domain=..., __the_thread__=0x7ffff000a000)
    at /home/iklam/jdk/cds/src/share/vm/classfile/systemDictionary.cpp:779
#11 0x00007ffff735f2b3 in SystemDictionary::resolve_or_null (class_name=0x800000240, class_loader=..., 


Metaspace::record_allocation doesn't consider the case where such deallocation/re-allocation may happen. As a result, -XX:+PrintSharedSpaces may crash here:

DumpAllocClosure::dump_stats(...) {
  ...
  assert(all_ro_bytes == ro_all, "everything should have been counted"); << CRASH HERE
  assert(all_rw_bytes == rw_all, "everything should have been counted");

}

Comments
Duplicate of JDK-8046070
18-06-2014

This bug will be addressed by the fixes for JDK-8046070
18-06-2014

The crash happens only in the combination of (a) debug builds, and (b) when the developer option -XX:+PrintSharedSpaces (disabled by default) is enabled, and (c) when dumping with AppCDS prototype using JavaFX demo "modena". The free/reallocation does not happen with -Xshare:dump when using the default classlist. Work-around is not to use -XX:+PrintSharedSpaces. Impact=M, Likelihood=L, Workaround=L, ILW=P5
13-11-2013

Patch is here: ==== diff -r 679fc6cc87ca -r 17b417be8b32 src/share/vm/memory/allocation.hpp --- a/src/share/vm/memory/allocation.hpp Sat Nov 02 21:40:42 2013 -0700 +++ b/src/share/vm/memory/allocation.hpp Sun Nov 10 13:51:57 2013 -0800 @@ -283,7 +283,8 @@ f(ConstantPool) \ f(ConstantPoolCache) \ f(Annotation) \ - f(MethodCounters) + f(MethodCounters) \ + f(Deallocated) #define METASPACE_OBJ_TYPE_DECLARE(name) name ## Type, #define METASPACE_OBJ_TYPE_NAME_CASE(name) case name ## Type: return #name; diff -r 679fc6cc87ca -r 17b417be8b32 src/share/vm/memory/metaspace.cpp --- a/src/share/vm/memory/metaspace.cpp Sat Nov 02 21:40:42 2013 -0700 +++ b/src/share/vm/memory/metaspace.cpp Sun Nov 10 13:51:57 2013 -0800 @@ -3172,6 +3172,10 @@ } void Metaspace::deallocate(MetaWord* ptr, size_t word_size, bool is_class) { + if (DumpSharedSpaces && PrintSharedSpaces) { + record_deallocation(ptr, vsm()->get_raw_word_size(word_size)); + } + if (SafepointSynchronize::is_at_safepoint()) { assert(Thread::current()->is_VM_thread(), "should be the VM thread"); // Don't take Heap_lock @@ -3229,7 +3233,7 @@ result = space->allocate(word_size, NonClassType); if (result == NULL) { report_out_of_shared_space(read_only ? SharedReadOnly : SharedReadWrite); - } else { + } else if (PrintSharedSpaces) { space->record_allocation(result, type, space->vsm()->get_raw_word_size(word_size)); } return Metablock::initialize(result, word_size); @@ -3274,15 +3278,55 @@ void Metaspace::record_allocation(void* ptr, MetaspaceObj::Type type, size_t word_size) { assert(DumpSharedSpaces, "sanity"); - AllocRecord *rec = new AllocRecord((address)ptr, type, (int)word_size * HeapWordSize); + int byte_size = (int)word_size * HeapWordSize; + AllocRecord *rec = new AllocRecord((address)ptr, type, byte_size); + if (_alloc_record_head == NULL) { _alloc_record_head = _alloc_record_tail = rec; - } else { + } else if (_alloc_record_tail->_ptr + _alloc_record_tail->_byte_size == (address)ptr) { _alloc_record_tail->_next = rec; _alloc_record_tail = rec; + } else { + // slow linear search, but this doesn't happen that often, and only when dumping + for (AllocRecord *old = _alloc_record_head; old; old = old->_next) { + if (old->_ptr == ptr) { + assert(old->_type == MetaspaceObj::DeallocatedType, "sanity"); + int remain_bytes = old->_byte_size - byte_size; + assert(remain_bytes >= 0, "sanity"); + old->_type = type; + + if (remain_bytes == 0) { + delete(rec); + } else { + address remain_ptr = address(ptr) + byte_size; + rec->_ptr = remain_ptr; + rec->_byte_size = remain_bytes; + rec->_type = MetaspaceObj::DeallocatedType; + rec->_next = old->_next; + old->_byte_size = byte_size; + old->_next = rec; + } + return; + } + } + assert(0, "reallocating a freed pointer that was not recorded"); } } +void Metaspace::record_deallocation(void* ptr, size_t word_size) { + assert(DumpSharedSpaces, "sanity"); + + for (AllocRecord *rec = _alloc_record_head; rec; rec = rec->_next) { + if (rec->_ptr == ptr) { + assert(rec->_byte_size == (int)word_size * HeapWordSize, "sanity"); + rec->_type = MetaspaceObj::DeallocatedType; + return; + } + } + + assert(0, "deallocating a pointer that was not recorded"); +} + void Metaspace::iterate(Metaspace::AllocRecordClosure *closure) { assert(DumpSharedSpaces, "unimplemented for !DumpSharedSpaces"); diff -r 679fc6cc87ca -r 17b417be8b32 src/share/vm/memory/metaspace.hpp --- a/src/share/vm/memory/metaspace.hpp Sat Nov 02 21:40:42 2013 -0700 +++ b/src/share/vm/memory/metaspace.hpp Sun Nov 10 13:51:57 2013 -0800 @@ -158,9 +158,10 @@ } private: - // This is used by DumpSharedSpaces only, where only _vsm is used. So we will + // These 2 methods are used by DumpSharedSpaces only, where only _vsm is used. So we will // maintain a single list for now. void record_allocation(void* ptr, MetaspaceObj::Type type, size_t word_size); + void record_deallocation(void* ptr, size_t word_size); #ifdef _LP64 static void set_narrow_klass_base_and_shift(address metaspace_base, address cds_base); ====
10-11-2013