mirror of
https://github.com/ruby/ruby.git
synced 2025-08-15 13:39:04 +02:00
fix sendfwd with send
and method_missing
combination with `send` method (optimized) or `method_missing` and forwarding send (`...`) needs to respect given `rb_forwarding_call_data`. Otherwize it causes critical error such as SEGV.
This commit is contained in:
parent
f5fd87b695
commit
b182f2a045
2 changed files with 65 additions and 16 deletions
|
@ -1315,14 +1315,32 @@ assert_equal 'ok', %q{
|
||||||
}
|
}
|
||||||
|
|
||||||
assert_equal 'ok', %q{
|
assert_equal 'ok', %q{
|
||||||
def foo(a, b) = a + b
|
def foo(a, b) = a + b
|
||||||
def bar(...) = foo(...)
|
def bar(...) = foo(...)
|
||||||
bar(1, 2)
|
bar(1, 2)
|
||||||
bar(1, 2)
|
bar(1, 2)
|
||||||
begin
|
begin
|
||||||
bar(1, 2, 3)
|
bar(1, 2, 3)
|
||||||
"ng"
|
"ng"
|
||||||
rescue ArgumentError
|
rescue ArgumentError
|
||||||
"ok"
|
"ok"
|
||||||
end
|
end
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_equal 'ok', %q{
|
||||||
|
class C
|
||||||
|
def foo(...) = :ok
|
||||||
|
def bar(...) = __send__(:foo, ...)
|
||||||
|
end
|
||||||
|
|
||||||
|
C.new.bar
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_equal 'ok', %q{
|
||||||
|
class C
|
||||||
|
def method_missing(...) = :ok
|
||||||
|
def foo(...) = xyzzy(...)
|
||||||
|
end
|
||||||
|
|
||||||
|
C.new.foo
|
||||||
}
|
}
|
||||||
|
|
|
@ -3069,6 +3069,9 @@ vm_callee_setup_arg(rb_execution_context_t *ec, struct rb_calling_info *calling,
|
||||||
const struct rb_callinfo *ci = calling->cd->ci;
|
const struct rb_callinfo *ci = calling->cd->ci;
|
||||||
const struct rb_callcache *cc = calling->cc;
|
const struct rb_callcache *cc = calling->cc;
|
||||||
|
|
||||||
|
VM_ASSERT((vm_ci_argc(ci), 1));
|
||||||
|
VM_ASSERT(vm_cc_cme(cc) != NULL);
|
||||||
|
|
||||||
if (UNLIKELY(!ISEQ_BODY(iseq)->param.flags.use_block &&
|
if (UNLIKELY(!ISEQ_BODY(iseq)->param.flags.use_block &&
|
||||||
calling->block_handler != VM_BLOCK_HANDLER_NONE &&
|
calling->block_handler != VM_BLOCK_HANDLER_NONE &&
|
||||||
!(vm_ci_flag(calling->cd->ci) & VM_CALL_SUPER))) {
|
!(vm_ci_flag(calling->cd->ci) & VM_CALL_SUPER))) {
|
||||||
|
@ -4235,10 +4238,23 @@ vm_call_symbol(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
calling->cd = &(struct rb_call_data) {
|
struct rb_forwarding_call_data new_fcd = {
|
||||||
.ci = &VM_CI_ON_STACK(mid, flags, argc, vm_ci_kwarg(ci)),
|
.cd = {
|
||||||
.cc = NULL,
|
.ci = &VM_CI_ON_STACK(mid, flags, argc, vm_ci_kwarg(ci)),
|
||||||
|
.cc = NULL,
|
||||||
|
},
|
||||||
|
.caller_ci = NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (!(vm_ci_flag(ci) & VM_CALL_FORWARDING)) {
|
||||||
|
calling->cd = &new_fcd.cd;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const struct rb_callinfo *caller_ci = ((struct rb_forwarding_call_data *)calling->cd)->caller_ci;
|
||||||
|
VM_ASSERT((vm_ci_argc(caller_ci), 1));
|
||||||
|
new_fcd.caller_ci = caller_ci;
|
||||||
|
calling->cd = (struct rb_call_data *)&new_fcd;
|
||||||
|
}
|
||||||
calling->cc = &VM_CC_ON_STACK(klass,
|
calling->cc = &VM_CC_ON_STACK(klass,
|
||||||
vm_call_general,
|
vm_call_general,
|
||||||
{ .method_missing_reason = missing_reason },
|
{ .method_missing_reason = missing_reason },
|
||||||
|
@ -4381,10 +4397,25 @@ vm_call_method_missing_body(rb_execution_context_t *ec, rb_control_frame_t *reg_
|
||||||
INC_SP(1);
|
INC_SP(1);
|
||||||
|
|
||||||
ec->method_missing_reason = reason;
|
ec->method_missing_reason = reason;
|
||||||
calling->cd = &(struct rb_call_data) {
|
|
||||||
.ci = &VM_CI_ON_STACK(idMethodMissing, flag, argc, vm_ci_kwarg(orig_ci)),
|
struct rb_forwarding_call_data new_fcd = {
|
||||||
.cc = NULL,
|
.cd = {
|
||||||
|
.ci = &VM_CI_ON_STACK(idMethodMissing, flag, argc, vm_ci_kwarg(orig_ci)),
|
||||||
|
.cc = NULL,
|
||||||
|
},
|
||||||
|
.caller_ci = NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (!(flag & VM_CALL_FORWARDING)) {
|
||||||
|
calling->cd = &new_fcd.cd;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const struct rb_callinfo *caller_ci = ((struct rb_forwarding_call_data *)calling->cd)->caller_ci;
|
||||||
|
VM_ASSERT((vm_ci_argc(caller_ci), 1));
|
||||||
|
new_fcd.caller_ci = caller_ci;
|
||||||
|
calling->cd = (struct rb_call_data *)&new_fcd;
|
||||||
|
}
|
||||||
|
|
||||||
calling->cc = &VM_CC_ON_STACK(Qundef, vm_call_general, {{ 0 }},
|
calling->cc = &VM_CC_ON_STACK(Qundef, vm_call_general, {{ 0 }},
|
||||||
rb_callable_method_entry_without_refinements(CLASS_OF(calling->recv), idMethodMissing, NULL));
|
rb_callable_method_entry_without_refinements(CLASS_OF(calling->recv), idMethodMissing, NULL));
|
||||||
return vm_call_method(ec, reg_cfp, calling);
|
return vm_call_method(ec, reg_cfp, calling);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue