ClassLoaderData::_handles was introduced to keep track of resolved reference array for the constant pools. The objects were created and immediately registered in the _handles area without any intervening safepoints.
From ClassLoaderData::initialize_resolved_references:
objArrayOop stom = oopFactory::new_objArray(SystemDictionary::Object_klass(), map_length, CHECK);
Handle refs_handle (THREAD, (oop)stom); // must handleize.
set_resolved_references(loader_data->add_handle(refs_handle));
There's a comment in CMSCollector::do_remark_non_parallel that describes this:
// We might have added oops to ClassLoaderData::_handles during the
// concurrent marking phase. These oops point to newly allocated objects
// that are guaranteed to be kept alive. Either by the direct allocation
// code, or when the young collector processes the roots. Hence,
// we don't have to revisit the _handles block during the remark phase.
However, the CLD::_handles area has been reused to store other oops that might not adhere to the requirement described in the comment above.
Two code path that register oops in the CLD::_handles are the Modules code and CDS when protection domain "handles" are created.
Two ways to fix this:
1) Make sure that the object is available in a root from the time it gets created until it has been added to the CLD::_handles list.
The code might already do this, but it needs to be checked / enforced.
2) Do more work in the CMS remark pause and visit all non-"resolved reference array" oops.
There's currently no separation between the "resolved reference array" oops and the other oops in CLD:_handles, so the code would probably have to visit all oops, unless they were separated somehow.