
Issue #21267 has been reported by jhawthorn (John Hawthorn). ---------------------------------------- Bug #21267: respond_to check in Class#allocate is inconsistent https://bugs.ruby-lang.org/issues/21267 * Author: jhawthorn (John Hawthorn) * Status: Open * Backport: 3.2: UNKNOWN, 3.3: UNKNOWN, 3.4: UNKNOWN ---------------------------------------- `Class#allocate` has an additional `rb_obj_respond_to(klass, rb_intern("allocate"))` check to forbid allocate being called on a class where it has been made private or undefined, even if used via ex. `bind_call`. ```
Rational.allocate (irb):1:in '<main>': undefined method 'allocate' for class Rational (NoMethodError) Class.instance_method(:allocate).bind_call(Rational) (irb):1:in 'Class#allocate': calling Rational.allocate is prohibited (TypeError)
However I don't think this provides any additional protection from users accessing an uninitialized object, as the user can redefine allocate to anything to bypass the check:
Class.instance_method(:allocate).bind_call(Class.new(Rational) {def self.allocate; end}) => (0/1)
Or even override `respond_to_missing?`
Class.instance_method(:allocate).bind_call(Class.new(Rational) {def self.respond_to_missing? *; true; end}) => (0/1)
So I think we should remove this check. For classes that we need to forbid allocation we should use `rb_undef_alloc_func`.
The classes I see this used for are:
* MatchData
* Refinement
* Module
* Complex
* Rational
My main motivation is that this check makes `Class#allocate` slow. There are ways we could improve that, but I don't think the check as-is is useful. If there's an alternative, more robust, check we'd like to do instead of simply removing this I'd be happy to implement it.
This makes `allocate` ~75% faster.
|allocate_no_params | 19.009M| 20.087M| | | -| 1.06x| |allocate_allocate | 20.587M| 35.882M| | | -| 1.74x| ``` https://github.com/ruby/ruby/pull/13116 -- https://bugs.ruby-lang.org/