]> git.kaiwu.me - quickjs.git/commitdiff
Fix use-after-free in ArrayBuffer.prototype.transfer (bnoordhuis) (#450) - use js_arr...
authorFabrice Bellard <fabrice@bellard.org>
Mon, 3 Nov 2025 17:23:19 +0000 (18:23 +0100)
committerFabrice Bellard <fabrice@bellard.org>
Mon, 3 Nov 2025 17:23:19 +0000 (18:23 +0100)
quickjs.c
tests/test_builtin.js

index b6113723f3c5ebe5f6a4a0ea5eecccc6cf5ac578..1930c5d08c2a2db31b2cd1b980420a3805831f30 100644 (file)
--- a/quickjs.c
+++ b/quickjs.c
@@ -55344,10 +55344,47 @@ static JSValue js_array_buffer_get_resizable(JSContext *ctx,
     return JS_NewBool(ctx, array_buffer_is_resizable(abuf));
 }
 
+static void js_array_buffer_update_typed_arrays(JSArrayBuffer *abuf)
+{
+    uint32_t size_log2, size_elem;
+    struct list_head *el;
+    JSTypedArray *ta;
+    JSObject *p;
+    uint8_t *data;
+    int64_t len;
+
+    len = abuf->byte_length;
+    data = abuf->data;
+    // update lengths of all typed arrays backed by this array buffer
+    list_for_each(el, &abuf->array_list) {
+        ta = list_entry(el, JSTypedArray, link);
+        p = ta->obj;
+        if (p->class_id == JS_CLASS_DATAVIEW) {
+            continue;
+        } else {
+            p->u.array.count = 0;
+            p->u.array.u.ptr = NULL;
+            size_log2 = typed_array_size_log2(p->class_id);
+            size_elem = 1 << size_log2;
+            if (ta->track_rab) {
+                if (len >= (int64_t)ta->offset + size_elem) {
+                    p->u.array.count = (len - ta->offset) >> size_log2;
+                    p->u.array.u.ptr = &data[ta->offset];
+                }
+            } else {
+                if (len >= (int64_t)ta->offset + ta->length) {
+                    p->u.array.count = ta->length >> size_log2;
+                    p->u.array.u.ptr = &data[ta->offset];
+                }
+            }
+        }
+    }
+    
+}
+
 void JS_DetachArrayBuffer(JSContext *ctx, JSValueConst obj)
 {
     JSArrayBuffer *abuf = JS_GetOpaque(obj, JS_CLASS_ARRAY_BUFFER);
-    struct list_head *el;
 
     if (!abuf || abuf->detached)
         return;
@@ -55356,19 +55393,7 @@ void JS_DetachArrayBuffer(JSContext *ctx, JSValueConst obj)
     abuf->data = NULL;
     abuf->byte_length = 0;
     abuf->detached = TRUE;
-
-    list_for_each(el, &abuf->array_list) {
-        JSTypedArray *ta;
-        JSObject *p;
-
-        ta = list_entry(el, JSTypedArray, link);
-        p = ta->obj;
-        /* Note: the typed array length and offset fields are not modified */
-        if (p->class_id != JS_CLASS_DATAVIEW) {
-            p->u.array.count = 0;
-            p->u.array.u.ptr = NULL;
-        }
-    }
+    js_array_buffer_update_typed_arrays(abuf);
 }
 
 /* get an ArrayBuffer or SharedArrayBuffer */
@@ -55483,6 +55508,7 @@ static JSValue js_array_buffer_transfer(JSContext *ctx,
         abuf->data = NULL;
         abuf->byte_length = 0;
         abuf->detached = TRUE;
+        js_array_buffer_update_typed_arrays(abuf);
         return js_array_buffer_constructor3(ctx, JS_UNDEFINED, new_len, pmax_len,
                                             JS_CLASS_ARRAY_BUFFER,
                                             bs, free_func,
@@ -55493,11 +55519,7 @@ static JSValue js_array_buffer_transfer(JSContext *ctx,
 static JSValue js_array_buffer_resize(JSContext *ctx, JSValueConst this_val,
                                       int argc, JSValueConst *argv, int class_id)
 {
-    uint32_t size_log2, size_elem;
-    struct list_head *el;
     JSArrayBuffer *abuf;
-    JSTypedArray *ta;
-    JSObject *p;
     uint8_t *data;
     int64_t len;
 
@@ -55540,29 +55562,7 @@ static JSValue js_array_buffer_resize(JSContext *ctx, JSValueConst this_val,
         abuf->byte_length = len;
         abuf->data = data;
     }
-    data = abuf->data;
-    // update lengths of all typed arrays backed by this array buffer
-    list_for_each(el, &abuf->array_list) {
-        ta = list_entry(el, JSTypedArray, link);
-        p = ta->obj;
-        if (p->class_id == JS_CLASS_DATAVIEW)
-            continue;
-        p->u.array.count = 0;
-        p->u.array.u.ptr = NULL;
-        size_log2 = typed_array_size_log2(p->class_id);
-        size_elem = 1 << size_log2;
-        if (ta->track_rab) {
-            if (len >= (int64_t)ta->offset + size_elem) {
-                p->u.array.count = (len - ta->offset) >> size_log2;
-                p->u.array.u.ptr = &data[ta->offset];
-            }
-        } else {
-            if (len >= (int64_t)ta->offset + ta->length) {
-                p->u.array.count = ta->length >> size_log2;
-                p->u.array.u.ptr = &data[ta->offset];
-            }
-        }
-    }
+    js_array_buffer_update_typed_arrays(abuf);
     return JS_UNDEFINED;
 }
 
index a11407e069934e1e8a05f7355fa7f7e4cc526caa..14bcc06d307ed8bcd0056a829f3c5867fc212240 100644 (file)
@@ -511,6 +511,14 @@ function test_typed_array()
     assert(a.toString(), "1,2,3,4");
     a.set([10, 11], 2);
     assert(a.toString(), "1,2,10,11");
+
+    // https://github.com/quickjs-ng/quickjs/issues/1208
+    buffer = new ArrayBuffer(16);
+    a = new Uint8Array(buffer);
+    a.fill(42);
+    assert(a[0], 42);
+    buffer.transfer();
+    assert(a[0], undefined);
 }
 
 /* return [s, line_num, col_num] where line_num and col_num are the