Skip to content

fix(printer): clamp out-of-range pos in getLineAndCharacter for source map emit#3939

Closed
Zelys-DFKH wants to merge 1 commit into
microsoft:mainfrom
Zelys-DFKH:fix/3900-sourcemap-unclosed-block
Closed

fix(printer): clamp out-of-range pos in getLineAndCharacter for source map emit#3939
Zelys-DFKH wants to merge 1 commit into
microsoft:mainfrom
Zelys-DFKH:fix/3900-sourcemap-unclosed-block

Conversation

@Zelys-DFKH
Copy link
Copy Markdown

Fixes #3900

Analysis

tsgo --sourceMap on any file that triggers a parse error producing a synthetic closing token will panic:

echo '{' > bug.ts && tsgo --sourceMap bug.ts
# panic: runtime error: slice bounds out of range [:3] with length 2

The crash is in lineCharacterCache.getLineAndCharacter (internal/printer/utilities.go). It computes source map character offsets by slicing the source text: c.text[cachedPos:pos]. When the parser encounters an unclosed {, it inserts a synthetic } at a position past the end of the file (position 3 for a 2-byte file, {\n). Go panics on the out-of-bounds slice.

TypeScript's original implementation doesn't have this problem because String.prototype.slice silently clamps its end index to string.length. The Go port replicates the algorithm but not that implicit clamp.

Fix

One guard at the top of getLineAndCharacter: if pos > len(c.text), clamp it to len(c.text). Positions within bounds pass through unchanged, so this only affects synthetic tokens at or past end-of-file. The clamped position maps them to EOF in the source map, matching what TypeScript's JS implementation produces.

Copilot Checklist

I successfully ran these commands at the end of my session, and they completed without error:

  • npx hereby build
  • npx hereby test
  • npx hereby lint
  • npx hereby format

…e map emit

Synthetic tokens (e.g. the auto-inserted '}' for an unclosed block) can
carry positions beyond the end of the source text. Go's slice operator
panics on out-of-bounds indices, but JavaScript's String.prototype.slice
silently clamps the end index to string.length. Add a pre-clamp to match
JS semantics and prevent the panic when emitting source maps for files
with parse errors that generate synthetic closing tokens.

Fixes microsoft#3900

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings May 17, 2026 21:47
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Fixes a panic in source map emission when the parser produces synthetic tokens positioned past end-of-file (e.g. an auto-inserted } for an unclosed block). The Go port's getLineAndCharacter sliced c.text[cachedPos:pos] directly, which panics on out-of-bounds, unlike JS's String.prototype.slice which clamps. The fix clamps pos to len(c.text).

Changes:

  • Clamp pos to len(c.text) at the top of lineCharacterCache.getLineAndCharacter.
  • Add a new compiler test sourceMapEmitUnclosedBlock.ts plus accepted baselines.

Reviewed changes

Copilot reviewed 6 out of 8 changed files in this pull request and generated no comments.

File Description
internal/printer/utilities.go Adds bounds clamp for out-of-range positions in getLineAndCharacter.
testdata/tests/cases/compiler/sourceMapEmitUnclosedBlock.ts New minimal repro test enabling --sourceMap on an unclosed block.
testdata/baselines/reference/compiler/sourceMapEmitUnclosedBlock.* Accepted baselines (js, js.map, sourcemap.txt, errors.txt, types, symbols) for the new test.
Files not reviewed (1)
  • testdata/baselines/reference/compiler/sourceMapEmitUnclosedBlock.js: Language not supported

@jakebailey
Copy link
Copy Markdown
Member

We already have #3923.

@Zelys-DFKH
Copy link
Copy Markdown
Author

Closing — #3923 already fixes this. Thanks for the quick catch, @jakebailey.

@Zelys-DFKH Zelys-DFKH closed this May 17, 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.

tsgo source-map emit panics for an unclosed block

3 participants