[PATCH] D33368: [libcxxabi][demangler] Fix a crash in the demangler

Erik Pilkington via Phabricator via cfe-commits cfe-commits at lists.llvm.org
Fri May 19 14:15:09 PDT 2017


erik.pilkington created this revision.
Herald added a reviewer: EricWF.

This patch fixes a bug in the demangler where a pack expansion template parameter substitution with more than one element in a lambda's parameter list resulted in either a misdemangle or a crash. I'll commit this change to ItaniumDemangle.cpp as well, as it has the same problem.

rdar://32098667

Thanks for taking a look,
Erik


https://reviews.llvm.org/D33368

Files:
  src/cxa_demangle.cpp
  test/test_demangle.pass.cpp


Index: test/test_demangle.pass.cpp
===================================================================
--- test/test_demangle.pass.cpp
+++ test/test_demangle.pass.cpp
@@ -29604,6 +29604,7 @@
     {"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]);
Index: src/cxa_demangle.cpp
===================================================================
--- src/cxa_demangle.cpp
+++ src/cxa_demangle.cpp
@@ -3015,6 +3015,7 @@
             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 +3025,42 @@
             }
             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);
+                    size_t k0 = db.names.size();
+                    const char* t1 = parse_type(t0, last, db);
+                    size_t k1 = db.names.size();
                     if (t1 == t0)
                         break;
-                    if (db.names.size() < 2)
+                    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.
+                    for (size_t k = k0; k < k1; ++k) {
+                        auto tmp = db.names[k].move_full();
+                        if (!tmp.empty())
+                        {
+                            if (!is_first_it)
+                                db.names[lambda_pos].first.append(", ");
+                            is_first_it = false;
+                            db.names[lambda_pos].first.append(tmp);
+                        }
                     }
+                    db.names.erase(db.names.begin() +
+                                       static_cast<long>(lambda_pos) + 1,
+                                   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(")");
             }


-------------- next part --------------
A non-text attachment was scrubbed...
Name: D33368.99625.patch
Type: text/x-patch
Size: 3698 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20170519/9f767e70/attachment-0001.bin>


More information about the cfe-commits mailing list