]> git.kaiwu.me - njs.git/commitdiff
Honor source view offset in same-type copies
authorDmitry Volyntsev <xeioex@nginx.com>
Fri, 12 Jun 2026 01:59:36 +0000 (18:59 -0700)
committerDmitry Volyntsev <xeioexception@gmail.com>
Tue, 16 Jun 2026 23:22:57 +0000 (16:22 -0700)
The same-type fast paths in the typed array constructor, slice(),
toReversed() and toSorted() copied from the start of the source buffer
instead of the view base, ignoring the source view's byte offset.  For an
offset or subarray source they copied the wrong elements and could read
past the view into adjacent data.

Use njs_typed_array_start()/njs_typed_array_offset() for the copy source.

src/njs_typed_array.c
src/test/njs_unit_test.c

index 508331bc065ee0e450fba446b83aca701acc4828..ce320a39d5dce6da6b5692767e6a32a4930dcd34 100644 (file)
@@ -155,7 +155,7 @@ njs_typed_array_alloc(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
             }
 
         } else {
-            memcpy(&buffer->u.u8[0], &src_tarray->buffer->u.u8[0], size);
+            memcpy(&buffer->u.u8[0], njs_typed_array_start(src_tarray), size);
         }
 
     } else if (!njs_is_array_buffer(value) && njs_is_object(value)) {
@@ -1008,7 +1008,9 @@ njs_typed_array_prototype_slice(njs_vm_t *vm, njs_value_t *args,
             start = start * element_size;
             count = count * element_size;
 
-            njs_slice_memcpy(&new_buffer->u.u8[0], &buffer->u.u8[start], count);
+            njs_slice_memcpy(&new_buffer->u.u8[0],
+                             &buffer->u.u8[njs_typed_array_offset(array) + start],
+                             count);
 
         } else {
             for (i = 0; i < count; i++) {
@@ -1647,7 +1649,7 @@ njs_typed_array_prototype_reverse(njs_vm_t *vm, njs_value_t *args,
             return NJS_ERROR;
         }
 
-        memcpy(&array->buffer->u.u8[0], &self->buffer->u.u8[0],
+        memcpy(&array->buffer->u.u8[0], njs_typed_array_start(self),
                self->byte_length);
     }
 
@@ -1951,7 +1953,7 @@ njs_typed_array_prototype_sort(njs_vm_t *vm, njs_value_t *args,
             return NJS_ERROR;
         }
 
-        memcpy(&array->buffer->u.u8[0], &self->buffer->u.u8[0],
+        memcpy(&array->buffer->u.u8[0], njs_typed_array_start(self),
                self->byte_length);
     }
 
index 8cc0e8bebb7ed66b9268133dc6ae00e46d48ea44..0645e8b0fc7e1a7930c8c51410767c060c56a787 100644 (file)
@@ -7326,6 +7326,28 @@ static njs_unit_test_t  njs_test[] =
               "           return [a.toReversed(), a].toString() === '1,2,3,3,2,1'})"),
       njs_str("true") },
 
+    /* Same-type copies must honor the source view offset. */
+
+    { njs_str(NJS_TYPED_ARRAY_LIST
+              ".every(v=>{var a = (new v([0,1,2,3,4])).subarray(2);"
+              "           return (new v(a)).toString() === '2,3,4'})"),
+      njs_str("true") },
+
+    { njs_str(NJS_TYPED_ARRAY_LIST
+              ".every(v=>{var a = (new v([0,1,2,3,4])).subarray(2);"
+              "           return a.slice(1, 3).toString() === '3,4'})"),
+      njs_str("true") },
+
+    { njs_str(NJS_TYPED_ARRAY_LIST
+              ".every(v=>{var a = (new v([0,1,2,3,4])).subarray(2);"
+              "           return a.toReversed().toString() === '4,3,2'})"),
+      njs_str("true") },
+
+    { njs_str(NJS_TYPED_ARRAY_LIST
+              ".every(v=>{var a = (new v([0,3,2,1,4])).subarray(2);"
+              "           return a.toSorted().toString() === '1,2,4'})"),
+      njs_str("true") },
+
     { njs_str("Uint8Array.prototype.sort.call(1)"),
       njs_str("TypeError: this is not a typed array") },