diff --git a/lib/checknullpointer.cpp b/lib/checknullpointer.cpp index 9747210eb..5a94545b9 100644 --- a/lib/checknullpointer.cpp +++ b/lib/checknullpointer.cpp @@ -115,26 +115,41 @@ void CheckNullPointer::parseFunctionCall(const Token &tok, std::listvarId() > 0) || - (value == 0 && Token::Match(&tok, "%var% ( %any% , 0 ,|)"))) { - if (functionNames2.find(tok.str()) != functionNames2.end()) - var.push_back(tok.tokAt(4)); + if (Token::Match(&tok, "%var% ( %any%")) { + const Token* secondParameter = tok.tokAt(2)->nextArgument(); + if (secondParameter && ((value == 0 && secondParameter->str() == "0") || (Token::Match(secondParameter, "%var%") && secondParameter->varId() > 0))) + if (functionNames2.find(tok.str()) != functionNames2.end()) + var.push_back(tok.tokAt(4)); } if (Token::Match(&tok, "printf|sprintf|snprintf|fprintf|fnprintf|scanf|sscanf|fscanf")) { const Token* argListTok = 0; // Points to first va_list argument std::string formatString; bool scan = Token::Match(&tok, "scanf|sscanf|fscanf"); - if (Token::Match(&tok, "printf|scanf ( %str% , %any%")) { + + if (Token::Match(&tok, "printf|scanf ( %str%")) { formatString = tok.strAt(2); - argListTok = tok.tokAt(4); - } else if (Token::Match(&tok, "sprintf|fprintf|sscanf|fscanf ( %var% , %str% , %any%")) { - formatString = tok.strAt(4); - argListTok = tok.tokAt(6); - } else if (Token::Match(&tok, "snprintf|fnprintf ( %var% , %any% , %str% , %any%")) { - formatString = tok.strAt(6); - argListTok = tok.tokAt(8); + if (tok.strAt(3) == ",") + argListTok = tok.tokAt(4); + else + argListTok = 0; + } else if (Token::Match(&tok, "sprintf|fprintf|sscanf|fscanf ( %any%")) { + const Token* formatStringTok = tok.tokAt(2)->nextArgument(); // Find second parameter (format string) + if (formatStringTok && Token::Match(formatStringTok, "%str%")) { + argListTok = formatStringTok->nextArgument(); // Find third parameter (first argument of va_args) + formatString = formatStringTok->str(); + } + } else if (Token::Match(&tok, "snprintf|fnprintf ( %any%")) { + const Token* formatStringTok = tok.tokAt(2); + for (int i = 0; i < 2 && formatStringTok; i++) { + formatStringTok = formatStringTok->nextArgument(); // Find third parameter (format string) + } + if (formatStringTok && Token::Match(formatStringTok, "%str%")) { + argListTok = formatStringTok->nextArgument(); // Find fourth parameter (first argument of va_args) + formatString = formatStringTok->str(); + } } + if (argListTok) { bool percent = false; for (std::string::iterator i = formatString.begin(); i != formatString.end(); ++i) { @@ -147,18 +162,10 @@ void CheckNullPointer::parseFunctionCall(const Token &tok, std::listnext()) { // Find next argument - if (argListTok->str() == "(") - argListTok = argListTok->link(); - if (argListTok == 0) - break; - if (argListTok->str() == ",") { - argListTok = argListTok->next(); - break; - } - } + argListTok = argListTok->nextArgument(); // Find next argument if (!argListTok) break; + percent = false; } } diff --git a/lib/token.cpp b/lib/token.cpp index 38bb15325..9cb9453b8 100644 --- a/lib/token.cpp +++ b/lib/token.cpp @@ -429,8 +429,8 @@ bool Token::Match(const Token *tok, const char pattern[], unsigned int varid) // Compare the first character of the string for optimization reasons // before doing more detailed checks. - bool patternUnderstood = false; if (p[0] == '%') { + bool patternUnderstood = false; switch (p[1]) { case 'v': // TODO: %var% should match only for @@ -696,6 +696,19 @@ void Token::move(Token *srcStart, Token *srcEnd, Token *newLocation) tok->_progressValue = newLocation->_progressValue; } +const Token* Token::nextArgument() const +{ + for (const Token* tok = this; tok; tok = tok->next()) { + if (tok->str() == ",") + return(tok->next()); + else if (tok->str() == "(" || tok->str() == "{" || tok->str() == "[") + tok = tok->link(); + else if (tok->str() == ")") + return(0); + } + return(0); +} + //--------------------------------------------------------------------------- const Token *Token::findmatch(const Token *tok, const char pattern[], unsigned int varId) diff --git a/lib/token.h b/lib/token.h index 281eb0d4e..605c0f596 100644 --- a/lib/token.h +++ b/lib/token.h @@ -388,6 +388,12 @@ public: tok->_progressValue = count++ * 100 / total_count; } + /** + * Returns the first token of the next argument. Does only work on argument + * lists. Returns 0, if there is no next argument + */ + const Token* nextArgument() const; + private: void next(Token *nextToken) { _next = nextToken; diff --git a/test/testtoken.cpp b/test/testtoken.cpp index 50434cec9..caca72443 100644 --- a/test/testtoken.cpp +++ b/test/testtoken.cpp @@ -38,6 +38,7 @@ private: TEST_CASE(strValue); TEST_CASE(deleteLast); + TEST_CASE(nextArgument); TEST_CASE(matchAny); TEST_CASE(matchSingleChar); @@ -129,6 +130,17 @@ private: ASSERT_EQUALS(true, tokensBack == &tok); } + void nextArgument() { + givenACodeSampleToTokenize example1("foo(1, 2, 3, 4);"); + ASSERT_EQUALS(true, Token::Match(example1.tokens()->tokAt(2)->nextArgument(), "2 , 3")); + + givenACodeSampleToTokenize example2("foo();"); + ASSERT_EQUALS(true, example2.tokens()->tokAt(2)->nextArgument() == 0); + + givenACodeSampleToTokenize example3("foo(bar(a, b), 2, 3);"); + ASSERT_EQUALS(true, Token::Match(example3.tokens()->tokAt(2)->nextArgument(), "2 , 3")); + } + void matchAny() { givenACodeSampleToTokenize varBitOrVar("abc|def");