Skip to content

Parser: exponential time and memory on nested a < (b = …) (failed type argument speculation is retried)Β #64763

Open

Description

@moznion

πŸ”Ž Search Terms

"parser exponential time", "parser out of memory", "type arguments speculation", "instantiation expression parse slow"

πŸ•— Version & Regression Information

  • This changed between versions 4.6.4 and 4.7.4 (likely Instantiation expressionsΒ #47607, "Instantiation expressions")

  • Reproduces in 4.7.4, 5.9.3, 6.0.3, 7.0.2, and 7.1.0-dev.20261012.1 (typescript@next)

ts.createSourceFile time for the code below, with nesting depth n:

n 3.3.4000 4.6.4 4.7.4 5.9.3 6.0.3
10 6 ms 10 ms 86 ms 72 ms 72 ms
12 6 ms 9 ms 667 ms 511 ms 516 ms

⏯ Playground Link

No response

πŸ’» Code

The input is valid TypeScript with no errors; only the nesting depth matters. Here n = 14 (183 bytes):

declare let a: any, b: any, x: any;
x = a < (b = a < (b = a < (b = a < (b = a < (b = a < (b = a < (b = a < (b = a < (b = a < (b = a < (b = a < (b = a < (b = a < (b = 0))))))))))))));

πŸ™ Actual behavior

Parse time and memory grow about 3Γ— with each nesting level. Numbers for tsc 7.0.2 (native); the file reports no errors:

n (bytes) Parse time Max RSS
6 (103) 0.01 s 0.11 GB
13 (173) 0.90 s 1.7 GB
14 (183) 2.8 s 4.8 GB
15 (193) 8.0 s 14.5 GB

typescript@next behaves the same. Malformed input grows even faster, about 5Γ— per level. "a=b<c<(".repeat(11) is 77 bytes and takes 13.8 s and 21.6 GB.

A single small file can therefore make the compiler or the language server hang, and then run out of memory.

To be clear, I don't think people write such code by hand. Depth up to about 6 costs nothing measurable. I found this by fuzzing a tool built on a TS parser, not from a real codebase. It can still come from generated code, from code mid-edit in an editor, or from untrusted input to services that parse TypeScript.

πŸ™‚ Expected behavior

Parse time and memory stay roughly proportional to the input size.

Additional information about the issue

I'm aware of the security properties page and #64370. I'm reporting this anyway for three reasons:

  • The trigger is small, valid code.
  • Memory grows without bound.
  • The fix mirrors an existing mechanism instead of adding a limit.

Activity

  1. moznion commented on Oct 13, 2026

    @moznion
    Author

    I’ve already prepared a patch in main...moznion:TypeScript:fix/parser-type-arguments-retry, so I’d be happy to submit a pull request to fix this issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions