From f84008a3e575d38698fd8192cd1df3163504edb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Tue, 5 Nov 2024 09:11:05 +0100 Subject: [PATCH] Don't throw oob exception when setting numeric indexes on TAs Relevant spec section: https://tc39.es/ecma262/multipage/ordinary-and-exotic-objects-behaviours.html#sec-typedarraysetelement It should only throw if Object.defineProperty is used and the TA is detached or OOB if a RAB is used. Fixes: https://github.com/quickjs-ng/quickjs/issues/645 --- quickjs.c | 26 +++----------------------- tests/bug645/0.js | 2 ++ tests/bug645/1.js | 9 +++++++++ tests/bug645/2.js | 7 +++++++ 4 files changed, 21 insertions(+), 23 deletions(-) create mode 100644 tests/bug645/0.js create mode 100644 tests/bug645/1.js create mode 100644 tests/bug645/2.js diff --git a/quickjs.c b/quickjs.c index a886ee23..858b29b9 100644 --- a/quickjs.c +++ b/quickjs.c @@ -1215,7 +1215,6 @@ static JSValue js_typed_array_constructor_ta(JSContext *ctx, JSValue src_obj, int classid, uint32_t len); static BOOL typed_array_is_oob(JSObject *p); -static BOOL typed_array_is_resizable(JSObject *p); static uint32_t typed_array_get_length(JSContext *ctx, JSObject *p); static JSValue JS_ThrowTypeErrorDetachedArrayBuffer(JSContext *ctx); static JSValue JS_ThrowTypeErrorArrayBufferOOB(JSContext *ctx); @@ -9034,14 +9033,9 @@ static int JS_SetPropertyValue(JSContext *ctx, JSValue this_obj, if (unlikely(idx >= (uint32_t)p->u.array.count)) { ta_out_of_bound: if (typed_array_is_oob(p)) - if (!(flags & JS_PROP_DEFINE_PROPERTY)) - return TRUE; // per spec: no OOB exception - // XXX(bnoordhuis) questionable but generic methods like - // Array.prototype.fill invoked on RABs can end up here - // and should, per spec, not error - if (typed_array_is_resizable(p)) - return TRUE; - return JS_ThrowTypeErrorOrFalse(ctx, flags, "out-of-bound numeric index"); + if (flags & JS_PROP_DEFINE_PROPERTY) + return JS_ThrowTypeErrorOrFalse(ctx, flags, "out-of-bound numeric index"); + return TRUE; // per spec: no OOB exception } p->u.array.u.double_ptr[idx] = d; break; @@ -51745,20 +51739,6 @@ static BOOL typed_array_is_oob(JSObject *p) return end > len; } -// |p| must be a typed array, *not* a DataView -static BOOL typed_array_is_resizable(JSObject *p) -{ - JSArrayBuffer *abuf; - JSTypedArray *ta; - - assert(p->class_id >= JS_CLASS_UINT8C_ARRAY); - assert(p->class_id <= JS_CLASS_FLOAT64_ARRAY); - - ta = p->u.typed_array; - abuf = ta->buffer->u.array_buffer; - return array_buffer_is_resizable(abuf); -} - /* WARNING: 'p' must be a typed array. Works even if the array buffer is detached */ static uint32_t typed_array_get_length(JSContext *ctx, JSObject *p) diff --git a/tests/bug645/0.js b/tests/bug645/0.js new file mode 100644 index 00000000..c6c5729d --- /dev/null +++ b/tests/bug645/0.js @@ -0,0 +1,2 @@ +const u8 = new Uint8Array(1); +u8[100] = 123; // Should not throw. diff --git a/tests/bug645/1.js b/tests/bug645/1.js new file mode 100644 index 00000000..8031be21 --- /dev/null +++ b/tests/bug645/1.js @@ -0,0 +1,9 @@ +import { assert, assertThrows } from "../assert.js"; +const ab = new ArrayBuffer(1); +const u8 = new Uint8Array(ab); +assert(!ab.detached); +// Detach the ArrayBuffer. +ab.transfer(); +assert(ab.detached); +u8[100] = 123; // Doesn't throw. +assertThrows(TypeError, () => Object.defineProperty(u8, "100", { value: 123 })); diff --git a/tests/bug645/2.js b/tests/bug645/2.js new file mode 100644 index 00000000..3076efa8 --- /dev/null +++ b/tests/bug645/2.js @@ -0,0 +1,7 @@ +import { assert, assertThrows } from "../assert.js"; +const ab = new ArrayBuffer(16, { maxByteLength: 32 }); +const u8 = new Uint8Array(ab, 16); +ab.resize(8); +assert(ab.byteLength, 8); +u8[1] = 123; // Doesn't throw. +assertThrows(TypeError, () => Object.defineProperty(u8, "1", { value: 123 }));