JDK-8027146 : Class loading verification failure if GC occurs in Universe::flush_dependents_on
  • Type: Bug
  • Component: hotspot
  • Sub-Component: runtime
  • Affected Version: hs25
  • Priority: P4
  • Status: Closed
  • Resolution: Fixed
  • Submitted: 2013-10-23
  • Updated: 2014-07-29
  • Resolved: 2014-02-15
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.
8u20Fixed 9 b04Fixed
If a GC (with verification enabled) occurs during _non-parallel_ class loading in the call chain 

SystemDictionary::add_to_hierarchy => Universe::flush_dependents_on => VM_Deoptimize

then verification in SystemDictionary::verify_obj_klass_present will fail for the class currently being defined, since it is in the Loaded state but not yet added to the SystemDictionary and not added to the Placeholder table.

The problem is easy to reproduce by adding a VM_Verify VMop in Universe::flush_dependents_on and running a test which loads classes with a non-PCL ClassLoader.

I=M (spurious assert with verification, potential race in class loading)
L=M (occurs only with non-parallel capable class loaders)
W=H (no known work-around)
updated ILW:
I=L (spurious assert with verification, no race in class loading)
L=M (only with non-parallel capable class loaders)
W=L (see comments for workaround)

The code should be deleted - since this verification isn't intended to be true. In addition, there is a comment that should be deleted that says that redefineclasses depends on this - that was my misunderstanding when I put in the comment - but checking with Dan Daugherty and David Holmes, actually redefineclasses can only get to a class in the system dictionary.
Apply the patch and run with -XX:+UseNewCode Without the patch there's a very rare condition: we can get a GC at the safepoint check when trying to run VM_Deoptimize, if that GC is run with verification enabled we can hit the assert.

How does this reproduce? With -XX:+VerifyBeforeGC and the UseNewCode attached?

I want to delete the whole function. I already added a conditional check_dictionary because we were checking that the klass was in the dictionary while traversing the system dictionary, which was wasteful. I could replace the check that the klass is added to it's loader_data list of klasses instead. Then we would have one less use of the GCMutexLocker too.

Just to answer Karen's question about anonymous classes, InstanceKlass::verify_on only checks the SystemDictionary if the IK is not anonymous.

This part of the Klass verification really belongs to Runtime, so no need to hand back to GC. I think the priority should be lowered. Given your analysis it seems like the Impact is low and the Workaround could be also be low since the user of fastdebug/debug builds can use -XX:SuppressErrorAt=systemDictionary.cpp:2618.

This is not a timing hole in class loading. This is a false assumption from whomever put the verify_obj_class_present logic in. It is not the case that a class marked "Loaded" is always in either the placeholder table or the SystemDictionary. There are three paths in for loading classes: 1. most class loading starts in the vm via resolution, or resolve_instance_class_or_null 2. Java ClassLoader LoadClass, which should call findClass, and then JVM_DefineClass, which goes into resolve_from_stream 3. unsafe anonymous defineClass or redefineclasses which go into parse_stream The first two paths do the following: 1. non-parallel class loaders: acquire class loader lock and keep it until the class is in the SystemDictionary. placeholder table is used during portions of the class loading, e.g. for parallel super class loading. 2. parallel class loaders/boot loader/special flag: skip class loader lock and use placeholder table queues to handle parallel SUPER_LOAD, LOAD_CLASS and not DEFINE_CLASS 3. non-parallel class loaders that call wait() on the class loader lock - we have special handling there during ricon which is used for their super loading RedefineClasses can't get a class to redefine until it shows up in the SystemDictionary. Anonymous classes never go into the SystemDictionary. So - the assumption of the verify_obj_class_present is inaccurate. What is the point of this part of the verification? Would it be helpful to check that the class is in a class loader data? That is true before the class is marked "Loaded". Giving back to the GC folks.

What happens with anonymous classes that never get added to the SystemDictionary nor the placeholder table, and I don't think should? Is there an assumption that every loaded class is either in the SystemDictionary or the placeholder table?

Test case to run together with the patch "trigger-classload-assert.diff" Run with -XX:+UseNewCode to see the assertion failure. If you supply -Dpcl=true the test's class loder will register as parallel capable and the assert won't reproduce.