convert method name to a Symbol

* vm_eval.c (send_internal), vm_insnhelper.c (vm_call_opt_send):
  convert String method name into a Symbol, as method_missing
  method expects its first argument to be a Symbol.  [Bug #10828]

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@49506 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
nobu 2015-02-05 04:41:05 +00:00
Родитель 73645c1c51
Коммит 738ce30f99
4 изменённых файлов: 45 добавлений и 11 удалений

Просмотреть файл

@ -1,4 +1,8 @@
Thu Feb 5 12:31:05 2015 Nobuyoshi Nakada <nobu@ruby-lang.org>
Thu Feb 5 13:41:01 2015 Nobuyoshi Nakada <nobu@ruby-lang.org>
* vm_eval.c (send_internal), vm_insnhelper.c (vm_call_opt_send):
convert String method name into a Symbol, as method_missing
method expects its first argument to be a Symbol. [Bug #10828]
* vm_insnhelper.c (ci_missing_reason): return the reason of method
missing in call info.

Просмотреть файл

@ -379,17 +379,17 @@ module Test_Symbol
def test_send_leak_string_custom_method_missing
x = Object.new
def x.method_missing(*); end
def x.method_missing(*); super; end
assert_no_immortal_symbol_created("send should not leak - str mm") do |name|
assert_nothing_raised(NoMethodError) {x.send(name)}
assert_raise(NoMethodError) {x.send(name)}
end
end
def test_send_leak_symbol_custom_method_missing
x = Object.new
def x.method_missing(*); end
def x.method_missing(*); super; end
assert_no_immortal_symbol_created("send should not leak - sym mm") do |name|
assert_nothing_raised(NoMethodError) {x.send(name.to_sym)}
assert_raise(NoMethodError) {x.send(name.to_sym)}
end
end
@ -407,17 +407,17 @@ module Test_Symbol
def test_send_leak_string_custom_method_missing_no_optimization
x = Object.new
def x.method_missing(*); end
def x.method_missing(*); super; end
assert_no_immortal_symbol_created("send should not leak - str mm slow") do |name|
assert_nothing_raised(NoMethodError) {x.method(:send).call(name)}
assert_raise(NoMethodError) {x.method(:send).call(name)}
end
end
def test_send_leak_symbol_custom_method_missing_no_optimization
x = Object.new
def x.method_missing(*); end
def x.method_missing(*); super; end
assert_no_immortal_symbol_created("send should not leak - sym mm slow") do |name|
assert_nothing_raised(NoMethodError) {x.method(:send).call(name.to_sym)}
assert_raise(NoMethodError) {x.method(:send).call(name.to_sym)}
end
end
end

Просмотреть файл

@ -865,12 +865,22 @@ rb_funcall_with_block(VALUE recv, ID mid, int argc, const VALUE *argv, VALUE pas
return rb_call(recv, mid, argc, argv, CALL_PUBLIC);
}
static VALUE *
current_vm_stack_arg(rb_thread_t *th, const VALUE *argv)
{
rb_control_frame_t *prev_cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(th->cfp);
if (RUBY_VM_CONTROL_FRAME_STACK_OVERFLOW_P(th, prev_cfp)) return NULL;
if (prev_cfp->sp + 1 != argv) return NULL;
return prev_cfp->sp + 1;
}
static VALUE
send_internal(int argc, const VALUE *argv, VALUE recv, call_type scope)
{
ID id;
VALUE vid;
VALUE self;
VALUE ret, vargv = 0;
rb_thread_t *th = GET_THREAD();
if (scope == CALL_PUBLIC) {
@ -893,12 +903,31 @@ send_internal(int argc, const VALUE *argv, VALUE recv, call_type scope)
recv, argc, argv);
rb_exc_raise(exc);
}
if (!SYMBOL_P(*argv)) {
VALUE *tmp_argv = current_vm_stack_arg(th, argv);
vid = rb_str_intern(vid);
if (tmp_argv) {
tmp_argv[0] = vid;
}
else if (argc > 1) {
tmp_argv = ALLOCV_N(VALUE, vargv, argc);
tmp_argv[0] = vid;
MEMCPY(tmp_argv+1, argv+1, VALUE, argc-1);
argv = tmp_argv;
}
else {
argv = &vid;
}
}
id = idMethodMissing;
} else {
}
else {
argv++; argc--;
}
PASS_PASSED_BLOCK_TH(th);
return rb_call0(recv, id, argc, argv, scope, self);
ret = rb_call0(recv, id, argc, argv, scope, self);
ALLOCV_END(vargv);
return ret;
}
/*

Просмотреть файл

@ -1544,6 +1544,7 @@ vm_call_opt_send(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_info_t *c
VALUE exc = make_no_method_exception(rb_eNoMethodError, NULL, ci->recv, rb_long2int(ci->argc), &TOPN(i));
rb_exc_raise(exc);
}
TOPN(i) = rb_str_intern(sym);
ci->mid = idMethodMissing;
th->method_missing_reason = ci->aux.missing_reason = ci_missing_reason(ci);
}