Permalink
Browse files

Fix instances where return value of mrb_method_search_vm is unchecked

Reported by @charliesome
  • Loading branch information...
EiNSTeiN- authored and bouk committed Nov 17, 2016
1 parent a630c4f commit a384bcce350acf5e8be5d45f0258e6ef5bdeb033
Showing with 68 additions and 10 deletions.
  1. +37 −10 src/vm.c
  2. +31 −0 test/t/nomethoderror.rb
View
@@ -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)
{
@@ -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);
@@ -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)
{
@@ -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));
}
@@ -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);
}
View
@@ -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.