From: "jhawthorn (John Hawthorn) via ruby-core" Date: 2025-05-08T04:55:51+00:00 Subject: [ruby-core:121899] [Ruby Bug#21267] respond_to check in Class#allocate is inconsistent Issue #21267 has been updated by jhawthorn (John Hawthorn). > Or core types could actually define dup & clone as overridden methods, and not use the alloc function at all and so use rb_undef_alloc_func(). That seems the cleanest actually, WDYT? Yes. The only options that work are to `rb_undef_alloc_func` or returning something safe from the alloc func. The `alloc_prohibited` approach we tried is a dead end. As far as I can tell in current Ruby uninitialized MatchData, Refinement, Module, Complex, Rational do not crash the VM (if they do we need to fix that, because again, users can access that today). Which is why we should remove it. If we want to adjust those classes to `rb_undef_alloc_func` that seems like a good idea and we can do that later. ---------------------------------------- Bug #21267: respond_to check in Class#allocate is inconsistent https://bugs.ruby-lang.org/issues/21267#change-112968 * 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 '
': 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/ ______________________________________________ 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/