Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 11 additions & 17 deletions lib/checknullpointer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,20 +59,13 @@ static bool checkNullpointerFunctionCallPlausibility(const Function* func, unsig
return !func || (func->argCount() >= arg && func->getArgumentVar(arg - 1) && func->getArgumentVar(arg - 1)->isPointer());
}

/**
* @brief parse a function call and extract information about variable usage
* @param tok first token
* @param var variables that the function read / write.
* @param library --library files data
* @param checkNullArg perform isnullargbad check for each argument?
*/
void CheckNullPointer::parseFunctionCall(const Token &tok, std::list<const Token *> &var, const Library &library, bool checkNullArg)
std::list<const Token*> CheckNullPointer::parseFunctionCall(const Token &tok, const Library &library, bool checkNullArg)
{
if (Token::Match(&tok, "%name% ( )") || !tok.tokAt(2))
return;
return {};

const std::vector<const Token *> args = getArguments(&tok);

std::list<const Token*> var;
for (int argnr = 1; argnr <= args.size(); ++argnr) {
const Token *param = args[argnr - 1];
if ((!checkNullArg || library.isnullargbad(&tok, argnr)) && checkNullpointerFunctionCallPlausibility(tok.function(), argnr))
Expand All @@ -87,14 +80,14 @@ void CheckNullPointer::parseFunctionCall(const Token &tok, std::list<const Token
if (library.formatstr_function(&tok)) {
const int formatStringArgNr = library.formatstr_argno(&tok);
if (formatStringArgNr < 0 || formatStringArgNr >= args.size())
return;
return var;

// 1st parameter..
if (Token::Match(&tok, "snprintf|vsnprintf|fnprintf|vfnprintf") && args.size() > 1 && !(args[1] && args[1]->hasKnownIntValue() && args[1]->getKnownIntValue() == 0)) // Only if length (second parameter) is not zero
var.push_back(args[0]);

if (args[formatStringArgNr]->tokType() != Token::eString)
return;
return var;
const std::string &formatString = args[formatStringArgNr]->strValue();
int argnr = formatStringArgNr + 1;
const bool scan = library.formatstr_scan(&tok);
Expand All @@ -116,7 +109,7 @@ void CheckNullPointer::parseFunctionCall(const Token &tok, std::list<const Token
}
++i;
if (i == formatString.end())
return;
return var;
}
if (_continue)
continue;
Expand All @@ -129,6 +122,7 @@ void CheckNullPointer::parseFunctionCall(const Token &tok, std::list<const Token
}
}
}
return var;
}

