summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Zhu <peter@peterzhu.ca>2025-09-21 10:20:24 -0400
committerPeter Zhu <peter@peterzhu.ca>2025-09-26 17:17:42 -0400
commitba52af6fc3e9ce8263794e8d2cad3fdf2785adad (patch)
treea28c2261e8ffb645d2cef0e5cc57582bbd7490a5
parent88dc3c41473a3bef78cb753f053f2370e6faa781 (diff)
Always set parent_object in GC
When we mark a T_NONE, we crash with the object and parent object information in the bug report. However, if the parent object is young then it is Qfalse. For example, a bug report looks like: [BUG] try to mark T_NONE object (obj: 0x00003990e42d7c70 T_NONE/, parent: (none)) This commit changes it to always set the parent object and also adds a new field parent_object_old_p to quickly determine if the parent object is old or not.
-rw-r--r--gc/default/default.c41
1 files changed, 12 insertions, 29 deletions
diff --git a/gc/default/default.c b/gc/default/default.c
index 423d27dde1..b5879b0ec2 100644
--- a/gc/default/default.c
+++ b/gc/default/default.c
@@ -577,7 +577,9 @@ typedef struct rb_objspace {
VALUE gc_stress_mode;
struct {
+ bool parent_object_old_p;
VALUE parent_object;
+
int need_major_gc;
size_t last_major_gc;
size_t uncollectible_wb_unprotected_objects;
@@ -4309,15 +4311,11 @@ init_mark_stack(mark_stack_t *stack)
static void
rgengc_check_relation(rb_objspace_t *objspace, VALUE obj)
{
- const VALUE old_parent = objspace->rgengc.parent_object;
-
- if (old_parent) { /* parent object is old */
+ if (objspace->rgengc.parent_object_old_p) {
if (RVALUE_WB_UNPROTECTED(objspace, obj) || !RVALUE_OLD_P(objspace, obj)) {
- rgengc_remember(objspace, old_parent);
+ rgengc_remember(objspace, objspace->rgengc.parent_object);
}
}
-
- GC_ASSERT(old_parent == objspace->rgengc.parent_object);
}
static inline int
@@ -4385,12 +4383,7 @@ gc_mark_check_t_none(rb_objspace_t *objspace, VALUE obj)
rb_raw_obj_info(obj_info_buf, info_size, obj);
char parent_obj_info_buf[info_size];
- if (objspace->rgengc.parent_object == Qfalse) {
- strlcpy(parent_obj_info_buf, "(none)", info_size);
- }
- else {
- rb_raw_obj_info(parent_obj_info_buf, info_size, objspace->rgengc.parent_object);
- }
+ rb_raw_obj_info(parent_obj_info_buf, info_size, objspace->rgengc.parent_object);
rb_bug("try to mark T_NONE object (obj: %s, parent: %s)", obj_info_buf, parent_obj_info_buf);
}
@@ -4405,14 +4398,9 @@ gc_mark(rb_objspace_t *objspace, VALUE obj)
if (!gc_mark_set(objspace, obj)) return; /* already marked */
if (0) { // for debug GC marking miss
- if (objspace->rgengc.parent_object) {
- RUBY_DEBUG_LOG("%p (%s) parent:%p (%s)",
- (void *)obj, obj_type_name(obj),
- (void *)objspace->rgengc.parent_object, obj_type_name(objspace->rgengc.parent_object));
- }
- else {
- RUBY_DEBUG_LOG("%p (%s)", (void *)obj, obj_type_name(obj));
- }
+ RUBY_DEBUG_LOG("%p (%s) parent:%p (%s)",
+ (void *)obj, obj_type_name(obj),
+ (void *)objspace->rgengc.parent_object, obj_type_name(objspace->rgengc.parent_object));
}
gc_mark_check_t_none(objspace, obj);
@@ -4505,8 +4493,6 @@ rb_gc_impl_mark_weak(void *objspace_ptr, VALUE *ptr)
{
rb_objspace_t *objspace = objspace_ptr;
- GC_ASSERT(objspace->rgengc.parent_object == 0 || !RVALUE_WB_UNPROTECTED(objspace, objspace->rgengc.parent_object));
-
VALUE obj = *ptr;
gc_mark_check_t_none(objspace, obj);
@@ -4565,7 +4551,8 @@ mark_roots(rb_objspace_t *objspace, const char **categoryp)
} while (0)
MARK_CHECKPOINT("objspace");
- objspace->rgengc.parent_object = Qfalse;
+ objspace->rgengc.parent_object = Qundef;
+ objspace->rgengc.parent_object_old_p = false;
if (finalizer_table != NULL) {
st_foreach(finalizer_table, pin_value, (st_data_t)objspace);
@@ -4580,12 +4567,8 @@ mark_roots(rb_objspace_t *objspace, const char **categoryp)
static inline void
gc_mark_set_parent(rb_objspace_t *objspace, VALUE obj)
{
- if (RVALUE_OLD_P(objspace, obj)) {
- objspace->rgengc.parent_object = obj;
- }
- else {
- objspace->rgengc.parent_object = Qfalse;
- }
+ objspace->rgengc.parent_object = obj;
+ objspace->rgengc.parent_object_old_p = RVALUE_OLD_P(objspace, obj);
}
static void