Fixed #629 (Tokenizer: expand nested strcat() calls)

http://sourceforge.net/apps/trac/cppcheck/ticket/629
This commit is contained in:
Slava Semushin 2009-09-05 23:46:27 +07:00
parent d86a2505f3
commit a9273c9d39
4 changed files with 91 additions and 0 deletions

View File

@ -1629,6 +1629,8 @@ void Tokenizer::simplifyTokenList()
simplifyIfNotNull(); simplifyIfNotNull();
simplifyIfAssign(); simplifyIfAssign();
simplifyNestedStrcat();
for (Token *tok = _tokens; tok; tok = tok->next()) for (Token *tok = _tokens; tok; tok = tok->next())
{ {
if (Token::Match(tok, "case %any% : %var%")) 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<Token *> 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;
}
}
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------

View File

@ -196,6 +196,9 @@ private:
/** Replace a "goto" with the statements */ /** Replace a "goto" with the statements */
void simplifyGoto(); void simplifyGoto();
/** Expand nested strcat() calls. */
void simplifyNestedStrcat();
/** Simplify "if else" */ /** Simplify "if else" */
void elseif(); void elseif();

View File

@ -568,6 +568,13 @@ private:
" strcat(n, \"def\");\n" " strcat(n, \"def\");\n"
"}\n"); "}\n");
ASSERT_EQUALS("[test.cpp:5]: (possible error) Buffer overrun\n", errout.str()); 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() void sprintf1()

View File

@ -108,6 +108,9 @@ private:
// Simplify goto.. // Simplify goto..
TEST_CASE(goto1); TEST_CASE(goto1);
// Simplify nested strcat() calls
TEST_CASE(strcat1);
} }
std::string tok(const char code[]) std::string tok(const char code[])
@ -1345,6 +1348,21 @@ private:
ASSERT_EQUALS(code, tok(code)); 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) REGISTER_TEST(TestSimplifyTokens)