mirror of
https://github.com/mruby/mruby
synced 2026-06-08 16:11:16 +00:00
vm.c: restore mrb->jmp on early return for task switch
mrb_vm_exec sets mrb->jmp to its own stack-local c_jmp on entry and
restores the caller's prev_jmp on every normal return path. The early
return added for task switching (RETURN_IF_TASK_STOPPED) skipped that
restore, so after a task was preempted via Task.pass the dangling
mrb->jmp pointed into mrb_vm_exec's freed stack frame. A subsequent
raise then longjmp'd into that freed frame and crashed.
Restore prev_jmp in the early-return path, matching the normal returns.
Task.new { Task.pass }
Task.pass
raise "boom" # SIGSEGV before this change
Fixes #6863.
Refs #6864.
Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -1594,11 +1594,21 @@ prepare_tagged_break(mrb_state *mrb, uint32_t tag, const mrb_callinfo *return_ci
|
||||
iteration is still active drifts the call-info stack and eventually
|
||||
crashes (issue #6862). Switches resume at the next OP boundary after
|
||||
the walk releases gc.iterating. A pending MRB_TASK_STOPPED is not
|
||||
deferred -- the task is going away. */
|
||||
deferred, since the task is going away.
|
||||
|
||||
mrb->jmp is restored to prev_jmp before returning, exactly as the
|
||||
normal return paths below do. mrb_vm_exec set mrb->jmp to its own
|
||||
stack-local c_jmp on entry; leaving it dangling after this early return
|
||||
means a later raise longjmps into a freed frame (issue #6863).
|
||||
|
||||
This macro must only be expanded where prev_jmp is in scope, i.e.
|
||||
inside mrb_vm_exec (via NEXT / END_DISPATCH). */
|
||||
#define RETURN_IF_TASK_STOPPED(mrb) do { \
|
||||
if (((mrb)->task.switching && !(mrb)->gc.iterating) || \
|
||||
(mrb)->c->status == MRB_TASK_STOPPED) \
|
||||
(mrb)->c->status == MRB_TASK_STOPPED) { \
|
||||
(mrb)->jmp = prev_jmp; \
|
||||
return mrb_nil_value(); \
|
||||
} \
|
||||
} while (0)
|
||||
#define TASK_STOP(mrb) do { \
|
||||
if (mrb->c->status != MRB_TASK_STOPPED) \
|
||||
|
||||
Reference in New Issue
Block a user