11/*
2- * Copyright (c) 2018, 2020 , Red Hat, Inc. All rights reserved.
2+ * Copyright (c) 2018, 2025 , Red Hat, Inc. All rights reserved.
33 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44 *
55 * This code is free software; you can redistribute it and/or modify it
2929#include " gc/shenandoah/shenandoahHeapRegionSet.inline.hpp"
3030#include " gc/shenandoah/shenandoahMarkingContext.inline.hpp"
3131#include " gc/shenandoah/shenandoahUtils.hpp"
32+ #include " oops/oop.inline.hpp"
3233#include " memory/resourceArea.hpp"
34+ #include " runtime/os.hpp"
35+ #include " utilities/vmError.hpp"
3336
3437void print_raw_memory (ShenandoahMessageBuffer &msg, void * loc) {
3538 // Be extra safe. Only access data that is guaranteed to be safe:
@@ -57,30 +60,42 @@ void ShenandoahAsserts::print_obj(ShenandoahMessageBuffer& msg, oop obj) {
5760
5861 ResourceMark rm;
5962 stringStream ss;
60- r->print_on (&ss);
61-
62- stringStream mw_ss;
63- obj->mark ().print_on (&mw_ss);
63+ StreamIndentor si (&ss);
6464
6565 ShenandoahMarkingContext* const ctx = heap->marking_context ();
6666
67- Klass* obj_klass = ShenandoahForwarding::klass (obj);
68-
69- msg.append (" " PTR_FORMAT " - klass " PTR_FORMAT " %s\n " , p2i (obj), p2i (obj_klass), obj_klass->external_name ());
70- msg.append (" %3s allocated after mark start\n " , ctx->allocated_after_mark_start (obj) ? " " : " not" );
71- msg.append (" %3s after update watermark\n " , cast_from_oop<HeapWord*>(obj) >= r->get_update_watermark () ? " " : " not" );
72- msg.append (" %3s marked strong\n " , ctx->is_marked_strong (obj) ? " " : " not" );
73- msg.append (" %3s marked weak\n " , ctx->is_marked_weak (obj) ? " " : " not" );
74- msg.append (" %3s in collection set\n " , heap->in_collection_set (obj) ? " " : " not" );
75- if (heap->mode ()->is_generational () && !obj->is_forwarded ()) {
76- msg.append (" age: %d\n " , obj->age ());
77- }
78- msg.append (" mark:%s\n " , mw_ss.freeze ());
79- msg.append (" region: %s" , ss.freeze ());
80- if (obj_klass == vmClasses::Class_klass ()) {
81- msg.append (" mirrored klass: " PTR_FORMAT " \n " , p2i (obj->metadata_field (java_lang_Class::klass_offset ())));
82- msg.append (" mirrored array klass: " PTR_FORMAT " \n " , p2i (obj->metadata_field (java_lang_Class::array_klass_offset ())));
67+ narrowKlass nk = 0 ;
68+ const Klass* obj_klass = nullptr ;
69+ const bool klass_valid = extract_klass_safely (obj, nk, obj_klass);
70+ const char * klass_text = " (invalid)" ;
71+ if (klass_valid && os::is_readable_pointer (obj_klass) && Metaspace::contains (obj_klass)) {
72+ klass_text = obj_klass->external_name ();
73+ }
74+ ss.print_cr (PTR_FORMAT " - nk %u klass " PTR_FORMAT " %s\n " , p2i (obj), nk, p2i (obj_klass), klass_text);
75+ {
76+ StreamIndentor si (&ss);
77+ ss.print_cr (" %3s allocated after mark start" , ctx->allocated_after_mark_start (obj) ? " " : " not" );
78+ ss.print_cr (" %3s after update watermark" , cast_from_oop<HeapWord*>(obj) >= r->get_update_watermark () ? " " : " not" );
79+ ss.print_cr (" %3s marked strong" , ctx->is_marked_strong (obj) ? " " : " not" );
80+ ss.print_cr (" %3s marked weak" , ctx->is_marked_weak (obj) ? " " : " not" );
81+ ss.print_cr (" %3s in collection set" , heap->in_collection_set (obj) ? " " : " not" );
82+ if (heap->mode ()->is_generational () && !obj->is_forwarded ()) {
83+ ss.print_cr (" age: %d" , obj->age ());
84+ }
85+ ss.print_raw (" mark: " );
86+ obj->mark ().print_on (&ss);
87+ ss.cr ();
88+ ss.print_raw (" region: " );
89+ r->print_on (&ss);
90+ ss.cr ();
91+ if (obj_klass == vmClasses::Class_klass ()) {
92+ msg.append (" mirrored klass: " PTR_FORMAT " \n " , p2i (obj->metadata_field (java_lang_Class::klass_offset ())));
93+ msg.append (" mirrored array klass: " PTR_FORMAT " \n " , p2i (obj->metadata_field (java_lang_Class::array_klass_offset ())));
94+ }
8395 }
96+ const_address loc = cast_from_oop<const_address>(obj);
97+ os::print_hex_dump (&ss, loc, loc + 64 , 4 , true , 32 , loc);
98+ msg.append (" %s" , ss.base ());
8499}
85100
86101void ShenandoahAsserts::print_non_obj (ShenandoahMessageBuffer& msg, void * loc) {
@@ -121,14 +136,18 @@ void ShenandoahAsserts::print_failure(SafeLevel level, oop obj, void* interior_l
121136 ShenandoahHeap* heap = ShenandoahHeap::heap ();
122137 ResourceMark rm;
123138
139+ if (!os::is_readable_pointer (obj)) {
140+ level = _safe_unknown;
141+ }
142+
124143 bool loc_in_heap = (loc != nullptr && heap->is_in_reserved (loc));
125144
126145 ShenandoahMessageBuffer msg (" %s; %s\n\n " , phase, label);
127146
128147 msg.append (" Referenced from:\n " );
129148 if (interior_loc != nullptr ) {
130149 msg.append (" interior location: " PTR_FORMAT " \n " , p2i (interior_loc));
131- if (loc_in_heap) {
150+ if (loc_in_heap && os::is_readable_pointer (loc) ) {
132151 print_obj (msg, loc);
133152 } else {
134153 print_non_obj (msg, interior_loc);
@@ -150,7 +169,7 @@ void ShenandoahAsserts::print_failure(SafeLevel level, oop obj, void* interior_l
150169 oop fwd = ShenandoahForwarding::get_forwardee_raw_unchecked (obj);
151170 msg.append (" Forwardee:\n " );
152171 if (obj != fwd) {
153- if (level >= _safe_oop_fwd) {
172+ if (level >= _safe_oop_fwd && os::is_readable_pointer (fwd) ) {
154173 print_obj (msg, fwd);
155174 } else {
156175 print_obj_safe (msg, fwd);
@@ -205,17 +224,10 @@ void ShenandoahAsserts::assert_correct(void* interior_loc, oop obj, const char*
205224 file, line);
206225 }
207226
208- Klass* obj_klass = ShenandoahForwarding::klass (obj);
209- if (obj_klass == nullptr ) {
210- print_failure (_safe_unknown, obj, interior_loc, nullptr , " Shenandoah assert_correct failed" ,
211- " Object klass pointer should not be null" ,
212- file,line);
213- }
214-
215- if (!Metaspace::contains (obj_klass)) {
227+ if (!os::is_readable_pointer (obj)) {
216228 print_failure (_safe_unknown, obj, interior_loc, nullptr , " Shenandoah assert_correct failed" ,
217- " Object klass pointer must go to metaspace " ,
218- file,line);
229+ " oop within heap bounds but at unreadable location " ,
230+ file, line);
219231 }
220232
221233 if (!heap->is_in (obj)) {
@@ -243,9 +255,9 @@ void ShenandoahAsserts::assert_correct(void* interior_loc, oop obj, const char*
243255 file, line);
244256 }
245257
246- if (obj_klass != ShenandoahForwarding::klass (fwd)) {
258+ if (! os::is_readable_pointer (fwd)) {
247259 print_failure (_safe_oop, obj, interior_loc, nullptr , " Shenandoah assert_correct failed" ,
248- " Forwardee klass disagrees with object class " ,
260+ " Forwardee within heap bounds but at unreadable location " ,
249261 file, line);
250262 }
251263
@@ -271,6 +283,32 @@ void ShenandoahAsserts::assert_correct(void* interior_loc, oop obj, const char*
271283 }
272284 }
273285
286+ const Klass* obj_klass = nullptr ;
287+ narrowKlass nk = 0 ;
288+ if (!extract_klass_safely (obj, nk, obj_klass)) {
289+ print_failure (_safe_oop, obj, interior_loc, nullptr , " Shenandoah assert_correct failed" ,
290+ " Object klass pointer invalid" ,
291+ file,line);
292+ }
293+
294+ if (obj_klass == nullptr ) {
295+ print_failure (_safe_oop, obj, interior_loc, nullptr , " Shenandoah assert_correct failed" ,
296+ " Object klass pointer should not be null" ,
297+ file,line);
298+ }
299+
300+ if (!Metaspace::contains (obj_klass)) {
301+ print_failure (_safe_oop, obj, interior_loc, nullptr , " Shenandoah assert_correct failed" ,
302+ " Object klass pointer must go to metaspace" ,
303+ file,line);
304+ }
305+
306+ if (!UseCompactObjectHeaders && obj_klass != fwd->klass_or_null ()) {
307+ print_failure (_safe_oop, obj, interior_loc, nullptr , " Shenandoah assert_correct failed" ,
308+ " Forwardee klass disagrees with object class" ,
309+ file, line);
310+ }
311+
274312 // Do additional checks for special objects: their fields can hold metadata as well.
275313 // We want to check class loading/unloading did not corrupt them. We can only reasonably
276314 // trust the forwarded objects, as the from-space object can have the klasses effectively
@@ -519,3 +557,30 @@ void ShenandoahAsserts::assert_generations_reconciled(const char* file, int line
519557 ShenandoahMessageBuffer msg (" Active(%d) & GC(%d) Generations aren't reconciled" , agen->type (), ggen->type ());
520558 report_vm_error (file, line, msg.buffer ());
521559}
560+
561+ bool ShenandoahAsserts::extract_klass_safely (oop obj, narrowKlass& nk, const Klass*& k) {
562+ nk = 0 ;
563+ k = nullptr ;
564+
565+ if (!os::is_readable_pointer (obj)) {
566+ return false ;
567+ }
568+ if (UseCompressedClassPointers) {
569+ if (UseCompactObjectHeaders) { // look in forwardee
570+ oop fwd = ShenandoahForwarding::get_forwardee_raw_unchecked (obj);
571+ if (!os::is_readable_pointer (fwd)) {
572+ return false ;
573+ }
574+ nk = fwd->mark ().narrow_klass ();
575+ } else {
576+ nk = obj->narrow_klass ();
577+ }
578+ if (!CompressedKlassPointers::is_valid_narrow_klass_id (nk)) {
579+ return false ;
580+ }
581+ k = CompressedKlassPointers::decode_not_null_without_asserts (nk);
582+ } else {
583+ k = obj->klass ();
584+ }
585+ return k != nullptr ;
586+ }
0 commit comments