[libcxxabi] r303718 - [demangler] Fix a crash in the demangler during parsing of a lamdba

Erik Pilkington via cfe-commits cfe-commits at lists.llvm.org
Tue May 23 22:44:20 PDT 2017


Author: epilk
Date: Wed May 24 00:44:19 2017
New Revision: 303718

URL: http://llvm.org/viewvc/llvm-project?rev=303718&view=rev
Log:
[demangler] Fix a crash in the demangler during parsing of a lamdba

The problem is that multiple types could have been parsed from parse_type(),
which the lamdba parameter parsing didn't handle.

Differential revision: https://reviews.llvm.org/D33368

Modified:
    libcxxabi/trunk/src/cxa_demangle.cpp
    libcxxabi/trunk/test/test_demangle.pass.cpp

Modified: libcxxabi/trunk/src/cxa_demangle.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxxabi/trunk/src/cxa_demangle.cpp?rev=303718&r1=303717&r2=303718&view=diff
==============================================================================
--- libcxxabi/trunk/src/cxa_demangle.cpp (original)
+++ libcxxabi/trunk/src/cxa_demangle.cpp Wed May 24 00:44:19 2017
@@ -15,6 +15,7 @@
 #include <algorithm>
 #include <string>
 #include <numeric>
+#include <cassert>
 #include <cstdlib>
 #include <cstring>
 #include <cctype>
@@ -3015,6 +3016,7 @@ parse_unnamed_type_name(const char* firs
             break;
         case 'l':
           {
+            size_t lambda_pos = db.names.size();
             db.names.push_back(typename C::String("'lambda'("));
             const char* t0 = first+2;
             if (first[2] == 'v')
@@ -3024,36 +3026,41 @@ parse_unnamed_type_name(const char* firs
             }
             else
             {
-                const char* t1 = parse_type(t0, last, db);
-                if (t1 == t0)
-                {
-                    if(!db.names.empty())
-                        db.names.pop_back();
-                    return first;
-                }
-                if (db.names.size() < 2)
-                    return first;
-                auto tmp = db.names.back().move_full();
-                db.names.pop_back();
-                db.names.back().first.append(tmp);
-                t0 = t1;
+                bool is_first_it = true;
                 while (true)
                 {
-                    t1 = parse_type(t0, last, db);
+                    long k0 = static_cast<long>(db.names.size());
+                    const char* t1 = parse_type(t0, last, db);
+                    long k1 = static_cast<long>(db.names.size());
                     if (t1 == t0)
                         break;
-                    if (db.names.size() < 2)
+                    assert(k0 <= k1 && "parse_type() mutated the name stack");
+                    if (k1 == k0)
                         return first;
-                    tmp = db.names.back().move_full();
-                    db.names.pop_back();
-                    if (!tmp.empty())
-                    {
-                        db.names.back().first.append(", ");
-                        db.names.back().first.append(tmp);
-                    }
+                    // If the call to parse_type above found a pack expansion
+                    // substitution, then multiple names could have been
+                    // inserted into the name table. Walk through the names,
+                    // appending each onto the lambda's parameter list.
+                    std::for_each(db.names.begin() + k0, db.names.begin() + k1,
+                                  [&](typename C::sub_type::value_type &pair) {
+                                      if (pair.empty())
+                                          return;
+                                      auto &lambda = db.names[lambda_pos].first;
+                                      if (!is_first_it)
+                                          lambda.append(", ");
+                                      is_first_it = false;
+                                      lambda.append(pair.move_full());
+                                  });
+                    db.names.erase(db.names.begin() + k0, db.names.end());
                     t0 = t1;
                 }
-                if(db.names.empty())
+                if (is_first_it)
+                {
+                    if (!db.names.empty())
+                        db.names.pop_back();
+                    return first;
+                }
+                if (db.names.empty() || db.names.size() - 1 != lambda_pos)
                   return first;
                 db.names.back().first.append(")");
             }
@@ -4964,6 +4971,7 @@ struct string_pair
         string_pair(const char (&s)[N]) : first(s, N-1) {}
 
     size_t size() const {return first.size() + second.size();}
+    bool empty() const { return first.empty() && second.empty(); }
     StrT full() const {return first + second;}
     StrT move_full() {return std::move(first) + std::move(second);}
 };

Modified: libcxxabi/trunk/test/test_demangle.pass.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxxabi/trunk/test/test_demangle.pass.cpp?rev=303718&r1=303717&r2=303718&view=diff
==============================================================================
--- libcxxabi/trunk/test/test_demangle.pass.cpp (original)
+++ libcxxabi/trunk/test/test_demangle.pass.cpp Wed May 24 00:44:19 2017
@@ -29604,6 +29604,7 @@ const char* cases[][2] =
     {"PFvRmOE", "void (*)(unsigned long&) &&"},
     {"_ZTW1x", "thread-local wrapper routine for x"},
     {"_ZTHN3fooE", "thread-local initialization routine for foo"},
+    {"_Z4algoIJiiiEEvZ1gEUlT_E_", "void algo<int, int, int>(g::'lambda'(int, int, int))"},
 };
 
 const unsigned N = sizeof(cases) / sizeof(cases[0]);
@@ -29664,7 +29665,8 @@ const char* invalid_cases[] =
     "\x44\x74\x71\x75\x35\x2A\xDF\x74\x44\x61\x73\x63\x35\x2A\x3B\x41\x72\x4D\x6E\x65\x34\x9F\xC1\x63\x41\x72\x4D\x6E\x77\x38\x9A\x8E\x44\x6F\x64\x6C\x53\xF9\x5F\x70\x74\x70\x69\x45\x33\x44\x76\x35",
     "\x44\x74\x70\x74\x71\x75\x32\x43\x41\x38\x65\x6E\x9B\x72\x4D\xC1\x43\x41\x72\x4D\x6E\x77\x38\x9A\x8E\x44\x6F\x64\x6C\x53\xF9\x5F\x70\x74\x70\x69\x45\x38\xD3\x73\x9E\x2A\x37",
     "\x46\x44\x74\x70\x74\x71\x75\x32\x43\x41\x72\x4D\x6E\x65\x34\x9F\xC1\x43\x41\x72\x4D\x6E\x77\x38\x9A\x8E\x44\x6F\x64\x6C\x53\xF9\x5F\x70\x74\x70\x69\x45\x34\xD3\x73\x9E\x2A\x37\x72\x33\x8E\x3A\x29\x8E\x44\x35",
-	"_ZcvCiIJEEDvT__FFFFT_vT_v",
+    "_ZcvCiIJEEDvT__FFFFT_vT_v",
+    "Z1JIJ1_T_EE3o00EUlT_E0",
 };
 
 const unsigned NI = sizeof(invalid_cases) / sizeof(invalid_cases[0]);




More information about the cfe-commits mailing list