Project

General

Profile

Actions

Bug #21324

open

Namespace loads RubyGems in root Namespace but it should not

Added by Eregon (Benoit Daloze) 4 days ago. Updated 1 day ago.

Status:
Open
Assignee:
-
Target version:
-
ruby -v:
ruby 3.5.0dev (2025-05-10T07:50:29Z namespace-on-read-.. bd4f57f96b) +PRISM [x86_64-linux]
[ruby-core:121988]

Description

RubyGems has tons of mutable state, isn't core library and isn't "builtin classes" either, so it should not be in root Namespace, but it is currently:

$ RUBY_NAMESPACE=1 ruby -ve 'ns = Namespace.new; p ns::Gem.equal?(Gem)'
ruby 3.5.0dev (2025-05-10T07:50:29Z namespace-on-read-.. bd4f57f96b) +PRISM [x86_64-linux]
ruby: warning: Namespace is experimental, and the behavior may change in the future!
See doc/namespace.md for know issues, etc.
true

A concrete example of what breaks most likely due to this:

$ gem i delegate:0.3.1
$ RUBY_NAMESPACE=1 ruby -ve 'require "delegate"; p Delegator::VERSION; ns = Namespace.new; File.write "ns.rb", "gem %{delegate}, %{0.3.1}; require :delegate.to_s; p Delegator::VERSION"; ns.require "./ns"'
ruby 3.5.0dev (2025-05-10T07:50:29Z namespace-on-read-.. bd4f57f96b) +PRISM [x86_64-linux]
ruby: warning: Namespace is experimental, and the behavior may change in the future!
See doc/namespace.md for know issues, etc.
"0.4.0"
/home/eregon/prefix/ruby-master/lib/ruby/3.5.0+0/rubygems/specification.rb:2232:in 'Gem::Specification#check_version_conflict': can't activate delegate-0.3.1, already activated delegate-0.4.0 (Gem::LoadError)
	from /home/eregon/prefix/ruby-master/lib/ruby/3.5.0+0/rubygems/specification.rb:1383:in 'Gem::Specification#activate'
	from /home/eregon/prefix/ruby-master/lib/ruby/3.5.0+0/rubygems/core_ext/kernel_gem.rb:62:in 'block in Kernel#gem'
	from /home/eregon/prefix/ruby-master/lib/ruby/3.5.0+0/rubygems/core_ext/kernel_gem.rb:62:in 'Thread::Mutex#synchronize'
	from /home/eregon/prefix/ruby-master/lib/ruby/3.5.0+0/rubygems/core_ext/kernel_gem.rb:62:in 'Kernel#gem'
	from /home/eregon/ns.rb:1:in '<top (required)>'
	from -e:1:in 'Namespace#require'
	from -e:1:in '<main>'

i.e. ns sees delegate-0.4.0 was loaded in main namespace but it shouldn't.

Previously mentioned in https://bugs.ruby-lang.org/issues/21311#note-36


Related issues 1 (1 open0 closed)

Related to Ruby - Bug #21323: irb fails to start with NamespaceOpenActions
Actions #1

Updated by Eregon (Benoit Daloze) 4 days ago

  • Related to Bug #21323: irb fails to start with Namespace added
Actions #2

Updated by Eregon (Benoit Daloze) 4 days ago

  • Description updated (diff)

Updated by mame (Yusuke Endoh) 4 days ago

  • Assignee set to prism

Updated by mame (Yusuke Endoh) 4 days ago

  • Assignee deleted (prism)

Updated by jas (Jasveen Sandral) 1 day ago

I've identified the issue and prepared a fix.

The problem is that RubyGems is being loaded into the root namespace during Ruby's boot process, and then all user namespaces inherit this same Gem constant through the Copy-on-Write mechanism. This causes all namespaces to share the same RubyGems environment and state, leading to version conflicts.

The fix involves:

  1. In rb_initialize_main_namespace():

    • Detecting if the Gem constant exists in Object
    • Removing it explicitly with rb_const_remove()
    • Loading a fresh RubyGems environment
  2. In namespace_initialize() (for Namespace.new):

    • Getting the namespace's own Object constant
    • Checking and removing any inherited Gem constant
    • Loading a clean RubyGems environment

This ensures each namespace (main and optional) gets its own isolated RubyGems state, preventing version conflicts when loading gems across namespaces.

I've created a PR with these changes: https://github.com/ruby/ruby/pull/13313

Updated by Eregon (Benoit Daloze) 1 day ago

Loading RubyGems creates more constants than just Gem:

$ ruby -v --disable-gems -e 'a=Object.constants; require "rubygems"; b=Object.constants; p b-a'
ruby 3.4.1 (2024-12-25 revision 48d4efcb85) +PRISM [x86_64-linux]
[:Monitor, :MonitorMixin, :Gem, :CROSS_COMPILING, :RbConfig, :RUBYGEMS_ACTIVATION_MONITOR]

It seems very messy to try to remove that from the root namespace.

The clean solution seems obvious: gem_prelude.rb shouldn't be loaded in the root namespace, but only in user namespaces.

Actions

Also available in: Atom PDF

Like0
Like0Like0Like0Like0Like0Like0