From: Dmitry Volyntsev Date: Thu, 24 Sep 2026 22:53:30 +0000 (-0700) Subject: Buffer: reject oversized QJS alloc() and concat() sizes X-Git-Tag: 1.0.2~20 X-Git-Url: https://git.kaiwu.me/?a=commitdiff_plain;h=5832bed4ecc1cb4cb199594ef8091f9a5b7b6195;p=njs.git Buffer: reject oversized QJS alloc() and concat() sizes Buffer.alloc() and Buffer.concat() converted sizes with JS_ToUint32(), which wraps values modulo 2^32: Buffer.alloc(2 ** 32 + 16) returned a 16-byte buffer. Use JS_ToIndex() instead, so these sizes throw a RangeError. In Buffer.concat(), the total length of the list could also overflow the 32-bit accumulator. Keep it in 64 bits and check it against QJS_BUFFER_MAX_LENGTH. The overflow now throws a RangeError instead of a TypeError, as in Node.js. --- diff --git a/src/qjs_buffer.c b/src/qjs_buffer.c index 9359a80e..65c57216 100644 --- a/src/qjs_buffer.c +++ b/src/qjs_buffer.c @@ -347,14 +347,14 @@ qjs_bufferobj_alloc(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int ignored) { JSValue buffer, ret; - uint32_t size; + uint64_t size; if (!JS_IsNumber(argv[0])) { return JS_ThrowTypeError(ctx, "The \"size\" argument must be of type" " number"); } - if (JS_ToUint32(ctx, &size, argv[0])) { + if (JS_ToIndex(ctx, &size, argv[0])) { return JS_EXCEPTION; } @@ -434,8 +434,9 @@ qjs_buffer_concat(JSContext *ctx, JSValueConst this_val, int argc, { u_char *p; size_t n; + uint64_t len; JSValue list, length, val, ret, buffer; - uint32_t i, len, list_len; + uint32_t i, list_len; njs_str_t buf, dst; list = argv[0]; @@ -472,16 +473,16 @@ qjs_buffer_concat(JSContext *ctx, JSValueConst this_val, int argc, " instance of Buffer or Uint8Array", i); } - if ((SIZE_MAX - len) < buf.length) { - return JS_ThrowTypeError(ctx, - "Total size of buffers is too large"); + if (buf.length > QJS_BUFFER_MAX_LENGTH - len) { + return JS_ThrowRangeError(ctx, + "Total size of buffers is too large"); } len += buf.length; } } else { - if (JS_ToUint32(ctx, &len, argv[1])) { + if (JS_ToIndex(ctx, &len, argv[1])) { return JS_EXCEPTION; } } diff --git a/test/buffer.t.js b/test/buffer.t.js index 1d749493..21fdedfd 100644 --- a/test/buffer.t.js +++ b/test/buffer.t.js @@ -35,6 +35,30 @@ let alloc_tsuite = { }; +let oversized_tsuite = { + name: "Buffer allocation size tests", + skip: () => (!has_buffer() || !has_njs()), + T: async (params) => { + assert.throws(RangeError, () => { + if (params.method === 'alloc') { + Buffer.alloc(params.size); + + } else { + Buffer.concat([], params.size); + } + }); + + return 'SUCCESS'; + }, + tests: [ + { method: 'alloc', size: 0x100000000 }, + { method: 'alloc', size: 0x100000010 }, + { method: 'concat', size: 0x100000000 }, + { method: 'concat', size: 0x100000010 }, + ], +}; + + let fromObject_tsuite = { name: "Buffer.from() array-like length tests", skip: () => (!has_buffer()), @@ -1158,6 +1182,7 @@ let writeGeneric_tsuite = { run([ alloc_tsuite, + oversized_tsuite, fromObject_tsuite, fromObjectLarge_tsuite, byteLength_tsuite,