https://github.com/AZero13 updated https://github.com/llvm/llvm-project/pull/221102
>From f1b5bdc3c76abfb86675ee0d95a6c4e9f83420a7 Mon Sep 17 00:00:00 2001 From: AZero13 <[email protected]> Date: Thu, 3 Sep 2026 19:44:13 -0400 Subject: [PATCH] [Clang][Parse] Fix heap-use-after-free when cleaning up TemplateIds When parsing deeply nested statement expressions, the preprocessor may exit caching mode while the parser's current token is still an `annot_template_id`. When `MaybeDestroyTemplateIds()` runs at the end of a statement, it aggressively destroyed all template ID annotations because caching mode was off. This left the current token holding a dangling pointer to a freed `TemplateIdAnnotation`, causing a crash during error recovery when extracting the `TemplateNameLoc`. This patch adds a check to ensure we don't destroy `TemplateIds` if the parser is actively holding onto an `annot_template_id` in `Tok`. Fixes #175702 --- clang/include/clang/Parse/Parser.h | 3 +- .../cxx-template-id-tentative-uaf-crash.cpp | 81 +++++++++++++++++++ 2 files changed, 83 insertions(+), 1 deletion(-) create mode 100644 clang/test/Parser/cxx-template-id-tentative-uaf-crash.cpp diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index 6913c42884a36..79f62c2e8d028 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -7964,7 +7964,8 @@ class Parser : public CodeCompletionHandler { if (DelayTemplateIdDestruction) return; if (!TemplateIds.empty() && - (Tok.is(tok::eof) || !PP.mightHavePendingAnnotationTokens())) + (Tok.is(tok::eof) || !PP.mightHavePendingAnnotationTokens()) && + Tok.isNot(tok::annot_template_id)) DestroyTemplateIds(); } void DestroyTemplateIds(); diff --git a/clang/test/Parser/cxx-template-id-tentative-uaf-crash.cpp b/clang/test/Parser/cxx-template-id-tentative-uaf-crash.cpp new file mode 100644 index 0000000000000..3e7d309c7d312 --- /dev/null +++ b/clang/test/Parser/cxx-template-id-tentative-uaf-crash.cpp @@ -0,0 +1,81 @@ +// RUN: not %clang_cc1 -fsyntax-only -Wno-everything %s + + +int main() { + typedef struct tree_el node i, sum = 0; + for (i = 1; i <= LAST; i++) { + sum += i; + } + printf("sum = %d\n", sum); + return printout(printf(printf( + i < cnt, cnt & (printout(printf(printf( + i < cnt, + 0x5b * printf(i < cnt, + 0x5b * (({ cnt & (printf(printf( + i < cnt, + 0x5b * (1 / (1 / (cnt & (printout( + printf(i < cnt, 0x5b * (1 / (({ + if ("%f%f%f") + break; + -((0.0 / (0xaf >> 3 & + (((0xaf >> 3 & + (({ for (i = 0, bi = i < 10; i < length; + ++i, ++bi) + if (cnt < (0xaf >> 3 & 1) >> 3) + break; + cnt < (0xaf >> 3 & 1) >> 3; + }))) + >> 0xb9 & 1) + >> 0xb9 & 1))))) + ; + }))) + ) >> + 3 & + 1))) + )))) >> + 3 & + 1))) + ) >> + 3 & + 1); + return 0; + i; + return (node())->val; +}))) + ))), + sum) >> + 3 & + 1); + return ((((({ cnt & (printf(printf( + i < cnt, + 0x5b * (({ cnt & (printf(printf( + i < cnt, + 0x5b * (1 / (1 / (cnt & (printout( + printf(i < cnt, 0x5b * (1 / (({ + if ("%f%f%f") + break; + -((0.0 / (0xaf >> 3 & + (((0xaf >> 3 & + (({ for (i = 0, bi = i < 10; i < length; ++i, ++bi) + if (cnt < (0xaf >> 3 & 1) >> 3) + break; + cnt < (0xaf >> 3 & 1) >> 3; + }))) + >> 0xb9 & 1) + >> 0xb9 & 1))))) + ; + }))) + ) >> + 3 & + 1))) + )))) >> + 3 & + 1))) + ) >> + 3 & + 1))) + , + sum)) >> + 3 & + 1))); +} _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
