Skip to content

An invalid array length or a failed allocation stops the program (#483) - #489

Merged
ASDAlexander77 merged 1 commit into
mainfrom
fix-array-length-checks
Oct 4, 2026
Merged

ASDAlexander77 merged 1 commit into
mainfrom
fix-array-length-checks

Conversation

@ASDAlexander77

Copy link
Copy Markdown
Owner

Fixes #483 with the design chosen there: an invalid array length or a failed allocation stops the program, as a failing assert does - not an exception.

The bug

Array sizes were never checked. a.length = -1 made the length a huge unsigned size; a.length = 2^42 asked the allocator for a block it could not give, and growth zeroed the new slots through the null it got back - an access violation under every model since #482 (before it: the length ignored under gc, or stored with no block behind it).

The fix

TypeScript throws a RangeError for a length that is not an integer in [0, 2^32 - 1]. tslang now stops with Invalid array length (and Out of memory for a failed allocation), after flushing what the program printed, with the file and line ahead of time - the same mechanism as a failing assert. try/catch does not see it.

  • length = with a number (MLIRGen): checked to be >= 0, <= 2^32 - 1 and to survive the round trip through an index (no fraction, not NaN), before the conversion to an index drops what would show it.
  • Growth (ArrayLayout::ensureCapacity: push, unshift, splice, a longer length =): the needed length is at most 2^32 - 1 (a negative integer, sign-extended, is not), the byte count does not overflow, and the allocator gave a block.
  • A new array of a length (new A(n) for type A = number[]): the same checks.
  • AssertLogic's failure path is now shared by assert and a new mid-lowering check, and depends on LLVMCodeHelperBase only, so ArrayLayout can use it. assert lowers as before.

Tests

  • array-length/{negative, huge, fraction, negative_integer, new_negative}.ts, each under gc, rc, none and own (20 tests): the output must show printed before, then assertion failed: Invalid array length, and never the length: line after it.
  • 00array_length_valid.ts: lengths from a number, shrinking, growth, a new array of a length still work.
  • The Out of memory path has no test: a valid length just under the limit asks for about 32 GB, which under rc was granted (Windows commits lazily) and under gc ran past 30 seconds.

Gates

Gate Result
Windows Release suite (ctest -C Release -j 12 --timeout 300, staged default library) 3781 / 3781 passed
Linux (WSL, on main 2e91a62, ninja release, ctest -j 8 --timeout 300) 3766 / 3766 passed (1 pre-existing disabled test)
Default library rebuilt (release and debug) with this compiler, its suite gc 159/159, rc 158/159, none 158/159 in each of release/debug x compile/jit - the one failure is weakref_basic, gc-only by design (#420)

Closes #483

🤖 Generated with Claude Code

Array sizes were never checked. `a.length = -1` made the length a huge
unsigned size, `a.length = 2^42` asked the allocator for a block it
could not give, and growth zeroed the new slots through the null it got
back: an access violation in every model since #482, and before it, a
length ignored or stored with no block behind it.

TypeScript throws a RangeError for a length that is not an integer in
[0, 2^32 - 1]. tslang now stops the program instead, as a failing
assert does (the message, after the output printed before it, with the
file and line ahead of time):

- `length =` with a number checks it is >= 0, <= 2^32 - 1 and survives
  the round trip through an index (no fraction, not NaN), in MLIRGen,
  before the conversion drops what would show it;
- growth (ArrayLayout::ensureCapacity: push, unshift, splice, a longer
  `length =`) checks the length it needs is at most 2^32 - 1 - which a
  negative integer, sign-extended, is not - that the byte count does
  not overflow, and that the allocator gave a block ("Out of memory");
- a new array of a length (`new A(n)` for `type A = number[]`) checks
  the same.

"Invalid array length" is the message for a length, as TypeScript's
RangeError says; "Out of memory" for a failed allocation. Neither is an
exception: try/catch does not see them.

AssertLogic's failure path is shared by `assert` and the new
mid-lowering `check`, and it depends on LLVMCodeHelperBase only, so
ArrayLayout can use it.

Closes #483

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@ASDAlexander77
ASDAlexander77 merged commit 86a9ec3 into main Oct 4, 2026
2 checks passed
@ASDAlexander77
ASDAlexander77 deleted the fix-array-length-checks branch October 4, 2026 15:40
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 this pull request may close these issues.

Array length is unchecked: a negative or huge length= crashes or gives a wrong length, and failed allocations are not detected

1 participant