JDK-7048782 : CMS: assert(last_chunk_index_to_check<= last_chunk_index) failed: parCardTableModRefBS.cpp:359
  • Type: Bug
  • Component: hotspot
  • Sub-Component: gc
  • Affected Version: 7
  • Priority: P4
  • Status: Closed
  • Resolution: Fixed
  • OS: generic
  • CPU: generic
  • Submitted: 2011-05-26
  • Updated: 2011-11-25
  • Resolved: 2011-09-30
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 7 JDK 8 Other
7u2Fixed 8Fixed hs22Fixed
Description
gc/gctests/LargeObjects/large005
http://sqeweb.sfbay.sun.com/nfs/results/vm/gtee/JDK7/NIGHTLY/VM/2011-05-25/GC_Baseline-Xconc/vm/solaris-amd64/server/mixed/solaris-amd64_vm_server_mixed_vm.gc.testlist/ResultDir/large005/hs_err_pid23650.log



;; Using jvm: "/export/local/common/jdk/baseline/solaris-amd64/jre/lib/amd64/server/libjvm.so"
#
# A fatal error has been detected by the Java Runtime Environment:
#
#  Internal Error (/tmp/jprt/P1/B/235027.ysr/source/src/share/vm/gc_implementation/parNew/parCardTableModRefBS.cpp:359), pid=23650, tid=4
#  assert(last_chunk_index_to_check<= last_chunk_index) failed: Out of bounds: last_chunk_index_to_check 0x0000000000000193 exceeds last_chunk_index 0x0000000000000192
#
# JRE version: 7.0-b143
# Java VM: Java HotSpot(TM) 64-Bit Server VM (21.0-b14-internal-201105232350.ysr.botloop-fastdebug mixed mode solaris-amd64 )
# Core dump written. Default location: /export/local/51065.JDK7.NIGHTLY.VM+solaris-amd64_vm_server_mixed_vm.gc.testlist/results/ResultDir/large005/core or core.23650
#
# If you would like to submit a bug report, please visit:
#   http://bugreport.sun.com/bugreport/crash.jsp
#

---------------  T H R E A D  ---------------

Current thread (0x0000000000467800):  GCTaskThread [stack: 0x0000000000000000,0x0000000000000000] [id=4]

Stack: 
[error occurred during error reporting (printing stack bounds), id 0xe0000000]

Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)
V  [libjvm.so+0x2601ff2]  void VMError::report(outputStream*)+0x8c6;;  void VMError::report(outputStream*)+0x8c6
V  [libjvm.so+0x2603131]  void VMError::report_and_die()+0x4fd;;  void VMError::report_and_die()+0x4fd
V  [libjvm.so+0xe45a27]  void report_vm_error(const char*,int,const char*,const char*)+0x55f;;  void report_vm_error(const char*,int,const char*,const char*)+0x55f
V  [libjvm.so+0x2602b3b]  void VMError::report(outputStream*)+0x140f;;  void VMError::report(outputStream*)+0x140f
V  [libjvm.so+0x2603131]  void VMError::report_and_die()+0x4fd;;  void VMError::report_and_die()+0x4fd
V  [libjvm.so+0xe45a27]  void report_vm_error(const char*,int,const char*,const char*)+0x55f;;  void report_vm_error(const char*,int,const char*,const char*)+0x55f
V  [libjvm.so+0x208bf16]  void CardTableModRefBS::process_chunk_boundaries(Space*,DirtyCardToOopClosure*,MemRegion,MemRegion,signed char**,unsigned long,unsigned long)+0x113a;;  void CardTableModRefBS::process_chunk_boundaries(Space*,DirtyCardToOopClosure*,MemRegion,MemRegion,signed char**,unsigned long,unsigned long)+0x113a
V  [libjvm.so+0x2089beb]  void CardTableModRefBS::non_clean_card_iterate_parallel_work(Space*,MemRegion,OopsInGenClosure*,CardTableRS*,int)+0x98f;;  void CardTableModRefBS::non_clean_card_iterate_parallel_work(Space*,MemRegion,OopsInGenClosure*,CardTableRS*,int)+0x98f
V  [libjvm.so+0xa72307]  void CardTableModRefBS::non_clean_card_iterate_possibly_parallel(Space*,MemRegion,OopsInGenClosure*,CardTableRS*)+0x93;;  void CardTableModRefBS::non_clean_card_iterate_possibly_parallel(Space*,MemRegion,OopsInGenClosure*,CardTableRS*)+0x93
V  [libjvm.so+0xa78492]  void CardTableRS::younger_refs_in_space_iterate(Space*,OopsInGenClosure*)+0x212;;  void CardTableRS::younger_refs_in_space_iterate(Space*,OopsInGenClosure*)+0x212
V  [libjvm.so+0xd5320a]  void ConcurrentMarkSweepGeneration::younger_refs_iterate(OopsInGenClosure*)+0x5e;;  void ConcurrentMarkSweepGeneration::younger_refs_iterate(OopsInGenClosure*)+0x5e
V  [libjvm.so+0x108b636]  void GenCollectedHeap::gen_process_strong_roots(int,bool,bool,bool,SharedHeap::ScanningOption,OopsInGenClosure*,bool,OopsInGenClosure*)+0x416;;  void GenCollectedHeap::gen_process_strong_roots(int,bool,bool,bool,SharedHeap::ScanningOption,OopsInGenClosure*,bool,OopsInGenClosure*)+0x416
V  [libjvm.so+0x20a7466]  void ParNewGenTask::work(int)+0x1ee;;  void ParNewGenTask::work(int)+0x1ee
V  [libjvm.so+0x263afab]  void GangWorker::loop()+0x51f;;  void GangWorker::loop()+0x51f
V  [libjvm.so+0x2052086]  java_start+0x6a6;;  java_start+0x6a6
C  [libc.so.1+0xd72cb]  _thr_setup+0x5b;;  _thr_setup+0x5b
C  [libc.so.1+0xd7500]  ht_pause+0x10;;  _lwp_start+0x0

