Skip to content

fix: use precise regexes for transform filter to avoid backtracking#21800

Merged
sapphi-red merged 6 commits intovitejs:mainfrom
o-m12a:fix/filter-regex-stack-overflow
Mar 16, 2026
Merged

fix: use precise regexes for transform filter to avoid backtracking#21800
sapphi-red merged 6 commits intovitejs:mainfrom
o-m12a:fix/filter-regex-stack-overflow

Conversation

@o-m12a
Copy link
Copy Markdown
Contributor

@o-m12a o-m12a commented Mar 9, 2026

What this PR solves

Fixes #21696

The filter.code regexes in workerImportMetaUrl, assetImportMetaUrl, and rolldownDepPlugin used .+ (or .+?) with the /s flag. On large files (5MB+) containing new URL(...) without import.meta.url, this caused catastrophic backtracking — leading to "Maximum call stack size exceeded" or multi-second stalls.

What caused the bug

The /s flag makes . match newlines, so .+ in /new\s+URL.+import\.meta\.url/s consumes the entire remaining file after each new URL occurrence. When import.meta.url is absent, the regex engine backtracks character by character across the whole file, repeated for each new URL match.

Implementation

The filter and handler regexes are unified into a single exported regex per plugin, with dg flags and a precise pattern that requires a string literal argument ('...', "...", or `...`). Each handler creates a fresh copy via new RegExp() to avoid shared lastIndex state between concurrent async invocations.

  • assetImportMetaUrl.ts: exports assetImportMetaUrlRE, used for both filter and handler
  • workerImportMetaUrl.ts: exports workerImportMetaUrlRE, used for both filter and handler
  • rolldownDepPlugin.ts: imports assetImportMetaUrlRE for both filter and handler

