Relax opt_getconstant_path IC assertion under multi-ractor

rb_vm_opt_getconstant_path() asserts on an inline constant cache hit that
the cached value equals a freshly recomputed constant chain:

    VM_ASSERT(val == vm_get_ev_const_chain(ec, segments));

On a non-main ractor an IC hit is only allowed for shareable values
(IMEMO_CONST_CACHE_SHAREABLE). Reassigning a shareable constant is legal
from a non-main ractor, and it invalidates ICs asynchronously via
rb_clear_constant_cache_for_id() (ic->entry = NULL) without locking the
reader side. So the hit path can load a still-valid, previously-assigned
shareable value while another ractor concurrently reassigns the constant;
the subsequent recomputation then observes the newer value and the two
legitimately differ (a benign TOCTOU). Both values were validly assigned
to the constant at some point, so no correctness or memory-safety issue
results -- only this debug-only assertion trips.

Guard the equality check with rb_multi_ractor_p(), mirroring the existing
workaround in vm_cc_invalidate() (vm_callinfo.h). Reproducible with several
ractors reassigning the same frozen constant in a loop; NDEBUG builds are
unaffected.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Koichi SasadaandClaude Opus 4.8 committed 2026-07-15 04:56:37 +09:00
1 parent 7facc9f2a1
commit be2a2eea8d
1 file changed
+5 -1
Notes: git 2026-07-14 19:57:09 +00:00
+5 -1
View File
@@ -6548,7 +6548,11 @@ rb_vm_opt_getconstant_path(rb_execution_context_t *ec, rb_control_frame_t *const
if (ice && vm_ic_hit_p(ice, GET_EP())) {
val = ice->value;
VM_ASSERT(val == vm_get_ev_const_chain(ec, segments));
// On a non-main ractor another ractor can concurrently reassign a
// shareable constant (which invalidates ICs asynchronously), so the
// cached-but-still-shareable value may legitimately differ from a
// freshly recomputed chain. Only assert equality when single-ractor.
VM_ASSERT(val == vm_get_ev_const_chain(ec, segments) || rb_multi_ractor_p());
}
else {
ruby_vm_constant_cache_misses++;