diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 7cef883c5..5d8f6a325 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -5300,6 +5300,10 @@ bool Tokenizer::simplifyFunctionReturn() const std::string pattern("(|[|=|return|%op% " + tok->str() + " ( ) ;|]|)|%cop%"); for (Token *tok2 = list.front(); tok2; tok2 = tok2->next()) { if (Token::Match(tok2, pattern.c_str())) { + if (tok->str() != tok2->strAt(1)) + // Ticket #7916: tok is for instance "foo < bar >", a single token for an instantiation, + // and tok2->strAt(1) is "foo"; bail out (TODO: we can probably handle this pattern) + continue; tok2 = tok2->next(); tok2->str(any->str()); tok2->deleteNext(2); diff --git a/test/testsimplifytokens.cpp b/test/testsimplifytokens.cpp index e86e46ff2..d79dd89c2 100644 --- a/test/testsimplifytokens.cpp +++ b/test/testsimplifytokens.cpp @@ -3322,6 +3322,30 @@ private: "const std :: string & Fred :: foo ( ) { return \"\" ; }"; ASSERT_EQUALS(expected, tok(code, false)); } + { + // Ticket #7916 + // Tokenization would include "int fact < 2 > ( ) { return 2 > ( ) ; }" and generate + // a parse error (and use after free) + const char code[] = "extern \"C\" void abort ();\n" + "template inline int fact2 ();\n" + "template inline int fact () {\n" + " return a * fact2 ();\n" + "}\n" + "template <> inline int fact<1> () {\n" + " return 1;\n" + "}\n" + "template inline int fact2 () {\n" + " return a * fact();\n" + "}\n" + "template <> inline int fact2<1> () {\n" + " return 1;\n" + "}\n" + "int main() {\n" + " fact2<3> ();\n" + " fact2<2> ();\n" + "}"; + tok(code); + } } void removeVoidFromFunction() {