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; 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) const Token *Token::findmatch(const Token *tok, const char pattern[], unsigned int varId)

View File

@ -274,6 +274,15 @@ public:
*/ */
std::string strValue() const; 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: private:
void next(Token *next) void next(Token *next)
{ {

View File

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

View File

@ -124,6 +124,7 @@ private:
// Simplify nested strcat() calls // Simplify nested strcat() calls
TEST_CASE(strcat1); TEST_CASE(strcat1);
TEST_CASE(strcat2);
// Syntax error // Syntax error
TEST_CASE(argumentsWithSameName) TEST_CASE(argumentsWithSameName)
@ -1940,6 +1941,15 @@ private:
ASSERT_EQUALS(expect, tok(code)); 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() void argumentsWithSameName()
{ {