...

Heap
 par new generation   total 19392K, used 17581K [0xfffffd7fb4800000, 0xfffffd7fb5d00000, 0xfffffd7fbee60000)
  eden space 17280K,  93% used [0xfffffd7fb4800000, 0xfffffd7fb57b2cc0, 0xfffffd7fb58e0000)
  from space 2112K,  71% used [0xfffffd7fb5af0000, 0xfffffd7fb5c68a00, 0xfffffd7fb5d00000)
  to   space 2112K,   0% used [0xfffffd7fb58e0000, 0xfffffd7fb58e0000, 0xfffffd7fb5af0000)
 concurrent mark-sweep generation total 68580K, used 68328K [0xfffffd7fbee60000, 0xfffffd7fc3159000, 0xfffffd7ff3800000)
 concurrent-mark-sweep perm gen total 21248K, used 4557K [0xfffffd7ff3800000, 0xfffffd7ff4cc0000, 0xfffffd7ff8a00000)

...

VM Arguments:
jvm_args: -Xmixed -XX:-PrintVMOptions -Xconcgc -XX:+CMSClassUnloadingEnabled -XX:+StartAttachListener -XX:+IgnoreUnrecognizedVMOptions -XX:-UseCompressedOops -XX:-UseGCOverheadLimit 
java_command: gc.gctests.LargeObjects.large001.large001 -largeClassesPath /export/local/common/testbase/7/vm/vm/bin/newclass -isOverLimitFields true -aggregationDepth 3 -t 1
Launcher Type: SUN_STANDARD

...

OS:                       Solaris 10 10/09 s10x_u8wos_08a X86
           Copyright 2009 Sun Microsystems, Inc.  All Rights Reserved.
                        Use is subject to license terms.
                           Assembled 16 September 2009

uname:SunOS 5.10 Generic_142901-13 i86pc  (T2 libthread)
rlimit: STACK 10000k, CORE infinity, NOFILE 65536, AS infinity
load average:1.27 1.49 1.71

CPU:total 2 (1 cores per cpu, 1 threads per core) family 15 model 37 stepping 1, cmov, cx8, fxsr, mmx, sse, sse2, sse3, mmxext, 3dnowpref

Memory: 4k page, physical 4127784k(2013980k free)

vm_info: Java HotSpot(TM) 64-Bit Server VM (21.0-b14-internal-201105232350.ysr.botloop-fastdebug) for solaris-amd64 JRE (1.7.0), built on May 23 2011 19:59:20 by "jprtadm" with Sun Studio 12u1

time: Wed May 25 21:59:55 2011
elapsed time: 3 seconds

