Commit 802e3964 authored by Yukihiro "Matz" Matsumoto's avatar Yukihiro "Matz" Matsumoto

Merge branch 'bouk-method-missing-segfault'

parents f6d19991 144006a2
...@@ -54,6 +54,10 @@ The value below allows about 60000 recursive calls in the simplest case. */ ...@@ -54,6 +54,10 @@ The value below allows about 60000 recursive calls in the simplest case. */
#define ARENA_RESTORE(mrb,ai) (mrb)->gc.arena_idx = (ai) #define ARENA_RESTORE(mrb,ai) (mrb)->gc.arena_idx = (ai)
#define CALL_MAXARGS 127
void mrb_method_missing(mrb_state *mrb, mrb_sym name, mrb_value self, mrb_value args);
static inline void static inline void
stack_clear(mrb_value *from, size_t count) stack_clear(mrb_value *from, size_t count)
{ {
...@@ -362,9 +366,13 @@ mrb_funcall_with_block(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc ...@@ -362,9 +366,13 @@ mrb_funcall_with_block(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc
c = mrb_class(mrb, self); c = mrb_class(mrb, self);
p = mrb_method_search_vm(mrb, &c, mid); p = mrb_method_search_vm(mrb, &c, mid);
if (!p) { if (!p) {
mrb_sym missing = mrb_intern_lit(mrb, "method_missing");
p = mrb_method_search_vm(mrb, &c, missing);
if (!p) {
mrb_value args = mrb_ary_new_from_values(mrb, argc, argv);
mrb_method_missing(mrb, mid, self, args);
}
undef = mid; undef = mid;
mid = mrb_intern_lit(mrb, "method_missing");
p = mrb_method_search_vm(mrb, &c, mid);
n++; argc++; n++; argc++;
} }
ci = cipush(mrb); ci = cipush(mrb);
...@@ -749,10 +757,6 @@ argnum_error(mrb_state *mrb, mrb_int num) ...@@ -749,10 +757,6 @@ argnum_error(mrb_state *mrb, mrb_int num)
#endif #endif
#define CALL_MAXARGS 127
void mrb_method_missing(mrb_state *mrb, mrb_sym name, mrb_value self, mrb_value args);
MRB_API mrb_value MRB_API mrb_value
mrb_vm_run(mrb_state *mrb, struct RProc *proc, mrb_value self, unsigned int stack_keep) mrb_vm_run(mrb_state *mrb, struct RProc *proc, mrb_value self, unsigned int stack_keep)
{ {
...@@ -1290,8 +1294,20 @@ RETRY_TRY_BLOCK: ...@@ -1290,8 +1294,20 @@ RETRY_TRY_BLOCK:
c = mrb->c->ci->target_class->super; c = mrb->c->ci->target_class->super;
m = mrb_method_search_vm(mrb, &c, mid); m = mrb_method_search_vm(mrb, &c, mid);
if (!m) { if (!m) {
mid = mrb_intern_lit(mrb, "method_missing"); mrb_sym missing = mrb_intern_lit(mrb, "method_missing");
m = mrb_method_search_vm(mrb, &c, mid); m = mrb_method_search_vm(mrb, &c, missing);
if (!m) {
mrb_value args;
if (n == CALL_MAXARGS) {
args = regs[a+1];
}
else {
args = mrb_ary_new_from_values(mrb, n, regs+a+1);
}
mrb_method_missing(mrb, mid, recv, args);
}
mid = missing;
if (n == CALL_MAXARGS) { if (n == CALL_MAXARGS) {
mrb_ary_unshift(mrb, regs[a+1], mrb_symbol_value(ci->mid)); mrb_ary_unshift(mrb, regs[a+1], mrb_symbol_value(ci->mid));
} }
...@@ -1681,9 +1697,20 @@ RETRY_TRY_BLOCK: ...@@ -1681,9 +1697,20 @@ RETRY_TRY_BLOCK:
m = mrb_method_search_vm(mrb, &c, mid); m = mrb_method_search_vm(mrb, &c, mid);
if (!m) { if (!m) {
mrb_value sym = mrb_symbol_value(mid); mrb_value sym = mrb_symbol_value(mid);
mrb_sym missing = mrb_intern_lit(mrb, "method_missing");
m = mrb_method_search_vm(mrb, &c, missing);
if (!m) {
mrb_value args;
mid = mrb_intern_lit(mrb, "method_missing"); if (n == CALL_MAXARGS) {
m = mrb_method_search_vm(mrb, &c, mid); args = regs[a+1];
}
else {
args = mrb_ary_new_from_values(mrb, n, regs+a+1);
}
mrb_method_missing(mrb, mid, recv, args);
}
mid = missing;
if (n == CALL_MAXARGS) { if (n == CALL_MAXARGS) {
mrb_ary_unshift(mrb, regs[a+1], sym); mrb_ary_unshift(mrb, regs[a+1], sym);
} }
......
...@@ -20,3 +20,34 @@ assert('NoMethodError#args', '15.2.32.2.1') do ...@@ -20,3 +20,34 @@ assert('NoMethodError#args', '15.2.32.2.1') do
end end
end end
end end
assert('Can still raise when BasicObject#method_missing is removed') do
assert_raise(NoMethodError) do
begin
BasicObject.alias_method(:old_method_missing, :method_missing)
BasicObject.remove_method(:method_missing)
1.__send__(:foo)
ensure
BasicObject.alias_method(:method_missing, :old_method_missing)
BasicObject.remove_method(:old_method_missing)
end
end
end
assert('Can still call super when BasicObject#method_missing is removed') do
assert_raise(NoMethodError) do
class A
def foo
super
end
end
begin
BasicObject.alias_method(:old_method_missing, :method_missing)
BasicObject.remove_method(:method_missing)
A.new.foo
ensure
BasicObject.alias_method(:method_missing, :old_method_missing)
BasicObject.remove_method(:old_method_missing)
end
end
end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment