Skip to content

Commit

Permalink
Fix instances where return value of mrb_method_search_vm is unchecked
Browse files Browse the repository at this point in the history
Reported by @charliesome
  • Loading branch information
EiNSTeiN- authored and bouk committed Nov 24, 2016
1 parent a630c4f commit a384bcc
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 10 deletions.
47 changes: 37 additions & 10 deletions src/vm.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 CALL_MAXARGS 127

void mrb_method_missing(mrb_state *mrb, mrb_sym name, mrb_value self, mrb_value args);

static inline void
stack_clear(mrb_value *from, size_t count)
{
Expand Down Expand Up @@ -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);
p = mrb_method_search_vm(mrb, &c, mid);
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;
mid = mrb_intern_lit(mrb, "method_missing");
p = mrb_method_search_vm(mrb, &c, mid);
n++; argc++;
}
ci = cipush(mrb);
Expand Down Expand Up @@ -749,10 +757,6 @@ argnum_error(mrb_state *mrb, mrb_int num)

#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_vm_run(mrb_state *mrb, struct RProc *proc, mrb_value self, unsigned int stack_keep)
{
Expand Down Expand Up @@ -1290,8 +1294,20 @@ mrb_vm_exec(mrb_state *mrb, struct RProc *proc, mrb_code *pc)
c = mrb->c->ci->target_class->super;
m = mrb_method_search_vm(mrb, &c, mid);
if (!m) {
mid = mrb_intern_lit(mrb, "method_missing");
m = mrb_method_search_vm(mrb, &c, mid);
mrb_sym missing = mrb_intern_lit(mrb, "method_missing");
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) {
mrb_ary_unshift(mrb, regs[a+1], mrb_symbol_value(ci->mid));
}
Expand Down Expand Up @@ -1681,9 +1697,20 @@ mrb_vm_exec(mrb_state *mrb, struct RProc *proc, mrb_code *pc)
m = mrb_method_search_vm(mrb, &c, mid);
if (!m) {
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");
m = mrb_method_search_vm(mrb, &c, mid);
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) {
mrb_ary_unshift(mrb, regs[a+1], sym);
}
Expand Down
31 changes: 31 additions & 0 deletions test/t/nomethoderror.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,34 @@
end
end
end

assert('Can still raise when BasicObject#method_missing is removed') do
assert_raise(TypeError) 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(TypeError) 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

0 comments on commit a384bcc

Please sign in to comment.