summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorErik Pilkington <erik.pilkington@gmail.com>2017-05-24 05:44:19 +0000
committerErik Pilkington <erik.pilkington@gmail.com>2017-05-24 05:44:19 +0000
commit0a91f7ab6633790706437fd2e76d31939aeb0025 (patch)
tree03dcc30a31dd2e62d8db2f50d1d189efc1644191 /src
parentc515867bc14c433febcc574baedd081c078124d1 (diff)
[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 git-svn-id: https://llvm.org/svn/llvm-project/libcxxabi/trunk@303718 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'src')
-rw-r--r--src/cxa_demangle.cpp54
1 files changed, 31 insertions, 23 deletions
diff --git a/src/cxa_demangle.cpp b/src/cxa_demangle.cpp
index 7a81ecb..25e6b9a 100644
--- a/src/cxa_demangle.cpp
+++ b/src/cxa_demangle.cpp
@@ -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* first, const char* last, C& db)
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* first, const char* last, C& db)
}
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);}
};