diff options
| author | Takashi Kokubun <takashikkbn@gmail.com> | 2026-05-11 13:43:47 -0700 |
|---|---|---|
| committer | Takashi Kokubun <takashikkbn@gmail.com> | 2026-05-11 13:43:47 -0700 |
| commit | dd78605b2d06600750c331f307083d60df702814 (patch) | |
| tree | b22fa335ca0ce8b83e9befebedb25fde5234817e | |
| parent | 926b0ec4ed0e181735f3778c3e6b79d891e70848 (diff) | |
merge revision(s) 526344b56ea968d5704bdefe6e10bb3cf7f4f569, 8ad6baa01746e8de0460f0ccdaee69953a70af17: [Backport #21933]
[PATCH] Fix Box regexp match vars after non-match
[PATCH] Use box_ready for $&, $`, $\', $+
These variables have rb_gvar_readonly_setter, so box_ready is sufficient.
Only $~ needs box_dynamic due to its custom match_setter.
| -rw-r--r-- | internal/variable.h | 1 | ||||
| -rw-r--r-- | re.c | 5 | ||||
| -rw-r--r-- | test/ruby/test_box.rb | 20 | ||||
| -rw-r--r-- | variable.c | 23 |
4 files changed, 44 insertions, 5 deletions
diff --git a/internal/variable.h b/internal/variable.h index ca5e189c90..f24486be0d 100644 --- a/internal/variable.h +++ b/internal/variable.h @@ -29,6 +29,7 @@ rb_gvar_setter_t *rb_gvar_setter_function_of(ID); void rb_gvar_readonly_setter(VALUE v, ID id, VALUE *_); void rb_gvar_ractor_local(const char *name); void rb_gvar_box_ready(const char *name); +void rb_gvar_box_dynamic(const char *name); /** * Sets the name of a module. @@ -4819,6 +4819,11 @@ Init_Regexp(void) rb_gvar_ractor_local("$`"); rb_gvar_ractor_local("$'"); rb_gvar_ractor_local("$+"); + rb_gvar_box_dynamic("$~"); + rb_gvar_box_ready("$&"); + rb_gvar_box_ready("$`"); + rb_gvar_box_ready("$'"); + rb_gvar_box_ready("$+"); rb_define_virtual_variable("$=", ignorecase_getter, ignorecase_setter); diff --git a/test/ruby/test_box.rb b/test/ruby/test_box.rb index 43a753b311..1e162279d4 100644 --- a/test/ruby/test_box.rb +++ b/test/ruby/test_box.rb @@ -531,6 +531,26 @@ class TestBox < Test::Unit::TestCase end end + def test_match_variables_are_not_cached_in_box + assert_separately([ENV_ENABLE_BOX], __FILE__, __LINE__, "#{<<~"begin;"}\n#{<<~'end;'}", ignore_stderr: true) + begin; + /(?<a>foo)/ =~ 'bar' + /(?<b>baz)/ =~ 'baz' + assert_equal "baz", b + assert_equal "baz", $~.to_s + + /foo/ =~ 'bar' + assert_nil $~ + /(?<word>foo)(bar)?/ =~ 'foo' + assert_equal "foo", word + assert_equal "foo", $~.to_s + assert_equal "foo", $& + assert_equal "", $` + assert_equal "", $' + assert_equal "foo", $+ + end; + end + def test_load_path_and_loaded_features setup_box diff --git a/variable.c b/variable.c index 11b186063e..04e2eaea52 100644 --- a/variable.c +++ b/variable.c @@ -534,6 +534,7 @@ struct rb_global_variable { rb_gvar_compact_t *compactor; struct trace_var *trace; bool box_ready; + bool box_dynamic; }; struct rb_global_entry { @@ -618,6 +619,13 @@ rb_gvar_box_ready(const char *name) entry->var->box_ready = true; } +void +rb_gvar_box_dynamic(const char *name) +{ + struct rb_global_entry *entry = rb_find_global_entry(rb_intern(name)); + entry->var->box_dynamic = true; +} + static void rb_gvar_undef_compactor(void *var) { @@ -646,6 +654,7 @@ rb_global_entry(ID id) var->block_trace = 0; var->trace = 0; var->box_ready = false; + var->box_dynamic = false; rb_id_table_insert(rb_global_tbl, id, (VALUE)entry); } } @@ -1000,9 +1009,13 @@ rb_gvar_set_entry(struct rb_global_entry *entry, VALUE val) return val; } -#define USE_BOX_GVAR_TBL(ns,entry) \ - (BOX_USER_P(ns) && \ - (!entry || !entry->var->box_ready || entry->var->setter != rb_gvar_readonly_setter)) +static inline bool +gvar_use_box_tbl(const rb_box_t *box, const struct rb_global_entry *entry) +{ + return BOX_USER_P(box) && + !entry->var->box_dynamic && + (!entry->var->box_ready || entry->var->setter != rb_gvar_readonly_setter); +} VALUE rb_gvar_set(ID id, VALUE val) @@ -1015,7 +1028,7 @@ rb_gvar_set(ID id, VALUE val) RB_VM_LOCKING() { entry = rb_global_entry(id); - if (USE_BOX_GVAR_TBL(box, entry)) { + if (gvar_use_box_tbl(box, entry)) { use_box_tbl = true; rb_hash_aset(box->gvar_tbl, rb_id2sym(entry->id), val); retval = val; @@ -1048,7 +1061,7 @@ rb_gvar_get(ID id) entry = rb_global_entry(id); var = entry->var; - if (USE_BOX_GVAR_TBL(box, entry)) { + if (gvar_use_box_tbl(box, entry)) { use_box_tbl = true; gvars = box->gvar_tbl; key = rb_id2sym(entry->id); |
