Project

General

Profile

Bug #12344

Updated by nobu (Nobuyoshi Nakada) almost 8 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`" "check_funcall_respond_to" would not yield that the `to_hash` to_hash method would be defined for objects of type `String`. String.    In Ruby 2.3, it behaves as if `to_hash` to_hash is defined on a `String` String just due to the fact that we've added a global `method_missing`. method_missing.    This is hugely problematic when calling a gsub as the second parameter is checked (in `str_gsub` str_gsub - string.c:4593) to see if it will act like a hash - i.e. is it a `Hash` Hash or does it have a `to_hash` to_hash method.    It appears that eventually `vm_respond_to()` vm_respond_to() calls `METHOD_ENTRY_BASIC()` METHOD_ENTRY_BASIC() which then makes the false statement that the object responds to the `to_hash` to_hash method. 

 I believe that a possible fix is to have vm_eval.c - `check_funcall_respond_to` check_funcall_respond_to be changed from: 

 ~~~c ~~~ 
 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**: 

 ~~~c ~~~ 
 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` NameError in the `method_missing`. method missing. 

 ~~~ruby ~~~ 
 def method_missing(name, *args, &block) 
      raise NameError, "#{name} not defined on #{self.inspect}" 
 end 

 puts "foo".gsub(/o/, "bar") 
 ~~~ 

Back