ruby/wasm/runtime.c
Yuta Saito c1fc1a00ea
[wasm] Fix Asyncify loop exit condition for normal return (#9007)
[wasm] Fix Asyncify loop exit condition for normal return

Stop calling `asyncify_stop_unwind` when the main function returns
without any unwinding. In the era when Asyncify buffers were allocated
on the stack, the `top` and `end` fields were remained in the stack
space even after the main function returned, so buffer-overflow check in
the `asyncify_stop_unwind` function passed. But now, the `top` and `end`
fields are part of the jump buffer allocated on the heap and they are
deallocated with `free` when the corresponding VM tag is popped. So, the
buffer-overflow check in the `asyncify_stop_unwind` function failed when
the main fuction returned without any unwinding, and we have to break
the asyncify loop before calling `asyncify_stop_unwind`.

Related commit: bc46b12b12
2023-11-22 16:59:54 +00:00

55 lines
1.6 KiB
C

#include "wasm/machine.h"
#include "wasm/setjmp.h"
#include "wasm/fiber.h"
#include "wasm/asyncify.h"
#include <stdlib.h>
int rb_wasm_rt_start(int (main)(int argc, char **argv), int argc, char **argv) {
int result;
void *asyncify_buf;
bool new_fiber_started = false;
void *arg0 = NULL, *arg1 = NULL;
void (*fiber_entry_point)(void *, void *) = NULL;
while (1) {
if (fiber_entry_point) {
fiber_entry_point(arg0, arg1);
} else {
result = main(argc, argv);
}
extern void *rb_asyncify_unwind_buf;
// Exit Asyncify loop if there is no unwound buffer, which
// means that main function has returned normally.
if (rb_asyncify_unwind_buf == NULL) {
break;
}
// NOTE: it's important to call 'asyncify_stop_unwind' here instead in rb_wasm_handle_jmp_unwind
// because unless that, Asyncify inserts another unwind check here and it unwinds to the root frame.
asyncify_stop_unwind();
if ((asyncify_buf = rb_wasm_handle_jmp_unwind()) != NULL) {
asyncify_start_rewind(asyncify_buf);
continue;
}
if ((asyncify_buf = rb_wasm_handle_scan_unwind()) != NULL) {
asyncify_start_rewind(asyncify_buf);
continue;
}
asyncify_buf = rb_wasm_handle_fiber_unwind(&fiber_entry_point, &arg0, &arg1, &new_fiber_started);
// Newly starting fiber doesn't have asyncify buffer yet, so don't rewind it for the first time entry
if (asyncify_buf) {
asyncify_start_rewind(asyncify_buf);
continue;
} else if (new_fiber_started) {
continue;
}
break;
}
return result;
}