From: "jeremyevans0 (Jeremy Evans) via ruby-core" Date: 2026-10-24T00:30:22+00:00 Subject: [ruby-core:127224] [Ruby Bug#22468] A read of a class variable after remove_class_variable returns a broken value, then SEGV on use Issue #22468 has been updated by jeremyevans0 (Jeremy Evans). In case it assists debugging, the example works correctly in Ruby 3.0 and 3.1 (`NameError`) and fails in Ruby 3.2 and 3.3 (SEGV). So it broke between Ruby 3.1 and 3.2. ---------------------------------------- Bug #22468: A read of a class variable after remove_class_variable returns a broken value, then SEGV on use https://bugs.ruby-lang.org/issues/22468#change-119641 * Author: hasumikin (hitoshi hasumi) * Status: Open * ruby -v: ruby 4.0.9 (2026-10-23 revision 3e93b23afc) +PRISM [x86_64-linux] * Backport: 3.3: UNKNOWN, 3.4: UNKNOWN, 4.0: UNKNOWN ---------------------------------------- ## Description A method that read a class variable once reads it again after `remove_class_variable`. The second read does not raise NameError. It returns a broken value, and a use of that value causes a segmentation fault. ## Steps to reproduce ```ruby class C @@x = 1 def self.x @@x end end C.x C.remove_class_variable(:@@x) p C.x ``` ## Expected result The second `C.x` raises NameError, as Ruby 2.7.8 does: ``` test.rb:4:in `x': uninitialized class variable @@x in C (NameError) from test.rb:9:in `
' ``` ## Actual result ``` test.rb:9: [BUG] Segmentation fault at 0x0000000000000034 ruby 4.0.9 (2026-10-23 revision 3e93b23afc) +PRISM [x86_64-linux] ``` The C level backtrace stops in `flo_to_s` (`rb_float_noflonum_value`, internal/numeric.h:287), which `p` calls through `rb_inspect`. ## Notes - Without the first `C.x` (line 7), the second `C.x` raises NameError correctly. So the inline cache of the class variable read can keep the removed entry. - The read itself does not crash. `p C.x.class` prints `Float`, so the read returns a broken value with no error. The crash comes when the program uses the value. - With `@@x = []` and `GC.start` before the second read, the crash is the same. - `--yjit` and `--zjit` give the same SEGV. With `--yjit --yjit-call-threshold=1` or `--zjit --zjit-call-threshold=1`, `p C.x` prints `main`, and then Ruby stops with a different bug: ``` main test.rb: [BUG] Stack consistency error (sp: 5, bp: -16598879043074) ruby 4.1.0dev (2026-10-24T08:43:21Z master e6403ebc10) +YJIT +PRISM [x86_64-linux] ``` ## Versions | Version | Result | |---|---| | ruby 2.7.8 | NameError (correct) | | ruby 3.4.12 (2026-10-23 revision 366f5fdc00) | SEGV | | ruby 4.0.9 (2026-10-23 revision 3e93b23afc) | SEGV | | ruby 4.1.0dev (2026-10-24T08:43:21Z master e6403ebc10) | SEGV | Platform: x86_64-linux (Ubuntu 24.04). -- https://bugs.ruby-lang.org/ ______________________________________________ ruby-core mailing list -- ruby-core@ml.ruby-lang.org To unsubscribe send an email to ruby-core-leave@ml.ruby-lang.org ruby-core info -- https://ml.ruby-lang.org/mailman3/lists/ruby-core.ml.ruby-lang.org/