From: Dmitry Volyntsev Date: Fri, 12 Jun 2026 01:59:36 +0000 (-0700) Subject: Honor source view offset in same-type copies X-Git-Tag: 1.0.0~1 X-Git-Url: http://git.kaiwu.me/postgresql/log/contrib/postgres_fdw/static/gitweb.js?a=commitdiff_plain;h=210bd6b161a84930d4d6217086d5be7b51758a41;p=njs.git Honor source view offset in same-type copies 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. --- diff --git a/src/njs_typed_array.c b/src/njs_typed_array.c index 508331bc..ce320a39 100644 --- a/src/njs_typed_array.c +++ b/src/njs_typed_array.c @@ -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); } diff --git a/src/test/njs_unit_test.c b/src/test/njs_unit_test.c index 8cc0e8be..0645e8b0 100644 --- a/src/test/njs_unit_test.c +++ b/src/test/njs_unit_test.c @@ -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") },