Thanks to visit codestin.com
Credit goes to github.com

Skip to content

add VM Lock around rb_const_remove operations (Module#remove_const) #13717

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

luke-gruber
Copy link
Contributor

Without a VM Lock, there's an unlocked rb_id_table_delete for the class's const_tbl which can cause problems. Example:

class C
  CONSTANT = 3
end
$VERBOSE = nil
rs = []
100.times do
  rs << Ractor.new do
    10_000.times do
      if defined?(C::CONSTANT)
        C.send(:remove_const, :CONSTANT) rescue NameError
      else
        C.send(:const_set, :CONSTANT, 3)
      end
    end
  end
end
while rs.any?
  r, obj = Ractor.select(*rs)
  rs.delete(r)
end

Without lock:
../ruby-release/test.rb:14: [BUG] Segmentation fault at 0x0000000000000001 -- Control frame information ----------------------------------------------- miniruby(82790,0x16f49f000) malloc: *** error for object 0x600000f880a0: pointer being freed was not allocated miniruby(82790,0x16f49f000) malloc: *** set a breakpoint in malloc_error_break to debug

Without a VM Lock, there's an unlocked `rb_id_table_delete` for the
class's const_tbl which can cause problems. Example:

```ruby
class C
  CONSTANT = 3
end
$VERBOSE = nil
rs = []
100.times do
  rs << Ractor.new do
    10_000.times do
      if defined?(C::CONSTANT)
        C.send(:remove_const, :CONSTANT) rescue NameError
      else
        C.send(:const_set, :CONSTANT, 3)
      end
    end
  end
end
while rs.any?
  r, obj = Ractor.select(*rs)
  rs.delete(r)
end
```

Without lock:
../ruby-release/test.rb:14: [BUG] Segmentation fault at 0x0000000000000001
-- Control frame information -----------------------------------------------
miniruby(82790,0x16f49f000) malloc: *** error for object 0x600000f880a0: pointer being freed was not allocated
miniruby(82790,0x16f49f000) malloc: *** set a breakpoint in malloc_error_break to debug
@jhawthorn
Copy link
Member

jhawthorn commented Jun 26, 2025

Seems like we might be missing locking for const lookup as well.

class C
  CONSTANT = 3
end
$VERBOSE = nil
rs = []
100.times do
  rs << Ractor.new do
    10_000.times do
      if defined?(C::CONSTANT)
        C.send(:remove_const, :CONSTANT) rescue NameError
      else
        C.send(:const_set, :CONSTANT, 3)
      end
      C.const_get(:CONSTANT) rescue NameError
      C.const_get(:CONSTANT) rescue NameError
    end
  end
end
while rs.any?
  r, obj = Ractor.select(*rs)
  rs.delete(r)
end
make run
./miniruby -I./lib -I. -I.ext/common  -r./x86_64-linux-fake  ./test.rb
<OBJ_INFO:[email protected]:1276> out-of-heap:0x000055700ced3ea0
./test.rb:14: [BUG] unreachable
ruby 3.5.0dev (2025-06-26T16:21:30Z ractor_safe_remove.. c3420bfd76) +PRISM [x86_64-linux]

-- Control frame information -----------------------------------------------
c:0005 p:---- s:0019 e:000018 CFUNC  :const_get
c:0004 p:0047 s:0014 e:000013 BLOCK  ./test.rb:14
c:0003 p:0024 s:0011 e:000010 METHOD <internal:numeric>:257
c:0002 p:0005 s:0006 e:000005 BLOCK  ./test.rb:8 [FINISH]
c:0001 p:---- s:0003 e:000002 DUMMY  [FINISH]

-- Ruby level backtrace information ----------------------------------------
./test.rb:8:in 'block (2 levels) in <main>'
<internal:numeric>:257:in 'times'
./test.rb:14:in 'block (3 levels) in <main>'
./test.rb:14:in 'const_get'

@byroot
Copy link
Member

byroot commented Jun 27, 2025

Should const_set and remove_const even be allowed from non-main ractor? It seems to me that if you can't set a class ivar, you shouldn't be able to set a const, no?

@luke-gruber
Copy link
Contributor Author

Yeah it's a good point, but for whatever reason this has always been allowed in ractors, and it was by design not by accident. As for why, I don't know but maybe it's to do with supporting autoloading in ractors. If you support autoloading constants, it's a small step away from supporting setting constants directly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants