From: Dmitry Volyntsev Date: Thu, 5 Nov 2026 00:49:18 +0000 (-0800) Subject: Modules: reject asynchronous work during module initialization X-Git-Url: https://git.kaiwu.me/%7B@url%7D?a=commitdiff_plain;h=72774fc2deabcf87f8d016a6fb76dda0142c64ee;p=njs.git Modules: reject asynchronous work during module initialization Global code is intended for synchronous initialization, but Fetch and timers could start request-bound work before clone publication. QuickJS Fetch dereferenced the unpublished engine, and module-level timers could escape initialization. Reject Fetch, setTimeout(), and setImmediate() before argument conversion or resource allocation in both engines. This does not prohibit ordinary promise jobs or synchronous module initialization. --- diff --git a/nginx/ngx_js.c b/nginx/ngx_js.c index 523799c3..282af631 100644 --- a/nginx/ngx_js.c +++ b/nginx/ngx_js.c @@ -1832,6 +1832,13 @@ ngx_qjs_ext_set_timeout(JSContext *cx, JSValueConst this_val, int argc, ngx_qjs_event_t *event; ngx_connection_t *c; + external = JS_GetContextOpaque(cx); + ctx = ngx_qjs_external_ctx(cx, external); + if (ctx->engine == NULL) { + return JS_ThrowTypeError(cx, "async operations are not allowed " + "during module initialization"); + } + if (!JS_IsFunction(cx, argv[0])) { return JS_ThrowTypeError(cx, "first arg must be a function"); } @@ -1846,9 +1853,6 @@ ngx_qjs_ext_set_timeout(JSContext *cx, JSValueConst this_val, int argc, n = immediate ? 1 : 2; argc = (argc >= n) ? argc - n : 0; - external = JS_GetContextOpaque(cx); - ctx = ngx_qjs_external_ctx(cx, external); - event = ngx_pcalloc(ngx_qjs_external_pool(cx, external), sizeof(ngx_qjs_event_t) + sizeof(JSValue) * argc); if (event == NULL) { @@ -3285,6 +3289,13 @@ njs_set_timer(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, ngx_js_event_t *event; ngx_connection_t *c; + ctx = ngx_external_ctx(vm, njs_vm_external_ptr(vm)); + if (ctx->engine == NULL) { + njs_vm_type_error(vm, "async operations are not allowed " + "during module initialization"); + return NJS_ERROR; + } + if (njs_slow_path(nargs < 2)) { njs_vm_type_error(vm, "too few arguments"); return NJS_ERROR; @@ -3320,7 +3331,6 @@ njs_set_timer(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, event->args = (njs_opaque_value_t *) &event[1]; event->destructor = ngx_js_clear_timer; - ctx = ngx_external_ctx(vm, njs_vm_external_ptr(vm)); event->fd = ctx->event_id++; c = ngx_external_connection(vm, njs_vm_external_ptr(vm)); diff --git a/nginx/ngx_js_fetch.c b/nginx/ngx_js_fetch.c index 003ded35..73abe8ff 100644 --- a/nginx/ngx_js_fetch.c +++ b/nginx/ngx_js_fetch.c @@ -510,6 +510,7 @@ ngx_js_ext_fetch(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, ngx_str_t *resolve_host; ngx_pool_t *pool; njs_value_t *init, *value; + ngx_js_ctx_t *jsctx; ngx_js_http_t *http; ngx_js_fetch_t *fetch; ngx_js_request_t request; @@ -525,6 +526,13 @@ ngx_js_ext_fetch(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, #endif external = njs_vm_external_ptr(vm); + jsctx = ngx_external_ctx(vm, external); + if (jsctx->engine == NULL) { + njs_vm_type_error(vm, "async operations are not allowed " + "during module initialization"); + return NJS_ERROR; + } + c = ngx_external_connection(vm, external); pool = ngx_external_pool(vm, external); diff --git a/nginx/ngx_qjs_fetch.c b/nginx/ngx_qjs_fetch.c index 7149b976..ff34dd55 100644 --- a/nginx/ngx_qjs_fetch.c +++ b/nginx/ngx_qjs_fetch.c @@ -257,6 +257,12 @@ ngx_qjs_ext_fetch(JSContext *cx, JSValueConst this_val, int argc, ngx_resolver_ctx_t *rs; external = JS_GetContextOpaque(cx); + ctx = ngx_qjs_external_ctx(cx, external); + if (ctx->engine == NULL) { + return JS_ThrowTypeError(cx, "async operations are not allowed " + "during module initialization"); + } + c = ngx_qjs_external_connection(cx, external); pool = ngx_qjs_external_pool(cx, external); @@ -353,8 +359,6 @@ ngx_qjs_ext_fetch(JSContext *cx, JSValueConst this_val, int argc, http->header_only = 1; } - ctx = ngx_qjs_external_ctx(cx, JS_GetContextOpaque(cx)); - NJS_CHB_MP_INIT(&http->chain, ctx->engine->pool); NJS_CHB_MP_INIT(&http->response.chain, ctx->engine->pool);