[libcxx-commits] [libcxxabi] fb6f1bd - [ItaniumDemangle] Strip __alloc_token_ to transparently demangle allocation functions (#191048)

via libcxx-commits libcxx-commits at lists.llvm.org
Wed Apr 22 08:57:36 PDT 2026


Author: Marco Elver
Date: 2026-04-22T17:57:30+02:00
New Revision: fb6f1bde00c4ed3650bd1152607718a95ca0ce6d

URL: https://github.com/llvm/llvm-project/commit/fb6f1bde00c4ed3650bd1152607718a95ca0ce6d
DIFF: https://github.com/llvm/llvm-project/commit/fb6f1bde00c4ed3650bd1152607718a95ca0ce6d.diff

LOG: [ItaniumDemangle] Strip __alloc_token_ to transparently demangle allocation functions (#191048)

Update the Itanium demangler to recognize and strip `__alloc_token_`
prefixes introduced by AllocToken instrumentation [1]. This ensures that
instrumented allocation functions (e.g., `__alloc_token__Znwm`) demangle
back to their original source-level names (e.g., `operator new(unsigned
long)`) with a suffix `(.alloc_token)` indicating their non-standard
origin.

Since AllocToken is intended to be transparent to users who continue to
use `operator new` as before, the demangled name should reflect this
reality instead of confusing users with internal instrumentation names
in stack traces or symbolization output.

Synchronize changes across llvm and libcxxabi copies.

[1] https://clang.llvm.org/docs/AllocToken.html

Original RFC: https://discourse.llvm.org/t/rfc-a-framework-for-allocator-partitioning-hints/87434

Added: 
    llvm/test/tools/llvm-cxxfilt/alloc-token.test

Modified: 
    libcxxabi/src/demangle/ItaniumDemangle.h
    libcxxabi/test/DemangleTestCases.inc
    llvm/include/llvm/Demangle/ItaniumDemangle.h
    llvm/include/llvm/Testing/Demangle/DemangleTestCases.inc
    llvm/lib/Demangle/Demangle.cpp

Removed: 
    


################################################################################
diff  --git a/libcxxabi/src/demangle/ItaniumDemangle.h b/libcxxabi/src/demangle/ItaniumDemangle.h
index b999438ff2ca8..c001a8d33f227 100644
--- a/libcxxabi/src/demangle/ItaniumDemangle.h
+++ b/libcxxabi/src/demangle/ItaniumDemangle.h
@@ -6157,8 +6157,17 @@ AbstractManglingParser<Derived, Alloc>::parseTemplateArgs(bool TagTemplates) {
 // extension      ::= ___Z <encoding> _block_invoke
 // extension      ::= ___Z <encoding> _block_invoke<decimal-digit>+
 // extension      ::= ___Z <encoding> _block_invoke_<decimal-digit>+
+// extension      ::= __alloc_token__Z <encoding>
+// extension      ::= __alloc_token_<decimal-digit>+__Z <encoding>
 template <typename Derived, typename Alloc>
 Node *AbstractManglingParser<Derived, Alloc>::parse(bool ParseParams) {
+  bool AllocToken = consumeIf("__alloc_token_");
+  if (AllocToken) {
+    const char *Saved = First;
+    if (parseNumber().empty() || !consumeIf('_'))
+      First = Saved;
+  }
+
   if (consumeIf("_Z") || consumeIf("__Z")) {
     Node *Encoding = getDerived().parseEncoding(ParseParams);
     if (Encoding == nullptr)
@@ -6168,6 +6177,8 @@ Node *AbstractManglingParser<Derived, Alloc>::parse(bool ParseParams) {
           make<DotSuffix>(Encoding, std::string_view(First, Last - First));
       First = Last;
     }
+    if (AllocToken)
+      Encoding = make<DotSuffix>(Encoding, ".alloc_token");
     if (numLeft() != 0)
       return nullptr;
     return Encoding;

diff  --git a/libcxxabi/test/DemangleTestCases.inc b/libcxxabi/test/DemangleTestCases.inc
index 2721d2aa5504e..307d0a8c02a41 100644
--- a/libcxxabi/test/DemangleTestCases.inc
+++ b/libcxxabi/test/DemangleTestCases.inc
@@ -30219,4 +30219,15 @@
 {"_Z3fooIPU9__ptrauthILj1ELb0ELj64EEPiEvT_", "void foo<int* __ptrauth<1u, false, 64u>*>(int* __ptrauth<1u, false, 64u>*)"},
 
 {"_ZN1CpmEi", "C::operator->*(int)"},
+
+// AllocToken instrumentation
+{"__alloc_token__Znwm", "operator new(unsigned long) (.alloc_token)"},
+{"__alloc_token__Znam", "operator new[](unsigned long) (.alloc_token)"},
+{"__alloc_token__ZnwmRKSt9nothrow_t", "operator new(unsigned long, std::nothrow_t const&) (.alloc_token)"},
+{"__alloc_token__ZnamRKSt9nothrow_t", "operator new[](unsigned long, std::nothrow_t const&) (.alloc_token)"},
+{"__alloc_token_0__Znwm", "operator new(unsigned long) (.alloc_token)"},
+{"__alloc_token_1__Znam", "operator new[](unsigned long) (.alloc_token)"},
+{"__alloc_token_123__ZnwmRKSt9nothrow_t", "operator new(unsigned long, std::nothrow_t const&) (.alloc_token)"},
+{"__alloc_token__Znwm.llvm.1234", "operator new(unsigned long) (.llvm.1234) (.alloc_token)"},
+{"__alloc_token_123__Z3foov", "foo() (.alloc_token)"},
     // clang-format on

diff  --git a/llvm/include/llvm/Demangle/ItaniumDemangle.h b/llvm/include/llvm/Demangle/ItaniumDemangle.h
index 67de123fdbad5..6d7f189a6e44c 100644
--- a/llvm/include/llvm/Demangle/ItaniumDemangle.h
+++ b/llvm/include/llvm/Demangle/ItaniumDemangle.h
@@ -6157,8 +6157,17 @@ AbstractManglingParser<Derived, Alloc>::parseTemplateArgs(bool TagTemplates) {
 // extension      ::= ___Z <encoding> _block_invoke
 // extension      ::= ___Z <encoding> _block_invoke<decimal-digit>+
 // extension      ::= ___Z <encoding> _block_invoke_<decimal-digit>+
+// extension      ::= __alloc_token__Z <encoding>
+// extension      ::= __alloc_token_<decimal-digit>+__Z <encoding>
 template <typename Derived, typename Alloc>
 Node *AbstractManglingParser<Derived, Alloc>::parse(bool ParseParams) {
+  bool AllocToken = consumeIf("__alloc_token_");
+  if (AllocToken) {
+    const char *Saved = First;
+    if (parseNumber().empty() || !consumeIf('_'))
+      First = Saved;
+  }
+
   if (consumeIf("_Z") || consumeIf("__Z")) {
     Node *Encoding = getDerived().parseEncoding(ParseParams);
     if (Encoding == nullptr)
@@ -6168,6 +6177,8 @@ Node *AbstractManglingParser<Derived, Alloc>::parse(bool ParseParams) {
           make<DotSuffix>(Encoding, std::string_view(First, Last - First));
       First = Last;
     }
+    if (AllocToken)
+      Encoding = make<DotSuffix>(Encoding, ".alloc_token");
     if (numLeft() != 0)
       return nullptr;
     return Encoding;

diff  --git a/llvm/include/llvm/Testing/Demangle/DemangleTestCases.inc b/llvm/include/llvm/Testing/Demangle/DemangleTestCases.inc
index 2721d2aa5504e..307d0a8c02a41 100644
--- a/llvm/include/llvm/Testing/Demangle/DemangleTestCases.inc
+++ b/llvm/include/llvm/Testing/Demangle/DemangleTestCases.inc
@@ -30219,4 +30219,15 @@
 {"_Z3fooIPU9__ptrauthILj1ELb0ELj64EEPiEvT_", "void foo<int* __ptrauth<1u, false, 64u>*>(int* __ptrauth<1u, false, 64u>*)"},
 
 {"_ZN1CpmEi", "C::operator->*(int)"},
+
+// AllocToken instrumentation
+{"__alloc_token__Znwm", "operator new(unsigned long) (.alloc_token)"},
+{"__alloc_token__Znam", "operator new[](unsigned long) (.alloc_token)"},
+{"__alloc_token__ZnwmRKSt9nothrow_t", "operator new(unsigned long, std::nothrow_t const&) (.alloc_token)"},
+{"__alloc_token__ZnamRKSt9nothrow_t", "operator new[](unsigned long, std::nothrow_t const&) (.alloc_token)"},
+{"__alloc_token_0__Znwm", "operator new(unsigned long) (.alloc_token)"},
+{"__alloc_token_1__Znam", "operator new[](unsigned long) (.alloc_token)"},
+{"__alloc_token_123__ZnwmRKSt9nothrow_t", "operator new(unsigned long, std::nothrow_t const&) (.alloc_token)"},
+{"__alloc_token__Znwm.llvm.1234", "operator new(unsigned long) (.llvm.1234) (.alloc_token)"},
+{"__alloc_token_123__Z3foov", "foo() (.alloc_token)"},
     // clang-format on

diff  --git a/llvm/lib/Demangle/Demangle.cpp b/llvm/lib/Demangle/Demangle.cpp
index f0f7eacac98e6..f311caa46b0fb 100644
--- a/llvm/lib/Demangle/Demangle.cpp
+++ b/llvm/lib/Demangle/Demangle.cpp
@@ -12,6 +12,7 @@
 
 #include "llvm/Demangle/Demangle.h"
 #include "llvm/Demangle/StringViewExtras.h"
+#include <cctype>
 #include <cstdlib>
 #include <string_view>
 
@@ -38,6 +39,15 @@ std::string llvm::demangle(std::string_view MangledName) {
 }
 
 static bool isItaniumEncoding(std::string_view S) {
+  if (starts_with(S, "__alloc_token_")) {
+    S.remove_prefix(sizeof("__alloc_token_") - 1);
+    if (!S.empty() && std::isdigit(S[0])) {
+      while (!S.empty() && std::isdigit(S[0]))
+        S.remove_prefix(1);
+      if (starts_with(S, "_"))
+        S.remove_prefix(1);
+    }
+  }
   // Itanium demangler supports prefixes with 1-4 underscores.
   const size_t Pos = S.find_first_not_of('_');
   return Pos > 0 && Pos <= 4 && S[Pos] == 'Z';

diff  --git a/llvm/test/tools/llvm-cxxfilt/alloc-token.test b/llvm/test/tools/llvm-cxxfilt/alloc-token.test
new file mode 100644
index 0000000000000..761aa727d4db2
--- /dev/null
+++ b/llvm/test/tools/llvm-cxxfilt/alloc-token.test
@@ -0,0 +1,16 @@
+## Show that llvm-cxxfilt can handle __alloc_token_ prefixed demangling.
+
+RUN: llvm-cxxfilt __alloc_token__Znwm \
+RUN:              __alloc_token__Znam \
+RUN:              __alloc_token_0__Znwm \
+RUN:              __alloc_token_1__Znam \
+RUN:              __alloc_token_123__Z3foov \
+RUN:              __alloc_token_malloc \
+RUN:   | FileCheck %s
+
+CHECK: operator new(unsigned long) (.alloc_token)
+CHECK-NEXT: operator new[](unsigned long) (.alloc_token)
+CHECK-NEXT: operator new(unsigned long) (.alloc_token)
+CHECK-NEXT: operator new[](unsigned long) (.alloc_token)
+CHECK-NEXT: foo() (.alloc_token)
+CHECK-NEXT: __alloc_token_malloc


        


More information about the libcxx-commits mailing list