]> git.kaiwu.me - njs.git/commitdiff
Zlib: copy QJS dictionaries before conversion
authorDmitry Volyntsev <xeioex@nginx.com>
Tue, 22 Sep 2026 04:13:22 +0000 (21:13 -0700)
committerDmitry Volyntsev <xeioexception@gmail.com>
Fri, 25 Sep 2026 23:00:29 +0000 (16:00 -0700)
Copy dictionary bytes before converting other JavaScript arguments so their
backing storage cannot be invalidated during zlib setup.

external/qjs_zlib_module.c

index a980c9b2f7573c15674b7ad375f74dfd1fccc0ef..20218c011f76a6ecdf64b8fddb350314cf5d7d53 100644 (file)
@@ -70,7 +70,8 @@ qjs_zlib_ext_deflate(JSContext *ctx, JSValueConst this_val, int argc,
     JSValueConst *argv, int raw)
 {
     int          rc, level, mem_level, strategy, window_bits;
-    size_t       chunk_size;
+    u_char       *dictionary_copy;
+    size_t       chunk_size, dictionary_length;
     uint64_t     chunk_size_value;
     JSValue      ret, options;
     z_stream     stream;
@@ -86,6 +87,8 @@ qjs_zlib_ext_deflate(JSContext *ctx, JSValueConst this_val, int argc,
     NJS_CHB_CTX_INIT(&chain, ctx);
     dictionary.start = NULL;
     dictionary.length = 0;
+    dictionary_copy = NULL;
+    dictionary_length = 0;
     stream.opaque = NULL;
 
     options = argv[1];
@@ -213,11 +216,23 @@ qjs_zlib_ext_deflate(JSContext *ctx, JSValueConst this_val, int argc,
             if (rc != 0) {
                 return JS_EXCEPTION;
             }
+
+            dictionary_copy = js_malloc(ctx, dictionary.length);
+            if (dictionary_copy == NULL && dictionary.length != 0) {
+                qjs_bytes_free(ctx, &dictionary);
+                return JS_EXCEPTION;
+            }
+
+            memcpy(dictionary_copy, dictionary.start, dictionary.length);
+            dictionary_length = dictionary.length;
+            qjs_bytes_free(ctx, &dictionary);
+            dictionary.start = NULL;
         }
     }
 
     rc = qjs_to_bytes(ctx, &bytes, argv[0]);
     if (rc != 0) {
+        js_free(ctx, dictionary_copy);
         return JS_EXCEPTION;
     }
 
@@ -235,8 +250,8 @@ qjs_zlib_ext_deflate(JSContext *ctx, JSValueConst this_val, int argc,
         goto fail;
     }
 
-    if (dictionary.start != NULL) {
-        rc = deflateSetDictionary(&stream, dictionary.start, dictionary.length);
+    if (dictionary_copy != NULL) {
+        rc = deflateSetDictionary(&stream, dictionary_copy, dictionary_length);
         if (rc != Z_OK) {
             JS_ThrowInternalError(ctx, "deflateSetDictionary() failed");
             goto fail;
@@ -267,9 +282,7 @@ qjs_zlib_ext_deflate(JSContext *ctx, JSValueConst this_val, int argc,
 
     qjs_bytes_free(ctx, &bytes);
 
-    if (dictionary.start != NULL) {
-        qjs_bytes_free(ctx, &dictionary);
-    }
+    js_free(ctx, dictionary_copy);
 
     ret = qjs_buffer_chb_alloc(ctx, &chain);
 
@@ -281,9 +294,7 @@ fail:
 
     qjs_bytes_free(ctx, &bytes);
 
-    if (dictionary.start != NULL) {
-        qjs_bytes_free(ctx, &dictionary);
-    }
+    js_free(ctx, dictionary_copy);
 
     if (stream.opaque != NULL) {
         deflateEnd(&stream);
@@ -302,7 +313,8 @@ qjs_zlib_ext_inflate(JSContext *ctx, JSValueConst this_val, int argc,
     JSValueConst *argv, int raw)
 {
     int          rc, window_bits;
-    size_t       chunk_size;
+    u_char       *dictionary_copy;
+    size_t       chunk_size, dictionary_length;
     uint64_t     chunk_size_value;
     JSValue      ret, options;
     z_stream     stream;
@@ -315,6 +327,8 @@ qjs_zlib_ext_inflate(JSContext *ctx, JSValueConst this_val, int argc,
     NJS_CHB_CTX_INIT(&chain, ctx);
     dictionary.start = NULL;
     dictionary.length = 0;
+    dictionary_copy = NULL;
+    dictionary_length = 0;
     stream.opaque = NULL;
 
     options = argv[1];
@@ -379,11 +393,23 @@ qjs_zlib_ext_inflate(JSContext *ctx, JSValueConst this_val, int argc,
             if (rc != 0) {
                 return JS_EXCEPTION;
             }
+
+            dictionary_copy = js_malloc(ctx, dictionary.length);
+            if (dictionary_copy == NULL && dictionary.length != 0) {
+                qjs_bytes_free(ctx, &dictionary);
+                return JS_EXCEPTION;
+            }
+
+            memcpy(dictionary_copy, dictionary.start, dictionary.length);
+            dictionary_length = dictionary.length;
+            qjs_bytes_free(ctx, &dictionary);
+            dictionary.start = NULL;
         }
     }
 
     rc = qjs_to_bytes(ctx, &bytes, argv[0]);
     if (rc != 0) {
+        js_free(ctx, dictionary_copy);
         return JS_EXCEPTION;
     }
 
@@ -400,8 +426,8 @@ qjs_zlib_ext_inflate(JSContext *ctx, JSValueConst this_val, int argc,
         goto fail;
     }
 
-    if (dictionary.start != NULL) {
-        rc = inflateSetDictionary(&stream, dictionary.start, dictionary.length);
+    if (dictionary_copy != NULL) {
+        rc = inflateSetDictionary(&stream, dictionary_copy, dictionary_length);
         if (rc != Z_OK) {
             JS_ThrowInternalError(ctx, "inflateSetDictionary() failed");
             goto fail;
@@ -440,9 +466,7 @@ qjs_zlib_ext_inflate(JSContext *ctx, JSValueConst this_val, int argc,
 
     qjs_bytes_free(ctx, &bytes);
 
-    if (dictionary.start != NULL) {
-        qjs_bytes_free(ctx, &dictionary);
-    }
+    js_free(ctx, dictionary_copy);
 
     ret = qjs_buffer_chb_alloc(ctx, &chain);
 
@@ -454,6 +478,8 @@ fail:
 
     qjs_bytes_free(ctx, &bytes);
 
+    js_free(ctx, dictionary_copy);
+
     if (dictionary.start != NULL) {
         qjs_bytes_free(ctx, &dictionary);
     }