diff --git a/gc.c b/gc.c index 46d2516fa5..919d57989a 100644 --- a/gc.c +++ b/gc.c @@ -9281,10 +9281,23 @@ rb_gc_register_address(VALUE *addr) rb_objspace_t *objspace = &rb_objspace; struct gc_list *tmp; + VALUE obj = *addr; + tmp = ALLOC(struct gc_list); tmp->next = global_list; tmp->varptr = addr; global_list = tmp; + + /* + * Because some C extensions have assignment-then-register bugs, + * we guard `obj` here so that it would not get swept defensively. + */ + RB_GC_GUARD(obj); + if (0 && !SPECIAL_CONST_P(obj)) { + rb_warn("Object is assigned to registering address already: %"PRIsVALUE, + rb_obj_class(obj)); + rb_print_backtrace(); + } } void diff --git a/include/ruby/internal/gc.h b/include/ruby/internal/gc.h index 66fc14e511..054e4b0f9c 100644 --- a/include/ruby/internal/gc.h +++ b/include/ruby/internal/gc.h @@ -26,10 +26,15 @@ RBIMPL_SYMBOL_EXPORT_BEGIN() /** - * Inform the garbage collector that `valptr` points to a live Ruby object that - * should not be moved. Note that extensions should use this API on global - * constants instead of assuming constants defined in Ruby are always alive. - * Ruby code can remove global constants. + * Inform the garbage collector that the global or static variable pointed by + * `valptr` stores a live Ruby object that should not be moved. Note that + * extensions should use this API on global constants instead of assuming + * constants defined in Ruby are always alive. Ruby code can remove global + * constants. + * + * Because this registration itself has a possibility to trigger a GC, this + * function must be called before any GC-able objects is assigned to the + * address pointed by `valptr`. */ void rb_gc_register_address(VALUE *valptr); diff --git a/io.c b/io.c index e4be073267..99ec59da29 100644 --- a/io.c +++ b/io.c @@ -15547,13 +15547,12 @@ Init_IO(void) rb_gvar_ractor_local("$>"); rb_gvar_ractor_local("$stderr"); - rb_stdin = rb_io_prep_stdin(); - rb_stdout = rb_io_prep_stdout(); - rb_stderr = rb_io_prep_stderr(); - rb_global_variable(&rb_stdin); + rb_stdin = rb_io_prep_stdin(); rb_global_variable(&rb_stdout); + rb_stdout = rb_io_prep_stdout(); rb_global_variable(&rb_stderr); + rb_stderr = rb_io_prep_stderr(); orig_stdout = rb_stdout; orig_stderr = rb_stderr; diff --git a/ruby.c b/ruby.c index 920a2490d2..09c81db86c 100644 --- a/ruby.c +++ b/ruby.c @@ -647,8 +647,8 @@ ruby_init_loadpath(void) # endif rb_obj_hide(selfpath); OBJ_FREEZE_RAW(selfpath); - rb_libruby_selfpath = selfpath; rb_gc_register_address(&rb_libruby_selfpath); + rb_libruby_selfpath = selfpath; # endif #endif diff --git a/spec/ruby/optional/capi/ext/gc_spec.c b/spec/ruby/optional/capi/ext/gc_spec.c index 082e4af59c..b323c2456d 100644 --- a/spec/ruby/optional/capi/ext/gc_spec.c +++ b/spec/ruby/optional/capi/ext/gc_spec.c @@ -28,8 +28,8 @@ static VALUE get_registered_before_rb_global_variable(VALUE self) { } static VALUE gc_spec_rb_gc_register_address(VALUE self) { - rb_gc_register_address_outside_init = rb_str_new_cstr("rb_gc_register_address() outside Init_"); rb_gc_register_address(&rb_gc_register_address_outside_init); + rb_gc_register_address_outside_init = rb_str_new_cstr("rb_gc_register_address() outside Init_"); return rb_gc_register_address_outside_init; } @@ -67,14 +67,14 @@ static VALUE gc_spec_rb_gc_register_mark_object(VALUE self, VALUE obj) { void Init_gc_spec(void) { VALUE cls = rb_define_class("CApiGCSpecs", rb_cObject); - registered_tagged_value = INT2NUM(10); - registered_reference_value = rb_str_new2("Globally registered data"); rb_gc_register_address(®istered_tagged_value); rb_gc_register_address(®istered_reference_value); rb_gc_register_address(®istered_before_rb_gc_register_address); rb_global_variable(®istered_before_rb_global_variable); + registered_tagged_value = INT2NUM(10); + registered_reference_value = rb_str_new2("Globally registered data"); registered_before_rb_gc_register_address = rb_str_new_cstr("registered before rb_gc_register_address()"); registered_before_rb_global_variable = rb_str_new_cstr("registered before rb_global_variable()"); diff --git a/version.h b/version.h index 832cf2b4a5..057246acaa 100644 --- a/version.h +++ b/version.h @@ -11,7 +11,7 @@ # define RUBY_VERSION_MINOR RUBY_API_VERSION_MINOR #define RUBY_VERSION_TEENY 7 #define RUBY_RELEASE_DATE RUBY_RELEASE_YEAR_STR"-"RUBY_RELEASE_MONTH_STR"-"RUBY_RELEASE_DAY_STR -#define RUBY_PATCHLEVEL 258 +#define RUBY_PATCHLEVEL 259 #include "ruby/version.h" #include "ruby/internal/abi.h"