[llvm] r338075 - [MS Demangler] Properly handle function parameter back-refs.

Zachary Turner via llvm-commits llvm-commits at lists.llvm.org
Thu Jul 26 15:13:40 PDT 2018


Author: zturner
Date: Thu Jul 26 15:13:39 2018
New Revision: 338075

URL: http://llvm.org/viewvc/llvm-project?rev=338075&view=rev
Log:
[MS Demangler] Properly handle function parameter back-refs.

Properly demangle function parameter back-references.

Previously we treated lists of function parameters and template
parameters the same. There are some important differences with regards
to back-references, and some less important differences regarding which
characters can appear before or after the name.

The important differences are that with a given type T, all instances of
a function parameter list share the same global back-ref table.
Specifically, if X and Y are function pointers, then there are 3
entities in the declaration X func(Y) which all affect and are affected
by the master parameter back-ref table:
  1) The parameter list of X's function type
  2) the parameter list of func itself
  3) The parameter list of Y's function type.

The previous code would create a back-reference table that was local to
a single parameter list, so it would not be shared across parameter
lists.

This was discovered when porting ms-back-references.test from clang's
mangling tests. All of these tests should now pass with the new changes.

In doing so, I split the function for parsing template and function
parameters into two separate functions. This makes the template
parameter list parsing code in particular very small and easy to
understand now.

Differential Revision: https://reviews.llvm.org/D49875

Added:
    llvm/trunk/test/Demangle/ms-back-references.test
Modified:
    llvm/trunk/lib/Demangle/MicrosoftDemangle.cpp

Modified: llvm/trunk/lib/Demangle/MicrosoftDemangle.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Demangle/MicrosoftDemangle.cpp?rev=338075&r1=338074&r2=338075&view=diff
==============================================================================
--- llvm/trunk/lib/Demangle/MicrosoftDemangle.cpp (original)
+++ llvm/trunk/lib/Demangle/MicrosoftDemangle.cpp Thu Jul 26 15:13:39 2018
@@ -751,7 +751,8 @@ private:
 
   ArrayType *demangleArrayType();
 
-  ParamList demangleParameterList();
+  ParamList demangleTemplateParameterList();
+  ParamList demangleFunctionParameterList();
 
   int demangleNumber();
   void demangleNamePiece(Name &Node, bool IsHead);
@@ -785,6 +786,22 @@ private:
   // Memory allocator.
   ArenaAllocator Arena;
 
+  // A single type uses one global back-ref table for all function params.
+  // This means back-refs can even go "into" other types.  Examples:
+  //
+  //  // Second int* is a back-ref to first.
+  //  void foo(int *, int*);
+  //
+  //  // Second int* is not a back-ref to first (first is not a function param).
+  //  int* foo(int*);
+  //
+  //  // Second int* is a back-ref to first (ALL function types share the same
+  //  // back-ref map.
+  //  using F = void(*)(int*);
+  //  F G(int *);
+  Type *FunctionParamBackRefs[10];
+  size_t FunctionParamBackRefCount = 0;
+
   // The first 10 BackReferences in a mangled name can be back-referenced by
   // special name @[0-9]. This is a storage for the first 10 BackReferences.
   StringView BackReferences[10];
