Fixed false negative: nullpointer passed as std::string argument (#7927)
Refactorization: Removed dead code from CheckNullPointer::parseFunctionCall()
This commit is contained in:
parent
fef52f2ea1
commit
b08f99a082
|
@ -48,7 +48,7 @@ static bool checkNullpointerFunctionCallPlausibility(const Function* func, unsig
|
|||
* @param value 0 => invalid with null pointers as parameter.
|
||||
* 1-.. => only invalid with uninitialized data.
|
||||
*/
|
||||
void CheckNullPointer::parseFunctionCall(const Token &tok, std::list<const Token *> &var, const Library *library, unsigned char value)
|
||||
void CheckNullPointer::parseFunctionCall(const Token &tok, std::list<const Token *> &var, const Library *library)
|
||||
{
|
||||
if (Token::Match(&tok, "%name% ( )") || !tok.tokAt(2))
|
||||
return;
|
||||
|
@ -57,21 +57,18 @@ void CheckNullPointer::parseFunctionCall(const Token &tok, std::list<const Token
|
|||
const Token* secondParam = firstParam->nextArgument();
|
||||
|
||||
// 1st parameter..
|
||||
if (Token::Match(firstParam, "%var% ,|)") ||
|
||||
(value == 0 && Token::Match(firstParam, "0|NULL ,|)"))) {
|
||||
if (value == 0 && Token::Match(&tok, "snprintf|vsnprintf|fnprintf|vfnprintf") && secondParam && secondParam->str() != "0") // Only if length (second parameter) is not zero
|
||||
if (Token::Match(&tok, "snprintf|vsnprintf|fnprintf|vfnprintf") && secondParam && secondParam->str() != "0") // Only if length (second parameter) is not zero
|
||||
var.push_back(firstParam);
|
||||
}
|
||||
|
||||
// Library
|
||||
if (library) {
|
||||
if (library || tok.function() != nullptr) {
|
||||
const Token *param = firstParam;
|
||||
int argnr = 1;
|
||||
while (param) {
|
||||
if (Token::Match(param, "%var% ,|)") || (value==0 && Token::Match(param, "0|NULL ,|)"))) {
|
||||
if (value == 0 && library->isnullargbad(&tok, argnr) && checkNullpointerFunctionCallPlausibility(tok.function(), argnr))
|
||||
if (library && library->isnullargbad(&tok, argnr) && checkNullpointerFunctionCallPlausibility(tok.function(), argnr))
|
||||
var.push_back(param);
|
||||
else if (value == 1 && library->isuninitargbad(&tok, argnr))
|
||||
else if (tok.function()) {
|
||||
const Variable* argVar = tok.function()->getArgumentVar(argnr-1);
|
||||
if (argVar && argVar->isStlStringType() && !argVar->isArrayOrPointer())
|
||||
var.push_back(param);
|
||||
}
|
||||
param = param->nextArgument();
|
||||
|
@ -124,11 +121,9 @@ void CheckNullPointer::parseFunctionCall(const Token &tok, std::list<const Token
|
|||
if (_continue)
|
||||
continue;
|
||||
|
||||
if ((*i == 'n' || *i == 's' || scan) && (!scan || value == 0)) {
|
||||
if ((value == 0 && argListTok->str() == "0") || Token::Match(argListTok, "%var% [,)]")) {
|
||||
if ((*i == 'n' || *i == 's' || scan)) {
|
||||
var.push_back(argListTok);
|
||||
}
|
||||
}
|
||||
|
||||
if (*i != 'm') // %m is a non-standard glibc extension that requires no parameter
|
||||
argListTok = argListTok->nextArgument(); // Find next argument
|
||||
|
@ -345,7 +340,7 @@ void CheckNullPointer::nullPointerByDeRefAndChec()
|
|||
if (!ftok || !ftok->previous())
|
||||
continue;
|
||||
std::list<const Token *> varlist;
|
||||
parseFunctionCall(*ftok->previous(), varlist, &_settings->library, 0);
|
||||
parseFunctionCall(*ftok->previous(), varlist, &_settings->library);
|
||||
if (std::find(varlist.begin(), varlist.end(), tok) != varlist.end()) {
|
||||
if (value->condition == nullptr)
|
||||
nullPointerError(tok, tok->str(), false, value->defaultArg, !value->isKnown());
|
||||
|
@ -422,7 +417,7 @@ void CheckNullPointer::nullConstantDereference()
|
|||
nullPointerError(tok);
|
||||
} else { // function call
|
||||
std::list<const Token *> var;
|
||||
parseFunctionCall(*tok, var, &_settings->library, 0);
|
||||
parseFunctionCall(*tok, var, &_settings->library);
|
||||
|
||||
// is one of the var items a NULL pointer?
|
||||
for (std::list<const Token *>::const_iterator it = var.begin(); it != var.end(); ++it) {
|
||||
|
|
|
@ -61,13 +61,10 @@ public:
|
|||
* @param tok first token
|
||||
* @param var variables that the function read / write.
|
||||
* @param library --library files data
|
||||
* @param value 0 => invalid with null pointers as parameter.
|
||||
* non-zero => invalid with uninitialized data.
|
||||
*/
|
||||
static void parseFunctionCall(const Token &tok,
|
||||
std::list<const Token *> &var,
|
||||
const Library *library,
|
||||
unsigned char value);
|
||||
const Library *library);
|
||||
|
||||
/**
|
||||
* Is there a pointer dereference? Everything that should result in
|
||||
|
|
|
@ -2075,6 +2075,16 @@ private:
|
|||
" ASSERT_MESSAGE(\"Error on s\", 0 == s.compare(\"Some text\"));\n"
|
||||
"}");
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
|
||||
check("void foo(int i, std::string s);\n"
|
||||
"void bar() {\n"
|
||||
" foo(0, \"\");\n"
|
||||
" foo(0, 0);\n"
|
||||
" foo(var, 0);\n"
|
||||
" foo(0, var);\n"
|
||||
"}");
|
||||
ASSERT_EQUALS("[test.cpp:4]: (error) Null pointer dereference\n"
|
||||
"[test.cpp:5]: (error) Null pointer dereference\n", errout.str());
|
||||
}
|
||||
|
||||
void nullpointerStdStream() {
|
||||
|
@ -2258,11 +2268,9 @@ private:
|
|||
library.functions["x"].argumentChecks[2] = arg;
|
||||
library.functions["x"].argumentChecks[3] = arg;
|
||||
|
||||
std::list<const Token *> null, uninit;
|
||||
CheckNullPointer::parseFunctionCall(*xtok, null, &library, 0U);
|
||||
CheckNullPointer::parseFunctionCall(*xtok, uninit, &library, 1U);
|
||||
std::list<const Token *> null;
|
||||
CheckNullPointer::parseFunctionCall(*xtok, null, &library);
|
||||
ASSERT_EQUALS(0U, null.size());
|
||||
ASSERT_EQUALS(0U, uninit.size());
|
||||
}
|
||||
|
||||
// for 1st parameter null pointer is not ok..
|
||||
|
@ -2274,46 +2282,10 @@ private:
|
|||
library.functions["x"].argumentChecks[3] = arg;
|
||||
library.functions["x"].argumentChecks[1].notnull = true;
|
||||
|
||||
std::list<const Token *> null,uninit;
|
||||
CheckNullPointer::parseFunctionCall(*xtok, null, &library, 0U);
|
||||
CheckNullPointer::parseFunctionCall(*xtok, uninit, &library, 1U);
|
||||
std::list<const Token *> null;
|
||||
CheckNullPointer::parseFunctionCall(*xtok, null, &library);
|
||||
ASSERT_EQUALS(1U, null.size());
|
||||
ASSERT_EQUALS("a", null.front()->str());
|
||||
ASSERT_EQUALS(0U, uninit.size());
|
||||
}
|
||||
|
||||
// for 2nd parameter uninit data is not ok..
|
||||
{
|
||||
Library library;
|
||||
Library::ArgumentChecks arg;
|
||||
library.functions["x"].argumentChecks[1] = arg;
|
||||
library.functions["x"].argumentChecks[2] = arg;
|
||||
library.functions["x"].argumentChecks[3] = arg;
|
||||
library.functions["x"].argumentChecks[2].notuninit = true;
|
||||
|
||||
std::list<const Token *> null,uninit;
|
||||
CheckNullPointer::parseFunctionCall(*xtok, null, &library, 0U);
|
||||
CheckNullPointer::parseFunctionCall(*xtok, uninit, &library, 1U);
|
||||
ASSERT_EQUALS(0U, null.size());
|
||||
ASSERT_EQUALS(1U, uninit.size());
|
||||
ASSERT_EQUALS("b", uninit.front()->str());
|
||||
}
|
||||
|
||||
// for 3rd parameter uninit data is not ok..
|
||||
{
|
||||
Library library;
|
||||
Library::ArgumentChecks arg;
|
||||
library.functions["x"].argumentChecks[1] = arg;
|
||||
library.functions["x"].argumentChecks[2] = arg;
|
||||
library.functions["x"].argumentChecks[3] = arg;
|
||||
library.functions["x"].argumentChecks[3].notuninit = true;
|
||||
|
||||
std::list<const Token *> null,uninit;
|
||||
CheckNullPointer::parseFunctionCall(*xtok, null, &library, 0U);
|
||||
CheckNullPointer::parseFunctionCall(*xtok, uninit, &library, 1U);
|
||||
ASSERT_EQUALS(0U, null.size());
|
||||
ASSERT_EQUALS(1U, uninit.size());
|
||||
ASSERT_EQUALS("c", uninit.front()->str());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue