Repository navigation
rc: a char or number cast to string reports its allocation; own: string length borrows (DefaultLib rc failures 20 -> 3) - #414
Merged
Merged
Conversation
…the casts apart `switch (c)` on a char with string cases casts `c` to a string once per case. That cast prints into a new block, but CastOp::getEffects reported an allocation only for a const array made an array and for a cast to `any`, so CSE merged the per-case casts into one. Under -mm=rc each case retains and releases its string, and with one string for all of them the first case's release freed it: every later case retained, compared and released freed memory, a use after free and a double free for each character that missed the first case. This is RegExp's constructor reading its flags in DefaultLib, and it was behind the regexp and replace failures under rc (regexp_indices, regexp_test2/3, string_match, string_matchAll, string_replace*, string_search): on the process heap the freed block usually still held the right text, so they failed some runs, spun, or corrupted the heap. getEffects now also reports an allocation for a cast to `string` that allocates, asking the same castToStringAllocates MLIRGen uses to mark the result owned; the predicate moves next to the op so both share it. Test 00switch_char_string_cases.ts (a flags-style switch in a loop). Without the fix it fails under rc with 0xC0000409 (heap corruption), compile and JIT. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`return box.text.length` was rejected under -mm=own ("'this value' borrows
a field and cannot be stored, returned or captured"): ts.StringLength was
not among the uses the ownership inference counts as borrows, so the
field's string was treated as taken. It reads the string and keeps
nothing, like ts.LengthOf already does for arrays.
Test own/own_string_length_borrow.ts (a field's string length returned
from a function, and a local's). Without the fix it does not compile.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR follows #413 and holds two commits:
-mm=ownfix.With them and the companion DefaultLib PR (ASDAlexander77/TypeScriptCompilerDefaultLib#15), DefaultLib under rc goes from 20 failing runs to 3. The 3 left are the known
sleep/weakref_basiclink errors.1. A number or char cast to
stringreports its allocationswitch (c)on a char with string cases castscto a string once per case, and each of those casts allocates a new string.CastOp::getEffectsreported an allocation for only two shapes: a const array cast to an array, and a cast toany. CSE therefore merged the per-case casts into one string.Under
-mm=rceach case retains and then releases its string. With one string shared by all cases:That is a use-after-free plus a double free for every character that misses the first case.
DefaultLib's
RegExpconstructor reads its flags exactly this way, so the bug was behind these tests:regexp_indices,regexp_test2/3,string_match,string_matchAll(which spun),string_replace*andstring_search. On the process heap a freed block usually still holds the right text, so they failed only some runs, looped, or corrupted the heap.The fix makes
getEffectsreport an allocation for any cast tostringthat allocates. It usescastToStringAllocates, the same predicate MLIRGen uses to mark the result as owned. That predicate moves next to the op so both places share it.Test:
00switch_char_string_cases.ts. Without the fix it fails under rc with 0xC0000409 (heap corruption) on both the exe and the JIT build, and passes under gc and none.2.
-mm=own: reading a string's length borrows itreturn box.text.lengthwas rejected with "borrows a field and cannot be stored, returned or captured".ts.StringLengthwas missing from the uses that own's inference counts as borrows, and anything missing from that list is treated as a take.ts.LengthOfwas already listed for arrays.Test:
own/own_string_length_borrow.ts. Without the fix it does not compile.How these were found
The flaky failures that #413 left were invisible to the quarantine heap, which never frees memory. So I temporarily replaced
ProcessHeap.hwith a guard-page heap. It is a diagnostic only and not part of this PR:Any overrun or use-after-free then faults at the instruction that does it, and a dump shows where. Two tests hit that heap on their first run:
fill, which is in the DefaultLib PR.With both fixed, the whole DefaultLib rc suite runs clean on that heap apart from the
sleep/weakref_basiclink errors.Results
sleep,weakref_basic)sleepandweakref_basic)Not in this PR
sleep.tsandweakref_basic.tsunder rc: they referenceGC_*symbols, and an rc program links no collector. This is a configuration question, not a memory bug.--ditogether with--opt: optimized DefaultLib tests fail to compile with "inlinable function call in a function with a DISubprogram location must have a debug location". I haven't looked into it yet.🤖 Generated with Claude Code