Separate jump destination check in `OP_R_RETURN`.

In the past code, the current `callinfo (ci)` was modified, thus it was
possible to pop `ci` beyond the `cibase`, that could cause out of memory
bound access for the code like the following:

```ruby
def m2
  lambda {
    Proc.new {
      return :return # return from the method
    }
  }.call.call
  :never_reached
end

p m2
```
parent b01207ea
......@@ -2029,11 +2029,20 @@ RETRY_TRY_BLOCK:
goto L_RAISE;
}
}
/* check jump destination */
while (cibase <= ci && ci->proc != dst) {
if (ci->acc < 0) {
if (ci->acc < 0) { /* jump cross C boudary */
localjump_error(mrb, LOCALJUMP_ERROR_RETURN);
goto L_RAISE;
}
ci--;
}
if (ci <= cibase) { /* no jump destination */
localjump_error(mrb, LOCALJUMP_ERROR_RETURN);
goto L_RAISE;
}
ci = mrb->c->ci;
while (cibase <= ci && ci->proc != dst) {
CHECKPOINT_RESTORE(RBREAK_TAG_RETURN_BLOCK) {
cibase = mrb->c->cibase;
dst = top_proc(mrb, proc);
......@@ -2045,12 +2054,8 @@ RETRY_TRY_BLOCK:
pc = ci->pc;
ci = cipop(mrb);
}
mrb->exc = NULL; /* clear break object */
proc = ci->proc;
if (ci <= cibase) {
localjump_error(mrb, LOCALJUMP_ERROR_RETURN);
goto L_RAISE;
}
mrb->exc = NULL; /* clear break object */
break;
}
/* fallthrough */
......
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