Skip to content

Copy owning elements by assignment, not memcpy; String.repeat stops one copy short - #14

Merged
ASDAlexander77 merged 2 commits into
mainfrom
rc-owning-copies
Sep 30, 2026
Merged

ASDAlexander77 merged 2 commits into
mainfrom
rc-owning-copies

Conversation

@ASDAlexander77

Copy link
Copy Markdown
Owner

Summary

Library-side fixes for the DefaultLib test failures under -mm=rc. This goes with ASDAlexander77/TypeScriptCompiler#413, which fixes the compiler side. Merge #413 first: the rc tests need both PRs.

Owning elements are copied by assignment, not memcpy

These places copied elements with memcpy/memmove:

  • Array.concat
  • Array.slice
  • Array.copyWithin
  • Set and Map growing their entries (resizeHelper)

Under rc, an element can own what it holds. Examples: a string built at run time, an any box, a Set<any> entry's value. A raw copy takes no reference, so the copy and the original both release the value. That freed it early and corrupted the heap:

  • set_union and set_symmetricDifference crashed at JIT teardown;
  • concat of non-literal strings double-freed.

Elements are now copied one assignment at a time. Each store takes and gives up references as usual. Under gc this is the same copy as before.

copyWithin still copies backwards when the ranges overlap that way, as memmove did. It also no longer copies past the end of the array.

String.repeat wrote one copy too many

repeat wrote count copies after the one that clone() had already placed. The last copy ran past the end of the string it had sized. It now writes count - 1.

Tests

  • New owning_copies.ts: non-literal strings through concat, slice and copyWithin, plus a growing Set and Map. The test uses non-literal strings on purpose: a literal is never freed, so it would hide the bug.
  • string_repeat.ts now asserts its results.

Results

With #413:

before after
rc, compile + JIT 52 of 314 runs failed 20 of 316 runs fail
gc, compile + JIT 157/157 158/158

The remaining rc failures are listed in #413 under "Not in this PR".

🤖 Generated with Claude Code

…ne copy short

Array.concat, slice and copyWithin, and Set and Map growing their entries,
copied elements with memcpy/memmove. Under -mm=rc an element can own what it
holds (a string built at run time, an `any` box, a Set<any> entry's value),
and a raw copy takes no reference to it: the copy and the original then both
release it, which freed it early and corrupted the heap - set_union and
set_symmetricDifference crashed at JIT teardown, and concat of non-literal
strings double-freed. The elements are now copied one assignment at a time,
which takes and gives up references as every store does and is the same copy
under gc. copyWithin copies backwards when the ranges overlap that way, as
memmove did, and no longer copies past the end of the array.

String.repeat wrote `count` copies after the one clone() had already placed,
running one copy past the end of the string it had sized; it now writes
count - 1.

New test owning_copies.ts (non-literal strings through concat, slice,
copyWithin, and a growing Set and Map; a literal is immortal and would hide
the bug), and string_repeat.ts now asserts its results. Needs the compiler
changes for `s.length = n`, rest-parameter packing and grown array slots
(TypeScriptCompiler PR) for the rc tests to pass.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
fill's loop ran `i <= end`, so it filled one element past the range, and
with the default `end = this.length` it wrote one element past the end of
the array it had just copied: a heap overrun, usually hidden by the
allocator rounding the block up, and the likely cause of array_fill's
intermittent 0xC0000374 under -mm=rc. A guard-page heap catches the write
every run. It now runs `i < end`.

array_fill.ts now asserts its results and adds `[1, 2, 3].fill(9, 1, 2)`,
which gave [1, 9, 9] before.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
@ASDAlexander77
ASDAlexander77 merged commit cb80992 into main Sep 30, 2026
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.

1 participant