Fix crash when printing RGENGC_DEBUG=5 output from GC
I was trying to debug an (unrelated) issue in the GC, and wanted to turn on the trace-level GC output by compiling it with -DRGENGC_DEBUG=5. Unfortunately, this actually causes a crash in newobj_init() because the code there tries to log the obj_info() of the newly created object. However, the object is not actually sufficiently set up for some of the things that obj_info() tries to do: * The instance variable table for a class is not yet initialized, and when using variable-length RVALUES, said ivar table is embedded in as-yet unitialized memory after the struct RValue. Attempting to read this, as obj_info() does, causes a crash. * T_DATA variables need to dereference their ->type field to print out the underlying C type name, which is not set up until newobj_fill() is called. To fix this, create a new method `obj_info_basic`, which dumps out only the parts of the object that are valid before the object is fully initialized. [Fixes #18795]
This commit is contained in:
parent
5906f6a50e
commit
25f5b83689
29
gc.c
29
gc.c
@ -1427,6 +1427,7 @@ static inline void gc_prof_set_heap_info(rb_objspace_t *);
|
||||
#endif
|
||||
PRINTF_ARGS(static void gc_report_body(int level, rb_objspace_t *objspace, const char *fmt, ...), 3, 4);
|
||||
static const char *obj_info(VALUE obj);
|
||||
static const char *obj_info_basic(VALUE obj);
|
||||
static const char *obj_type_name(VALUE obj);
|
||||
|
||||
static void gc_finalize_deferred(void *dmy);
|
||||
@ -2638,7 +2639,7 @@ newobj_init(VALUE klass, VALUE flags, int wb_protected, rb_objspace_t *objspace,
|
||||
GC_ASSERT(!SPECIAL_CONST_P(obj)); /* check alignment */
|
||||
#endif
|
||||
|
||||
gc_report(5, objspace, "newobj: %s\n", obj_info(obj));
|
||||
gc_report(5, objspace, "newobj: %s\n", obj_info_basic(obj));
|
||||
|
||||
// RUBY_DEBUG_LOG("obj:%p (%s)", (void *)obj, obj_type_name(obj));
|
||||
return obj;
|
||||
@ -14099,6 +14100,17 @@ rb_raw_obj_info(char *const buff, const size_t buff_size, VALUE obj)
|
||||
return buff;
|
||||
}
|
||||
|
||||
const char *
|
||||
rb_raw_obj_info_basic(char *const buff, const size_t buff_size, VALUE obj)
|
||||
{
|
||||
asan_unpoisoning_object(obj) {
|
||||
size_t pos = rb_raw_obj_info_common(buff, buff_size, obj);
|
||||
if (pos >= buff_size) {} // truncated
|
||||
}
|
||||
|
||||
return buff;
|
||||
}
|
||||
|
||||
#undef APPEND_S
|
||||
#undef APPEND_F
|
||||
#undef BUFF_ARGS
|
||||
@ -14130,12 +14142,27 @@ obj_info(VALUE obj)
|
||||
char *const buff = obj_info_buffers[index];
|
||||
return rb_raw_obj_info(buff, OBJ_INFO_BUFFERS_SIZE, obj);
|
||||
}
|
||||
|
||||
static const char *
|
||||
obj_info_basic(VALUE obj)
|
||||
{
|
||||
rb_atomic_t index = atomic_inc_wraparound(&obj_info_buffers_index, OBJ_INFO_BUFFERS_NUM);
|
||||
char *const buff = obj_info_buffers[index];
|
||||
return rb_raw_obj_info_basic(buff, OBJ_INFO_BUFFERS_SIZE, obj);
|
||||
}
|
||||
#else
|
||||
static const char *
|
||||
obj_info(VALUE obj)
|
||||
{
|
||||
return obj_type_name(obj);
|
||||
}
|
||||
|
||||
static const char *
|
||||
obj_info_basic(VALUE obj)
|
||||
{
|
||||
return obj_type_name(obj);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
const char *
|
||||
|
@ -122,6 +122,7 @@ int ruby_get_stack_grow_direction(volatile VALUE *addr);
|
||||
|
||||
const char *rb_obj_info(VALUE obj);
|
||||
const char *rb_raw_obj_info(char *const buff, const size_t buff_size, VALUE obj);
|
||||
const char *rb_raw_obj_info_basic(char *const buff, const size_t buff_size, VALUE obj);
|
||||
|
||||
size_t rb_size_pool_slot_size(unsigned char pool_id);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user