Fix #1018 (strcat(strcat()) causes assertion in Tokenizer::validate)

Test case provided by povaddict
http://sourceforge.net/apps/trac/cppcheck/ticket/1018
This commit is contained in:
Reijo Tomperi 2009-11-27 23:21:13 +02:00
parent c94ecfe1a3
commit 2c51542cf1
4 changed files with 48 additions and 46 deletions

View File

@ -535,6 +535,23 @@ bool Token::isStandardType() const
return ret;
}
void Token::move(Token *srcStart, Token *srcEnd, Token *newLocation)
{
/**[newLocation] -> b -> c -> [srcStart] -> [srcEnd] -> f */
// Fix the gap, which tokens to be moved will leave
srcStart->previous()->next(srcEnd->next());
srcEnd->next()->previous(srcStart->previous());
// Fix the tokens to be moved
srcEnd->next(newLocation->next());
srcStart->previous(newLocation);
// Fix the tokens at newLocation
newLocation->next()->previous(srcEnd);
newLocation->next(srcStart);
}
//---------------------------------------------------------------------------
const Token *Token::findmatch(const Token *tok, const char pattern[], unsigned int varId)

View File

@ -274,6 +274,15 @@ public:
*/
std::string strValue() const;
/**
* Move srcStart and srcEnd tokens and all tokens between then
* into new a location. Only links between tokens are changed.
* @param srcStart This is the first token to be moved
* @param srcEnd The last token to be moved
* @param newLocation srcStart will be placed after this token.
*/
static void move(Token *srcStart, Token *srcEnd, Token *newLocation);
private:
void next(Token *next)
{

View File

@ -3983,9 +3983,6 @@ void Tokenizer::simplifyNestedStrcat()
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"))
@ -3993,52 +3990,21 @@ void Tokenizer::simplifyNestedStrcat()
tok2 = tok2->tokAt(2);
}
Token *end = tok2->next()->link()->next();
Token *endOfFirstArg = NULL;
std::stack<Token *> brackets;
unsigned int lineno = tok->next()->linenr();
// If we have this code:
// strcat(strcat(dst, foo), bar);
// We move this part of code before all strcat() calls: strcat(dst, foo)
// And place "dst" token where the code was.
Token *prevTok = tok2->previous();
// copy tokens to new place
for (Token *cur = tok2; cur != end; cur = cur->next())
{
insertPos->insertToken(cur->strAt(0));
insertPos = insertPos->next();
// Move tokens to new place
Token::move(tok2, tok2->next()->link(), tok);
tok = tok2->next()->link();
if (cur->str() == "," && endOfFirstArg == NULL)
{
endOfFirstArg = cur;
}
// Insert the "dst" token
prevTok->insertToken(tok2->strAt(2));
// preserve varId
if (cur->varId())
{
insertPos->varId(cur->varId());
}
// use line number of first strcat token for all new
// tokens
insertPos->linenr(lineno);
// 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;
// Insert semicolon after the moved strcat()
tok->insertToken(";");
}
}

View File

@ -124,6 +124,7 @@ private:
// Simplify nested strcat() calls
TEST_CASE(strcat1);
TEST_CASE(strcat2);
// Syntax error
TEST_CASE(argumentsWithSameName)
@ -1940,6 +1941,15 @@ private:
ASSERT_EQUALS(expect, tok(code));
}
void strcat2()
{
const char code[] = "; strcat(strcat(dst, foo[0]), \" \");";
const char expect[] = "; "
"strcat ( dst , foo [ 0 ] ) ; "
"strcat ( dst , \" \" ) ;";
ASSERT_EQUALS(expect, tok(code));
}
void argumentsWithSameName()
{