Prevent macro expansion hang from exponential token growth#154968
Open
vincenzopalazzo wants to merge 2 commits intorust-lang:mainfrom
Open
Prevent macro expansion hang from exponential token growth#154968vincenzopalazzo wants to merge 2 commits intorust-lang:mainfrom
vincenzopalazzo wants to merge 2 commits intorust-lang:mainfrom
Conversation
Add a configurable `macro_token_limit` that caps the number of tokens allowed as input to a single `macro_rules!` expansion. This prevents recursive macros that double their output on each expansion from hanging the compiler — the token count can grow exponentially (e.g. 2^128) long before the recursion depth limit is reached. The default limit is 2^20 (~1 million) top-level tokens. Users can override it with `#![macro_token_limit = "N"]`, following the same pattern as `#![recursion_limit = "N"]`. Fixes rust-lang#95698
Collaborator
|
Some changes occurred in compiler/rustc_hir/src/attrs cc @jdonszelmann, @JonathanBrouwer Some changes occurred in compiler/rustc_attr_parsing cc @jdonszelmann, @JonathanBrouwer Some changes occurred in compiler/rustc_passes/src/check_attr.rs |
Collaborator
|
r? @jackh726 rustbot has assigned @jackh726. Use Why was this reviewer chosen?The reviewer was selected based on:
|
Collaborator
|
This comment has been minimized.
This comment has been minimized.
Collaborator
|
The job Click to see the possible cause of the failure (guessed by this bot) |
Contributor
|
☔ The latest upstream changes (presumably #154958) made this pull request unmergeable. Please resolve the merge conflicts. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes #95698
Recursive
macro_rules!macros can produce exponentially growing token streams that hang the compiler. While the recursion depth limit (default 128) eventually catches infinite recursion, a macro that doubles its output per expansion would produce 2^128 tokens before the depth limit fires — the compiler hangs trying to parse this astronomical input throughparse_tt.This PR adds a new configurable
macro_token_limitthat caps the number of top-level tokens allowed as input to a singlemacro_rules!expansion:#![macro_token_limit = "N"], following the same pattern as#![recursion_limit = "N"]macro_rules!(not proc macros)Why 2^20 as the default?
Based on research across real-world Rust codebases:
The 2^20 default provides ~10x headroom over typical large macros. In the pathological case (exponential doubling from 3 tokens), the limit fires at recursion depth ~19 — producing an error in ~200ms instead of hanging indefinitely. The
#![macro_token_limit]attribute provides an escape hatch for the rare legitimate case that needs more.Reproducer (previously hung the compiler)
Now produces:
Changes
rustc_span/src/symbol.rsmacro_token_limitsymbolrustc_feature/src/builtin_attrs.rsrustc_hir/src/attrs/data_structures.rsMacroTokenLimittoAttributeKindrustc_hir/src/attrs/encode_cross_crate.rsNocross-crate encodingrustc_attr_parsing/src/attributes/crate_level.rsMacroTokenLimitParserrustc_attr_parsing/src/context.rsrustc_interface/src/limits.rsget_macro_token_limit()with defaultrustc_interface/src/passes.rsrustc_expand/src/expand.rsmacro_token_limitfield toExpansionConfigrustc_expand/src/mbe/macro_rules.rsexpand_macrorustc_expand/src/errors.rsMacroInputTooLargediagnosticrustc_passes/src/check_attr.rsTest plan
tests/ui/macros/issue-95698-exponential-token-growth.rsx.py test tests/ui/macros/issue-95698-exponential-token-growth.rspasses (blessed)x.py check compiler/rustc_expandpasses