From a9273c9d39eaebb0820296e31d12199c2dfc4e99 Mon Sep 17 00:00:00 2001 From: Slava Semushin Date: Sat, 5 Sep 2009 23:46:27 +0700 Subject: [PATCH] Fixed #629 (Tokenizer: expand nested strcat() calls) http://sourceforge.net/apps/trac/cppcheck/ticket/629 --- src/tokenize.cpp | 63 +++++++++++++++++++++++++++++++++++++ src/tokenize.h | 3 ++ test/testbufferoverrun.cpp | 7 +++++ test/testsimplifytokens.cpp | 18 +++++++++++ 4 files changed, 91 insertions(+) diff --git a/src/tokenize.cpp b/src/tokenize.cpp index edb1c1dfd..9a59fb74d 100644 --- a/src/tokenize.cpp +++ b/src/tokenize.cpp @@ -1629,6 +1629,8 @@ void Tokenizer::simplifyTokenList() simplifyIfNotNull(); simplifyIfAssign(); + simplifyNestedStrcat(); + for (Token *tok = _tokens; tok; tok = tok->next()) { if (Token::Match(tok, "case %any% : %var%")) @@ -3313,8 +3315,69 @@ void Tokenizer::simplifyGoto() } } +void Tokenizer::simplifyNestedStrcat() +{ + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (! Token::Match(tok, "[;{}] strcat ( strcat (")) + { + continue; + } + // insert extracted function calls before first strcat call + Token *insertPos = tok; + // find inner strcat call + Token *tok2 = tok->tokAt(3); + while (Token::simpleMatch(tok2, "strcat ( strcat")) + { + tok2 = tok2->tokAt(2); + } + + Token *end = tok2->next()->link()->next(); + Token *endOfFirstArg = NULL; + std::stack brackets; + + // copy tokens to new place + for (Token *cur = tok2; cur != end; cur = cur->next()) + { + insertPos->insertToken(cur->strAt(0)); + insertPos = insertPos->next(); + + if (cur->str() == "," && endOfFirstArg == NULL) + { + endOfFirstArg = cur; + } + + // preserve varId + if (cur->varId()) + { + insertPos->varId(cur->varId()); + } + + // linkify braces + if (insertPos->str() == "(") + { + brackets.push(insertPos); + } + else if (insertPos->str() == ")") + { + Token::createMutualLinks(brackets.top(), insertPos); + brackets.pop(); + } + } + insertPos->insertToken(";"); + + // remove tokens at old place, but don't remove token with + // variable name (1st argument) + Token::eraseTokens(tok2->previous(), tok2->tokAt(2)); + Token::eraseTokens(endOfFirstArg->previous(), end); + + // skip just inserted tokens + tok = insertPos; + } + +} //--------------------------------------------------------------------------- diff --git a/src/tokenize.h b/src/tokenize.h index dfb3e594a..9ee6f7f6b 100644 --- a/src/tokenize.h +++ b/src/tokenize.h @@ -196,6 +196,9 @@ private: /** Replace a "goto" with the statements */ void simplifyGoto(); + /** Expand nested strcat() calls. */ + void simplifyNestedStrcat(); + /** Simplify "if else" */ void elseif(); diff --git a/test/testbufferoverrun.cpp b/test/testbufferoverrun.cpp index d4babff2b..b3bd3ebab 100644 --- a/test/testbufferoverrun.cpp +++ b/test/testbufferoverrun.cpp @@ -568,6 +568,13 @@ private: " strcat(n, \"def\");\n" "}\n"); ASSERT_EQUALS("[test.cpp:5]: (possible error) Buffer overrun\n", errout.str()); + + check("void f()\n" + "{\n" + " char n[5];\n" + " strcat(strcat(n, \"abc\"), \"def\");\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:4]: (possible error) Buffer overrun\n", errout.str()); } void sprintf1() diff --git a/test/testsimplifytokens.cpp b/test/testsimplifytokens.cpp index d59c85da8..5e04b8857 100644 --- a/test/testsimplifytokens.cpp +++ b/test/testsimplifytokens.cpp @@ -108,6 +108,9 @@ private: // Simplify goto.. TEST_CASE(goto1); + + // Simplify nested strcat() calls + TEST_CASE(strcat1); } std::string tok(const char code[]) @@ -1345,6 +1348,21 @@ private: ASSERT_EQUALS(code, tok(code)); } } + + + void strcat1() + { + const char code[] = "; strcat(strcat(strcat(strcat(strcat(strcat(dst, \"this \"), \"\"), \"is \"), \"a \"), \"test\"), \".\");"; + const char expect[] = "; " + "strcat ( dst , \"this \" ) ; " + "strcat ( dst , \"\" ) ; " + "strcat ( dst , \"is \" ) ; " + "strcat ( dst , \"a \" ) ; " + "strcat ( dst , \"test\" ) ; " + "strcat ( dst , \".\" ) ;"; + + ASSERT_EQUALS(expect, tok(code)); + } }; REGISTER_TEST(TestSimplifyTokens)