diff --git a/gc/default/default.c b/gc/default/default.c index b5879b0ec25e7c..9b40fed09768a6 100644 --- a/gc/default/default.c +++ b/gc/default/default.c @@ -4393,6 +4393,7 @@ static void gc_mark(rb_objspace_t *objspace, VALUE obj) { GC_ASSERT(during_gc); + GC_ASSERT(!objspace->flags.during_reference_updating); rgengc_check_relation(objspace, obj); if (!gc_mark_set(objspace, obj)) return; /* already marked */ @@ -4543,6 +4544,28 @@ pin_value(st_data_t key, st_data_t value, st_data_t data) return ST_CONTINUE; } +static inline void +gc_mark_set_parent_raw(rb_objspace_t *objspace, VALUE obj, bool old_p) +{ + asan_unpoison_memory_region(&objspace->rgengc.parent_object, sizeof(objspace->rgengc.parent_object), false); + asan_unpoison_memory_region(&objspace->rgengc.parent_object_old_p, sizeof(objspace->rgengc.parent_object_old_p), false); + objspace->rgengc.parent_object = obj; + objspace->rgengc.parent_object_old_p = old_p; +} + +static inline void +gc_mark_set_parent(rb_objspace_t *objspace, VALUE obj) +{ + gc_mark_set_parent_raw(objspace, obj, RVALUE_OLD_P(objspace, obj)); +} + +static inline void +gc_mark_set_parent_invalid(rb_objspace_t *objspace) +{ + asan_poison_memory_region(&objspace->rgengc.parent_object, sizeof(objspace->rgengc.parent_object)); + asan_poison_memory_region(&objspace->rgengc.parent_object_old_p, sizeof(objspace->rgengc.parent_object_old_p)); +} + static void mark_roots(rb_objspace_t *objspace, const char **categoryp) { @@ -4551,8 +4574,7 @@ mark_roots(rb_objspace_t *objspace, const char **categoryp) } while (0) MARK_CHECKPOINT("objspace"); - objspace->rgengc.parent_object = Qundef; - objspace->rgengc.parent_object_old_p = false; + gc_mark_set_parent_raw(objspace, Qundef, false); if (finalizer_table != NULL) { st_foreach(finalizer_table, pin_value, (st_data_t)objspace); @@ -4562,13 +4584,7 @@ mark_roots(rb_objspace_t *objspace, const char **categoryp) rb_gc_save_machine_context(); rb_gc_mark_roots(objspace, categoryp); -} - -static inline void -gc_mark_set_parent(rb_objspace_t *objspace, VALUE obj) -{ - objspace->rgengc.parent_object = obj; - objspace->rgengc.parent_object_old_p = RVALUE_OLD_P(objspace, obj); + gc_mark_set_parent_invalid(objspace); } static void @@ -4576,6 +4592,7 @@ gc_mark_children(rb_objspace_t *objspace, VALUE obj) { gc_mark_set_parent(objspace, obj); rb_gc_mark_children(objspace, obj); + gc_mark_set_parent_invalid(objspace); } /** @@ -5985,9 +6002,11 @@ gc_mark_from(rb_objspace_t *objspace, VALUE obj, VALUE parent) { gc_mark_set_parent(objspace, parent); rgengc_check_relation(objspace, obj); - if (gc_mark_set(objspace, obj) == FALSE) return; - gc_aging(objspace, obj); - gc_grey(objspace, obj); + if (gc_mark_set(objspace, obj) != FALSE) { + gc_aging(objspace, obj); + gc_grey(objspace, obj); + } + gc_mark_set_parent_invalid(objspace); } NOINLINE(static void gc_writebarrier_incremental(VALUE a, VALUE b, rb_objspace_t *objspace)); diff --git a/io_buffer.c b/io_buffer.c index 96f13c364afc30..87e392b79181d6 100644 --- a/io_buffer.c +++ b/io_buffer.c @@ -273,7 +273,7 @@ io_buffer_free(struct rb_io_buffer *buffer) } static void -rb_io_buffer_type_mark_and_move(void *_buffer) +rb_io_buffer_type_mark(void *_buffer) { struct rb_io_buffer *buffer = _buffer; if (buffer->source != Qnil) { @@ -282,7 +282,21 @@ rb_io_buffer_type_mark_and_move(void *_buffer) // which can be otherwise moved by GC compaction. rb_gc_mark(buffer->source); } else { - rb_gc_mark_and_move(&buffer->source); + rb_gc_mark_movable(buffer->source); + } + } +} + +static void +rb_io_buffer_type_compact(void *_buffer) +{ + struct rb_io_buffer *buffer = _buffer; + if (buffer->source != Qnil) { + if (RB_TYPE_P(buffer->source, T_STRING)) { + // The `source` String has to be pinned, because the `base` may point to the embedded String content, + // which can be otherwise moved by GC compaction. + } else { + buffer->source = rb_gc_location(buffer->source); } } } @@ -311,10 +325,10 @@ rb_io_buffer_type_size(const void *_buffer) static const rb_data_type_t rb_io_buffer_type = { .wrap_struct_name = "IO::Buffer", .function = { - .dmark = rb_io_buffer_type_mark_and_move, + .dmark = rb_io_buffer_type_mark, .dfree = rb_io_buffer_type_free, .dsize = rb_io_buffer_type_size, - .dcompact = rb_io_buffer_type_mark_and_move, + .dcompact = rb_io_buffer_type_compact, }, .data = NULL, .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_EMBEDDABLE, diff --git a/vm.c b/vm.c index 431db0cb0bc88d..8bdf9e4fc20ae2 100644 --- a/vm.c +++ b/vm.c @@ -3343,10 +3343,8 @@ ruby_vm_destruct(rb_vm_t *vm) rb_objspace_free_objects(objspace); rb_free_generic_fields_tbl_(); rb_free_default_rand_key(); - if (th && vm->fork_gen == 0) { - /* If we have forked, main_thread may not be the initial thread */ - ruby_mimfree(th); - } + + ruby_mimfree(th); } rb_objspace_free(objspace); }