# Host info: SunOS vm-v20z-5 5.10 Generic_142901-13 i86pc i386 i86pc

Comments
EVALUATION http://hg.openjdk.java.net/hsx/hotspot-rt/hotspot/rev/5c0a3c1858b1
08-07-2011

EVALUATION http://hg.openjdk.java.net/hsx/hotspot-comp/hotspot/rev/5c0a3c1858b1
08-07-2011

EVALUATION http://hg.openjdk.java.net/hsx/hotspot-gc/hotspot/rev/5c0a3c1858b1
08-06-2011

WORK AROUND The bug can be worked around by setting -Xmx == -Xms *and* -XX:PermSize == -XXMaxPermSize.
27-05-2011

EVALUATION The above evaluation is not entirely correct. It is true that the assert will not hold when the heap expands. However, the assert does check a property that had better hold or else we may end up accessing past the end of the LNC array and potentially read junk or, worse, segv in the read if that portion is not mapped. So the largeset chunk index to check should in fact be bounded by the largest chunk index that the assert was checking against. Thus, this affects not only debug code but also product code. See suggested fix for the delta under test and (which will be submitted for) review.
27-05-2011

SUGGESTED FIX diff --git a/src/share/vm/gc_implementation/parNew/parCardTableModRefBS.cpp b/src/share/vm/gc_implementation/parNew/parCardTableModRefBS.cpp --- a/src/share/vm/gc_implementation/parNew/parCardTableModRefBS.cpp +++ b/src/share/vm/gc_implementation/parNew/parCardTableModRefBS.cpp @@ -348,15 +348,30 @@ // cleared before we had a chance to examine it. In that case, the value // will have been logged in the LNC for that chunk. // We need to examine as many chunks to the right as this object - // covers. - const uintptr_t last_chunk_index_to_check = addr_to_chunk_index(last_block + last_block_size - 1) - - lowest_non_clean_base_chunk_index; - DEBUG_ONLY(const uintptr_t last_chunk_index = addr_to_chunk_index(used.last()) - - lowest_non_clean_base_chunk_index;) - assert(last_chunk_index_to_check <= last_chunk_index, - err_msg("Out of bounds: last_chunk_index_to_check " INTPTR_FORMAT - " exceeds last_chunk_index " INTPTR_FORMAT, - last_chunk_index_to_check, last_chunk_index)); + // covers. However, we need to bound this checking to the largest + // entry in the LNC array: this is because the heap may expand + // after the LNC array has been created but before we reach this point, + // and the last block in our chunk may have been expanded to include + // the expansion delta (and possibly subsequently allocated from, so + // it wouldn't be sufficient to check whether that last block was + // or was not an object at this point). + uintptr_t last_chunk_index_to_check = addr_to_chunk_index(last_block + last_block_size - 1) + - lowest_non_clean_base_chunk_index; + const uintptr_t last_chunk_index = addr_to_chunk_index(used.last()) + - lowest_non_clean_base_chunk_index; + if (last_chunk_index_to_check > last_chunk_index) { + assert(last_block + last_block_size > used.end(), + err_msg("Inconsistency detected: last_block [" PTR_FORMAT "," PTR_FORMAT "]" + " does not exceed used.end() = " PTR_FORMAT "," + " yet last_chunk_index_to_check " PTR_FORMAT " exceeds last_chunk_index " PTR_FORMAT, + last_chunk_index_to_check, last_chunk_index)); + assert(sp->used_region().end() > used.end(), + err_msg("Expansion did not happen: " + "[" PTR_FORMAT "," PTR_FORMAT ") -> [" PTR_FORMAT "," PTR_FORMAT ")", + sp->used_region().start(), sp->used_region().end(), used.start(), used.end())); + NOISY(tty->print_cr(" process_chunk_boundary: heap expanded; explicitly bounding last_chunk");) + last_chunk_index_to_check = last_chunk_index; + } for (uintptr_t lnc_index = cur_chunk_index + 1; lnc_index <= last_chunk_index_to_check; lnc_index++) {
27-05-2011

EVALUATION The assert is to strong when the heap is expanding and a previously co-terminal free chunk is coalesced with the expansion delta. Basically at that point the "used" has changed to a larger value so the old snapshot is not valid, and the last block can potentially exceed the end of the old snapshot. The assert should be suitably adjusted to account for this occurrence.
26-05-2011