From adf66801ec632786838f6f3e98e4db38d6be77c1 Mon Sep 17 00:00:00 2001 From: Dmitry Volyntsev Date: Fri, 22 May 2026 17:07:47 -0700 Subject: [PATCH] Fixed memory overlap checks --- src/njs_buffer.c | 6 ++---- src/njs_str.h | 12 ++++++++++++ src/njs_typed_array.c | 3 +-- src/qjs_buffer.c | 8 +++----- test/buffer.t.js | 20 ++++++++++++++++++-- 5 files changed, 36 insertions(+), 13 deletions(-) diff --git a/src/njs_buffer.c b/src/njs_buffer.c index 49ead277..622d9068 100644 --- a/src/njs_buffer.c +++ b/src/njs_buffer.c @@ -2007,7 +2007,7 @@ njs_buffer_prototype_copy(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_int_t ret; njs_value_t *val1, *val2; njs_typed_array_t *source, *target; - njs_array_buffer_t *buffer, *array; + njs_array_buffer_t *buffer; val1 = njs_argument(args, 0); val2 = njs_arg(args, nargs, 1); @@ -2041,11 +2041,9 @@ njs_buffer_prototype_copy(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, return NJS_ERROR; } - array = njs_typed_array_buffer(source); - size = njs_min(trg_end - trg, src_end - src); - if (buffer->u.data != array->u.data) { + if (!njs_memory_overlaps(trg, size, src, size)) { memcpy(trg, src, size); } else { diff --git a/src/njs_str.h b/src/njs_str.h index e64d88a9..1eb46aaf 100644 --- a/src/njs_str.h +++ b/src/njs_str.h @@ -85,6 +85,18 @@ njs_cpymem(dst, src, n) \ (((u_char *) memcpy(dst, src, n)) + (n)) +njs_inline njs_bool_t +njs_memory_overlaps(const u_char *p1, size_t n1, const u_char *p2, size_t n2) +{ + uintptr_t s1, s2; + + s1 = (uintptr_t) p1; + s2 = (uintptr_t) p2; + + return (s1 < s2 + n2 && s2 < s1 + n1); +} + + #define \ njs_strncmp(s1, s2, n) \ strncmp((char *) s1, (char *) s2, n) diff --git a/src/njs_typed_array.c b/src/njs_typed_array.c index f74f175f..d007285a 100644 --- a/src/njs_typed_array.c +++ b/src/njs_typed_array.c @@ -920,8 +920,7 @@ njs_typed_array_prototype_fill(njs_vm_t *vm, njs_value_t *args, static void njs_slice_memcpy(uint8_t *dst, const uint8_t *src, size_t len) { - if (dst + len <= src || dst >= src + len) { - /* no overlap: can use memcpy */ + if (!njs_memory_overlaps(dst, len, src, len)) { memcpy(dst, src, len); } else { diff --git a/src/qjs_buffer.c b/src/qjs_buffer.c index 2243822d..b870be91 100644 --- a/src/qjs_buffer.c +++ b/src/qjs_buffer.c @@ -582,8 +582,8 @@ qjs_buffer_fill(JSContext *ctx, JSValueConst buffer, JSValueConst fill, return buffer; } - if (src.start >= (dst.start + dst.length) - || dst.start >= (dst.start + dst.length)) + if (!njs_memory_overlaps(dst.start + offset, end - offset, + src.start, src.length)) { while (offset < end) { n = njs_min(src.length, end - offset); @@ -862,9 +862,7 @@ qjs_buffer_prototype_copy(JSContext *ctx, JSValueConst this_val, int argc, size = njs_min(src.length, target.length); - if (src.start >= (target.start + size) - || target.start >= (src.start + size)) - { + if (!njs_memory_overlaps(target.start, size, src.start, size)) { memcpy(target.start, src.start, size); } else { diff --git a/test/buffer.t.js b/test/buffer.t.js index d02dca1f..c10b0180 100644 --- a/test/buffer.t.js +++ b/test/buffer.t.js @@ -254,11 +254,18 @@ let fill_tsuite = { name: "buf.fill() tests", skip: () => (!has_buffer()), T: async (params) => { + let value = params.value; + + if (params.value_from_buf) { + value = params.buf.subarray(params.value_from_buf[0], + params.value_from_buf[1]); + } + if (params.detach_value) { - detach(params.value.buffer); + detach(value.buffer); } - let r = params.buf.fill(params.value, params.offset, params.end); + let r = params.buf.fill(value, params.offset, params.end); if (r.toString() !== params.expected) { throw Error(`unexpected output "${r.toString()}" != "${params.expected}"`); @@ -286,6 +293,15 @@ let fill_tsuite = { { buf: Buffer.from(new Uint8Array([0x60, 0x61, 0x62, 0x63]).buffer, 1), value: Buffer.from('def'), expected: 'def' }, + { buf: Buffer.from('0123456789'), + value_from_buf: [0, 4], + offset: 6, + expected: '0123450123' }, + { buf: Buffer.from('0123456789'), + value_from_buf: [0, 4], + offset: 2, + end: 8, + expected: '0101230189' }, ], }; -- 2.47.3