Project

General

Profile

Bug #18795 ยป 0001-Fix-crash-when-printing-RGENGC_DEBUG-5-output-from-G.patch

kjtsanaktsidis (KJ Tsanaktsidis), 05/22/2022 07:27 AM

View differences:

gc.c
#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);
/*
......
GC_ASSERT(!SPECIAL_CONST_P(obj)); /* check alignment */
#endif
gc_report(5, objspace, "newobj: %s\n", obj_info(obj));
#if RGENGC_OLD_NEWOBJ_CHECK > 0
{
static int newobj_cnt = RGENGC_OLD_NEWOBJ_CHECK;
......
p->as.values.v1 = v1;
p->as.values.v2 = v2;
p->as.values.v3 = v3;
// Must call obj_info_basic() here, not obj_info(), because some of the things
// that obj_info tries to print (e.g. the iv table for a class) won't be setup yet.
// This also needs to be here, NOT in newobj_init, because fetching the type of T_DATA
// things depends on RTYPEDDATA(obj)->type, which is set up above (as v1).
gc_report(5, &rb_objspace, "newobj: %s\n", obj_info_basic(obj));
return obj;
}
......
return (int)len;
}
const char *
rb_raw_obj_info(char *buff, const int buff_size, VALUE obj)
#define OBJ_INFO_EXT 1 << 0
static const char *
rb_raw_obj_info_impl(char *buff, const int buff_size, VALUE obj, int obj_info_flags)
{
int pos = 0;
void *poisoned = asan_poisoned_object_p(obj);
......
APPENDF((BUFF_ARGS, "@%s:%d", RANY(obj)->file, RANY(obj)->line));
#endif
switch (type) {
case T_NODE:
UNEXPECTED_NODE(rb_raw_obj_info);
break;
case T_ARRAY:
if (FL_TEST(obj, ELTS_SHARED)) {
APPENDF((BUFF_ARGS, "shared -> %s",
rb_obj_info(RARRAY(obj)->as.heap.aux.shared_root)));
}
else if (FL_TEST(obj, RARRAY_EMBED_FLAG)) {
APPENDF((BUFF_ARGS, "[%s%s] len: %ld (embed)",
C(ARY_EMBED_P(obj), "E"),
C(ARY_SHARED_P(obj), "S"),
RARRAY_LEN(obj)));
}
else {
APPENDF((BUFF_ARGS, "[%s%s%s] len: %ld, capa:%ld ptr:%p",
C(ARY_EMBED_P(obj), "E"),
C(ARY_SHARED_P(obj), "S"),
C(RARRAY_TRANSIENT_P(obj), "T"),
RARRAY_LEN(obj),
ARY_EMBED_P(obj) ? -1L : RARRAY(obj)->as.heap.aux.capa,
(void *)RARRAY_CONST_PTR_TRANSIENT(obj)));
}
break;
case T_STRING: {
if (STR_SHARED_P(obj)) {
APPENDF((BUFF_ARGS, " [shared] len: %ld", RSTRING_LEN(obj)));
}
else {
if (STR_EMBED_P(obj)) APPENDF((BUFF_ARGS, " [embed]"));
APPENDF((BUFF_ARGS, " len: %ld, capa: %" PRIdSIZE, RSTRING_LEN(obj), rb_str_capacity(obj)));
}
APPENDF((BUFF_ARGS, " \"%.*s\"", str_len_no_raise(obj), RSTRING_PTR(obj)));
break;
}
case T_SYMBOL: {
VALUE fstr = RSYMBOL(obj)->fstr;
ID id = RSYMBOL(obj)->id;
if (RB_TYPE_P(fstr, T_STRING)) {
APPENDF((BUFF_ARGS, ":%s id:%d", RSTRING_PTR(fstr), (unsigned int)id));
}
else {
APPENDF((BUFF_ARGS, "(%p) id:%d", (void *)fstr, (unsigned int)id));
}
break;
}
case T_MOVED: {
APPENDF((BUFF_ARGS, "-> %p", (void*)rb_gc_location(obj)));
if (obj_info_flags & OBJ_INFO_EXT) {
switch (type) {
case T_NODE:
UNEXPECTED_NODE(rb_raw_obj_info);
break;
}
case T_HASH: {
APPENDF((BUFF_ARGS, "[%c%c] %"PRIdSIZE,
RHASH_AR_TABLE_P(obj) ? 'A' : 'S',
RHASH_TRANSIENT_P(obj) ? 'T' : ' ',
RHASH_SIZE(obj)));
break;
}
case T_CLASS:
case T_MODULE:
{
VALUE class_path = rb_class_path_cached(obj);
if (!NIL_P(class_path)) {
APPENDF((BUFF_ARGS, "%s", RSTRING_PTR(class_path)));
case T_ARRAY:
if (FL_TEST(obj, ELTS_SHARED)) {
APPENDF((BUFF_ARGS, "shared -> %s",
rb_obj_info(RARRAY(obj)->as.heap.aux.shared_root)));
}
else if (FL_TEST(obj, RARRAY_EMBED_FLAG)) {
APPENDF((BUFF_ARGS, "[%s%s] len: %ld (embed)",
C(ARY_EMBED_P(obj), "E"),
C(ARY_SHARED_P(obj), "S"),
RARRAY_LEN(obj)));
}
else {
APPENDF((BUFF_ARGS, "(annon)"));
APPENDF((BUFF_ARGS, "[%s%s%s] len: %ld, capa:%ld ptr:%p",
C(ARY_EMBED_P(obj), "E"),
C(ARY_SHARED_P(obj), "S"),
C(RARRAY_TRANSIENT_P(obj), "T"),
RARRAY_LEN(obj),
ARY_EMBED_P(obj) ? -1L : RARRAY(obj)->as.heap.aux.capa,
(void *)RARRAY_CONST_PTR_TRANSIENT(obj)));
}
break;
}
case T_ICLASS:
{
VALUE class_path = rb_class_path_cached(RBASIC_CLASS(obj));
if (!NIL_P(class_path)) {
APPENDF((BUFF_ARGS, "src:%s", RSTRING_PTR(class_path)));
break;
case T_STRING: {
if (STR_SHARED_P(obj)) {
APPENDF((BUFF_ARGS, " [shared] len: %ld", RSTRING_LEN(obj)));
}
break;
}
case T_OBJECT:
{
uint32_t len = ROBJECT_NUMIV(obj);
else {
if (STR_EMBED_P(obj)) APPENDF((BUFF_ARGS, " [embed]"));
if (RANY(obj)->as.basic.flags & ROBJECT_EMBED) {
APPENDF((BUFF_ARGS, "(embed) len:%d", len));
APPENDF((BUFF_ARGS, " len: %ld, capa: %" PRIdSIZE, RSTRING_LEN(obj), rb_str_capacity(obj)));
}
APPENDF((BUFF_ARGS, " \"%.*s\"", str_len_no_raise(obj), RSTRING_PTR(obj)));
break;
}
case T_SYMBOL: {
VALUE fstr = RSYMBOL(obj)->fstr;
ID id = RSYMBOL(obj)->id;
if (RB_TYPE_P(fstr, T_STRING)) {
APPENDF((BUFF_ARGS, ":%s id:%d", RSTRING_PTR(fstr), (unsigned int)id));
}
else {
VALUE *ptr = ROBJECT_IVPTR(obj);
APPENDF((BUFF_ARGS, "len:%d ptr:%p", len, (void *)ptr));
APPENDF((BUFF_ARGS, "(%p) id:%d", (void *)fstr, (unsigned int)id));
}
break;
}
break;
case T_DATA: {
const struct rb_block *block;
const rb_iseq_t *iseq;
if (rb_obj_is_proc(obj) &&
(block = vm_proc_block(obj)) != NULL &&
(vm_block_type(block) == block_type_iseq) &&
(iseq = vm_block_iseq(block)) != NULL) {
rb_raw_iseq_info(BUFF_ARGS, iseq);
}
else if (rb_ractor_p(obj)) {
rb_ractor_t *r = (void *)DATA_PTR(obj);
if (r) {
APPENDF((BUFF_ARGS, "r:%d", r->pub.id));
}
case T_MOVED: {
APPENDF((BUFF_ARGS, "-> %p", (void*)rb_gc_location(obj)));
break;
}
else {
const char * const type_name = rb_objspace_data_type_name(obj);
if (type_name) {
APPENDF((BUFF_ARGS, "%s", type_name));
}
}
break;
}
case T_IMEMO: {
APPENDF((BUFF_ARGS, "<%s> ", rb_imemo_name(imemo_type(obj))));
switch (imemo_type(obj)) {
case imemo_ment:
case T_HASH: {
APPENDF((BUFF_ARGS, "[%c%c] %"PRIdSIZE,
RHASH_AR_TABLE_P(obj) ? 'A' : 'S',
RHASH_TRANSIENT_P(obj) ? 'T' : ' ',
RHASH_SIZE(obj)));
break;
}
case T_CLASS:
case T_MODULE:
{
const rb_method_entry_t *me = &RANY(obj)->as.imemo.ment;
APPENDF((BUFF_ARGS, ":%s (%s%s%s%s) type:%s alias:%d owner:%p defined_class:%p",
rb_id2name(me->called_id),
METHOD_ENTRY_VISI(me) == METHOD_VISI_PUBLIC ? "pub" :
METHOD_ENTRY_VISI(me) == METHOD_VISI_PRIVATE ? "pri" : "pro",
METHOD_ENTRY_COMPLEMENTED(me) ? ",cmp" : "",
METHOD_ENTRY_CACHED(me) ? ",cc" : "",
METHOD_ENTRY_INVALIDATED(me) ? ",inv" : "",
me->def ? rb_method_type_name(me->def->type) : "NULL",
me->def ? me->def->alias_count : -1,
(void *)me->owner, // obj_info(me->owner),
(void *)me->defined_class)); //obj_info(me->defined_class)));
if (me->def) {
switch (me->def->type) {
case VM_METHOD_TYPE_ISEQ:
APPENDF((BUFF_ARGS, " (iseq:%s)", obj_info((VALUE)me->def->body.iseq.iseqptr)));
break;
default:
break;
}
VALUE class_path = rb_class_path_cached(obj);
if (!NIL_P(class_path)) {
APPENDF((BUFF_ARGS, "%s", RSTRING_PTR(class_path)));
}
else {
APPENDF((BUFF_ARGS, "(annon)"));
}
break;
}
case imemo_iseq: {
const rb_iseq_t *iseq = (const rb_iseq_t *)obj;
rb_raw_iseq_info(BUFF_ARGS, iseq);
break;
}
case imemo_callinfo:
case T_ICLASS:
{
const struct rb_callinfo *ci = (const struct rb_callinfo *)obj;
APPENDF((BUFF_ARGS, "(mid:%s, flag:%x argc:%d, kwarg:%s)",
rb_id2name(vm_ci_mid(ci)),
vm_ci_flag(ci),
vm_ci_argc(ci),
vm_ci_kwarg(ci) ? "available" : "NULL"));
VALUE class_path = rb_class_path_cached(RBASIC_CLASS(obj));
if (!NIL_P(class_path)) {
APPENDF((BUFF_ARGS, "src:%s", RSTRING_PTR(class_path)));
}
break;
}
case imemo_callcache:
case T_OBJECT:
{
const struct rb_callcache *cc = (const struct rb_callcache *)obj;
VALUE class_path = cc->klass ? rb_class_path_cached(cc->klass) : Qnil;
const rb_callable_method_entry_t *cme = vm_cc_cme(cc);
APPENDF((BUFF_ARGS, "(klass:%s cme:%s%s (%p) call:%p",
NIL_P(class_path) ? (cc->klass ? "??" : "<NULL>") : RSTRING_PTR(class_path),
cme ? rb_id2name(cme->called_id) : "<NULL>",
cme ? (METHOD_ENTRY_INVALIDATED(cme) ? " [inv]" : "") : "",
(void *)cme,
(void *)vm_cc_call(cc)));
break;
uint32_t len = ROBJECT_NUMIV(obj);
if (RANY(obj)->as.basic.flags & ROBJECT_EMBED) {
APPENDF((BUFF_ARGS, "(embed) len:%d", len));
}
else {
VALUE *ptr = ROBJECT_IVPTR(obj);
APPENDF((BUFF_ARGS, "len:%d ptr:%p", len, (void *)ptr));
}
}
default:
break;
}
}
default:
break;
}
break;
case T_DATA: {
const struct rb_block *block;
const rb_iseq_t *iseq;
if (rb_obj_is_proc(obj) &&
(block = vm_proc_block(obj)) != NULL &&
(vm_block_type(block) == block_type_iseq) &&
(iseq = vm_block_iseq(block)) != NULL) {
rb_raw_iseq_info(BUFF_ARGS, iseq);
}
else if (rb_ractor_p(obj)) {
rb_ractor_t *r = (void *)DATA_PTR(obj);
if (r) {
APPENDF((BUFF_ARGS, "r:%d", r->pub.id));
}
}
else {
const char * const type_name = rb_objspace_data_type_name(obj);
if (type_name) {
APPENDF((BUFF_ARGS, "%s", type_name));
}
}
break;
}
case T_IMEMO: {
APPENDF((BUFF_ARGS, "<%s> ", rb_imemo_name(imemo_type(obj))));
switch (imemo_type(obj)) {
case imemo_ment:
{
const rb_method_entry_t *me = &RANY(obj)->as.imemo.ment;
APPENDF((BUFF_ARGS, ":%s (%s%s%s%s) type:%s alias:%d owner:%p defined_class:%p",
rb_id2name(me->called_id),
METHOD_ENTRY_VISI(me) == METHOD_VISI_PUBLIC ? "pub" :
METHOD_ENTRY_VISI(me) == METHOD_VISI_PRIVATE ? "pri" : "pro",
METHOD_ENTRY_COMPLEMENTED(me) ? ",cmp" : "",
METHOD_ENTRY_CACHED(me) ? ",cc" : "",
METHOD_ENTRY_INVALIDATED(me) ? ",inv" : "",
me->def ? rb_method_type_name(me->def->type) : "NULL",
me->def ? me->def->alias_count : -1,
(void *)me->owner, // obj_info(me->owner),
(void *)me->defined_class)); //obj_info(me->defined_class)));
if (me->def) {
switch (me->def->type) {
case VM_METHOD_TYPE_ISEQ:
APPENDF((BUFF_ARGS, " (iseq:%s)", obj_info((VALUE)me->def->body.iseq.iseqptr)));
break;
default:
break;
}
}
break;
}
case imemo_iseq: {
const rb_iseq_t *iseq = (const rb_iseq_t *)obj;
rb_raw_iseq_info(BUFF_ARGS, iseq);
break;
}
case imemo_callinfo:
{
const struct rb_callinfo *ci = (const struct rb_callinfo *)obj;
APPENDF((BUFF_ARGS, "(mid:%s, flag:%x argc:%d, kwarg:%s)",
rb_id2name(vm_ci_mid(ci)),
vm_ci_flag(ci),
vm_ci_argc(ci),
vm_ci_kwarg(ci) ? "available" : "NULL"));
break;
}
case imemo_callcache:
{
const struct rb_callcache *cc = (const struct rb_callcache *)obj;
VALUE class_path = cc->klass ? rb_class_path_cached(cc->klass) : Qnil;
const rb_callable_method_entry_t *cme = vm_cc_cme(cc);
APPENDF((BUFF_ARGS, "(klass:%s cme:%s%s (%p) call:%p",
NIL_P(class_path) ? (cc->klass ? "??" : "<NULL>") : RSTRING_PTR(class_path),
cme ? rb_id2name(cme->called_id) : "<NULL>",
cme ? (METHOD_ENTRY_INVALIDATED(cme) ? " [inv]" : "") : "",
(void *)cme,
(void *)vm_cc_call(cc)));
break;
}
default:
break;
}
}
default:
break;
}
}
#undef TF
#undef C
}
......
#undef BUFF_ARGS
}
const char *
rb_raw_obj_info(char *buff, const int buff_size, VALUE obj)
{
return rb_raw_obj_info_impl(buff, buff_size, obj, OBJ_INFO_EXT);
}
#if RGENGC_OBJ_INFO
#define OBJ_INFO_BUFFERS_NUM 10
#define OBJ_INFO_BUFFERS_SIZE 0x100
......
static char obj_info_buffers[OBJ_INFO_BUFFERS_NUM][OBJ_INFO_BUFFERS_SIZE];
static const char *
obj_info(VALUE obj)
obj_info_impl(VALUE obj, int obj_info_flags)
{
const int index = obj_info_buffers_index++;
char *const buff = &obj_info_buffers[index][0];
......
obj_info_buffers_index = 0;
}
return rb_raw_obj_info(buff, OBJ_INFO_BUFFERS_SIZE, obj);
return rb_raw_obj_info_impl(buff, OBJ_INFO_BUFFERS_SIZE, obj, obj_info_flags);
}
static const char *
obj_info(VALUE obj)
{
return obj_info_impl(obj, OBJ_INFO_EXT);
}
static const char *
obj_info_basic(VALUE obj)
{
return obj_info_impl(obj, 0);
}
#else
static const char *
......
{
return obj_type_name(obj);
}
static const char *
obj_info_basic(VALUE obj)
{
return obj_type_name(obj);
}
#endif
MJIT_FUNC_EXPORTED const char *
    (1-1/1)