[ruby-core:120915] [Ruby master Bug#21125] Kernel is called first

Issue #21125 has been reported by mikik0 (Hashino Mikiko). ---------------------------------------- Bug #21125: Kernel is called first https://bugs.ruby-lang.org/issues/21125 * Author: mikik0 (Hashino Mikiko) * Status: Open * ruby -v: ruby 3.4.1 (2024-12-25 revision 48d4efcb85) +PRISM [arm64-darwin24] * Backport: 3.1: UNKNOWN, 3.2: UNKNOWN, 3.3: UNKNOWN, 3.4: UNKNOWN ---------------------------------------- Kernel#system is being called when there is a column or method name named system. The other methods of Kernel reproduce the problem. Ex.Rand returns a random value, and exit terminates the program. ## Reproducible script: ``` ruby class ObjectifiedHash def initialize(hash) @hash = hash end private attr_reader :hash def method_missing(method_name, *args, &block) if hash.key?(method_name.to_sym) hash[method_name.to_sym] else super end end def respond_to_missing?(method_name, include_private = false) hash.key?(method_name.to_sym) || super end end class Foo def system(...) # Kernel#system is called raw.system(...) # (...) passes if there is no # raw.system end def initialize(raw) @raw = raw end def get_system system end private attr_reader :raw end class Test def self.run obj = ObjectifiedHash.new({ system: 'system' }) foo = Foo.new(obj) # foo.system would pass. # After executing foo.system, hoge.get_system also passes. # p foo.system p foo.get_system end end Test.run ``` ## Execution Results ``` shell hoge.rb:26:in 'Kernel#system': wrong number of arguments (given 0, expected 1+) (ArgumentError) raw.system(...) ^^^ from ruby.rb:26:in 'Foo#system' from ruby.rb:36:in 'Foo#get_system' from ruby.rb:54:in 'Test.run' from ruby.rb:58:in '<main>' ``` ## Expected results ``` shell "system" ``` PR that may be relevant: https://github.com/ruby/ruby/pull/11028 -- https://bugs.ruby-lang.org/

Issue #21125 has been updated by jeremyevans0 (Jeremy Evans). Status changed from Open to Rejected This isn't a bug. If you want `method_missing` to be called instead of a method in Kernel, you need to undefine the existing method: ```ruby class ObjectifiedHash undef_method :system # rest of your example ``` You could consider the following instead, so that methods in Kernel are not included in the class: ```ruby class ObjectifiedHash < BasicObject # rest of your example ``` ---------------------------------------- Bug #21125: Kernel is called first https://bugs.ruby-lang.org/issues/21125#change-111798 * Author: mikik0 (Hashino Mikiko) * Status: Rejected * ruby -v: ruby 3.4.1 (2024-12-25 revision 48d4efcb85) +PRISM [arm64-darwin24] * Backport: 3.1: UNKNOWN, 3.2: UNKNOWN, 3.3: UNKNOWN, 3.4: UNKNOWN ---------------------------------------- Kernel#system is being called when there is a column or method name named system. The other methods of Kernel reproduce the problem. Ex.Rand returns a random value, and exit terminates the program. ## Reproducible script: ``` ruby class ObjectifiedHash def initialize(hash) @hash = hash end private attr_reader :hash def method_missing(method_name, *args, &block) if hash.key?(method_name.to_sym) hash[method_name.to_sym] else super end end def respond_to_missing?(method_name, include_private = false) hash.key?(method_name.to_sym) || super end end class Foo def system(...) # Kernel#system is called raw.system(...) # (...) passes if there is no # raw.system end def initialize(raw) @raw = raw end def get_system system end private attr_reader :raw end class Test def self.run obj = ObjectifiedHash.new({ system: 'system' }) foo = Foo.new(obj) # foo.system would pass. # After executing foo.system, hoge.get_system also passes. # p foo.system p foo.get_system end end Test.run ``` ## Execution Results ``` shell hoge.rb:26:in 'Kernel#system': wrong number of arguments (given 0, expected 1+) (ArgumentError) raw.system(...) ^^^ from ruby.rb:26:in 'Foo#system' from ruby.rb:36:in 'Foo#get_system' from ruby.rb:54:in 'Test.run' from ruby.rb:58:in '<main>' ``` ## Expected results ``` shell "system" ``` PR that may be relevant: https://github.com/ruby/ruby/pull/11028 -- https://bugs.ruby-lang.org/

Issue #21125 has been updated by mikik0 (Hashino Mikiko). @jeremyevans0 san It works with Ruby 3.3 series, but not from Ruby 3.4. Is it a specification? ---------------------------------------- Bug #21125: Kernel is called first https://bugs.ruby-lang.org/issues/21125#change-111799 * Author: mikik0 (Hashino Mikiko) * Status: Rejected * ruby -v: ruby 3.4.1 (2024-12-25 revision 48d4efcb85) +PRISM [arm64-darwin24] * Backport: 3.1: UNKNOWN, 3.2: UNKNOWN, 3.3: UNKNOWN, 3.4: UNKNOWN ---------------------------------------- Kernel#system is being called when there is a column or method name named system. The other methods of Kernel reproduce the problem. Ex.Rand returns a random value, and exit terminates the program. ## Reproducible script: ``` ruby class ObjectifiedHash def initialize(hash) @hash = hash end private attr_reader :hash def method_missing(method_name, *args, &block) if hash.key?(method_name.to_sym) hash[method_name.to_sym] else super end end def respond_to_missing?(method_name, include_private = false) hash.key?(method_name.to_sym) || super end end class Foo def system(...) # Kernel#system is called raw.system(...) # (...) passes if there is no # raw.system end def initialize(raw) @raw = raw end def get_system system end private attr_reader :raw end class Test def self.run obj = ObjectifiedHash.new({ system: 'system' }) foo = Foo.new(obj) # foo.system would pass. # After executing foo.system, hoge.get_system also passes. # p foo.system p foo.get_system end end Test.run ``` ## Execution Results ``` shell hoge.rb:26:in 'Kernel#system': wrong number of arguments (given 0, expected 1+) (ArgumentError) raw.system(...) ^^^ from ruby.rb:26:in 'Foo#system' from ruby.rb:36:in 'Foo#get_system' from ruby.rb:54:in 'Test.run' from ruby.rb:58:in '<main>' ``` ## Expected results ``` shell "system" ``` PR that may be relevant: https://github.com/ruby/ruby/pull/11028 -- https://bugs.ruby-lang.org/

Issue #21125 has been updated by jeremyevans0 (Jeremy Evans). Status changed from Rejected to Open mikik0 (Hashino Mikiko) wrote in #note-2:
@jeremyevans0 san It works with Ruby 3.3 series, but not from Ruby 3.4. Is it a specification?
You are correct. It also works on Ruby 3.4 when using `--parser=parse.y`, so this appears to be related to prism. I'll have to do more analysis to determine which behavior is correct, but it's certainly a bug that the behavior is not the same between prism and parse.y. ---------------------------------------- Bug #21125: Kernel is called first https://bugs.ruby-lang.org/issues/21125#change-111800 * Author: mikik0 (Hashino Mikiko) * Status: Open * ruby -v: ruby 3.4.1 (2024-12-25 revision 48d4efcb85) +PRISM [arm64-darwin24] * Backport: 3.1: UNKNOWN, 3.2: UNKNOWN, 3.3: UNKNOWN, 3.4: UNKNOWN ---------------------------------------- Kernel#system is being called when there is a column or method name named system. The other methods of Kernel reproduce the problem. Ex.Rand returns a random value, and exit terminates the program. ## Reproducible script: ``` ruby class ObjectifiedHash def initialize(hash) @hash = hash end private attr_reader :hash def method_missing(method_name, *args, &block) if hash.key?(method_name.to_sym) hash[method_name.to_sym] else super end end def respond_to_missing?(method_name, include_private = false) hash.key?(method_name.to_sym) || super end end class Foo def system(...) # Kernel#system is called raw.system(...) # (...) passes if there is no # raw.system end def initialize(raw) @raw = raw end def get_system system end private attr_reader :raw end class Test def self.run obj = ObjectifiedHash.new({ system: 'system' }) foo = Foo.new(obj) # foo.system would pass. # After executing foo.system, hoge.get_system also passes. # p foo.system p foo.get_system end end Test.run ``` ## Execution Results ``` shell hoge.rb:26:in 'Kernel#system': wrong number of arguments (given 0, expected 1+) (ArgumentError) raw.system(...) ^^^ from ruby.rb:26:in 'Foo#system' from ruby.rb:36:in 'Foo#get_system' from ruby.rb:54:in 'Test.run' from ruby.rb:58:in '<main>' ``` ## Expected results ``` shell "system" ``` PR that may be relevant: https://github.com/ruby/ruby/pull/11028 -- https://bugs.ruby-lang.org/

Issue #21125 has been updated by jeremyevans0 (Jeremy Evans). jeremyevans0 (Jeremy Evans) wrote in #note-3:
mikik0 (Hashino Mikiko) wrote in #note-2:
@jeremyevans0 san It works with Ruby 3.3 series, but not from Ruby 3.4. Is it a specification?
You are correct. It also works on Ruby 3.4 when using `--parser=parse.y`, so this appears to be related to prism. I'll have to do more analysis to determine which behavior is correct, but it's certainly a bug that the behavior is not the same between prism and parse.y.
Sorry, that was me testing the wrong version. The behavior is the same between prism and parse.y, so this is a difference in behavior between Ruby 3.3 and 3.4. I still need to more analysis to determine which behavior is correct. ---------------------------------------- Bug #21125: Kernel is called first https://bugs.ruby-lang.org/issues/21125#change-111801 * Author: mikik0 (Hashino Mikiko) * Status: Open * ruby -v: ruby 3.4.1 (2024-12-25 revision 48d4efcb85) +PRISM [arm64-darwin24] * Backport: 3.1: UNKNOWN, 3.2: UNKNOWN, 3.3: UNKNOWN, 3.4: UNKNOWN ---------------------------------------- Kernel#system is being called when there is a column or method name named system. The other methods of Kernel reproduce the problem. Ex.Rand returns a random value, and exit terminates the program. ## Reproducible script: ``` ruby class ObjectifiedHash def initialize(hash) @hash = hash end private attr_reader :hash def method_missing(method_name, *args, &block) if hash.key?(method_name.to_sym) hash[method_name.to_sym] else super end end def respond_to_missing?(method_name, include_private = false) hash.key?(method_name.to_sym) || super end end class Foo def system(...) # Kernel#system is called raw.system(...) # (...) passes if there is no # raw.system end def initialize(raw) @raw = raw end def get_system system end private attr_reader :raw end class Test def self.run obj = ObjectifiedHash.new({ system: 'system' }) foo = Foo.new(obj) # foo.system would pass. # After executing foo.system, hoge.get_system also passes. # p foo.system p foo.get_system end end Test.run ``` ## Execution Results ``` shell hoge.rb:26:in 'Kernel#system': wrong number of arguments (given 0, expected 1+) (ArgumentError) raw.system(...) ^^^ from ruby.rb:26:in 'Foo#system' from ruby.rb:36:in 'Foo#get_system' from ruby.rb:54:in 'Test.run' from ruby.rb:58:in '<main>' ``` ## Expected results ``` shell "system" ``` PR that may be relevant: https://github.com/ruby/ruby/pull/11028 -- https://bugs.ruby-lang.org/

Issue #21125 has been updated by jeremyevans0 (Jeremy Evans). Assignee set to tenderlovemaking (Aaron Patterson) The reason this works in Ruby 3.3 and below is that `system` is a private method and not a public method, and calls to private methods where the receiver is not `self` call `method_missing`. `raw.system` is a method call where the receiver is not `self`, but `Kernel#system` is a private method, so this should be calling `method_missing`. The fact that `method_missing` is not called in Ruby 3.4 is a bug. I've determined the bug is in generic argument forwarding. If you switch `...` (generic argument forwarding) to `*, **, &` (anonymous splat usage), things work correctly. Assigning to @tenderlovemaking. ---------------------------------------- Bug #21125: Kernel is called first https://bugs.ruby-lang.org/issues/21125#change-111802 * Author: mikik0 (Hashino Mikiko) * Status: Open * Assignee: tenderlovemaking (Aaron Patterson) * ruby -v: ruby 3.4.1 (2024-12-25 revision 48d4efcb85) +PRISM [arm64-darwin24] * Backport: 3.1: UNKNOWN, 3.2: UNKNOWN, 3.3: UNKNOWN, 3.4: UNKNOWN ---------------------------------------- Kernel#system is being called when there is a column or method name named system. The other methods of Kernel reproduce the problem. Ex.Rand returns a random value, and exit terminates the program. ## Reproducible script: ``` ruby class ObjectifiedHash def initialize(hash) @hash = hash end private attr_reader :hash def method_missing(method_name, *args, &block) if hash.key?(method_name.to_sym) hash[method_name.to_sym] else super end end def respond_to_missing?(method_name, include_private = false) hash.key?(method_name.to_sym) || super end end class Foo def system(...) # Kernel#system is called raw.system(...) # (...) passes if there is no # raw.system end def initialize(raw) @raw = raw end def get_system system end private attr_reader :raw end class Test def self.run obj = ObjectifiedHash.new({ system: 'system' }) foo = Foo.new(obj) # foo.system would pass. # After executing foo.system, hoge.get_system also passes. # p foo.system p foo.get_system end end Test.run ``` ## Execution Results ``` shell hoge.rb:26:in 'Kernel#system': wrong number of arguments (given 0, expected 1+) (ArgumentError) raw.system(...) ^^^ from ruby.rb:26:in 'Foo#system' from ruby.rb:36:in 'Foo#get_system' from ruby.rb:54:in 'Test.run' from ruby.rb:58:in '<main>' ``` ## Expected results ``` shell "system" ``` PR that may be relevant: https://github.com/ruby/ruby/pull/11028 -- https://bugs.ruby-lang.org/

Issue #21125 has been updated by tenderlovemaking (Aaron Patterson). Status changed from Open to Closed This is fixed in 595040ba271175e18c8461a926c34903742788de Thanks for reporting it! ---------------------------------------- Bug #21125: Kernel is called first https://bugs.ruby-lang.org/issues/21125#change-112431 * Author: mikik0 (Hashino Mikiko) * Status: Closed * Assignee: tenderlovemaking (Aaron Patterson) * ruby -v: ruby 3.4.1 (2024-12-25 revision 48d4efcb85) +PRISM [arm64-darwin24] * Backport: 3.1: DONTNEED, 3.2: DONTNEED, 3.3: DONTNEED, 3.4: REQUIRED ---------------------------------------- Kernel#system is being called when there is a column or method name named system. The other methods of Kernel reproduce the problem. Ex.Rand returns a random value, and exit terminates the program. This problem did not occur until Ruby 3.3 series, but has occurred since Ruby 3.4. ## Reproducible script: ``` ruby class ObjectifiedHash def initialize(hash) @hash = hash end private attr_reader :hash def method_missing(method_name, *args, &block) if hash.key?(method_name.to_sym) hash[method_name.to_sym] else super end end def respond_to_missing?(method_name, include_private = false) hash.key?(method_name.to_sym) || super end end class Foo def system(...) # Kernel#system is called raw.system(...) # (...) passes if there is no # raw.system end def initialize(raw) @raw = raw end def get_system system end private attr_reader :raw end class Test def self.run obj = ObjectifiedHash.new({ system: 'system' }) foo = Foo.new(obj) # foo.system would pass. # After executing foo.system, hoge.get_system also passes. # p foo.system p foo.get_system end end Test.run ``` ## Execution Results ``` shell hoge.rb:26:in 'Kernel#system': wrong number of arguments (given 0, expected 1+) (ArgumentError) raw.system(...) ^^^ from ruby.rb:26:in 'Foo#system' from ruby.rb:36:in 'Foo#get_system' from ruby.rb:54:in 'Test.run' from ruby.rb:58:in '<main>' ``` ## Expected results ``` shell "system" ``` PR that may be relevant: https://github.com/ruby/ruby/pull/11028 -- https://bugs.ruby-lang.org/
participants (3)
-
jeremyevans0 (Jeremy Evans)
-
mikik0 (Hashino Mikiko)
-
tenderlovemaking (Aaron Patterson)