From e8c90acf691f4de2661774556f426d369da84132 Mon Sep 17 00:00:00 2001 From: Robert0303-C Date: Tue, 31 Mar 2026 11:05:59 +0800 Subject: [PATCH] fix: isolate async web API unwind from setjmp/longjmp The issue is that both setjmp/longjmp and async web APIs use the same asyncify mechanism (pl_asyncify_unwind_buf), causing re-entrancy conflicts when an async web API call happens during a setjmp context. Solution: Add a separate unwind buffer for async web API operations that is isolated from the setjmp unwind state: 1. machine.h/c: Add async_web_api_unwind(), async_web_api_stop(), async_web_api_handle_unwind() with separate _async_web_api_buf 2. runtime.c: Check async_web_api_handle_unwind() in the asyncify handling loop to properly handle async web API rewind This allows setjmp and async web APIs to coexist without conflicts. Fixes #7 --- stubs/machine.c | 31 +++++++++++++++++++++++++++++++ stubs/machine.h | 9 +++++++++ stubs/runtime.c | 6 ++++++ 3 files changed, 46 insertions(+) diff --git a/stubs/machine.c b/stubs/machine.c index aafb0ec..e73f644 100644 --- a/stubs/machine.c +++ b/stubs/machine.c @@ -22,6 +22,10 @@ static void init_asyncify_buf(struct asyncify_buf *buf) static void *_asyncjmp_active_scan_buf = NULL; +// Separate buffer for async web API operations (isolated from setjmp) +static struct asyncify_buf _async_web_api_buf; +static int _async_web_api_in_unwind = 0; + void asyncjmp_scan_locals(asyncjmp_scan_func scan) { static struct asyncify_buf buf; @@ -42,6 +46,33 @@ void asyncjmp_scan_locals(asyncjmp_scan_func scan) } } +// Start async web API unwind - saves setjmp state if active +void async_web_api_unwind(void) +{ + if (!_async_web_api_in_unwind) + { + _async_web_api_in_unwind = 1; + init_asyncify_buf(&_async_web_api_buf); + asyncify_start_unwind(&_async_web_api_buf); + } +} + +// Stop async web API unwind and restore setjmp context +void async_web_api_stop(void) +{ + if (_async_web_api_in_unwind) + { + asyncify_stop_rewind(); + _async_web_api_in_unwind = 0; + } +} + +// Handle async web API unwind - called from runtime.c +void *async_web_api_handle_unwind(void) +{ + return (_async_web_api_in_unwind) ? &_async_web_api_buf : NULL; +} + static void *asyncjmp_stack_base = NULL; __attribute__((constructor)) int asyncjmp_record_stack_base(void) diff --git a/stubs/machine.h b/stubs/machine.h index d4fcc9c..576cfb5 100644 --- a/stubs/machine.h +++ b/stubs/machine.h @@ -21,4 +21,13 @@ void asyncjmp_set_stack_pointer(void *sp); // Used by the top level Asyncify handling in wasm/runtime.c void *asyncjmp_handle_scan_unwind(void); +// Start async web API unwind - uses separate buffer from setjmp +void async_web_api_unwind(void); + +// Stop async web API unwind +void async_web_api_stop(void); + +// Handle async web API unwind +void *async_web_api_handle_unwind(void); + #endif \ No newline at end of file diff --git a/stubs/runtime.c b/stubs/runtime.c index b1a0f7d..b5506e4 100644 --- a/stubs/runtime.c +++ b/stubs/runtime.c @@ -34,6 +34,12 @@ int asyncjmp_rt_start(int(main)(int argc, char **argv), int argc, char **argv) asyncify_start_rewind(asyncify_buf); continue; } + // Handle async web API unwind - uses separate buffer from setjmp + if ((asyncify_buf = async_web_api_handle_unwind()) != NULL) + { + asyncify_start_rewind(asyncify_buf); + continue; + } break; }