Bug #12344
Updated by mbedalov (Matt Bedalov) about 9 years ago
Prior to ruby 2.3, and specifically I believe prior to the implementation of this change: > Thu Aug 20 14:13:27 2015 Nobuyoshi Nakada <nobu@ruby-lang.org> > vm_eval.c (check_funcall_respond_to) > share the behavior with rb_obj_respond_to. [ruby-core:70460] [Bug #11465] > > vm_method.c (vm_respond_to) > extract from rb_obj_respond_to and merge r39881. When a global method_missing was defined, I believe that "check_funcall_respond_to" would not yield that the to_hash method would be defined for objects of type String. In Ruby 2.3, it behaves as if to_hash is defined on a String just due to the fact that we've added a global method_missing. This is hugely problematic when calling a gsub as the second parameter is checked (in str_gsub - string.c:4593) to see if it will act like a hash - i.e. is it a Hash or does it have a to_hash method. It appears that eventually vm_respond_to() calls METHOD_ENTRY_BASIC() which then makes the false statement that the object responds to the to_hash method. I believe that a possible fix is to have vm_eval.c - check_funcall_respond_to be changed from: ~~~ static int check_funcall_respond_to(rb_thread_t *th, VALUE klass, VALUE recv, ID mid) { return vm_respond_to(th, klass, recv, mid, TRUE); } ~~~ **to**: ~~~ static int check_funcall_respond_to(rb_thread_t *th, VALUE klass, VALUE recv, ID mid) { return rb_obj_respond_to(recv, mid, TRUE); } ~~~ With the current behavior, the following in my opinion is incorrectly throwing the NameError in the method missing. ~~~ def method_missing(name, *args, &block) raise NameError, "#{name} not defined on #{self.inspect}" end puts "foo".gsub(/o/, "bar") ~~~