Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

"TypeError: out-of-bound numeric index" on typed arrays in strict mode #645

Closed
TooTallNate opened this issue Nov 4, 2024 · 4 comments · Fixed by #647
Closed

"TypeError: out-of-bound numeric index" on typed arrays in strict mode #645

TooTallNate opened this issue Nov 4, 2024 · 4 comments · Fixed by #647

Comments

@TooTallNate
Copy link
Contributor

QuickJS has an unexpected behavior (at least when compared with other JS engines), where it throws when a typed array is attempting to be set at a index that is out of bounds:

'use strict';
const a = new Uint8Array(1);
console.log(a[0] = 1);
console.log(a[1] = 2);
console.log(a);
$ qjs o.mjs 
1
TypeError: out-of-bound numeric index
    at <anonymous> (o.mjs:4:20)

Compared to other runtimes:

$ node o.mjs 
1
2
Uint8Array(1) [ 1 ]
$ bun o.mjs 
1
2
Uint8Array(1) [ 1 ]
$ deno run o.mjs 
1
2
Uint8Array(1) [ 1 ]

I believe the relevant part of the spec is here: TypedArraySetElement

It's not super clear to be if this is technically incorrect behavior or not (that is, I see that the function may result in a throw completion, but I don't see where that would happen based on the steps described).

I also found this 10 year old mailing list thread which seems relevant (but never seemed to reach a conclusion): https://esdiscuss.org/topic/should-assigning-to-out-of-bounds-elements-of-a-typed-array-throw-in-strict-mode-code

In practice, this is making the __toBinary() function defined by esbuild throw this out of bounds error in certain cases,
For reference:

var __toBinary = /* @__PURE__ */ (() => {
  var table = new Uint8Array(128);
  for (var i = 0; i < 64; i++)
    table[i < 26 ? i + 65 : i < 52 ? i + 71 : i < 62 ? i - 4 : i * 4 - 205] = i;
  return (base64) => {
    var n = base64.length, bytes = new Uint8Array((n - (base64[n - 1] == "=") - (base64[n - 2] == "=")) * 3 / 4 | 0);
    for (var i2 = 0, j = 0; i2 < n; ) {
      var c0 = table[base64.charCodeAt(i2++)], c1 = table[base64.charCodeAt(i2++)];
      var c2 = table[base64.charCodeAt(i2++)], c3 = table[base64.charCodeAt(i2++)];
      bytes[j++] = c0 << 2 | c1 >> 4;
      bytes[j++] = c1 << 4 | c2 >> 2;
      bytes[j++] = c2 << 6 | c3;
    }
    return bytes;
  };
})();

My vote would be to remove this behavior from QuickJS and make the behavior match other JS engines.

@saghul
Copy link
Contributor

saghul commented Nov 5, 2024

I'll dive in the spec, but aligning with other engines would likely be good here.

saghul added a commit that referenced this issue Nov 5, 2024
Relevant spec section: https://tc39.es/ecma262/multipage/ordinary-and-exotic-objects-behaviours.html#sec-typedarraysetelement

It should only throw if the backing buffer is detached, which test262
tests for.

Fixes: #645
@saghul
Copy link
Contributor

saghul commented Nov 5, 2024

PR: #647

It's interesting test262 doesn't seem to cover this. It does, however, cover the case of setting a numeric property on a TA where the backing array buffer is detached.

@saghul
Copy link
Contributor

saghul commented Nov 7, 2024

This is fixed as of #646

@saghul saghul closed this as completed Nov 7, 2024
@saghul saghul reopened this Nov 7, 2024
@saghul
Copy link
Contributor

saghul commented Nov 7, 2024

Sorry, my bad, strict mode!

saghul added a commit that referenced this issue Nov 7, 2024
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
saghul added a commit that referenced this issue Nov 7, 2024
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
@saghul saghul closed this as completed in e30da0e Nov 7, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants