From 68caa5f226401a7e148fb8f7358d4688c71372aa Mon Sep 17 00:00:00 2001 From: Fabrice Bellard Date: Sat, 21 Mar 2026 12:23:53 +0100 Subject: [PATCH] fixed TypedArray constructor semantics which removes a buffer overflow (#478) --- TODO | 2 +- quickjs.c | 57 +++++++++++++++++++++++++++------------------- test262_errors.txt | 2 -- 3 files changed, 35 insertions(+), 26 deletions(-) diff --git a/TODO b/TODO index 4e87a71..4385b3e 100644 --- a/TODO +++ b/TODO @@ -63,4 +63,4 @@ Test262o: 0/11262 errors, 463 excluded Test262o commit: 7da91bceb9ce7613f87db47ddd1292a2dda58b42 (es5-tests branch) Test262: -Result: 64/83341 errors, 2567 excluded, 5767 skipped +Result: 62/83341 errors, 2567 excluded, 5767 skipped diff --git a/quickjs.c b/quickjs.c index 727cf8d..4422544 100644 --- a/quickjs.c +++ b/quickjs.c @@ -58148,38 +58148,54 @@ static JSValue js_typed_array_constructor(JSContext *ctx, if (JS_VALUE_GET_TAG(argv[0]) != JS_TAG_OBJECT) { if (JS_ToIndex(ctx, &len, argv[0])) return JS_EXCEPTION; + obj = js_create_from_ctor(ctx, new_target, classid); + if (JS_IsException(obj)) + return JS_EXCEPTION; buffer = js_array_buffer_constructor1(ctx, JS_UNDEFINED, len << size_log2, NULL); if (JS_IsException(buffer)) - return JS_EXCEPTION; + goto fail; offset = 0; } else { JSObject *p = JS_VALUE_GET_OBJ(argv[0]); if (p->class_id == JS_CLASS_ARRAY_BUFFER || p->class_id == JS_CLASS_SHARED_ARRAY_BUFFER) { - abuf = p->u.array_buffer; - if (JS_ToIndex(ctx, &offset, argv[1])) + obj = js_create_from_ctor(ctx, new_target, classid); + if (JS_IsException(obj)) return JS_EXCEPTION; - if (abuf->detached) - return JS_ThrowTypeErrorDetachedArrayBuffer(ctx); - if ((offset & ((1 << size_log2) - 1)) != 0 || - offset > abuf->byte_length) - return JS_ThrowRangeError(ctx, "invalid offset"); + if (JS_ToIndex(ctx, &offset, argv[1])) + goto fail; + if ((offset & ((1 << size_log2) - 1)) != 0) + goto invalid_offset; + abuf = p->u.array_buffer; if (JS_IsUndefined(argv[2])) { + if (abuf->detached) { + JS_ThrowTypeErrorDetachedArrayBuffer(ctx); + goto fail; + } + if (offset > abuf->byte_length) { + invalid_offset: + JS_ThrowRangeError(ctx, "invalid offset"); + goto fail; + } track_rab = array_buffer_is_resizable(abuf); - if (!track_rab) + if (!track_rab) { if ((abuf->byte_length & ((1 << size_log2) - 1)) != 0) goto invalid_length; + } len = (abuf->byte_length - offset) >> size_log2; } else { if (JS_ToIndex(ctx, &len, argv[2])) - return JS_EXCEPTION; - if (abuf->detached) - return JS_ThrowTypeErrorDetachedArrayBuffer(ctx); + goto fail; + if (abuf->detached) { + JS_ThrowTypeErrorDetachedArrayBuffer(ctx); + goto fail; + } if ((offset + (len << size_log2)) > abuf->byte_length) { invalid_length: - return JS_ThrowRangeError(ctx, "invalid length"); + JS_ThrowRangeError(ctx, "invalid length"); + goto fail; } } buffer = JS_DupValue(ctx, argv[0]); @@ -58193,17 +58209,12 @@ static JSValue js_typed_array_constructor(JSContext *ctx, } } } - - obj = js_create_from_ctor(ctx, new_target, classid); - if (JS_IsException(obj)) { - JS_FreeValue(ctx, buffer); - return JS_EXCEPTION; - } - if (typed_array_init(ctx, obj, buffer, offset, len, track_rab)) { - JS_FreeValue(ctx, obj); - return JS_EXCEPTION; - } + if (typed_array_init(ctx, obj, buffer, offset, len, track_rab)) + goto fail; return obj; + fail: + JS_FreeValue(ctx, obj); + return JS_EXCEPTION; } static void js_typed_array_finalizer(JSRuntime *rt, JSValue val) diff --git a/test262_errors.txt b/test262_errors.txt index 6974d27..6ccde33 100644 --- a/test262_errors.txt +++ b/test262_errors.txt @@ -33,8 +33,6 @@ test262/test/staging/sm/Function/invalid-parameter-list.js:13: Test262Error: Exp test262/test/staging/sm/Function/invalid-parameter-list.js:13: strict mode: Test262Error: Expected a SyntaxError to be thrown but no exception was thrown at all test262/test/staging/sm/String/string-upper-lower-mapping.js:16: Test262Error: Expected SameValue(«"꟏"», «"꟎"») to be true test262/test/staging/sm/String/string-upper-lower-mapping.js:16: strict mode: Test262Error: Expected SameValue(«"꟏"», «"꟎"») to be true -test262/test/staging/sm/TypedArray/constructor-buffer-sequence.js:29: Test262Error: Expected a ExpectedError but got a Error -test262/test/staging/sm/TypedArray/constructor-buffer-sequence.js:29: strict mode: Test262Error: Expected a ExpectedError but got a Error test262/test/staging/sm/TypedArray/prototype-constructor-identity.js:17: Test262Error: Expected SameValue(«2», «6») to be true test262/test/staging/sm/TypedArray/prototype-constructor-identity.js:17: strict mode: Test262Error: Expected SameValue(«2», «6») to be true test262/test/staging/sm/async-functions/async-contains-unicode-escape.js:11: Test262Error: Expected a SyntaxError to be thrown but no exception was thrown at all