Crash in ArchiveHeapWriter::compute_ptrmap when archiving heap objects of excluded classes

ioi.lam at oracle.com ioi.lam at oracle.com
Tue Feb 10 01:02:36 UTC 2026


Hi Anton,

Thanks for the bug report. I have created 
https://bugs.openjdk.org/browse/JDK-8377512

(I am not sure if you have permission to edit the bug, but I think some 
of your colleagues at Azul should have permission).

Do you have more information, such as an hs_err file?

My guess is we have a ResolvedMethodName object that points to a method 
of an excluded class

void HeapShared::mark_native_pointers(oop orig_obj) {
   if (java_lang_Class::is_instance(orig_obj)) {
     ArchiveHeapWriter::mark_native_pointer(orig_obj, 
java_lang_Class::klass_offset());
     ArchiveHeapWriter::mark_native_pointer(orig_obj, 
java_lang_Class::array_klass_offset());
   } else if (java_lang_invoke_ResolvedMethodName::is_instance(orig_obj)) {
     ArchiveHeapWriter::mark_native_pointer(orig_obj, 
java_lang_invoke_ResolvedMethodName::vmtarget_offset());
   }
}

However, we should exclude all resolved lambda sites that reference an 
excluded class. As a result, we should never archive such 
a ResolvedMethodName:

  0 AOTConstantPoolResolver::check_methodtype_signature
  1 AOTConstantPoolResolver::check_lambda_metafactory_methodtype_arg
  2 AOTConstantPoolResolver::is_indy_resolution_deterministic
  3 AOTConstantPoolResolver::is_resolution_deterministic
  4 ConstantPoolCache::remove_resolved_indy_entries_if_non_deterministic
  5 ConstantPoolCache::remove_unshareable_info
  6 ConstantPool::remove_unshareable_entries
  7 ConstantPool::remove_unshareable_info
  8 ArchiveBuilder::make_klasses_shareable
  9 VM_PopulateDumpSharedSpace::doit
10 VM_Operation::evaluate

We have test cases in here:

LambdaContainsOldInf.java: output.shouldMatch("Cannot aot-resolve Lambda 
proxy because OldProvider is excluded");
resolvedConstants/ResolvedConstants.java:  .shouldContain("Cannot 
aot-resolve Lambda proxy of interface type InterfaceWithClinit")
resolvedConstants/AOTLinkedLambdas.java: dumpOut.shouldContain("Can 
aot-resolve Lambda proxy of interface type IA");

If you can find a way to reproduce the problem it would be great. You 
can find more information about the failure with this:

diff --git a/src/hotspot/share/cds/archiveHeapWriter.cpp 
b/src/hotspot/share/cds/archiveHeapWriter.cpp
index ee1e334e84b..7f68e648431 100644
--- a/src/hotspot/share/cds/archiveHeapWriter.cpp
+++ b/src/hotspot/share/cds/archiveHeapWriter.cpp
@@ -754,6 +754,14 @@ void 
ArchiveHeapWriter::compute_ptrmap(ArchiveHeapInfo* heap_info) {
      Metadata** buffered_field_addr = 
requested_addr_to_buffered_addr(requested_field_addr);
      Metadata* native_ptr = *buffered_field_addr;
      guarantee(native_ptr != nullptr, "sanity");
+    if 
(!ArchiveBuilder::current()->has_been_buffered((address)native_ptr)) {
+      ResourceMark rm;
+      tty->print_cr("Marking native pointer for oop %p (type = %s, 
offset = %d)",
+                    cast_from_oop<void*>(src_obj), 
src_obj->klass()->external_name(), field_offset);
+      src_obj->print_on(tty);
+      tty->cr();
+    }
+

Thanks

- Ioi

On 2/9/26 7:24 AM, Anton Voznia wrote:
>
> Hi all,
>
>
> I have a question about a potential bug in AOT heap archiving.
>
>
> We observe a crash (guarantee failure) while creating the AOT cache 
> with JDK 25, at:
>
> _https://github.com/openjdk/jdk25u-dev/blob/40ec273de548b47fc08d02bbe7c1cb3b48ebad17/src/hotspot/share/cds/archiveHeapWriter.cpp#L757_
>
>
> The failure happens because:
>
> get_buffered_addr(src_addr) == nullptr
>
>
> What means that a native pointer is present in _native_pointers but 
> there is no corresponding buffered address, even though the 
> SourceObjInfo was successfully added to _src_obj_table.
>
> The failing check is:
>
> guarantee(ArchiveBuilder::current()->has_been_buffered((address)native_ptr),
>
>         "Metadata %p should have been archived", native_ptr);
>
>
> further investigation showed that we collect pointers into 
> _native_pointers without checking whether the corresponding class was 
> excluded (via class exclusion or link-time verification failures):
>
> _https://github.com/openjdk/jdk25u-dev/blob/40ec273de548b47fc08d02bbe7c1cb3b48ebad17/src/hotspot/share/cds/heapShared.cpp#L308_
>
>
> However, the SourceObjInfo::_buffered_addr seems to be assigned only 
> for objects that are actually copied (i.e., not excluded).
>
>
> In particular, this SourceObjInfo didn’t end up in _ro_src_objs or 
> _rw_src_objs because it didn’t satisfy the following condition:
>
> _https://github.com/openjdk/jdk25u-dev/blob/40ec273de548b47fc08d02bbe7c1cb3b48ebad17/src/hotspot/share/cds/archiveBuilder.cpp#L467_
>
>
> if (created && src_info.should_copy()) {
>
>   if (read_only) {
>
>     _ro_src_objs.append(p);
>
>   } else {
>
>     _rw_src_objs.append(p);
>
>   }
>
>   return true; // Need to recurse into this ref only if we are copying it
>
> }
>
>
> created is true (object exists in _src_obj_table), but 
> src_info.should_copy() is false because _follow_mode is set_to_null 
> (not make_a_copy).
>
>
> So it looks like we may end up with an item in _native_pointers for 
> which we will never assign a buffered address.
>
> However, later we expect every item in _native_pointers to have one 
> buffered address.
>
>
> Is this logic correct, or am I missing a step that guarantees 
> buffering for all _native_pointers items?
>
> It seems, we have to check for a class exclusion before adding into 
> _native_pointers.
>
>
> Unfortunately, I wasn’t able to reproduce the issue locally.
>
>
> Thanks and best regards,
> Anton Voznia
>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/leyden-dev/attachments/20260209/2a1d7fff/attachment.htm>


More information about the leyden-dev mailing list