@@ -941,7 +958,7 @@ void Demangler::demangleNamePiece(Name &
   } else if (MangledName.consumeFront("?$")) {
     // Class template.
     Node.Str = demangleString(false);
-    Node.TemplateParams = demangleParameterList();
+    Node.TemplateParams = demangleTemplateParameterList();
   } else if (!IsHead && MangledName.consumeFront("?A")) {
     // Anonymous namespace starts with ?A.  So does overloaded operator[],
     // but the distinguishing factor is that namespace themselves are not
@@ -1311,7 +1328,7 @@ FunctionType *Demangler::demangleFunctio
   if (!IsStructor)
     FTy->ReturnType = demangleType(QualifierMangleMode::Result);
 
-  FTy->Params = demangleParameterList();
+  FTy->Params = demangleFunctionParameterList();
 
   demangleThrowSpecification();
 
@@ -1543,14 +1560,8 @@ ArrayType *Demangler::demangleArrayType(
 }
 
 // Reads a function or a template parameters.
-ParamList Demangler::demangleParameterList() {
-  // Within the same parameter list, you can backreference the first 10 types.
-  Type *BackRef[10];
-  int Idx = 0;
-
+ParamList Demangler::demangleFunctionParameterList() {
   // Empty parameter list.
-  // FIXME: Will this cause problems if demangleParameterList() is called in the
-  // context of a template parameter list?
   if (MangledName.consumeFront('X'))
     return {};
 
@@ -1558,29 +1569,34 @@ ParamList Demangler::demangleParameterLi
   ParamList **Current = &Head;
   while (!Error && !MangledName.startsWith('@') &&
          !MangledName.startsWith('Z')) {
+
     if (startsWithDigit(MangledName)) {
       int N = MangledName[0] - '0';
-      if (N >= Idx) {
+      if (N >= FunctionParamBackRefCount) {
         Error = true;
         return {};
       }
       MangledName = MangledName.dropFront();
 
       *Current = Arena.alloc<ParamList>();
-      (*Current)->Current = BackRef[N]->clone(Arena);
+      (*Current)->Current = FunctionParamBackRefs[N]->clone(Arena);
       Current = &(*Current)->Next;
       continue;
     }
 
-    size_t ArrayDimension = MangledName.size();
+    size_t OldSize = MangledName.size();
 
     *Current = Arena.alloc<ParamList>();
     (*Current)->Current = demangleType(QualifierMangleMode::Drop);
 
-    // Single-letter types are ignored for backreferences because
-    // memorizing them doesn't save anything.
-    if (Idx <= 9 && ArrayDimension - MangledName.size() > 1)
-      BackRef[Idx++] = (*Current)->Current;
+    size_t CharsConsumed = OldSize - MangledName.size();
+    assert(CharsConsumed != 0);
+
+    // Single-letter types are ignored for backreferences because memorizing
+    // them doesn't save anything.
+    if (FunctionParamBackRefCount <= 9 && CharsConsumed > 1)
+      FunctionParamBackRefs[FunctionParamBackRefCount++] = (*Current)->Current;
+
     Current = &(*Current)->Next;
   }
 
@@ -1601,6 +1617,29 @@ ParamList Demangler::demangleParameterLi
   Error = true;
   return {};
 }
+
+ParamList Demangler::demangleTemplateParameterList() {
+  ParamList *Head;
+  ParamList **Current = &Head;
+  while (!Error && !MangledName.startsWith('@')) {
+
+    // Template parameter lists don't participate in back-referencing.
+    *Current = Arena.alloc<ParamList>();
+    (*Current)->Current = demangleType(QualifierMangleMode::Drop);
+
+    Current = &(*Current)->Next;
+  }
+
+  if (Error)
+    return {};
+
+  // Template parameter lists cannot be variadic, so it can only be terminated
+  // by @.
+  if (MangledName.consumeFront('@'))
+    return *Head;
+  Error = true;
+  return {};
+}
 
 void Demangler::output() {
   // Converts an AST to a string.

Added: llvm/trunk/test/Demangle/ms-back-references.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Demangle/ms-back-references.test?rev=338075&view=auto
==============================================================================
--- llvm/trunk/test/Demangle/ms-back-references.test (added)
+++ llvm/trunk/test/Demangle/ms-back-references.test Thu Jul 26 15:13:39 2018
@@ -0,0 +1,53 @@
+; RUN: llvm-undname < %s | FileCheck %s
+
+; CHECK-NOT: Invalid mangled name
+
+?f1@@YAXPBD0 at Z
+; CHECK: void __cdecl f1(char const *, char const *)
+
+?f2@@YAXPBDPAD at Z
+; CHECK: void __cdecl f2(char const *, char *)
+
+?f3@@YAXHPBD0 at Z
+; CHECK: void __cdecl f3(int, char const *, char const *)
+
+?f4@@YAPBDPBD0 at Z
+; CHECK: char const * __cdecl f4(char const *, char const *)
+
+?f5@@YAXPBDIDPBX0I at Z
+; CHECK: void __cdecl f5(char const *, unsigned int, char, void const *, char const *, unsigned int)
+
+?f6@@YAX_N0 at Z
+; CHECK: void __cdecl f6(bool, bool)
+
+?f7@@YAXHPAHH0_N1PA_N at Z
+; CHECK: void __cdecl f7(int, int *, int, int *, bool, bool, bool *)
+
+; FIXME: tests for more than 10 types?
+
+?g1@@YAXUS@@@Z
+; CHECK: void __cdecl g1(struct S)
+
+?g2@@YAXUS@@0 at Z
+; CHECK: void __cdecl g2(struct S, struct S)
+
+?g3@@YAXUS@@0PAU1 at 1@Z
+; CHECK: void __cdecl g3(struct S, struct S, struct S *, struct S *)
+
+?g4@@YAXPBDPAUS@@01 at Z
+; CHECK: void __cdecl g4(char const *, struct S *, char const *, struct S *)
+
+?mbb at S@@QAEX_N0 at Z
+; CHECK: void __thiscall S::mbb(bool, bool)
+
+?h1@@YAXPBD0P6AXXZ1 at Z
+; CHECK: void __cdecl h1(char const *, char const *, void (__cdecl *)(void), void (__cdecl *)(void))
+
+?h2@@YAXP6AXPAX at Z0@Z
+; CHECK: void __cdecl h2(void (__cdecl *)(void *), void *)
+
+?h3@@YAP6APAHPAH0 at ZP6APAH00@Z10 at Z
+; CHECK: int * (__cdecl * __cdecl h3(int * (__cdecl *)(int *, int *), int * (__cdecl *)(int *, int *), int *))(int *, int *)
+
+?foo at 0@YAXXZ
+; CHECK: void __cdecl foo::foo(void)




More information about the llvm-commits mailing list