Skip to content

Commit

Permalink
Don't throw oob exception when setting numeric indexes on TAs
Browse files Browse the repository at this point in the history
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: #645
  • Loading branch information
saghul committed Nov 7, 2024
1 parent 9c5c441 commit f84008a
Show file tree
Hide file tree
Showing 4 changed files with 21 additions and 23 deletions.
26 changes: 3 additions & 23 deletions quickjs.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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)
Expand Down
2 changes: 2 additions & 0 deletions tests/bug645/0.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
const u8 = new Uint8Array(1);
u8[100] = 123; // Should not throw.
9 changes: 9 additions & 0 deletions tests/bug645/1.js
Original file line number Diff line number Diff line change
@@ -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 }));
7 changes: 7 additions & 0 deletions tests/bug645/2.js
Original file line number Diff line number Diff line change
@@ -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 }));

0 comments on commit f84008a

Please sign in to comment.