The `mrb_ary_cmp()` function calls `mrb_cmp()` for comparison, but `mrb_cmp()` may call the `obj.<=>` method internally.
If a user-defined `<=>` method is called and the array object under comparison is expanded or reduced, a reference to an invalid address may subsequently be made.
We assumed there's no need for gc_arena_keep() when MRB_GC_FIXED_ARENA
is set. But it turned out that gc_protect() still can cause use-after-free
with fixed arena.
Revert "gc.c (gc_protect): should not call gc_arena_keep twice from allocation"
This reverts commit 28ece4ed8b.
Revert "gc.c (gc_arena_keep): reorganized for MRB_GC_FIXED_ARENA; ref #6329"
This reverts commit 33dd623a02.
When GC occurs during the expansion of the GC arena by `gc_protect()` in `mrb_obj_alloc()`, the object page just allocated by `add_heap()` is released.
Therefore, as soon as control returns from `gc_protect()`, there is a possibility of illegal writing or reading to the address just released.
This issue was discovered during the investigation of #6326.
The following assertions can be added to omit the `if` block
- env object must be non-null
- env object must be in a shared state with the stack
The current caller is believed to satisfy the condition.
A reference to an invalid address might occur in `is_dead()` of `obj_free()` called from `incremental_sweep_phase()`.
This would happen if the heap page was freed ahead of time in the same `incremental_sweep_phase()`.
fixed#6326
If comparing function (block or `<=>`) modifies the sorting array and GC
happens after the modification, objects passed to comparison may be
freed by GC.
- Can refer directly to `proc->e.env` after `MRB_PROC_ENV_P()`.
- Can omit `MRB_ENV_ONSTACK_P()` since `mrb->c` is never NULL and can be directly compared to `env->cxt`.
- Can avoid `goto` by putting the code block that raises the `LocalJumpError` at the end.
It used to check all `start`, `end` and `step`. If either of them are
float number, `#step` iterated over float number. Now we don't check the
type of `end` argument.
Clearing errors at the beginning of `mrb_vm_exec()` essentially keeps the mruby VM in a non-error state.
For consistency, functions such as `mrb_funcall()` check for errors when control returns from a C function as a method.
In the case of a tail call, it should return to `mrb_vm_exec()` afterwards, so error checking is performed there.
Instructions issued while `mrb->exc` is non-null should be limited to `OP_EXCEPT`, the jump target of the catch handler table.