Attention for reviewers

  • The regexes no longer have the /s flag, so they do not match across newlines. This is intentional — the precise patterns use character classes like [^']+ that do not need cross-line matching.
  • The regex is slightly more restrictive than the old one (requires a string literal), but this matches the behavior of the transform handler itself, so no valid cases should be missed.

Tests

Added unit tests that run the exported regexes against a large input (~2.4MB with 200 new URL(...) occurrences). Tests rely on the default test timeout to catch backtracking regressions.

o-m12a and others added 2 commits March 10, 2026 00:36
…ktracking

The filter.code regexes in workerImportMetaUrl, assetImportMetaUrl,
and rolldownDepPlugin used `.+` with the `/s` flag, which caused
catastrophic backtracking on large files containing `new URL()`
without `import.meta.url`.

Replace them with the precise regexes that require a string literal
argument, matching the patterns already used in the transform handlers.
This allows the regex to fail fast on non-matching input.

Closes vitejs#21696

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace `expect(duration).toBeLessThan(1000)` with relying on the
default test timeout to catch backtracking regressions. This avoids
flaky failures on slow CI runners.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Comment thread packages/vite/src/node/__tests__/filterRegex.spec.ts
Comment thread packages/vite/src/node/optimizer/rolldownDepPlugin.ts Outdated
Comment thread packages/vite/src/node/plugins/assetImportMetaUrl.ts Outdated
Comment thread packages/vite/src/node/plugins/workerImportMetaUrl.ts Outdated
o-m12a and others added 4 commits March 10, 2026 18:32
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
lastIndex = 0 doesn't work for async handlers with await inside
the exec loop, as concurrent handler invocations can overwrite
the shared lastIndex.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@sapphi-red sapphi-red changed the title fix(optimizer): use precise regexes for transform filter to avoid backtracking fix: use precise regexes for transform filter to avoid backtracking Mar 16, 2026
@sapphi-red sapphi-red added the p3-minor-bug An edge case that only affects very specific usage (priority) label Mar 16, 2026
@sapphi-red sapphi-red merged commit dbe41bd into vitejs:main Mar 16, 2026
19 checks passed
renovate bot added a commit to andrei-picus-tink/auto-renovate that referenced this pull request Mar 31, 2026
| datasource | package | from  | to    |
| ---------- | ------- | ----- | ----- |
| npm        | vite    | 7.3.1 | 8.0.3 |


## [v8.0.3](https://github.com/vitejs/vite/blob/HEAD/packages/vite/CHANGELOG.md#small-803-2026-03-26-small)

##### Features

- update rolldown to 1.0.0-rc.12 ([#22024](vitejs/vite#22024)) ([84164ef](vitejs/vite@84164ef))

##### Bug Fixes

- **html:** cache unfiltered CSS list to prevent missing styles across entries ([#22017](vitejs/vite#22017)) ([5464190](vitejs/vite@5464190))
- **module-runner:** handle non-ascii characters in base64 sourcemaps ([#21985](vitejs/vite#21985)) ([77c95bf](vitejs/vite@77c95bf))
- **module-runner:** skip re-import if the runner is closed ([#22020](vitejs/vite#22020)) ([ee2c2cd](vitejs/vite@ee2c2cd))
- **optimizer:** scan is not resolving sub path import if used in a glob import ([#22018](vitejs/vite#22018)) ([ddfe20d](vitejs/vite@ddfe20d))
- **ssr:** ssrTransform incorrectly rewrites `meta` identifier inside `import.meta` when a binding named `meta` exists ([#22019](vitejs/vite#22019)) ([cff5f0c](vitejs/vite@cff5f0c))

##### Miscellaneous Chores

- **deps:** bump picomatch from 4.0.3 to 4.0.4 ([#22027](vitejs/vite#22027)) ([7e56003](vitejs/vite@7e56003))

##### Tests

- **html:** add tests for `getCssFilesForChunk` ([#22016](vitejs/vite#22016)) ([43fbbf9](vitejs/vite@43fbbf9))


## [v8.0.2](https://github.com/vitejs/vite/blob/HEAD/packages/vite/CHANGELOG.md#small-802-2026-03-23-small)

##### Features

- update rolldown to 1.0.0-rc.11 ([#21998](vitejs/vite#21998)) ([ff91c31](vitejs/vite@ff91c31))

##### Bug Fixes

- **deps:** update all non-major dependencies ([#21988](vitejs/vite#21988)) ([9b7d150](vitejs/vite@9b7d150))

##### Miscellaneous Chores

- **deps:** update dependency [@vitejs/devtools](https://github.com/vitejs/devtools) to ^0.1.5 ([#21992](vitejs/vite#21992)) ([b2dd65b](vitejs/vite@b2dd65b))


## [v8.0.1](https://github.com/vitejs/vite/blob/HEAD/packages/vite/CHANGELOG.md#small-801-2026-03-19-small)

##### Features

- update rolldown to 1.0.0-rc.10 ([#21932](vitejs/vite#21932)) ([b3c067d](vitejs/vite@b3c067d))

##### Bug Fixes

- **bundled-dev:** properly disable `inlineConst` optimization ([#21865](vitejs/vite#21865)) ([6d97142](vitejs/vite@6d97142))
- **css:** lightningcss minify failed when `build.target: 'es6'` ([#21933](vitejs/vite#21933)) ([5fcce46](vitejs/vite@5fcce46))
- **deps:** update all non-major dependencies ([#21878](vitejs/vite#21878)) ([6dbbd7f](vitejs/vite@6dbbd7f))
- **dev:** always use ESM Oxc runtime ([#21829](vitejs/vite#21829)) ([d323ed7](vitejs/vite@d323ed7))
- **dev:** handle concurrent restarts in `_createServer` ([#21810](vitejs/vite#21810)) ([40bc729](vitejs/vite@40bc729))
- handle `+` symbol in package subpath exports during dep optimization ([#21886](vitejs/vite#21886)) ([86db93d](vitejs/vite@86db93d))
- improve `no-cors` request block error ([#21902](vitejs/vite#21902)) ([5ba688b](vitejs/vite@5ba688b))
- use precise regexes for transform filter to avoid backtracking ([#21800](vitejs/vite#21800)) ([dbe41bd](vitejs/vite@dbe41bd))
- **worker:** `require(json)` result should not be wrapped ([#21847](vitejs/vite#21847)) ([0672fd2](vitejs/vite@0672fd2))
- **worker:** make worker output consistent with client and SSR ([#21871](vitejs/vite#21871)) ([69454d7](vitejs/vite@69454d7))

##### Miscellaneous Chores

- add changelog rearrange script ([#21835](vitejs/vite#21835)) ([efef073](vitejs/vite@efef073))
- **deps:** bump required `@vitejs/devtools` version to 0.1+ ([#21925](vitejs/vite#21925)) ([12932f5](vitejs/vite@12932f5))
- **deps:** update rolldown-related dependencies ([#21787](vitejs/vite#21787)) ([1af1d3a](vitejs/vite@1af1d3a))
- rearrange 8.0 changelog ([8e05b61](vitejs/vite@8e05b61))
- rearrange 8.0 changelog ([#21834](vitejs/vite#21834)) ([86edeee](vitejs/vite@86edeee))


## [v8.0.0](https://github.com/vitejs/vite/blob/HEAD/packages/vite/CHANGELOG.md#800-2026-03-12)

##### Features

- update rolldown to 1.0.0-rc.9 ([#21813](vitejs/vite#21813)) ([f05be0e](vitejs/vite@f05be0e))
- warn when `vite-tsconfig-paths` plugin is detected ([#21781](vitejs/vite#21781)) ([ada493e](vitejs/vite@ada493e))

##### Bug Fixes

- **deps:** update all non-major dependencies ([#21786](vitejs/vite#21786)) ([eaa4352](vitejs/vite@eaa4352))
renovate bot added a commit to andrei-picus-tink/auto-renovate that referenced this pull request Apr 15, 2026
| datasource | package | from  | to    |
| ---------- | ------- | ----- | ----- |
| npm        | vite    | 7.3.1 | 8.0.8 |


## [v8.0.8](https://github.com/vitejs/vite/blob/HEAD/packages/vite/CHANGELOG.md#small-808-2026-04-09-small)

##### Features

- update rolldown to 1.0.0-rc.15 ([#22201](vitejs/vite#22201)) ([6baf587](vitejs/vite@6baf587))

##### Bug Fixes

- avoid `dns.getDefaultResultOrder` temporary ([#22202](vitejs/vite#22202)) ([15f1c15](vitejs/vite@15f1c15))
- **ssr:** class property keys hoisting matching imports ([#22199](vitejs/vite#22199)) ([e137601](vitejs/vite@e137601))


## [v8.0.7](https://github.com/vitejs/vite/blob/HEAD/packages/vite/CHANGELOG.md#small-807-2026-04-07-small)

##### Bug Fixes

- use sync dns.getDefaultResultOrder instead of dns.promises ([#22185](vitejs/vite#22185)) ([5c05b04](vitejs/vite@5c05b04))


## [v8.0.6](https://github.com/vitejs/vite/blob/HEAD/packages/vite/CHANGELOG.md#small-806-2026-04-07-small)

##### Features

- update rolldown to 1.0.0-rc.13 ([#22097](vitejs/vite#22097)) ([51d3e48](vitejs/vite@51d3e48))

##### Bug Fixes

- **css:** avoid mutating sass error multiple times ([#22115](vitejs/vite#22115)) ([d5081c2](vitejs/vite@d5081c2))
- **optimize-deps:** hoist CJS interop assignment ([#22156](vitejs/vite#22156)) ([17a8f9e](vitejs/vite@17a8f9e))

##### Performance Improvements

- early return in `getLocalhostAddressIfDiffersFromDNS` when DNS order is `verbatim` ([#22151](vitejs/vite#22151)) ([56ec256](vitejs/vite@56ec256))

##### Miscellaneous Chores

- **create-vite:** remove unnecessary DOM.Iterable ([#22168](vitejs/vite#22168)) ([bdc53ab](vitejs/vite@bdc53ab))
- replace remaining prettier script ([#22179](vitejs/vite#22179)) ([af71fb2](vitejs/vite@af71fb2))


## [v8.0.5](https://github.com/vitejs/vite/blob/HEAD/packages/vite/CHANGELOG.md#small-805-2026-04-06-small)

##### Bug Fixes

- apply server.fs check to env transport ([#22159](vitejs/vite#22159)) ([f02d9fd](vitejs/vite@f02d9fd))
- avoid path traversal with optimize deps sourcemap handler ([#22161](vitejs/vite#22161)) ([79f002f](vitejs/vite@79f002f))
- check `server.fs` after stripping query as well ([#22160](vitejs/vite#22160)) ([a9a3df2](vitejs/vite@a9a3df2))
- disallow referencing files outside the package from sourcemap ([#22158](vitejs/vite#22158)) ([f05f501](vitejs/vite@f05f501))


## [v8.0.4](https://github.com/vitejs/vite/blob/HEAD/packages/vite/CHANGELOG.md#small-804-2026-04-06-small)

##### Features

- allow esbuild 0.28 as peer deps ([#22155](vitejs/vite#22155)) ([b0da973](vitejs/vite@b0da973))
- **hmr:** truncate list of files on hmr update ([#21535](vitejs/vite#21535)) ([d00e806](vitejs/vite@d00e806))
- **optimizer:** log when dependency scanning or bundling takes over 1s ([#21797](vitejs/vite#21797)) ([f61a1ab](vitejs/vite@f61a1ab))

##### Bug Fixes

- `hasBothRollupOptionsAndRolldownOptions` should return `false` for proxy case ([#22043](vitejs/vite#22043)) ([99897d2](vitejs/vite@99897d2))
- add types for `vite/modulepreload-polyfill` ([#22126](vitejs/vite#22126)) ([17330d2](vitejs/vite@17330d2))
- **deps:** update all non-major dependencies ([#22073](vitejs/vite#22073)) ([6daa10f](vitejs/vite@6daa10f))
- **deps:** update all non-major dependencies ([#22143](vitejs/vite#22143)) ([22b0166](vitejs/vite@22b0166))
- **resolve:** resolve tsconfig paths starting with `#` ([#22038](vitejs/vite#22038)) ([3460fc5](vitejs/vite@3460fc5))
- **ssr:** use browser platform for webworker SSR builds (fix [#21969](vitejs/vite#21969)) ([#21963](vitejs/vite#21963)) ([364c227](vitejs/vite@364c227))

##### Documentation

- add `environment.fetchModule` documentation ([#22035](vitejs/vite#22035)) ([54229e7](vitejs/vite@54229e7))

##### Miscellaneous Chores

- **deps:** update rolldown-related dependencies ([#21989](vitejs/vite#21989)) ([0ded627](vitejs/vite@0ded627))

##### Code Refactoring

- upgrade to typescript 6 ([#22110](vitejs/vite#22110)) ([cc41398](vitejs/vite@cc41398))


## [v8.0.3](https://github.com/vitejs/vite/blob/HEAD/packages/vite/CHANGELOG.md#small-803-2026-03-26-small)

##### Features

- update rolldown to 1.0.0-rc.12 ([#22024](vitejs/vite#22024)) ([84164ef](vitejs/vite@84164ef))

##### Bug Fixes

- **html:** cache unfiltered CSS list to prevent missing styles across entries ([#22017](vitejs/vite#22017)) ([5464190](vitejs/vite@5464190))
- **module-runner:** handle non-ascii characters in base64 sourcemaps ([#21985](vitejs/vite#21985)) ([77c95bf](vitejs/vite@77c95bf))
- **module-runner:** skip re-import if the runner is closed ([#22020](vitejs/vite#22020)) ([ee2c2cd](vitejs/vite@ee2c2cd))
- **optimizer:** scan is not resolving sub path import if used in a glob import ([#22018](vitejs/vite#22018)) ([ddfe20d](vitejs/vite@ddfe20d))
- **ssr:** ssrTransform incorrectly rewrites `meta` identifier inside `import.meta` when a binding named `meta` exists ([#22019](vitejs/vite#22019)) ([cff5f0c](vitejs/vite@cff5f0c))

##### Miscellaneous Chores

- **deps:** bump picomatch from 4.0.3 to 4.0.4 ([#22027](vitejs/vite#22027)) ([7e56003](vitejs/vite@7e56003))

##### Tests

- **html:** add tests for `getCssFilesForChunk` ([#22016](vitejs/vite#22016)) ([43fbbf9](vitejs/vite@43fbbf9))


## [v8.0.2](https://github.com/vitejs/vite/blob/HEAD/packages/vite/CHANGELOG.md#small-802-2026-03-23-small)

##### Features

- update rolldown to 1.0.0-rc.11 ([#21998](vitejs/vite#21998)) ([ff91c31](vitejs/vite@ff91c31))

##### Bug Fixes

- **deps:** update all non-major dependencies ([#21988](vitejs/vite#21988)) ([9b7d150](vitejs/vite@9b7d150))

##### Miscellaneous Chores

- **deps:** update dependency [@vitejs/devtools](https://github.com/vitejs/devtools) to ^0.1.5 ([#21992](vitejs/vite#21992)) ([b2dd65b](vitejs/vite@b2dd65b))


## [v8.0.1](https://github.com/vitejs/vite/blob/HEAD/packages/vite/CHANGELOG.md#small-801-2026-03-19-small)

##### Features

- update rolldown to 1.0.0-rc.10 ([#21932](vitejs/vite#21932)) ([b3c067d](vitejs/vite@b3c067d))

##### Bug Fixes

- **bundled-dev:** properly disable `inlineConst` optimization ([#21865](vitejs/vite#21865)) ([6d97142](vitejs/vite@6d97142))
- **css:** lightningcss minify failed when `build.target: 'es6'` ([#21933](vitejs/vite#21933)) ([5fcce46](vitejs/vite@5fcce46))
- **deps:** update all non-major dependencies ([#21878](vitejs/vite#21878)) ([6dbbd7f](vitejs/vite@6dbbd7f))
- **dev:** always use ESM Oxc runtime ([#21829](vitejs/vite#21829)) ([d323ed7](vitejs/vite@d323ed7))
- **dev:** handle concurrent restarts in `_createServer` ([#21810](vitejs/vite#21810)) ([40bc729](vitejs/vite@40bc729))
- handle `+` symbol in package subpath exports during dep optimization ([#21886](vitejs/vite#21886)) ([86db93d](vitejs/vite@86db93d))
- improve `no-cors` request block error ([#21902](vitejs/vite#21902)) ([5ba688b](vitejs/vite@5ba688b))
- use precise regexes for transform filter to avoid backtracking ([#21800](vitejs/vite#21800)) ([dbe41bd](vitejs/vite@dbe41bd))
- **worker:** `require(json)` result should not be wrapped ([#21847](vitejs/vite#21847)) ([0672fd2](vitejs/vite@0672fd2))
- **worker:** make worker output consistent with client and SSR ([#21871](vitejs/vite#21871)) ([69454d7](vitejs/vite@69454d7))

##### Miscellaneous Chores

- add changelog rearrange script ([#21835](vitejs/vite#21835)) ([efef073](vitejs/vite@efef073))
- **deps:** bump required `@vitejs/devtools` version to 0.1+ ([#21925](vitejs/vite#21925)) ([12932f5](vitejs/vite@12932f5))
- **deps:** update rolldown-related dependencies ([#21787](vitejs/vite#21787)) ([1af1d3a](vitejs/vite@1af1d3a))
- rearrange 8.0 changelog ([8e05b61](vitejs/vite@8e05b61))
- rearrange 8.0 changelog ([#21834](vitejs/vite#21834)) ([86edeee](vitejs/vite@86edeee))


## [v8.0.0](https://github.com/vitejs/vite/blob/HEAD/packages/vite/CHANGELOG.md#800-2026-03-12)

##### Features

- update rolldown to 1.0.0-rc.9 ([#21813](vitejs/vite#21813)) ([f05be0e](vitejs/vite@f05be0e))
- warn when `vite-tsconfig-paths` plugin is detected ([#21781](vitejs/vite#21781)) ([ada493e](vitejs/vite@ada493e))

##### Bug Fixes

- **deps:** update all non-major dependencies ([#21786](vitejs/vite#21786)) ([eaa4352](vitejs/vite@eaa4352))


## [v7.3.2](https://github.com/vitejs/vite/releases/tag/v7.3.2)

Please refer to [CHANGELOG.md](https://github.com/vitejs/vite/blob/v7.3.2/packages/vite/CHANGELOG.md) for details.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

p3-minor-bug An edge case that only affects very specific usage (priority)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

transform.filter.code regexes with .+ and /s flag cause "Maximum call stack size exceeded" on large files

3 participants