Skip to content

Prevent crash when computing emit output paths - #4900

Merged
Jake Bailey (jakebailey) merged 14 commits into
mainfrom
copilot/fix-crash-getsourcefilepathinnewdir
Aug 19, 2026
Merged

Prevent crash when computing emit output paths#4900
Jake Bailey (jakebailey) merged 14 commits into
mainfrom
copilot/fix-crash-getsourcefilepathinnewdir

Conversation

Copilot AI commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

GetSourceFilePathInNewDir could panic when normalized path containment succeeded but the raw common-directory string was longer than the source path, causing an out-of-bounds slice.

  • Output path handling

    • Delegate to GetSourceFilePathInNewDirWorker, matching the TypeScript reference implementation’s canonical prefix behavior.
    • Remove the inconsistent structural containment check.
  • Regression coverage

    • Cover a source path equal to the common source directory, including its trailing separator.

Copilot AI and others added 4 commits August 13, 2026 22:17
Co-authored-by: DanielRosenwasser <972891+DanielRosenwasser@users.noreply.github.com>
Co-authored-by: DanielRosenwasser <972891+DanielRosenwasser@users.noreply.github.com>
Co-authored-by: DanielRosenwasser <972891+DanielRosenwasser@users.noreply.github.com>
Co-authored-by: DanielRosenwasser <972891+DanielRosenwasser@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix crash at GetSourceFilePathInNewDir Prevent crash when computing emit output paths Aug 13, 2026
@DanielRosenwasser

Copy link
Copy Markdown
Member

Copilot this really needs an integration/compiler test as well.

Co-authored-by: DanielRosenwasser <972891+DanielRosenwasser@users.noreply.github.com>

Copilot AI commented Aug 14, 2026

Copy link
Copy Markdown
Contributor Author

Copilot this really needs an integration/compiler test as well.

Added compiler regression coverage in 6e4cd80. The test reproduces the pre-fix slice bounds out of range panic and passes with the fix.

Comment on lines +2 to +4
// @rootDir: /a/K.ts
// @outDir: /a/out
// @useCaseSensitiveFileNames: false

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot why do these need to differ by casing for this test case?

You need to explain the motivation of this test case, especially in this test file.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The casing difference was unnecessary, so I removed it in a551473. The renamed test now uses identical source and rootDir paths and explains that the compiler-added trailing separator caused the old [8:7] slice panic. Commit 4465775 also clarifies that the file-valued rootDir is intentional malformed input.

Copilot AI and others added 2 commits August 17, 2026 17:54
Co-authored-by: DanielRosenwasser <972891+DanielRosenwasser@users.noreply.github.com>
Co-authored-by: DanielRosenwasser <972891+DanielRosenwasser@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Prevents emit-path crashes by aligning path relocation with the reference implementation.

Changes:

  • Delegate output-path computation to the shared worker.
  • Add unit and compiler regression coverage.
  • Add generated emit, type, and symbol baselines.
Show a summary per file
File Description
internal/outputpaths/outputpaths.go Delegates path computation to the shared worker.
internal/outputpaths/outputpaths_test.go Tests the reported trailing-separator case.
testdata/tests/cases/compiler/emitOutputPathWithSourceEqualToRootDir.ts Adds compiler regression coverage.
testdata/baselines/reference/compiler/emitOutputPathWithSourceEqualToRootDir.js Records emitted JavaScript.
testdata/baselines/reference/compiler/emitOutputPathWithSourceEqualToRootDir.symbols Records symbol output.
testdata/baselines/reference/compiler/emitOutputPathWithSourceEqualToRootDir.types Records inferred types.

Review details

💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.

  • Files reviewed: 6/6 changed files
  • Comments generated: 1
  • Review effort level: Balanced

sourceFilePath = sourceFilePath[len(commonSourceDirectory):]
}
return tspath.CombinePaths(newDirPath, sourceFilePath)
return GetSourceFilePathInNewDirWorker(fileName, newDirPath, currentDirectory, commonSourceDirectory, useCaseSensitiveFileNames)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot add a test with that example, ensure that it fails, and then fix up the worker appropriately.

Also investigate whether Strada/TypeScript 6.0 has the same issue and elaborate.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added the exact example as a unit test (TestGetSourceFilePathInNewDirCanonicalizationShrinksCommonDirectory), confirmed it panics with [13:9]/[11:9]-style slice bounds errors on the old code, and added an end-to-end compiler regression test (emitOutputPathWithCaseFoldingRootDir.ts) with @useCaseSensitiveFileNames: false that panics on the old worker and passes after the fix.

Fixed the worker to trim the common-directory prefix by rune count (via the canonicalized commonDir, which the prefix check already verified) instead of raw byte length, clamping to the end of the string — GetCanonicalFileName's case-folding preserves rune count even when it changes UTF-8 byte width (e.g. the Kelvin sign \u212Ak), so this can't panic.

Strada/TypeScript 6.0 doesn't hit this: getSourceFilePathInNewDirWorker uses sourceFilePath.substring(commonSourceDirectory.length), and JS's String.prototype.substring silently clamps out-of-range indices to the string's end rather than throwing, so the equivalent case there just produces an empty/short suffix instead of crashing.

Comment thread testdata/tests/cases/compiler/emitOutputPathWithCaseFoldingRootDir.ts Outdated
Comment thread internal/outputpaths/outputpaths.go Outdated
isSourceFileInCommonSourceDirectory := strings.HasPrefix(canonFile, commonDir)
if isSourceFileInCommonSourceDirectory {
sourceFilePath = sourceFilePath[len(commonSourceDirectory):]
// The reference implementation strips the prefix by slicing on

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Delete this massive overcomplicated comment and replace with just

// Use `trimRunePrefix` instead of raw slice to support length mismatches caused by case-folding, eg, of the kelvin sign '\u212A' (where two runes case fold into one) in `commonDir`

Also:
Copilot Is there anywhere else in our codebase we're doing a basic slice on case-folded paths using non-case-folded indexes that has a similar error? This feels like a footgun that we didn't anticipate in a straight port that has to have cropped up in more places than just here, which makes me think we can't be just slicing strings based on the lengths of other strings-with-differing-case-fold-state willy-nilly.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Replaced with tspath.TrimFilePathPrefix (see internal/tspath/path.go) — a shared helper that both outputpaths.go and other call sites now use, instead of inlining trimRunePrefix with a bespoke comment.

Yes — found two more occurrences of the exact same footgun (canonical-prefix check via GetCanonicalFileName, then slicing the raw path by len(rawPrefix)):

  • internal/ls/string_completions.go's tryRemoveDirectoryPrefix (used for typings-directory completions)
  • internal/ls/file_rename.go's createPathUpdater (used by rename-file refactoring, via tspath.StartsWithDirectory + path[len(oldPath):])

Both are ported verbatim from Strada's tryRemovePrefix/equivalent JS code, which relies on substring's clamping — so yes, this pattern shows up wherever we ported string-slicing logic that assumed JS's forgiving substring. Fixed both to use tspath.TrimFilePathPrefix in b12e1e2.

Comment thread internal/outputpaths/outputpaths.go Outdated

// trimRunePrefix returns the suffix of s after skipping up to runeCount runes,
// clamping to the end of s if it has fewer runes than runeCount.
func trimRunePrefix(s string, runeCount int) string {

@weswigham Wesley Wigham (weswigham) Aug 18, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot Is there really no golang builtin method for slicing a string by rune count like this? Or just, like, a case-insensitivity-respecting strings.CutPrefix that already handles this? Minimally, reusing existing helpers and operating at a slightly higher level of abstraction, I feel like it could be something like (in tspath):

func TrimFilePathPrefix(path string, prefix string, useCaseSensitiveFileNames bool) string {
    // fast path, case-sensitive comparison
    caseMatchedRes, caseMatchedFound := strings.CutPrefix(path, prefix)
    if caseMatchedFound || useCaseSensitiveFileNames { return caseMatchedRes }

    canonPrefix := GetCanonicalFileName(prefix, false)
    res, found := strings.CutPrefix(GetCanonicalFileName(path, false), canonPrefix)
    if found {
        // `path` is non-canonical (potentially uppercased), and we found a case-differing match.
        // Returning `res` would implicitly canonicalize the result, but we also can't just slice based on the length of `prefix` because of case-folding byte count differences (e.g. the Kelvin sign '\u212A' folds to the single-byte 'k')
        prefixRuneLen := utf8.RuneCountInString(canonPrefix)
        runeCount := 0
        for idx, _ := range path { // leverage rune iteration to identify rune-based slice point
            runeCount++
            if prefixRuneLen == runeCount { return path[idx:] } // This is silly, why is there no stdlib method for slicing a string based on rune indices
        }
        return ""
    }
    return path
}

There some reason that doesn't work?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That design works and is basically what I implemented in 2d688cftspath.TrimFilePathPrefix(path, prefix, useCaseSensitiveFileNames) (string, bool), with the case-sensitive fast path via strings.CutPrefix and a rune-indexed trim for the case-insensitive path (I named the helper trimRuneCount instead of inlining the loop).

No stdlib rune-count slicing helper — strings/utf8 don't expose one; the manual DecodeRuneInString loop (or []rune(s)[n:], which is worse since it copies/allocates the whole string) is the idiomatic way to do this in Go.

Copilot AI and others added 2 commits August 18, 2026 21:39
Co-authored-by: weswigham <2932786+weswigham@users.noreply.github.com>
…e one code path

Co-authored-by: weswigham <2932786+weswigham@users.noreply.github.com>
Co-authored-by: weswigham <2932786+weswigham@users.noreply.github.com>
@weswigham

Copy link
Copy Markdown
Member

Copilot can you find and add regression tests for the new sites you updated to use TrimFilePathPrefix that prove the necessity of the changes to fix crashes?

Co-authored-by: weswigham <2932786+weswigham@users.noreply.github.com>

Copilot AI commented Aug 18, 2026

Copy link
Copy Markdown
Contributor Author

Copilot can you find and add regression tests for the new sites you updated to use TrimFilePathPrefix that prove the necessity of the changes to fix crashes?

Added in c0521eb: TestTryRemoveDirectoryPrefixCaseFoldingShrinksPrefix (internal/ls/string_completions_test.go) and TestCreatePathUpdaterCaseFoldingShrinksOldPath (internal/ls/file_rename_test.go). Both use a Kelvin-sign prefix/oldPath whose raw byte length (15) exceeds the canonically-equal path's byte length (12); I verified each panics with slice bounds out of range [15:12] against the pre-fix code and passes with the TrimFilePathPrefix-based fix.

@DanielRosenwasser

Copy link
Copy Markdown
Member

TypeScript Bot (@typescript-bot) perf test this

@typescript-automation

typescript-automation Bot commented Aug 19, 2026

Copy link
Copy Markdown

Starting jobs; this comment will be updated as builds start and complete.

Command Status Results
perf test this ✅ Started 👀 Results

@typescript-automation

Copy link
Copy Markdown

Daniel Rosenwasser (@DanielRosenwasser)
The results of the perf run you requested are in!

Here they are:

tsc

Comparison Report - baseline..pr
Metric baseline pr Delta Best Worst p-value
Compiler-Unions - native
Errors 41 41 ~ ~ ~ p=1.000 n=12
Symbols 115,480 115,480 ~ ~ ~ p=1.000 n=12
Types 96,945 96,945 ~ ~ ~ p=1.000 n=12
Memory Used 148,531k (± 0.40%) 148,825k (± 0.44%) ~ 146,735k 149,948k p=0.347 n=12
Memory Allocs 2,272,074 (± 0.01%) 2,270,769 (± 0.00%) -1,306 (- 0.06%) 2,270,516 2,271,090 p=0.000 n=12
Config Time 0.000s 0.000s ~ ~ ~ p=1.000 n=12
Parse Time 0.051s (± 2.75%) 0.049s (± 3.17%) ~ 0.046s 0.053s p=0.141 n=12
Bind Time 0.014s (± 8.23%) 0.017s (±13.75%) ~ 0.012s 0.022s p=0.252 n=12
Check Time 0.593s (± 1.09%) 0.587s (± 0.58%) ~ 0.580s 0.596s p=0.131 n=12
Emit Time 0.326s (± 1.88%) 0.330s (± 1.92%) ~ 0.306s 0.342s p=0.213 n=12
Total Time 0.992s (± 0.92%) 0.990s (± 0.79%) ~ 0.959s 1.003s p=0.875 n=12
angular-1 - native
Errors 3 3 ~ ~ ~ p=1.000 n=12
Symbols 847,093 (± 0.06%) 847,387 (± 0.07%) ~ 844,855 848,247 p=0.291 n=12
Types 249,858 (± 0.00%) 249,860 (± 0.00%) ~ 249,856 249,868 p=0.701 n=12
Memory Used 793,476k (± 0.05%) 794,140k (± 0.07%) ~ 792,906k 795,343k p=0.054 n=12
Memory Allocs 13,037,064 (± 0.06%) 12,949,416 (± 0.01%) -87,648 (- 0.67%) 12,945,627 12,956,132 p=0.000 n=12
Config Time 0.020s (± 1.23%) 0.021s (± 4.74%) ~ 0.020s 0.024s p=0.137 n=12
Parse Time 0.358s (± 1.70%) 0.348s (± 3.36%) ~ 0.317s 0.375s p=0.224 n=12
Bind Time 0.077s (± 8.32%) 0.081s (±10.18%) ~ 0.073s 0.119s p=0.161 n=12
Check Time 0s 0s ~ ~ ~ p=1.000 n=12
Emit Time 1.960s (± 0.82%) 1.986s (± 1.18%) ~ 1.937s 2.067s p=0.091 n=12
Total Time 2.434s (± 0.95%) 2.457s (± 1.25%) ~ 2.398s 2.564s p=0.259 n=12
mui-docs - native
Errors 11,273 (± 0.04%) 11,277 (± 0.04%) ~ 11,260 11,282 p=0.145 n=12
Symbols 4,592,664 4,592,664 ~ ~ ~ p=1.000 n=12
Types 1,636,666 1,636,666 ~ ~ ~ p=1.000 n=12
Memory Used 5,568,032k (± 0.03%) 5,566,422k (± 0.03%) ~ 5,562,227k 5,572,964k p=0.219 n=12
Memory Allocs 53,330,069 (± 0.04%) 53,322,545 (± 0.03%) ~ 53,276,694 53,379,576 p=0.514 n=12
Config Time 0.019s 0.019s ~ ~ ~ p=1.000 n=12
Parse Time 0.670s (± 1.83%) 0.669s (± 2.43%) ~ 0.627s 0.721s p=0.385 n=12
Bind Time 0.002s (±13.40%) 0.003s (±13.14%) ~ 0.002s 0.003s p=1.000 n=12
Check Time 20.275s (± 0.38%) 20.246s (± 0.40%) ~ 20.057s 20.388s p=0.887 n=12
Emit Time 0.540s (± 3.05%) 0.543s (± 3.38%) ~ 0.516s 0.577s p=0.503 n=12
Total Time 22.424s (± 0.40%) 22.401s (± 0.33%) ~ 22.241s 22.520s p=0.989 n=12
strada-build-src - native
Errors 0 0 ~ ~ ~ p=1.000 n=12
Symbols 1,394,339 1,394,339 ~ ~ ~ p=1.000 n=12
Types 443,465 443,465 ~ ~ ~ p=1.000 n=12
Memory Used 1,648,537k (± 0.32%) 1,649,114k (± 0.29%) ~ 1,632,342k 1,662,618k p=0.977 n=12
Memory Allocs 97,229,114 (± 0.05%) 97,075,366 (± 0.04%) -153,748 (- 0.16%) 96,988,117 97,150,890 p=0.000 n=12
Config Time 0.004s (± 9.45%) 0.005s (±10.14%) ~ 0.004s 0.006s p=0.109 n=12
Parse Time 0.237s (± 3.09%) 0.240s (± 2.47%) ~ 0.226s 0.253s p=0.485 n=12
Bind Time 0.000s 0.000s ~ ~ ~ p=1.000 n=12
Check Time 2.146s (± 0.48%) 2.145s (± 0.33%) ~ 2.125s 2.162s p=0.899 n=12
Emit Time 0.357s (± 5.73%) 0.337s (± 4.89%) ~ 0.297s 0.380s p=0.183 n=12
Total Time 29.852s (± 0.69%) 29.779s (± 0.39%) ~ 29.535s 30.103s p=0.713 n=12
strada-compiler - native
Errors 0 0 ~ ~ ~ p=1.000 n=12
Symbols 337,586 337,586 ~ ~ ~ p=1.000 n=12
Types 198,869 198,869 ~ ~ ~ p=1.000 n=12
Memory Used 319,661k (± 0.09%) 319,586k (± 0.03%) ~ 319,285k 319,797k p=0.660 n=12
Memory Allocs 4,676,492 (± 0.01%) 4,674,175 (± 0.01%) -2,317 (- 0.05%) 4,673,302 4,675,085 p=0.000 n=12
Config Time 0.001s 0.001s ~ ~ ~ p=1.000 n=12
Parse Time 0.114s (± 3.66%) 0.116s (± 4.54%) ~ 0.102s 0.126s p=0.434 n=12
Bind Time 0.000s 0.000s ~ ~ ~ p=1.000 n=12
Check Time 1.031s (± 0.52%) 1.032s (± 0.47%) ~ 1.024s 1.046s p=0.921 n=12
Emit Time 0.145s (±10.38%) 0.136s (±11.29%) ~ 0.098s 0.162s p=0.173 n=12
Total Time 1.342s (± 0.84%) 1.335s (± 1.01%) ~ 1.299s 1.366s p=0.600 n=12
ts-pre-modules - native
Errors 87 87 ~ ~ ~ p=1.000 n=12
Symbols 305,317 305,317 ~ ~ ~ p=1.000 n=12
Types 181,984 181,984 ~ ~ ~ p=1.000 n=12
Memory Used 277,212k (± 0.03%) 277,290k (± 0.03%) ~ 277,102k 277,561k p=0.235 n=12
Memory Allocs 1,644,200 (± 0.01%) 1,643,040 (± 0.01%) -1,160 (- 0.07%) 1,642,507 1,643,769 p=0.000 n=12
Config Time 0.000s (±217.90%) 0.000s (±217.90%) ~ 0.000s 0.001s p=1.000 n=12
Parse Time 0.098s (± 3.80%) 0.097s (± 5.48%) ~ 0.083s 0.115s p=0.467 n=12
Bind Time 0.036s (±10.98%) 0.040s (±13.50%) ~ 0.028s 0.053s p=0.201 n=12
Check Time 0.828s (± 0.58%) 0.829s (± 0.75%) ~ 0.817s 0.843s p=0.598 n=12
Emit Time 0.000s 0.000s ~ ~ ~ p=1.000 n=12
Total Time 0.977s (± 0.88%) 0.981s (± 0.98%) ~ 0.958s 1.008s p=0.832 n=12
vscode - native
Errors 0 0 ~ ~ ~ p=1.000 n=12
Symbols 7,826,718 7,826,718 ~ ~ ~ p=1.000 n=12
Types 2,697,943 2,697,943 ~ ~ ~ p=1.000 n=12
Memory Used 5,273,125k (± 0.03%) 5,273,298k (± 0.02%) ~ 5,271,522k 5,276,381k p=0.630 n=12
Memory Allocs 40,909,210 (± 0.02%) 40,595,199 (± 0.01%) -314,011 (- 0.77%) 40,587,212 40,611,100 p=0.000 n=12
Config Time 0.062s (± 0.68%) 0.062s (± 0.50%) ~ 0.061s 0.062s p=0.680 n=12
Parse Time 1.587s (± 3.00%) 1.607s (± 1.46%) ~ 1.526s 1.677s p=0.541 n=12
Bind Time 0.413s (±21.83%) 0.333s (± 0.48%) 🟩-0.080s (-19.31%) 0.329s 0.340s p=0.033 n=12
Check Time 9.765s (± 1.69%) 9.997s (± 0.59%) +0.231s (+ 2.37%) 9.890s 10.270s p=0.001 n=12
Emit Time 3.508s (±13.62%) 3.016s (± 0.65%) 🟩-0.492s (-14.02%) 2.979s 3.070s p=0.040 n=12
Total Time 15.418s (± 2.40%) 15.094s (± 0.47%) ~ 14.975s 15.416s p=0.378 n=12
webpack - native
Errors 2 2 ~ ~ ~ p=1.000 n=12
Symbols 1,380 1,380 ~ ~ ~ p=1.000 n=12
Types 340 340 ~ ~ ~ p=1.000 n=12
Memory Used 199,027k (± 0.07%) 199,044k (± 0.05%) ~ 198,776k 199,363k p=0.990 n=12
Memory Allocs 843,165 (± 0.11%) 844,291 (± 0.36%) ~ 841,657 859,240 p=0.977 n=12
Config Time 0.006s (± 3.97%) 0.006s ~ ~ ~ p=0.478 n=12
Parse Time 0.168s (± 3.04%) 0.166s (± 1.98%) ~ 0.157s 0.177s p=0.338 n=12
Bind Time 0s 0s ~ ~ ~ p=1.000 n=12
Check Time 0s 0s ~ ~ ~ p=1.000 n=12
Emit Time 0.000s 0.000s ~ ~ ~ p=1.000 n=12
Total Time 0.174s (± 2.98%) 0.173s (± 1.92%) ~ 0.164s 0.184s p=0.311 n=12
xstate-main - native
Errors 0 0 ~ ~ ~ p=1.000 n=12
Symbols 1,019,981 1,019,981 ~ ~ ~ p=1.000 n=12
Types 376,182 376,182 ~ ~ ~ p=1.000 n=12
Memory Used 603,309k (± 0.02%) 603,264k (± 0.02%) ~ 602,794k 603,630k p=0.682 n=12
Memory Allocs 4,748,187 (± 0.03%) 4,749,481 (± 0.05%) ~ 4,745,613 4,758,420 p=0.713 n=12
Config Time 0.002s 0.002s ~ ~ ~ p=1.000 n=12
Parse Time 0.115s (± 2.98%) 0.113s (± 3.13%) ~ 0.105s 0.122s p=0.339 n=12
Bind Time 0.032s (±15.50%) 0.039s (±20.49%) ~ 0.026s 0.059s p=0.169 n=12
Check Time 0.845s (± 1.17%) 0.845s (± 0.82%) ~ 0.825s 0.868s p=0.809 n=12
Emit Time 0.000s 0.000s ~ ~ ~ p=1.000 n=12
Total Time 1.004s (± 1.16%) 1.009s (± 0.90%) ~ 0.980s 1.029s p=0.639 n=12
System info unknown
Hosts
  • native
Scenarios
  • Compiler-Unions - native
  • angular-1 - native
  • mui-docs - native
  • strada-build-src - native
  • strada-compiler - native
  • ts-pre-modules - native
  • vscode - native
  • webpack - native
  • xstate-main - native
Benchmark Name Iterations
Current pr 12
Baseline baseline 12

lsp

Comparison Report - baseline..pr
Metric baseline pr Delta Best Worst p-value
Compiler-UnionsLSP - native
Req 1 - updateOpen 12ms (± 6.64%) 12ms (± 3.87%) ~ 11ms 14ms p=0.986 n=12
Req 2 - geterr 554ms (± 0.38%) 556ms (± 0.26%) ~ 552ms 559ms p=0.209 n=12
Req 3 - references 44ms (± 2.50%) 45ms (± 1.28%) ~ 42ms 45ms p=0.118 n=12
Req 4 - navto 17ms (± 1.95%) 17ms (± 1.95%) ~ 16ms 17ms p=1.000 n=12
Req 5 - completionInfo count 1,363 1,363 ~ ~ ~ p=1.000 n=12
Req 5 - completionInfo 19ms (± 8.72%) 19ms (± 8.23%) ~ 17ms 24ms p=0.547 n=12
CompilerLSP - native
Req 1 - updateOpen 13ms (± 7.24%) 13ms (± 3.07%) ~ 12ms 14ms p=0.994 n=12
Req 2 - geterr 292ms (± 0.58%) 291ms (± 0.55%) ~ 287ms 296ms p=0.222 n=12
Req 3 - references 50ms (± 3.53%) 51ms (± 4.53%) ~ 47ms 57ms p=0.319 n=12
Req 4 - navto 17ms (± 1.99%) 17ms (± 1.70%) ~ 16ms 17ms p=0.400 n=12
Req 5 - completionInfo count 1,525 1,525 ~ ~ ~ p=1.000 n=12
Req 5 - completionInfo 18ms (± 3.40%) 17ms (± 8.38%) ~ 15ms 21ms p=0.229 n=12
System info unknown
Hosts
  • native
Scenarios
  • CompilerLSP - native
  • Compiler-UnionsLSP - native
  • xstate-main-1-LSP - native
Benchmark Name Iterations
Current pr 12
Baseline baseline 12

startup

Comparison Report - baseline..pr
Metric baseline pr Delta Best Worst p-value
lsp-startup - native
Execution time 4.84ms (±365.09%) 4.83ms (±365.10%) -0.01ms (- 0.15%) 0.00ms 485.75ms p=0.000 n=1200
tsgo-startup - native
Execution time 5.96ms (±365.12%) 5.99ms (±365.12%) +0.03ms (+ 0.49%) 0.00ms 607.90ms p=0.000 n=1200
System info unknown
Hosts
  • native
Scenarios
  • lsp-startup - native
  • tsgo-startup - native
Benchmark Name Iterations
Current pr 12
Baseline baseline 12

Developer Information:

Download Benchmarks

@jakebailey Jake Bailey (jakebailey) left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel like this is fairly cursed and I wonder if we have this same problem elsewhere, but, I guess it's fine?

@jakebailey
Jake Bailey (jakebailey) removed this pull request from the merge queue due to a manual request Aug 19, 2026
@jakebailey

Copy link
Copy Markdown
Member

Wesley Wigham (@weswigham) Do you have any last comments on this?

@weswigham
Wesley Wigham (weswigham) added this pull request to the merge queue Aug 19, 2026
@weswigham

Copy link
Copy Markdown
Member

I wonder if we have this same problem elsewhere

Probably! Copilot found two extras just in this PR - I don't see how it's not just a systemic problem with string slices not being the same (w.r.t. bounds checking) as the js substrings we ported from. Hopefully these are the easier-to-trigger ones, though.

@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Aug 19, 2026
@jakebailey
Jake Bailey (jakebailey) added this pull request to the merge queue Aug 19, 2026
Merged via the queue into main with commit 65535b2 Aug 19, 2026
21 checks passed
@jakebailey
Jake Bailey (jakebailey) deleted the copilot/fix-crash-getsourcefilepathinnewdir branch August 19, 2026 21:13
Jake Bailey (jakebailey) pushed a commit to jakebailey/TypeScript that referenced this pull request Aug 19, 2026
…go#4900)

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: DanielRosenwasser <972891+DanielRosenwasser@users.noreply.github.com>
Co-authored-by: weswigham <2932786+weswigham@users.noreply.github.com>
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.

Crash at GetSourceFilePathInNewDir

5 participants