]> git.kaiwu.me - njs.git/commitdiff
QuickJS: distinguish buffer copies and storage ownership
authorDmitry Volyntsev <xeioex@nginx.com>
Tue, 10 Nov 2026 01:45:32 +0000 (17:45 -0800)
committerDmitry Volyntsev <xeioexception@gmail.com>
Wed, 11 Nov 2026 21:33:45 +0000 (13:33 -0800)
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.

external/njs_shell.c
external/qjs_crypto_module.c
external/qjs_fs_module.c
external/qjs_webcrypto_module.c
external/qjs_xml_module.c
external/qjs_zlib_module.c
nginx/ngx_js.h
nginx/ngx_qjs_fetch.c
src/qjs.c
src/qjs.h
src/qjs_buffer.c

index 126ca9db54f5e1312171de65c892c8cee740f71c..044762e1ac0ce38b2dc3ca4b3a1fe01d7c091b85 100644 (file)
@@ -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,
index 9d8510e74a99b9c55db97a50c329c81f36ea5908..d1e942acb51de4d10956e31d6d3146533d345a5c 100644 (file)
@@ -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);
 }
 
 
index 42db4ff0b8569a5c200e6039725651a79edf0d22..05271924fc04218575cce6d0937522073cebfafe 100644 (file)
@@ -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);
index 3b4bfc5a83221d0a539e9b8c7563f0ee9216838e..8adcf40712e9efcff2c1e179934305a1abcb8068 100644 (file)
@@ -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;
         }
index 14cb06339a009df46804b7133abacb14f4a0560d..bbd24760a377c741f770713f4abad449f965e725 100644 (file)
@@ -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);
     }
 
index 20218c011f76a6ecdf64b8fddb350314cf5d7d53..adbe3dc7064bb5b6048bf1caf68037143591d0af 100644 (file)
@@ -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);
 
index 7d5cd4e050fed673ecd502e0a6963c69c5f501ca..aa866d42d8376b0c62b00edf2867916f7864eff1 100644 (file)
@@ -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]
index d501be756c87d855e11e52137e6be71aea12ed64..fc818a769ddc535aa8a9818dcfb8b2ad2f6b0da4 100644 (file)
@@ -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);
         }
index 4c5e971ab0656da4fed1aa911e61e2d710d79e4a..c1c8c1d35c87f65b0773d7c6b1dcccb1e510299a 100644 (file)
--- 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);
 }
 
 
index 3b89bb71e2285003a6e673ed52bf0830771844dc..e6008cc7b918fb6c0758ef9add2b8b39225a027f 100644 (file)
--- 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);
index 2eb12e3ae755ac83ab93d6b88bf54b3d4431cd84..c21e835bf6b62e6e19596d7ba7771b459a397080 100644 (file)
@@ -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;