Skip to content

Commit 4c3d436

Browse files
committed
Add a check in non-debug mode for a T_NONE class
Although a crash could occur anywhere, one of the most common symptoms we see from getting a reference to a garbage collected object is crashing while attempting to call a method on it. These crashes usually occur when trying to perform an rb_id_table_lookup in the "class" cc_tbl, where the class is usually another garbage collected object, because the freelist is stored in the class pointer. This commit aims to have a better error message in this case, in hopes of having a better grouping of errors and to give a better hint to those investigating and triaging crashes.
1 parent 4c7f28d commit 4c3d436

2 files changed

Lines changed: 24 additions & 0 deletions

File tree

vm_insnhelper.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2178,6 +2178,18 @@ rb_vm_search_method_slowpath(const struct rb_callinfo *ci, VALUE klass)
21782178
{
21792179
const struct rb_callcache *cc;
21802180

2181+
VM_ASSERT(!SPECIAL_CONST_P(klass));
2182+
2183+
if (RB_BUILTIN_TYPE(klass) == T_NONE) {
2184+
// If we find a T_NONE here, it's most likely we called CLASS_OF(obj) on a
2185+
// garbage collected object (the freelist is stored in the class pointer),
2186+
// but it's possible that just the class was GC'd.
2187+
// This message intentionally tries to imply the former, but make an
2188+
// accurate statement for either case.
2189+
rb_bug("attempted to search method '%s' on a garbage collected object",
2190+
rb_id2name(vm_ci_mid(ci)));
2191+
}
2192+
21812193
VM_ASSERT_TYPE2(klass, T_CLASS, T_ICLASS);
21822194

21832195
cc = vm_search_cc(klass, ci);

vm_method.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2007,6 +2007,18 @@ callable_method_entry_or_negative(VALUE klass, ID mid, VALUE *defined_class_ptr)
20072007
{
20082008
const rb_callable_method_entry_t *cme;
20092009

2010+
VM_ASSERT(!SPECIAL_CONST_P(klass));
2011+
2012+
if (RB_BUILTIN_TYPE(klass) == T_NONE) {
2013+
// If we find a T_NONE here, it's most likely we called CLASS_OF(obj) on a
2014+
// garbage collected object (the freelist is stored in the class pointer),
2015+
// but it's possible that just the class was GC'd.
2016+
// This message intentionally tries to imply the former, but make an
2017+
// accurate statement for either case.
2018+
rb_bug("attempted to search method '%s' on a garbage collected object",
2019+
rb_id2name(mid));
2020+
}
2021+
20102022
VM_ASSERT_TYPE2(klass, T_CLASS, T_ICLASS);
20112023

20122024
/* Fast path: lock-free read from cache */

0 commit comments

Comments
 (0)