Files
bun.sh/test/regression/issue/jsx-template-string-crash.test.ts
robobun f5ef9cda3c Fix panic in JavaScript lexer when parsing invalid template strings in JSX (#21967)
## Summary

- Fixes a crash where invalid slice bounds caused a panic with message:
"start index N is larger than end index M"
- The issue occurred in `js_lexer.zig:767` when calculating string
literal content slice bounds
- Adds proper bounds checking to prevent slice bounds violations
- Includes regression test to prevent future occurrences

## Root Cause

The crash happened when `suffix_len` was larger than `lexer.end`,
causing the calculation `lexer.end - suffix_len` to result in a value
smaller than the `base` position. This created invalid slice bounds like
`[114..113]`.

## Solution

Added bounds checking to ensure:
1. `end_pos` is calculated safely: `if (lexer.end >= suffix_len)
lexer.end - suffix_len else lexer.end`
2. `slice_end` is always >= `base`: `@max(base, end_pos)`

## Test Plan

- [x] Added regression test in
`test/regression/issue/jsx-template-string-crash.test.ts`
- [x] Test verifies no crashes occur with JSX template string patterns
- [x] Verified normal template string functionality still works
- [x] All tests pass

🤖 Generated with [Claude Code](https://claude.ai/code)

---------

Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-08-19 18:47:04 -07:00

31 lines
1.2 KiB
TypeScript

import { expect, test } from "bun:test";
import { bunEnv, bunExe, normalizeBunSnapshot } from "harness";
test("JSX lexer should not crash with slice bounds issues", async () => {
// This used to crash with: "panic: start index N is larger than end index M"
// due to invalid slice bounds in js_lexer.zig:767 when calculating string literal content
// The issue occurred when suffix_len > lexer.end, causing end_pos < base
// Test JSX with empty template strings that could trigger slice bounds issues
const { stderr, exitCode, stdout } = Bun.spawnSync({
cmd: [bunExe(), "-e", "export function x(){return<div a=``/>}"],
env: bunEnv,
stderr: "pipe",
stdout: "pipe",
});
expect(exitCode).toBe(1);
expect(normalizeBunSnapshot(stderr.toString().replace(/(Bun v.*)$/gm, ""))).toMatchInlineSnapshot(`
"1 | export function x(){return<div a=\`\`/>}
^
error: Expected "{" but found "\`"
at <cwd>/[eval]:1:34
1 | export function x(){return<div a=\`\`/>}
^
error: Unexpected >
at <cwd>/[eval]:1:37"
`);
expect(normalizeBunSnapshot(stdout.toString())).toMatchInlineSnapshot(`""`);
});