From 1ab49722468dd6bcf0b0e9c5422351efce25544e Mon Sep 17 00:00:00 2001 From: Nick Vatamaniuc Date: Sun, 29 Jun 2025 13:50:55 -0400 Subject: [PATCH] For TypedArrays read byteOffset before getting start and final Previously, in issue #418 and pr #417 I misread the spec that in `subarray` we should be able to access the `byteOffset` from a detached buffer. Thinking more about it, something didn't seem right and I started a discussion in the TC39 group [1]. It turns out we shouldn't be able to read the ``byteOffset`` from detched buffers. Instead, the spec says we should just read the `byteOffset` value before we access `start` and `finish`. In the test262 test [2] the buffer is detached when accessing the `end` inside the `valueOf()` conversion, and the test expects to see the `byteOffset` before it was detached. So to fix it, ensure we access and save the `byteOffset` value first, then get the `start` and `finish`. [1] https://es.discourse.group/t/typedarray-subarray-byteoffset-with-detached-buffers/2381 [2] https://github.com/tc39/test262/blob/main/test/built-ins/TypedArray/prototype/subarray/byteoffset-with-detached-buffer.js --- quickjs.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/quickjs.c b/quickjs.c index caad931..9992d35 100644 --- a/quickjs.c +++ b/quickjs.c @@ -54097,14 +54097,24 @@ static JSValue js_typed_array_subarray(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { JSValueConst args[4]; - JSValue arr, ta_buffer; - JSTypedArray *ta; + JSValue arr, byteOffset, ta_buffer; JSObject *p; - int len, start, final, count, shift, offset; + int len, start, final, count, shift, byte_offset, offset; p = get_typed_array(ctx, this_val, 0); if (!p) goto exception; + + /* Fetch byteOffset first, then access start and final. It's technically + possible for the buffer to be detached when accessing start of final, by + way of `valueOf()` for instance, and the spec indicates we should preserve + the byteOffset value from before it might be detached */ + byteOffset = js_typed_array_get_byteOffset(ctx, this_val, 0); + if (JS_IsException(byteOffset)) + goto exception; + byte_offset = JS_VALUE_GET_INT(byteOffset); + JS_FreeValue(ctx, byteOffset); + len = p->u.array.count; if (JS_ToInt32Clamp(ctx, &start, argv[0], 0, len, len)) goto exception; @@ -54116,9 +54126,7 @@ static JSValue js_typed_array_subarray(JSContext *ctx, JSValueConst this_val, } count = max_int(final - start, 0); shift = typed_array_size_log2(p->class_id); - ta = p->u.typed_array; - /* Read byteOffset (ta->offset) even if detached */ - offset = ta->offset + (start << shift); + offset = byte_offset + (start << shift); ta_buffer = js_typed_array_get_buffer(ctx, this_val, 0); if (JS_IsException(ta_buffer)) goto exception;