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
This commit is contained in:
Saúl Ibarra Corretgé 2024-11-05 09:11:05 +01:00
parent 9c5c441744
commit e30da0e8bc
4 changed files with 23 additions and 23 deletions

View file

@ -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;
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)

4
tests/bug645/0.js Normal file
View file

@ -0,0 +1,4 @@
"use strict";
const u8 = new Uint8Array(1);
u8[100] = 123; // Should not throw.

9
tests/bug645/1.js Normal file
View file

@ -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
tests/bug645/2.js Normal file
View file

@ -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 }));