namespace {
Expand Down Expand Up @@ -166,8 +160,7 @@ bool CheckNullPointer::isPointerDeRef(const Token *tok, bool &unknown, const Set
ftok = ftok->previous();
}
if (ftok && ftok->previous()) {
std::list<const Token *> varlist;
parseFunctionCall(*ftok->previous(), varlist, settings.library, checkNullArg);
const std::list<const Token *> varlist = parseFunctionCall(*ftok->previous(), settings.library, checkNullArg);
if (std::find(varlist.cbegin(), varlist.cend(), tok) != varlist.cend()) {
return true;
}
Expand Down Expand Up @@ -376,8 +369,7 @@ void CheckNullPointer::nullConstantDereference()
if (var && !var->isPointer() && !var->isArray() && var->isStlStringType())
nullPointerError(tok);
} else { // function call
std::list<const Token *> var;
parseFunctionCall(*tok, var, mSettings->library);
const std::list<const Token *> var = parseFunctionCall(*tok, mSettings->library);

// is one of the var items a NULL pointer?
for (const Token *vartok : var) {
Expand Down Expand Up @@ -456,6 +448,8 @@ void CheckNullPointer::nullPointerError(const Token *tok, const std::string &var
reportError(tok, Severity::warning, "nullPointerOutOfResources", "Null pointer dereference", CWE_NULL_POINTER_DEREFERENCE, Certainty::normal);
return;
}
if (diag(tok))
return;

if (!value) {
reportError(tok, Severity::error, "nullPointer", "Null pointer dereference", CWE_NULL_POINTER_DEREFERENCE, inconclusive ? Certainty::inconclusive : Certainty::normal);
Expand Down
14 changes: 10 additions & 4 deletions lib/checknullpointer.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include "config.h"

#include <list>
#include <set>
#include <string>

class ErrorLogger;
Expand Down Expand Up @@ -69,12 +70,11 @@ class CPPCHECKLIB CheckNullPointer : public Check {
/**
* @brief parse a function call and extract information about variable usage
* @param tok first token
* @param var variables that the function read / write.
* @param library --library files data
* @param checkNullArg perform isnullargbad check for each argument?
* @return list of variables that the function reads / writes.
*/
static void parseFunctionCall(const Token &tok,
std::list<const Token *> &var,
const Library &library, bool checkNullArg = true);
static std::list<const Token*> parseFunctionCall(const Token &tok, const Library &library, bool checkNullArg = true);

/** @brief This constructor is used when running checks. */
CheckNullPointer(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger)
Expand Down Expand Up @@ -125,6 +125,12 @@ class CPPCHECKLIB CheckNullPointer : public Check {
void arithmetic();
void pointerArithmeticError(const Token* tok, const ValueFlow::Value *value, bool inconclusive);
void redundantConditionWarning(const Token* tok, const ValueFlow::Value *value, const Token *condition, bool inconclusive);

bool diag(const Token* tok) {
return !mDiag.emplace(tok).second;
}

std::set<const Token*> mDiag;
};
/// @}
//---------------------------------------------------------------------------
Expand Down
25 changes: 8 additions & 17 deletions test/testnullpointer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3489,8 +3489,7 @@ class TestNullPointer : public TestFixture {
" printf(\"%s\", s);\n"
"}");
ASSERT_EQUALS(
"[test.cpp:3:18]: (error) Null pointer dereference: s [nullPointer]\n"
"[test.cpp:3:18]: (error) Null pointer dereference [nullPointer]\n",
"[test.cpp:3:18]: (error) Null pointer dereference: s [nullPointer]\n",
errout_str());

check("void f() {\n"
Expand All @@ -3514,8 +3513,7 @@ class TestNullPointer : public TestFixture {
" printf(\"%u%s\", 123, s);\n"
"}");
ASSERT_EQUALS(
"[test.cpp:3:25]: (error) Null pointer dereference: s [nullPointer]\n"
"[test.cpp:3:25]: (error) Null pointer dereference [nullPointer]\n",
"[test.cpp:3:25]: (error) Null pointer dereference: s [nullPointer]\n",
errout_str());


Expand Down Expand Up @@ -3560,16 +3558,14 @@ class TestNullPointer : public TestFixture {
" sscanf(s, \"%s\", 0);\n"
"}");
ASSERT_EQUALS(
"[test.cpp:2:21]: (error) Null pointer dereference [nullPointer]\n"
"[test.cpp:2:21]: (error) Null pointer dereference [nullPointer]\n", // duplicate
"[test.cpp:2:21]: (error) Null pointer dereference [nullPointer]\n",
errout_str());

check("void f() {\n"
" scanf(\"%d\", 0);\n"
"}");
ASSERT_EQUALS(
"[test.cpp:2:17]: (error) Null pointer dereference [nullPointer]\n"
"[test.cpp:2:17]: (error) Null pointer dereference [nullPointer]\n", // duplicate
"[test.cpp:2:17]: (error) Null pointer dereference [nullPointer]\n",
errout_str());

check("void f(char* foo) {\n"
Expand All @@ -3590,9 +3586,7 @@ class TestNullPointer : public TestFixture {
" sscanf(dummy, \"%d\", iVal);\n"
"}");
ASSERT_EQUALS(
"[test.cpp:3:25]: (error) Null pointer dereference: iVal [nullPointer]\n"
"[test.cpp:3:25]: (error) Null pointer dereference [nullPointer]\n"
"[test.cpp:3:25]: (error) Null pointer dereference [nullPointer]\n", // duplicate
"[test.cpp:3:25]: (error) Null pointer dereference: iVal [nullPointer]\n",
errout_str());

check("void f(char *dummy) {\n"
Expand All @@ -3611,8 +3605,7 @@ class TestNullPointer : public TestFixture {
" sscanf(dummy, \"%*d%u\", 0);\n"
"}");
ASSERT_EQUALS(
"[test.cpp:2:28]: (error) Null pointer dereference [nullPointer]\n"
"[test.cpp:2:28]: (error) Null pointer dereference [nullPointer]\n", // duplicate
"[test.cpp:2:28]: (error) Null pointer dereference [nullPointer]\n",
errout_str());
}

Expand Down Expand Up @@ -4333,8 +4326,7 @@ class TestNullPointer : public TestFixture {
Library library;
ASSERT(LibraryHelper::loadxmldata(library, xmldata, sizeof(xmldata)));

std::list<const Token *> null;
CheckNullPointer::parseFunctionCall(*xtok, null, library);
const std::list<const Token *> null = CheckNullPointer::parseFunctionCall(*xtok, library);
ASSERT_EQUALS(0U, null.size());
}

Expand All @@ -4352,8 +4344,7 @@ class TestNullPointer : public TestFixture {
Library library;
ASSERT(LibraryHelper::loadxmldata(library, xmldata, sizeof(xmldata)));

std::list<const Token *> null;
CheckNullPointer::parseFunctionCall(*xtok, null, library);
const std::list<const Token *> null = CheckNullPointer::parseFunctionCall(*xtok, library);
ASSERT_EQUALS(1U, null.size());
ASSERT_EQUALS("a", null.front()->str());
}
Expand Down