[libcxxabi] r197063 - Fix demangling crasher. The crasher involved nested <encoding> involving parameter packs, which exposed a logic bug causing an empty vector<string> to be accessed with back(). In addition to fixing the bug, I've inserted numerous preemptive checks for similar bugs in the hopes that if another bug is uncovered, the bug results in an invalid mangled string instead of a demangler crash. Test suite updated with string that was causing the crash.
Howard Hinnant
hhinnant at apple.com
Wed Dec 11 11:44:25 PST 2013
Author: hhinnant
Date: Wed Dec 11 13:44:25 2013
New Revision: 197063
URL: http://llvm.org/viewvc/llvm-project?rev=197063&view=rev
Log:
Fix demangling crasher. The crasher involved nested <encoding> involving parameter packs, which exposed a logic bug causing an empty vector<string> to be accessed with back(). In addition to fixing the bug, I've inserted numerous preemptive checks for similar bugs in the hopes that if another bug is uncovered, the bug results in an invalid mangled string instead of a demangler crash. Test suite updated with string that was causing the crash.
Modified:
libcxxabi/trunk/src/cxa_demangle.cpp
libcxxabi/trunk/test/test_demangle.cpp
Modified: libcxxabi/trunk/src/cxa_demangle.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxxabi/trunk/src/cxa_demangle.cpp?rev=197063&r1=197062&r2=197063&view=diff
==============================================================================
--- libcxxabi/trunk/src/cxa_demangle.cpp (original)
+++ libcxxabi/trunk/src/cxa_demangle.cpp Wed Dec 11 13:44:25 2013
@@ -539,6 +539,8 @@ parse_template_param(const char* first,
{
if (first[1] == '_')
{
+ if (db.template_param.empty())
+ return first;
if (!db.template_param.back().empty())
{
for (auto& t : db.template_param.back().front())
@@ -561,7 +563,7 @@ parse_template_param(const char* first,
sub *= 10;
sub += static_cast<size_t>(*t - '0');
}
- if (t == last || *t != '_')
+ if (t == last || *t != '_' || db.template_param.empty())
return first;
++sub;
if (sub < db.template_param.back().size())
@@ -596,6 +598,8 @@ parse_const_cast_expr(const char* first,
const char* t1 = parse_expression(t, last, db);
if (t1 != t)
{
+ if (db.names.size() < 2)
+ return first;
auto expr = db.names.back().move_full();
db.names.pop_back();
db.names.back() = "const_cast<" + db.names.back().move_full() + ">(" + expr + ")";
@@ -620,6 +624,8 @@ parse_dynamic_cast_expr(const char* firs
const char* t1 = parse_expression(t, last, db);
if (t1 != t)
{
+ if (db.names.size() < 2)
+ return first;
auto expr = db.names.back().move_full();
db.names.pop_back();
db.names.back() = "dynamic_cast<" + db.names.back().move_full() + ">(" + expr + ")";
@@ -644,6 +650,8 @@ parse_reinterpret_cast_expr(const char*
const char* t1 = parse_expression(t, last, db);
if (t1 != t)
{
+ if (db.names.size() < 2)
+ return first;
auto expr = db.names.back().move_full();
db.names.pop_back();
db.names.back() = "reinterpret_cast<" + db.names.back().move_full() + ">(" + expr + ")";
@@ -668,6 +676,8 @@ parse_static_cast_expr(const char* first
const char* t1 = parse_expression(t, last, db);
if (t1 != t)
{
+ if (db.names.size() < 2)
+ return first;
auto expr = db.names.back().move_full();
db.names.pop_back();
db.names.back() = "static_cast<" + db.names.back().move_full() + ">(" + expr + ")";
@@ -704,6 +714,8 @@ parse_sizeof_type_expr(const char* first
const char* t = parse_type(first+2, last, db);
if (t != first+2)
{
+ if (db.names.empty())
+ return first;
db.names.back() = "sizeof (" + db.names.back().move_full() + ")";
first = t;
}
@@ -722,6 +734,8 @@ parse_sizeof_expr_expr(const char* first
const char* t = parse_expression(first+2, last, db);
if (t != first+2)
{
+ if (db.names.empty())
+ return first;
db.names.back() = "sizeof (" + db.names.back().move_full() + ")";
first = t;
}
@@ -813,6 +827,8 @@ parse_sizeof_function_param_pack_expr(co
const char* t = parse_function_param(first+2, last, db);
if (t != first+2)
{
+ if (db.names.empty())
+ return first;
db.names.back() = "sizeof...(" + db.names.back().move_full() + ")";
first = t;
}
@@ -836,6 +852,8 @@ parse_typeid_expr(const char* first, con
t = parse_type(first+2, last, db);
if (t != first+2)
{
+ if (db.names.empty())
+ return first;
db.names.back() = "typeid(" + db.names.back().move_full() + ")";
first = t;
}
@@ -854,6 +872,8 @@ parse_throw_expr(const char* first, cons
const char* t = parse_expression(first+2, last, db);
if (t != first+2)
{
+ if (db.names.empty())
+ return first;
db.names.back() = "throw " + db.names.back().move_full();
first = t;
}
@@ -875,6 +895,8 @@ parse_dot_star_expr(const char* first, c
const char* t1 = parse_expression(t, last, db);
if (t1 != t)
{
+ if (db.names.size() < 2)
+ return first;
auto expr = db.names.back().move_full();
db.names.pop_back();
db.names.back().first += ".*" + expr;
@@ -899,6 +921,8 @@ parse_simple_id(const char* first, const
const char* t1 = parse_template_args(t, last, db);
if (t1 != t)
{
+ if (db.names.size() < 2)
+ return first;
auto args = db.names.back().move_full();
db.names.pop_back();
db.names.back().first += std::move(args);
@@ -945,6 +969,8 @@ parse_unresolved_type(const char* first,
t = parse_decltype(first, last, db);
if (t != first)
{
+ if (db.names.empty())
+ return first;
db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
first = t;
}
@@ -960,6 +986,8 @@ parse_unresolved_type(const char* first,
t = parse_unqualified_name(first+2, last, db);
if (t != first+2)
{
+ if (db.names.empty())
+ return first;
db.names.back().first.insert(0, "std::");
db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
first = t;
@@ -986,6 +1014,8 @@ parse_destructor_name(const char* first,
t = parse_simple_id(first, last, db);
if (t != first)
{
+ if (db.names.empty())
+ return first;
db.names.back().first.insert(0, "~");
first = t;
}
@@ -1017,6 +1047,8 @@ parse_base_unresolved_name(const char* f
first = parse_template_args(t, last, db);
if (first != t)
{
+ if (db.names.size() < 2)
+ return first;
auto args = db.names.back().move_full();
db.names.pop_back();
db.names.back().first += std::move(args);
@@ -1041,6 +1073,8 @@ parse_base_unresolved_name(const char* f
first = parse_template_args(t, last, db);
if (first != t)
{
+ if (db.names.size() < 2)
+ return first;
auto args = db.names.back().move_full();
db.names.pop_back();
db.names.back().first += std::move(args);
@@ -1090,7 +1124,11 @@ parse_unresolved_name(const char* first,
if (t2 != t)
{
if (global)
+ {
+ if (db.names.empty())
+ return first;
db.names.back().first.insert(0, "::");
+ }
first = t2;
}
else if (last - t > 2 && t[0] == 's' && t[1] == 'r')
@@ -1105,6 +1143,8 @@ parse_unresolved_name(const char* first,
t1 = parse_template_args(t, last, db);
if (t1 != t)
{
+ if (db.names.size() < 2)
+ return first;
auto args = db.names.back().move_full();
db.names.pop_back();
db.names.back().first += std::move(args);
@@ -1118,7 +1158,7 @@ parse_unresolved_name(const char* first,
while (*t != 'E')
{
t1 = parse_unresolved_qualifier_level(t, last, db);
- if (t1 == t || t1 == last)
+ if (t1 == t || t1 == last || db.names.size() < 2)
return first;
auto s = db.names.back().move_full();
db.names.pop_back();
@@ -1129,9 +1169,12 @@ parse_unresolved_name(const char* first,
t1 = parse_base_unresolved_name(t, last, db);
if (t1 == t)
{
- db.names.pop_back();
+ if (!db.names.empty())
+ db.names.pop_back();
return first;
}
+ if (db.names.size() < 2)
+ return first;
auto s = db.names.back().move_full();
db.names.pop_back();
db.names.back().first += "::" + std::move(s);
@@ -1147,6 +1190,8 @@ parse_unresolved_name(const char* first,
t1 = parse_template_args(t, last, db);
if (t1 != t)
{
+ if (db.names.size() < 2)
+ return first;
auto args = db.names.back().move_full();
db.names.pop_back();
db.names.back().first += std::move(args);
@@ -1155,9 +1200,12 @@ parse_unresolved_name(const char* first,
t1 = parse_base_unresolved_name(t, last, db);
if (t1 == t)
{
- db.names.pop_back();
+ if (!db.names.empty())
+ db.names.pop_back();
return first;
}
+ if (db.names.size() < 2)
+ return first;
auto s = db.names.back().move_full();
db.names.pop_back();
db.names.back().first += "::" + std::move(s);
@@ -1170,11 +1218,15 @@ parse_unresolved_name(const char* first,
return first;
t = t1;
if (global)
+ {
+ if (db.names.empty())
+ return first;
db.names.back().first.insert(0, "::");
+ }
while (*t != 'E')
{
t1 = parse_unresolved_qualifier_level(t, last, db);
- if (t1 == t || t1 == last)
+ if (t1 == t || t1 == last || db.names.size() < 2)
return first;
auto s = db.names.back().move_full();
db.names.pop_back();
@@ -1185,9 +1237,12 @@ parse_unresolved_name(const char* first,
t1 = parse_base_unresolved_name(t, last, db);
if (t1 == t)
{
- db.names.pop_back();
+ if (!db.names.empty())
+ db.names.pop_back();
return first;
}
+ if (db.names.size() < 2)
+ return first;
auto s = db.names.back().move_full();
db.names.pop_back();
db.names.back().first += "::" + std::move(s);
@@ -1213,6 +1268,8 @@ parse_dot_expr(const char* first, const
const char* t1 = parse_unresolved_name(t, last, db);
if (t1 != t)
{
+ if (db.names.size() < 2)
+ return first;
auto name = db.names.back().move_full();
db.names.pop_back();
db.names.back().first += "." + name;
@@ -1236,6 +1293,8 @@ parse_call_expr(const char* first, const
{
if (t == last)
return first;
+ if (db.names.empty())
+ return first;
db.names.back().first += db.names.back().second;
db.names.back().second = typename C::String();
db.names.back().first.append("(");
@@ -1245,10 +1304,14 @@ parse_call_expr(const char* first, const
const char* t1 = parse_expression(t, last, db);
if (t1 == t || t1 == last)
return first;
+ if (db.names.empty())
+ return first;
auto tmp = db.names.back().move_full();
db.names.pop_back();
if (!tmp.empty())
{
+ if (db.names.empty())
+ return first;
if (!first_expr)
{
db.names.back().first.append(", ");
@@ -1259,6 +1322,8 @@ parse_call_expr(const char* first, const
t = t1;
}
++t;
+ if (db.names.empty())
+ return first;
db.names.back().first.append(")");
first = t;
}
@@ -1301,10 +1366,14 @@ parse_new_expr(const char* first, const
has_expr_list = true;
if (!first_expr)
{
+ if (db.names.empty())
+ return first;
auto tmp = db.names.back().move_full();
db.names.pop_back();
if (!tmp.empty())
{
+ if (db.names.empty())
+ return first;
db.names.back().first.append(", ");
db.names.back().first.append(tmp);
first_expr = false;
@@ -1330,10 +1399,14 @@ parse_new_expr(const char* first, const
return first;
if (!first_expr)
{
+ if (db.names.empty())
+ return first;
auto tmp = db.names.back().move_full();
db.names.pop_back();
if (!tmp.empty())
{
+ if (db.names.empty())
+ return first;
db.names.back().first.append(", ");
db.names.back().first.append(tmp);
first_expr = false;
@@ -1347,14 +1420,20 @@ parse_new_expr(const char* first, const
typename C::String init_list;
if (has_init)
{
+ if (db.names.empty())
+ return first;
init_list = db.names.back().move_full();
db.names.pop_back();
}
+ if (db.names.empty())
+ return first;
auto type = db.names.back().move_full();
db.names.pop_back();
typename C::String expr_list;
if (has_expr_list)
{
+ if (db.names.empty())
+ return first;
expr_list = db.names.back().move_full();
db.names.pop_back();
}
@@ -1416,10 +1495,14 @@ parse_conversion_expr(const char* first,
return first;
if (!first_expr)
{
+ if (db.names.empty())
+ return first;
auto tmp = db.names.back().move_full();
db.names.pop_back();
if (!tmp.empty())
{
+ if (db.names.empty())
+ return first;
db.names.back().first.append(", ");
db.names.back().first.append(tmp);
first_expr = false;
@@ -1430,6 +1513,8 @@ parse_conversion_expr(const char* first,
}
++t;
}
+ if (db.names.size() < 2)
+ return first;
auto tmp = db.names.back().move_full();
db.names.pop_back();
db.names.back() = "(" + db.names.back().move_full() + ")(" + tmp + ")";
@@ -1453,6 +1538,8 @@ parse_arrow_expr(const char* first, cons
const char* t1 = parse_expression(t, last, db);
if (t1 != t)
{
+ if (db.names.size() < 2)
+ return first;
auto tmp = db.names.back().move_full();
db.names.pop_back();
db.names.back().first += "->";
@@ -1545,6 +1632,8 @@ parse_function_type(const char* first, c
sig += " &&";
break;
}
+ if (db.names.empty())
+ return first;
db.names.back().first += " ";
db.names.back().second.insert(0, sig);
first = t;
@@ -1568,6 +1657,8 @@ parse_pointer_to_member_type(const char*
const char* t2 = parse_type(t, last, db);
if (t2 != t)
{
+ if (db.names.size() < 2)
+ return first;
auto func = std::move(db.names.back());
db.names.pop_back();
auto class_type = std::move(db.names.back());
@@ -1602,6 +1693,8 @@ parse_array_type(const char* first, cons
const char* t = parse_type(first+2, last, db);
if (t != first+2)
{
+ if (db.names.empty())
+ return first;
if (db.names.back().second.substr(0, 2) == " [")
db.names.back().second.erase(0, 1);
db.names.back().second.insert(0, " []");
@@ -1616,6 +1709,8 @@ parse_array_type(const char* first, cons
const char* t2 = parse_type(t+1, last, db);
if (t2 != t+1)
{
+ if (db.names.empty())
+ return first;
if (db.names.back().second.substr(0, 2) == " [")
db.names.back().second.erase(0, 1);
db.names.back().second.insert(0, " [" + typename C::String(first+1, t) + "]");
@@ -1631,6 +1726,8 @@ parse_array_type(const char* first, cons
const char* t2 = parse_type(++t, last, db);
if (t2 != t)
{
+ if (db.names.size() < 2)
+ return first;
auto type = std::move(db.names.back());
db.names.pop_back();
auto expr = std::move(db.names.back());
@@ -1663,6 +1760,8 @@ parse_decltype(const char* first, const
const char* t = parse_expression(first+2, last, db);
if (t != first+2 && t != last && *t == 'E')
{
+ if (db.names.empty())
+ return first;
db.names.back() = "decltype(" + db.names.back().move_full() + ")";
first = t+1;
}
@@ -1700,6 +1799,8 @@ parse_vector_type(const char* first, con
const char* t1 = parse_type(t, last, db);
if (t1 != t)
{
+ if (db.names.empty())
+ return first;
db.names.back().first += " vector[" + typename C::String(num, sz) + "]";
first = t1;
}
@@ -1721,6 +1822,8 @@ parse_vector_type(const char* first, con
const char* t = parse_expression(t1, last, db);
if (t != t1)
{
+ if (db.names.empty())
+ return first;
num = db.names.back().move_full();
db.names.pop_back();
t1 = t;
@@ -1731,6 +1834,8 @@ parse_vector_type(const char* first, con
const char* t = parse_type(t1, last, db);
if (t != t1)
{
+ if (db.names.empty())
+ return first;
db.names.back().first += " vector[" + num + "]";
first = t;
}
@@ -1841,6 +1946,8 @@ parse_type(const char* first, const char
t = parse_array_type(first, last, db);
if (t != first)
{
+ if (db.names.empty())
+ return first;
first = t;
db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
}
@@ -1849,6 +1956,8 @@ parse_type(const char* first, const char
t = parse_type(first+1, last, db);
if (t != first+1)
{
+ if (db.names.empty())
+ return first;
db.names.back().first.append(" complex");
first = t;
db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
@@ -1858,6 +1967,8 @@ parse_type(const char* first, const char
t = parse_function_type(first, last, db);
if (t != first)
{
+ if (db.names.empty())
+ return first;
first = t;
db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
}
@@ -1866,6 +1977,8 @@ parse_type(const char* first, const char
t = parse_type(first+1, last, db);
if (t != first+1)
{
+ if (db.names.empty())
+ return first;
db.names.back().first.append(" imaginary");
first = t;
db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
@@ -1875,6 +1988,8 @@ parse_type(const char* first, const char
t = parse_pointer_to_member_type(first, last, db);
if (t != first)
{
+ if (db.names.empty())
+ return first;
first = t;
db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
}
@@ -2002,6 +2117,8 @@ parse_type(const char* first, const char
const char* t2 = parse_type(t, last, db);
if (t2 != t)
{
+ if (db.names.size() < 2)
+ return first;
auto type = db.names.back().move_full();
db.names.pop_back();
if (db.names.back().first.substr(0, 9) != "objcproto")
@@ -2034,6 +2151,8 @@ parse_type(const char* first, const char
t = parse_name(first, last, db);
if (t != first)
{
+ if (db.names.empty())
+ return first;
db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
first = t;
}
@@ -2049,6 +2168,8 @@ parse_type(const char* first, const char
t = parse_template_args(first, last, db);
if (t != first)
{
+ if (db.names.size() < 2)
+ return first;
auto template_args = db.names.back().move_full();
db.names.pop_back();
db.names.back().first += template_args;
@@ -2084,6 +2205,8 @@ parse_type(const char* first, const char
t = parse_decltype(first, last, db);
if (t != first)
{
+ if (db.names.empty())
+ return first;
db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
first = t;
return first;
@@ -2093,6 +2216,8 @@ parse_type(const char* first, const char
t = parse_vector_type(first, last, db);
if (t != first)
{
+ if (db.names.empty())
+ return first;
db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
first = t;
return first;
@@ -2114,6 +2239,8 @@ parse_type(const char* first, const char
t = parse_name(first, last, db);
if (t != first)
{
+ if (db.names.empty())
+ return first;
db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
first = t;
}
@@ -2232,6 +2359,8 @@ parse_operator_name(const char* first, c
db.try_to_parse_template_args = try_to_parse_template_args;
if (t != first+2)
{
+ if (db.names.empty())
+ return first;
db.names.back().first.insert(0, "operator ");
db.parsed_ctor_dtor_cv = true;
first = t;
@@ -2453,6 +2582,8 @@ parse_operator_name(const char* first, c
const char* t = parse_source_name(first+2, last, db);
if (t != first+2)
{
+ if (db.names.empty())
+ return first;
db.names.back().first.insert(0, "operator ");
first = t;
}
@@ -2662,6 +2793,8 @@ parse_expr_primary(const char* first, co
;
if (n != t && n != last && *n == 'E')
{
+ if (db.names.empty())
+ return first;
db.names.back() = "(" + db.names.back().move_full() + ")" + typename C::String(t, n);
first = n+1;
break;
@@ -2762,6 +2895,8 @@ parse_ctor_dtor_name(const char* first,
case '2':
case '3':
case '5':
+ if (db.names.empty())
+ return first;
db.names.push_back(base_name(db.names.back().first));
first += 2;
db.parsed_ctor_dtor_cv = true;
@@ -2775,6 +2910,8 @@ parse_ctor_dtor_name(const char* first,
case '1':
case '2':
case '5':
+ if (db.names.empty())
+ return first;
db.names.push_back("~" + base_name(db.names.back().first));
first += 2;
db.parsed_ctor_dtor_cv = true;
@@ -2845,6 +2982,8 @@ parse_unnamed_type_name(const char* firs
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);
@@ -2854,6 +2993,8 @@ parse_unnamed_type_name(const char* firs
t1 = parse_type(t0, last, db);
if (t1 == t0)
break;
+ if (db.names.size() < 2)
+ return first;
tmp = db.names.back().move_full();
db.names.pop_back();
if (!tmp.empty())
@@ -2968,7 +3109,11 @@ parse_unscoped_name(const char* first, c
if (t1 != t0)
{
if (St)
+ {
+ if (db.names.empty())
+ return first;
db.names.back().first.insert(0, "std::");
+ }
first = t1;
}
}
@@ -2986,6 +3131,8 @@ parse_alignof_type(const char* first, co
const char* t = parse_type(first+2, last, db);
if (t != first+2)
{
+ if (db.names.empty())
+ return first;
db.names.back().first = "alignof (" + db.names.back().move_full() + ")";
first = t;
}
@@ -3004,6 +3151,8 @@ parse_alignof_expr(const char* first, co
const char* t = parse_expression(first+2, last, db);
if (t != first+2)
{
+ if (db.names.empty())
+ return first;
db.names.back().first = "alignof (" + db.names.back().move_full() + ")";
first = t;
}
@@ -3018,6 +3167,8 @@ parse_noexcept_expression(const char* fi
const char* t1 = parse_expression(first, last, db);
if (t1 != first)
{
+ if (db.names.empty())
+ return first;
db.names.back().first = "noexcept (" + db.names.back().move_full() + ")";
first = t1;
}
@@ -3031,6 +3182,8 @@ parse_prefix_expression(const char* firs
const char* t1 = parse_expression(first, last, db);
if (t1 != first)
{
+ if (db.names.empty())
+ return first;
db.names.back().first = op + "(" + db.names.back().move_full() + ")";
first = t1;
}
@@ -3047,6 +3200,8 @@ parse_binary_expression(const char* firs
const char* t2 = parse_expression(t1, last, db);
if (t2 != t1)
{
+ if (db.names.size() < 2)
+ return first;
auto op2 = db.names.back().move_full();
db.names.pop_back();
auto op1 = db.names.back().move_full();
@@ -3197,6 +3352,8 @@ parse_expression(const char* first, cons
const char* t1 = parse_expression(t+2, last, db);
if (t1 != t+2)
{
+ if (db.names.empty())
+ return first;
db.names.back().first = (parsed_gs ? typename C::String("::") : typename C::String()) +
"delete[] " + db.names.back().move_full();
first = t1;
@@ -3216,6 +3373,8 @@ parse_expression(const char* first, cons
const char* t1 = parse_expression(t+2, last, db);
if (t1 != t+2)
{
+ if (db.names.empty())
+ return first;
db.names.back().first = (parsed_gs ? typename C::String("::") : typename C::String()) +
"delete " + db.names.back().move_full();
first = t1;
@@ -3286,6 +3445,8 @@ parse_expression(const char* first, cons
const char* t2 = parse_expression(t1, last, db);
if (t2 != t1)
{
+ if (db.names.size() < 2)
+ return first;
auto op2 = db.names.back().move_full();
db.names.pop_back();
auto op1 = db.names.back().move_full();
@@ -3357,6 +3518,8 @@ parse_expression(const char* first, cons
const char* t1 = parse_expression(first+2, last, db);
if (t1 != first+2)
{
+ if (db.names.empty())
+ return first;
db.names.back() = "(" + db.names.back().move_full() + ")--";
first = t1;
}
@@ -3445,6 +3608,8 @@ parse_expression(const char* first, cons
const char* t1 = parse_expression(first+2, last, db);
if (t1 != first+2)
{
+ if (db.names.empty())
+ return first;
db.names.back() = "(" + db.names.back().move_full() + ")++";
first = t1;
}
@@ -3472,6 +3637,8 @@ parse_expression(const char* first, cons
const char* t3 = parse_expression(t2, last, db);
if (t3 != t2)
{
+ if (db.names.size() < 3)
+ return first;
auto op3 = db.names.back().move_full();
db.names.pop_back();
auto op2 = db.names.back().move_full();
@@ -3899,6 +4066,8 @@ parse_local_name(const char* first, cons
{
case 's':
first = parse_discriminator(t+1, last);
+ if (db.names.empty())
+ return first;
db.names.back().first.append("::string literal");
break;
case 'd':
@@ -3911,6 +4080,8 @@ parse_local_name(const char* first, cons
t1 = parse_name(t, last, db);
if (t1 != t)
{
+ if (db.names.size() < 2)
+ return first;
auto name = db.names.back().move_full();
db.names.pop_back();
db.names.back().first.append("::");
@@ -3929,6 +4100,8 @@ parse_local_name(const char* first, cons
{
// parse but ignore discriminator
first = parse_discriminator(t1, last);
+ if (db.names.size() < 2)
+ return first;
auto name = db.names.back().move_full();
db.names.pop_back();
db.names.back().first.append("::");
@@ -3985,11 +4158,15 @@ parse_name(const char* first, const char
{
if (t1 != last && *t1 == 'I') // <unscoped-template-name> <template-args>
{
+ if (db.names.empty())
+ return first;
db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
t0 = t1;
t1 = parse_template_args(t0, last, db);
if (t1 != t0)
{
+ if (db.names.size() < 2)
+ return first;
auto tmp = db.names.back().move_full();
db.names.pop_back();
db.names.back().first += tmp;
@@ -4008,6 +4185,8 @@ parse_name(const char* first, const char
t1 = parse_template_args(t0, last, db);
if (t1 != t0)
{
+ if (db.names.size() < 2)
+ return first;
auto tmp = db.names.back().move_full();
db.names.pop_back();
db.names.back().first += tmp;
@@ -4093,6 +4272,8 @@ parse_special_name(const char* first, co
t = parse_type(first+2, last, db);
if (t != first+2)
{
+ if (db.names.empty())
+ return first;
db.names.back().first.insert(0, "vtable for ");
first = t;
}
@@ -4102,6 +4283,8 @@ parse_special_name(const char* first, co
t = parse_type(first+2, last, db);
if (t != first+2)
{
+ if (db.names.empty())
+ return first;
db.names.back().first.insert(0, "VTT for ");
first = t;
}
@@ -4111,6 +4294,8 @@ parse_special_name(const char* first, co
t = parse_type(first+2, last, db);
if (t != first+2)
{
+ if (db.names.empty())
+ return first;
db.names.back().first.insert(0, "typeinfo for ");
first = t;
}
@@ -4120,6 +4305,8 @@ parse_special_name(const char* first, co
t = parse_type(first+2, last, db);
if (t != first+2)
{
+ if (db.names.empty())
+ return first;
db.names.back().first.insert(0, "typeinfo name for ");
first = t;
}
@@ -4136,6 +4323,8 @@ parse_special_name(const char* first, co
t = parse_encoding(t1, last, db);
if (t != t1)
{
+ if (db.names.empty())
+ return first;
db.names.back().first.insert(0, "covariant return thunk to ");
first = t;
}
@@ -4152,6 +4341,8 @@ parse_special_name(const char* first, co
const char* t1 = parse_type(++t0, last, db);
if (t1 != t0)
{
+ if (db.names.size() < 2)
+ return first;
auto left = db.names.back().move_full();
db.names.pop_back();
db.names.back().first = "construction vtable for " +
@@ -4171,6 +4362,8 @@ parse_special_name(const char* first, co
t = parse_encoding(t0, last, db);
if (t != t0)
{
+ if (db.names.empty())
+ return first;
if (first[2] == 'v')
{
db.names.back().first.insert(0, "virtual thunk to ");
@@ -4194,6 +4387,8 @@ parse_special_name(const char* first, co
t = parse_name(first+2, last, db);
if (t != first+2)
{
+ if (db.names.empty())
+ return first;
db.names.back().first.insert(0, "guard variable for ");
first = t;
}
@@ -4203,6 +4398,8 @@ parse_special_name(const char* first, co
t = parse_name(first+2, last, db);
if (t != first+2)
{
+ if (db.names.empty())
+ return first;
db.names.back().first.insert(0, "reference temporary for ");
first = t;
}
@@ -4214,6 +4411,26 @@ parse_special_name(const char* first, co
return first;
}
+template <class T>
+class save_value
+{
+ T& restore_;
+ T original_value_;
+public:
+ save_value(T& restore)
+ : restore_(restore),
+ original_value_(restore)
+ {}
+
+ ~save_value()
+ {
+ restore_ = std::move(original_value_);
+ }
+
+ save_value(const save_value&) = delete;
+ save_value& operator=(const save_value&) = delete;
+};
+
// <encoding> ::= <function name> <bare-function-type>
// ::= <data name>
// ::= <special-name>
@@ -4224,6 +4441,11 @@ parse_encoding(const char* first, const
{
if (first != last)
{
+ save_value<decltype(db.encoding_depth)> su(db.encoding_depth);
+ ++db.encoding_depth;
+ save_value<decltype(db.tag_templates)> sb(db.tag_templates);
+ if (db.encoding_depth > 1)
+ db.tag_templates = true;
switch (*first)
{
case 'G':
@@ -4239,17 +4461,23 @@ parse_encoding(const char* first, const
{
if (t != last && *t != 'E' && *t != '.')
{
- bool tag_templates = db.tag_templates;
+ save_value<bool> sb2(db.tag_templates);
db.tag_templates = false;
const char* t2;
typename C::String ret2;
+ if (db.names.empty())
+ return first;
const typename C::String& nm = db.names.back().first;
+ if (nm.empty())
+ return first;
if (!db.parsed_ctor_dtor_cv && nm.back() == '>' && nm[nm.size()-2] != '-'
&& nm[nm.size()-2] != '>')
{
t2 = parse_type(t, last, db);
if (t2 == t)
return first;
+ if (db.names.size() < 2)
+ return first;
auto ret1 = std::move(db.names.back().first);
ret2 = std::move(db.names.back().second);
if (ret2.empty())
@@ -4286,6 +4514,8 @@ parse_encoding(const char* first, const
db.names.pop_back();
if (!tmp.empty())
{
+ if (db.names.empty())
+ return first;
if (!first_arg)
db.names.back().first += ", ";
else
@@ -4296,6 +4526,8 @@ parse_encoding(const char* first, const
t = t2;
}
}
+ if (db.names.empty())
+ return first;
db.names.back().first += ')';
if (cv & 1)
db.names.back().first.append(" const");
@@ -4309,7 +4541,6 @@ parse_encoding(const char* first, const
db.names.back().first.append(" &&");
db.names.back().first += ret2;
first = t;
- db.tag_templates = tag_templates;
}
else
first = t;
@@ -4351,6 +4582,8 @@ parse_block_invoke(const char* first, co
while (t != last && isdigit(*t))
++t;
}
+ if (db.names.empty())
+ return first;
db.names.back().first.insert(0, "invocation function for block in ");
first = t;
}
@@ -4366,6 +4599,8 @@ parse_dot_suffix(const char* first, cons
{
if (first != last && *first == '.')
{
+ if (db.names.empty())
+ return first;
db.names.back().first += " (" + typename C::String(first, last) + ")";
first = last;
}
@@ -4601,6 +4836,7 @@ struct Db
Vector<template_param_type> template_param;
unsigned cv;
unsigned ref;
+ unsigned encoding_depth;
bool parsed_ctor_dtor_cv;
bool tag_templates;
bool fix_forward_references;
@@ -4632,6 +4868,7 @@ __cxa_demangle(const char* mangled_name,
Db db(a);
db.cv = 0;
db.ref = 0;
+ db.encoding_depth = 0;
db.parsed_ctor_dtor_cv = false;
db.tag_templates = true;
db.template_param.emplace_back(a);
Modified: libcxxabi/trunk/test/test_demangle.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxxabi/trunk/test/test_demangle.cpp?rev=197063&r1=197062&r2=197063&view=diff
==============================================================================
--- libcxxabi/trunk/test/test_demangle.cpp (original)
+++ libcxxabi/trunk/test/test_demangle.cpp Wed Dec 11 13:44:25 2013
@@ -29583,6 +29583,7 @@ const char* cases[][2] =
{"_Z1fPU11objcproto1A11objc_object", "f(id<A>)"},
{"_Z1fPKU11objcproto1A7NSArray", "f(NSArray<A> const*)"},
{"_ZNK1AIJ1Z1Y1XEEcv1BIJDpPT_EEIJS2_S1_S0_EEEv", "A<Z, Y, X>::operator B<X*, Y*, Z*><X, Y, Z>() const"},
+ {"_ZNK3Ncr6Silver7Utility6detail12CallOnThreadIZ53-[DeploymentSetupController handleManualServerEntry:]E3$_5EclIJEEEDTclclL_ZNS2_4getTIS4_EERT_vEEspclsr3stdE7forwardIT_Efp_EEEDpOSA_", "decltype(-[DeploymentSetupController handleManualServerEntry:]::$_5& Ncr::Silver::Utility::detail::getT<-[DeploymentSetupController handleManualServerEntry:]::$_5>()()(std::forward<-[DeploymentSetupController handleManualServerEntry:]::$_5>(fp))) Ncr::Silver::Utility::detail::CallOnThread<-[DeploymentSetupController handleManualServerEntry:]::$_5>::operator()<>(-[DeploymentSetupController handleManualServerEntry:]::$_5&&) const"},
};
const unsigned N = sizeof(cases) / sizeof(cases[0]);
@@ -29663,7 +29664,9 @@ int main()
std::string input;
while (std::cin)
{
- std::cin >> input;
+ std::getline(std::cin, input);
+ if (std::cin.fail())
+ break;
std::size_t len = 0;
int status;
len = 0;
More information about the cfe-commits
mailing list