From: Dmitry Volyntsev Date: Tue, 10 Nov 2026 01:45:32 +0000 (-0800) Subject: QuickJS: distinguish buffer copies and storage ownership X-Git-Url: https://git.kaiwu.me/%7B@url%7D?a=commitdiff_plain;h=4f89b8ec32f9f63895af512976211addbaa3cc44;p=njs.git QuickJS: distinguish buffer copies and storage ownership The creation helpers do not express whether they copy bytes or take responsibility for an existing allocation. Use copy names for Buffer snapshots and adopt for owned ArrayBuffer storage. Create the external SharedArrayBuffer directly in the sole shell caller instead of exposing a non-owning wrapper as a common helper. Preserve the existing ownership and allocation-failure contracts. --- diff --git a/external/njs_shell.c b/external/njs_shell.c index 126ca9db..044762e1 100644 --- a/external/njs_shell.c +++ b/external/njs_shell.c @@ -2084,8 +2084,15 @@ njs_qjs_agent(void *arg) pthread_cond_signal(&console->agent_cond); pthread_mutex_unlock(&console->agent_mutex); - args[0] = qjs_new_external_array_buffer(ctx, - agent->broadcast_sab_buf, agent->broadcast_sab_size, 1); +#ifdef NJS_HAVE_QUICKJS_ARRAY_BUFFER_MAX_LEN + args[0] = JS_NewArrayBuffer(ctx, agent->broadcast_sab_buf, + agent->broadcast_sab_size, 0, + NULL, NULL, 1); +#else + args[0] = JS_NewArrayBuffer(ctx, agent->broadcast_sab_buf, + agent->broadcast_sab_size, + NULL, NULL, 1); +#endif args[1] = JS_NewInt32(ctx, agent->broadcast_val); ret_val = JS_Call(ctx, agent->broadcast_func, JS_UNDEFINED, diff --git a/external/qjs_crypto_module.c b/external/qjs_crypto_module.c index 9d8510e7..d1e942ac 100644 --- a/external/qjs_crypto_module.c +++ b/external/qjs_crypto_module.c @@ -583,7 +583,7 @@ qjs_crypto_encoding(JSContext *cx, JSValueConst val) static JSValue qjs_buffer_digest(JSContext *cx, const njs_str_t *src) { - return qjs_buffer_create(cx, src->start, src->length); + return qjs_buffer_copy(cx, src->start, src->length); } diff --git a/external/qjs_fs_module.c b/external/qjs_fs_module.c index 42db4ff0..05271924 100644 --- a/external/qjs_fs_module.c +++ b/external/qjs_fs_module.c @@ -2866,7 +2866,7 @@ qjs_fs_encode(JSContext *cx, const qjs_buffer_encoding_t *encoding, njs_str_t data; if (encoding == NULL) { - return qjs_buffer_create(cx, str->start, str->length); + return qjs_buffer_copy(cx, str->start, str->length); } else if (encoding->encode_length != NULL) { data.length = encoding->encode_length(cx, str); diff --git a/external/qjs_webcrypto_module.c b/external/qjs_webcrypto_module.c index 3b4bfc5a..8adcf407 100644 --- a/external/qjs_webcrypto_module.c +++ b/external/qjs_webcrypto_module.c @@ -711,7 +711,7 @@ qjs_cipher_pkey(JSContext *cx, njs_str_t *data, qjs_webcrypto_key_t *key, goto fail; } - ret = qjs_new_array_buffer(cx, dst, outlen); + ret = qjs_array_buffer_adopt(cx, dst, outlen); fail: @@ -892,7 +892,7 @@ qjs_cipher_aes_gcm(JSContext *cx, njs_str_t *data, qjs_webcrypto_key_t *key, outlen += taglen; } - ret = qjs_new_array_buffer(cx, dst, outlen); + ret = qjs_array_buffer_adopt(cx, dst, outlen); EVP_CIPHER_CTX_free(ctx); @@ -1197,7 +1197,7 @@ qjs_cipher_aes_ctr(JSContext *cx, njs_str_t *data, qjs_webcrypto_key_t *key, done: - ret = qjs_new_array_buffer(cx, dst, len); + ret = qjs_array_buffer_adopt(cx, dst, len); fail: @@ -1320,7 +1320,7 @@ qjs_cipher_aes_cbc(JSContext *cx, njs_str_t *data, qjs_webcrypto_key_t *key, olen += olen2; - ret = qjs_new_array_buffer(cx, dst, olen); + ret = qjs_array_buffer_adopt(cx, dst, olen); fail: @@ -1420,7 +1420,7 @@ qjs_cipher_aes_kw(JSContext *cx, njs_str_t *data, qjs_webcrypto_key_t *key, goto fail; } - ret = qjs_new_array_buffer(cx, dst, olen); + ret = qjs_array_buffer_adopt(cx, dst, olen); fail: @@ -1945,7 +1945,7 @@ qjs_export_raw_ec(JSContext *cx, qjs_webcrypto_key_t *key) return JS_EXCEPTION; } - return qjs_new_array_buffer(cx, dst, size); + return qjs_array_buffer_adopt(cx, dst, size); } @@ -2123,7 +2123,7 @@ qjs_derive_ecdh(JSContext *cx, JSValueConst *argv, int argc, int derive_key, dkey->u.s.raw.length = length; } else { - result = qjs_new_array_buffer(cx, k, length); + result = qjs_array_buffer_adopt(cx, k, length); } return qjs_promise_result(cx, result); @@ -2433,7 +2433,7 @@ free: } else { - ret = qjs_new_array_buffer(cx, k, length); + ret = qjs_array_buffer_adopt(cx, k, length); } return qjs_promise_result(cx, ret); @@ -2484,7 +2484,7 @@ qjs_webcrypto_digest(JSContext *cx, JSValueConst this_val, int argc, return JS_EXCEPTION; } - ret = qjs_new_array_buffer(cx, dst, olen); + ret = qjs_array_buffer_adopt(cx, dst, olen); return ret; } @@ -4899,7 +4899,7 @@ qjs_webcrypto_sign(JSContext *cx, JSValueConst this_val, int argc, } if (!verify) { - ret = qjs_new_array_buffer(cx, dst, outlen); + ret = qjs_array_buffer_adopt(cx, dst, outlen); if (JS_IsException(ret)) { goto fail; } diff --git a/external/qjs_xml_module.c b/external/qjs_xml_module.c index 14cb0633..bbd24760 100644 --- a/external/qjs_xml_module.c +++ b/external/qjs_xml_module.c @@ -390,7 +390,7 @@ qjs_xml_canonicalization(JSContext *cx, JSValueConst this_val, int argc, ret = qjs_string_create_chb(cx, &chain); } else { - ret = qjs_buffer_chb_alloc(cx, &chain); + ret = qjs_buffer_chb_copy(cx, &chain); njs_chb_destroy(&chain); } diff --git a/external/qjs_zlib_module.c b/external/qjs_zlib_module.c index 20218c01..adbe3dc7 100644 --- a/external/qjs_zlib_module.c +++ b/external/qjs_zlib_module.c @@ -284,7 +284,7 @@ qjs_zlib_ext_deflate(JSContext *ctx, JSValueConst this_val, int argc, js_free(ctx, dictionary_copy); - ret = qjs_buffer_chb_alloc(ctx, &chain); + ret = qjs_buffer_chb_copy(ctx, &chain); njs_chb_destroy(&chain); @@ -468,7 +468,7 @@ qjs_zlib_ext_inflate(JSContext *ctx, JSValueConst this_val, int argc, js_free(ctx, dictionary_copy); - ret = qjs_buffer_chb_alloc(ctx, &chain); + ret = qjs_buffer_chb_copy(ctx, &chain); njs_chb_destroy(&chain); diff --git a/nginx/ngx_js.h b/nginx/ngx_js.h index 7d5cd4e0..aa866d42 100644 --- a/nginx/ngx_js.h +++ b/nginx/ngx_js.h @@ -416,7 +416,7 @@ JSValue ngx_qjs_ext_fetch(JSContext *cx, JSValueConst this_val, int argc, #define ngx_qjs_prop(cx, type, start, len) \ ((type == NGX_JS_STRING) ? qjs_string_create(cx, start, len) \ - : qjs_buffer_create(cx, (u_char *) start, len)) + : qjs_buffer_copy(cx, (u_char *) start, len)) #define ngx_qjs_meta(cx, i) \ ((uintptr_t *) JS_GetRuntimeOpaque(JS_GetRuntime(cx)))[i] diff --git a/nginx/ngx_qjs_fetch.c b/nginx/ngx_qjs_fetch.c index d501be75..fc818a76 100644 --- a/nginx/ngx_qjs_fetch.c +++ b/nginx/ngx_qjs_fetch.c @@ -2352,7 +2352,7 @@ ngx_qjs_ext_fetch_response_body(JSContext *cx, JSValueConst this_val, njs_chb_join_to(&response->chain, p); njs_chb_destroy(&response->chain); - result = qjs_new_array_buffer(cx, p, size); + result = qjs_array_buffer_adopt(cx, p, size); if (JS_IsException(result)) { js_free(cx, p); } diff --git a/src/qjs.c b/src/qjs.c index 4c5e971a..c1c8c1d3 100644 --- a/src/qjs.c +++ b/src/qjs.c @@ -1318,23 +1318,15 @@ qjs_array_buffer_free(JSRuntime *rt, void *opaque, void *ptr) #endif -JSValue -qjs_new_array_buffer(JSContext *cx, uint8_t *src, size_t len) -{ - return qjs_array_buffer_create(cx, src, len, qjs_array_buffer_free, 0); -} - - /* - * The memory is not managed by the engine, the caller is responsible for - * keeping it alive while the buffer is reachable. + * The allocation must use the runtime allocator. Ownership is transferred + * on success; the caller retains it on failure. */ JSValue -qjs_new_external_array_buffer(JSContext *cx, uint8_t *src, size_t len, - int is_shared) +qjs_array_buffer_adopt(JSContext *cx, uint8_t *src, size_t len) { - return qjs_array_buffer_create(cx, src, len, NULL, is_shared); + return qjs_array_buffer_create(cx, src, len, qjs_array_buffer_free, 0); } diff --git a/src/qjs.h b/src/qjs.h index 3b89bb71..e6008cc7 100644 --- a/src/qjs.h +++ b/src/qjs.h @@ -68,12 +68,10 @@ void qjs_chb_rt_free(void *rt, void *p); JSValue qjs_new_uint8_array(JSContext *ctx, int argc, JSValueConst *argv); -JSValue qjs_new_array_buffer(JSContext *cx, uint8_t *src, size_t len); -JSValue qjs_new_external_array_buffer(JSContext *cx, uint8_t *src, size_t len, - int is_shared); +JSValue qjs_array_buffer_adopt(JSContext *cx, uint8_t *src, size_t len); JSValue qjs_buffer_alloc(JSContext *ctx, uint64_t size); -JSValue qjs_buffer_create(JSContext *ctx, u_char *start, size_t size); -JSValue qjs_buffer_chb_alloc(JSContext *ctx, njs_chb_t *chain); +JSValue qjs_buffer_copy(JSContext *ctx, u_char *start, size_t size); +JSValue qjs_buffer_chb_copy(JSContext *ctx, njs_chb_t *chain); typedef int (*qjs_buffer_encode_t)(JSContext *ctx, const njs_str_t *src, njs_str_t *dst); diff --git a/src/qjs_buffer.c b/src/qjs_buffer.c index 2eb12e3a..c21e835b 100644 --- a/src/qjs_buffer.c +++ b/src/qjs_buffer.c @@ -2606,7 +2606,7 @@ qjs_buffer_alloc(JSContext *ctx, uint64_t size) JSValue -qjs_buffer_create(JSContext *ctx, u_char *start, size_t size) +qjs_buffer_copy(JSContext *ctx, u_char *start, size_t size) { JSValue buffer, ret; njs_str_t dst; @@ -2629,7 +2629,7 @@ qjs_buffer_create(JSContext *ctx, u_char *start, size_t size) JSValue -qjs_buffer_chb_alloc(JSContext *ctx, njs_chb_t *chain) +qjs_buffer_chb_copy(JSContext *ctx, njs_chb_t *chain) { ssize_t size; JSValue ret;