Skip to content

Commit 0e4c508

Browse files
zingsheimPKEuS
authored andcommitted
Fixed danmar#4272 and danmar#6237 (Crash from running out of memory with many templates)
1 parent fe468ac commit 0e4c508

File tree

3 files changed

+80
-5
lines changed

3 files changed

+80
-5
lines changed

lib/templatesimplifier.cpp

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -721,7 +721,19 @@ void TemplateSimplifier::expandTemplate(
721721
std::vector<const Token *> &typesUsedInTemplateInstantiation,
722722
std::list<Token *> &templateInstantiations)
723723
{
724+
bool inTemplateDefinition=false;
725+
std::vector<const Token *> localTypeParametersInDeclaration;
724726
for (const Token *tok3 = tokenlist.front(); tok3; tok3 = tok3 ? tok3->next() : nullptr) {
727+
if (tok3->str()=="template") {
728+
if (tok3->next() && tok3->next()->str()=="<") {
729+
TemplateParametersInDeclaration(tok3->tokAt(2), localTypeParametersInDeclaration);
730+
if (localTypeParametersInDeclaration.size() != typeParametersInDeclaration.size())
731+
inTemplateDefinition = false; // Partial specialization
732+
else
733+
inTemplateDefinition = true;
734+
} else
735+
inTemplateDefinition = false; // Only template instantiation
736+
}
725737
if (Token::Match(tok3, "{|(|["))
726738
tok3 = tok3->link();
727739

@@ -731,7 +743,8 @@ void TemplateSimplifier::expandTemplate(
731743
}
732744

733745
// member function implemented outside class definition
734-
else if (TemplateSimplifier::instantiateMatch(tok3, name, typeParametersInDeclaration.size(), ":: ~| %var% (")) {
746+
else if (inTemplateDefinition &&
747+
TemplateSimplifier::instantiateMatch(tok3, name, typeParametersInDeclaration.size(), ":: ~| %var% (")) {
735748
tokenlist.addtoken(newName, tok3->linenr(), tok3->fileIndex());
736749
while (tok3 && tok3->str() != "::")
737750
tok3 = tok3->next();
@@ -1150,6 +1163,17 @@ bool TemplateSimplifier::simplifyCalculations(Token *_tokens)
11501163
return ret;
11511164
}
11521165

1166+
const Token * TemplateSimplifier::TemplateParametersInDeclaration(
1167+
const Token * tok,
1168+
std::vector<const Token *> & typeParametersInDeclaration)
1169+
{
1170+
typeParametersInDeclaration.clear();
1171+
for (; tok && tok->str() != ">"; tok = tok->next()) {
1172+
if (Token::Match(tok, "%var% ,|>"))
1173+
typeParametersInDeclaration.push_back(tok);
1174+
}
1175+
return tok;
1176+
}
11531177

11541178
bool TemplateSimplifier::simplifyTemplateInstantiations(
11551179
TokenList& tokenlist,
@@ -1165,10 +1189,7 @@ bool TemplateSimplifier::simplifyTemplateInstantiations(
11651189

11661190
// Contains tokens such as "T"
11671191
std::vector<const Token *> typeParametersInDeclaration;
1168-
for (tok = tok->tokAt(2); tok && tok->str() != ">"; tok = tok->next()) {
1169-
if (Token::Match(tok, "%var% ,|>"))
1170-
typeParametersInDeclaration.push_back(tok);
1171-
}
1192+
tok = TemplateParametersInDeclaration(tok->tokAt(2), typeParametersInDeclaration);
11721193

11731194
// bail out if the end of the file was reached
11741195
if (!tok)

lib/templatesimplifier.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,19 @@ class CPPCHECKLIB TemplateSimplifier {
117117
std::vector<const Token *> &typesUsedInTemplateInstantiation,
118118
std::list<Token *> &templateInstantiations);
119119

120+
/**
121+
* @brief TemplateParametersInDeclaration
122+
* @param tok template < typename T, typename S >
123+
* ^ tok
124+
* @param typeParametersInDeclaration template < typename T, typename S >
125+
* ^ [0] ^ [1]
126+
* @return template < typename T, typename S >
127+
* ^ return
128+
*/
129+
static const Token * TemplateParametersInDeclaration(
130+
const Token * tok,
131+
std::vector<const Token *> & typeParametersInDeclaration);
132+
120133
/**
121134
* Simplify templates : expand all instantiations for a template
122135
* @todo It seems that inner templates should be instantiated recursively

test/testsimplifytemplate.cpp

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,8 @@ class TestSimplifyTemplate : public TestFixture {
8383
TEST_CASE(template46); // #5816 - syntax error reported for valid code
8484
TEST_CASE(template47); // #6023 - syntax error reported for valid code
8585
TEST_CASE(template48); // #6134 - 100% CPU upon invalid code
86+
TEST_CASE(template49); // #6237 - template instantiation
87+
TEST_CASE(template50); // #4272 - simple partial specialization
8688
TEST_CASE(template_unhandled);
8789
TEST_CASE(template_default_parameter);
8890
TEST_CASE(template_default_type);
@@ -878,6 +880,45 @@ class TestSimplifyTemplate : public TestFixture {
878880
ASSERT_EQUALS("", errout.str());
879881
}
880882

883+
void template49() { // #6237
884+
const char code[] = "template <classname T> class Fred { void f(); void g(); };\n"
885+
"template <classname T> void Fred<T>::f() { }\n"
886+
"template <classname T> void Fred<T>::g() { }\n"
887+
"template void Fred<float>::f();\n"
888+
"template void Fred<int>::g();\n";
889+
890+
const std::string expected("template < classname T > void Fred<T> :: f ( ) { } "
891+
"template < classname T > void Fred<T> :: g ( ) { } "
892+
"template void Fred<float> :: f ( ) ; "
893+
"template void Fred<int> :: g ( ) ; "
894+
"class Fred<T> { void f ( ) ; void g ( ) ; } ; "
895+
"Fred<T> :: f ( ) { } "
896+
"Fred<T> :: g ( ) { } "
897+
"class Fred<float> { void f ( ) ; void g ( ) ; } ; "
898+
"class Fred<int> { void f ( ) ; void g ( ) ; } ;");
899+
900+
ASSERT_EQUALS(expected, tok(code));
901+
}
902+
903+
void template50() { // #4272
904+
const char code[] = "template <classname T> class Fred { void f(); };\n"
905+
"template <classname T> void Fred<T>::f() { }\n"
906+
"template<> void Fred<float>::f() { }\n"
907+
"template<> void Fred<int>::g() { }\n";
908+
909+
const std::string expected("template < classname T > void Fred<T> :: f ( ) { } "
910+
"template < > void Fred<float> :: f ( ) { } "
911+
"template < > void Fred<int> :: g ( ) { } "
912+
"class Fred<T> { void f ( ) ; } ; "
913+
"Fred<T> :: f ( ) { } "
914+
"class Fred<float> { void f ( ) ; } ; "
915+
"class Fred<int> { void f ( ) ; } ;");
916+
917+
ASSERT_EQUALS(expected, tok(code));
918+
}
919+
920+
921+
881922
void template_default_parameter() {
882923
{
883924
const char code[] = "template <class T, int n=3>\n"

0 commit comments

Comments
 (0)