[clang] [Clang][Parse] Fix heap-use-after-free when cleaning up TemplateIds (PR #221102)

via cfe-commits cfe-commits at lists.llvm.org
Mon Sep 7 11:32:49 PDT 2026


https://github.com/AZero13 updated https://github.com/llvm/llvm-project/pull/221102

>From 536b616a3df156247daa1db7e10d19c83f8584fc Mon Sep 17 00:00:00 2001
From: AZero13 <gfunni234 at gmail.com>
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/Lex/Preprocessor.h        |  6 +-
 .../cxx-template-id-tentative-uaf-crash.cpp   | 81 +++++++++++++++++++
 2 files changed, 85 insertions(+), 2 deletions(-)
 create mode 100644 clang/test/Parser/cxx-template-id-tentative-uaf-crash.cpp

diff --git a/clang/include/clang/Lex/Preprocessor.h b/clang/include/clang/Lex/Preprocessor.h
index d94f3d2cbe8ed..c1c4e84771dcf 100644
--- a/clang/include/clang/Lex/Preprocessor.h
+++ b/clang/include/clang/Lex/Preprocessor.h
@@ -2051,9 +2051,11 @@ class Preprocessor {
                             void *AnnotationVal);
 
   /// Determine whether it's possible for a future call to Lex to produce an
-  /// annotation token created by a previous call to EnterAnnotationToken.
+  /// annotation token created by a previous call to EnterAnnotationToken,
+  /// or if the parser is currently holding an annotation token that was just
+  /// retrieved from the cache.
   bool mightHavePendingAnnotationTokens() {
-    return CurLexerCallback != CLK_Lexer;
+    return CurLexerCallback != CLK_Lexer || !CachedTokens.empty();
   }
 
   /// Update the current token to represent the provided
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)));
+}



More information about the cfe-commits mailing list