CheckNullPointer: Removed some of the old checking that doesn't use ValueFlow

This commit is contained in:
Daniel Marjamäki 2014-01-17 17:47:59 +01:00
parent 311059f603
commit 5721e1d745
1 changed files with 45 additions and 223 deletions

View File

@ -753,233 +753,55 @@ void CheckNullPointer::nullPointerByDeRefAndChec()
{ {
const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase(); const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase();
if (_settings->valueFlow) { for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) {
for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) { if (!tok->isName() || tok->values.empty())
if (!tok->isName() || tok->values.empty()) continue;
continue;
const Variable *var = tok->variable(); const Variable *var = tok->variable();
if (!var || !var->isPointer() || tok == var->nameToken()) if (!var || !var->isPointer() || tok == var->nameToken())
continue; continue;
// Can pointer be NULL? // Can pointer be NULL?
const ValueFlow::Value *value = 0; const ValueFlow::Value *value = 0;
for (std::list<ValueFlow::Value>::const_iterator it = tok->values.begin(); it != tok->values.end(); ++it) { for (std::list<ValueFlow::Value>::const_iterator it = tok->values.begin(); it != tok->values.end(); ++it) {
if (it->intvalue == 0) { if (it->intvalue == 0) {
value = &(*it); value = &(*it);
break; break;
}
}
if (!value)
continue;
// Is pointer used as function parameter?
if (Token::Match(tok->previous(), "[(,] %var% [,)]")) {
const Token *ftok = tok->previous();
while (ftok && ftok->str() != "(") {
if (ftok->str() == ")")
ftok = ftok->link();
ftok = ftok->previous();
}
if (!ftok || !ftok->previous())
continue;
std::list<const Token *> varlist;
parseFunctionCall(*ftok->previous(), varlist, &_settings->library, 0);
if (std::find(varlist.begin(), varlist.end(), tok) != varlist.end()) {
if (value->condition == NULL)
nullPointerError(tok);
else if (_settings->isEnabled("warning"))
nullPointerError(tok, tok->str(), value->condition, value->inconclusive);
}
continue;
}
// Pointer dereference.
bool unknown = false;
if (!isPointerDeRef(tok,unknown))
continue;
if (value->condition == NULL)
nullPointerError(tok);
else if (_settings->isEnabled("warning"))
nullPointerError(tok, tok->str(), value->condition, value->inconclusive);
}
return;
}
// Dereferencing a pointer and then checking if it's NULL..
// This check will first scan for the check. And then scan backwards
// from the check, searching for dereferencing.
for (std::list<Scope>::const_iterator i = symbolDatabase->scopeList.begin(); i != symbolDatabase->scopeList.end(); ++i) {
// TODO: false negatives.
// - logical operators
const Token* tok = i->classDef;
if ((i->type == Scope::eIf || i->type == Scope::eElseIf || i->type == Scope::eWhile) &&
tok && Token::Match(tok, "else| %var% ( !| %var% )|%oror%|&&") && !tok->tokAt(tok->str()=="else"?1:0)->isExpandedMacro()) {
if (tok->str() == "else")
tok = tok->next();
const Token * vartok = tok->tokAt(2);
if (vartok->str() == "!")
vartok = vartok->next();
const Variable *var = vartok->variable();
// Check that variable is a pointer..
if (!var || !var->isPointer())
continue;
// Variable id for pointer
const unsigned int varid(vartok->varId());
// bailout for while scope if pointer is assigned inside the loop
if (i->type == Scope::eWhile) {
bool assign = false;
for (const Token *tok2 = i->classStart; tok2 && tok2 != i->classEnd; tok2 = tok2->next()) {
if (Token::Match(tok2, "%varid% =", varid)) {
assign = true;
break;
}
}
if (assign)
continue;
}
// Name of pointer
const std::string& varname(vartok->str());
const Token * const decltok = var->nameToken();
bool inconclusive = false;
for (const Token *tok1 = tok->previous(); tok1 && tok1 != decltok; tok1 = tok1->previous()) {
if (tok1->str() == ")" && Token::Match(tok1->link()->previous(), "%var% (")) {
const Token *tok2 = tok1->link();
while (tok2 && !Token::Match(tok2, "[;{}?:]"))
tok2 = tok2->previous();
if (Token::Match(tok2, "[?:]"))
break;
if (Token::Match(tok2->next(), "%varid% = %var%", varid))
break;
if (Token::Match(tok2->next(), "while ( %varid%", varid))
break;
if (Token::Match(tok1->link(), "( ! %varid% %oror%", varid) ||
Token::Match(tok1->link(), "( %varid% &&", varid)) {
tok1 = tok1->link();
continue;
}
if (Token::simpleMatch(tok1->link()->previous(), "sizeof (")) {
tok1 = tok1->link()->previous();
continue;
}
if (Token::Match(tok2->next(), "%var% ( %varid% ,", varid)) {
std::list<const Token *> varlist;
parseFunctionCall(*(tok2->next()), varlist, &_settings->library, 0);
if (!varlist.empty() && varlist.front() == tok2->tokAt(3)) {
nullPointerError(tok2->tokAt(3), varname, tok, inconclusive);
break;
}
}
// Passing pointer as parameter..
if (Token::Match(tok2->next(), "%type% (")) {
bool unknown = false;
if (CanFunctionAssignPointer(tok2->next(), varid, unknown)) {
if (!_settings->inconclusive || !unknown)
break;
inconclusive = true;
}
}
// calling unknown function => it might initialize the pointer
if (!(var->isLocal() || var->isArgument()))
break;
}
if (tok1->str() == "break")
break;
if (tok1->varId() == varid) {
// Don't write warning if the dereferencing is
// guarded by ?: or &&
const Token *tok2 = tok1->previous();
if (tok2 && (tok2->isArithmeticalOp() || Token::Match(tok2, "[(,]"))) {
while (tok2 && !Token::Match(tok2, "[;{}?:]")) {
if (tok2->str() == ")") {
tok2 = tok2->link();
if (Token::Match(tok2, "( %varid% =", varid)) {
tok2 = tok2->next();
break;
}
}
// guarded by && or ||
if (Token::Match(tok2, "%varid% &&|%oror%",varid))
break;
tok2 = tok2->previous();
}
}
if (!tok2 || Token::Match(tok2, "[?:]") || tok2->varId() == varid)
continue;
// unknown : this is set by isPointerDeRef if it is
// uncertain
bool unknown = _settings->inconclusive;
// reassign : is the pointer reassigned like this:
// tok = tok->next();
bool reassign = false;
if (Token::Match(tok1->previous(), "= %varid% .", varid)) {
const Token *back = tok1->tokAt(-2);
while (back) {
if (back->varId() == varid) {
reassign = true;
break;
}
if (Token::Match(back, "[{};,(]")) {
break;
}
back = back->previous();
}
} else if (Token::Match(tok1->tokAt(-4), "%varid% = ( * %varid%", varid)) {
reassign = true;
} else if (Token::Match(tok1->tokAt(-3), "%varid% = * %varid%", varid)) {
reassign = true;
}
if (reassign) {
break;
} else if (Token::simpleMatch(tok1->tokAt(-2), "* )") &&
Token::Match(tok1->linkAt(-1)->tokAt(-2), "%varid% = (", tok1->varId())) {
break;
} else if (Token::simpleMatch(tok1->tokAt(-3), "* ) (") &&
Token::Match(tok1->linkAt(-2)->tokAt(-2), "%varid% = (", tok1->varId())) {
break;
} else if (Token::Match(tok1->previous(), "&&|%oror%")) {
break;
} else if (Token::Match(tok1->tokAt(-2), "&&|%oror% !")) {
break;
} else if (CheckNullPointer::isPointerDeRef(tok1, unknown)) {
nullPointerError(tok1, varname, tok, inconclusive);
break;
} else if (tok1->strAt(-1) == "&") {
break;
} else if (tok1->strAt(1) == "=") {
break;
}
}
else if (tok1->str() == "{" ||
tok1->str() == "}")
break;
// label..
else if (Token::Match(tok1, "%type% :"))
break;
} }
} }
if (!value)
continue;
// Is pointer used as function parameter?
if (Token::Match(tok->previous(), "[(,] %var% [,)]")) {
const Token *ftok = tok->previous();
while (ftok && ftok->str() != "(") {
if (ftok->str() == ")")
ftok = ftok->link();
ftok = ftok->previous();
}
if (!ftok || !ftok->previous())
continue;
std::list<const Token *> varlist;
parseFunctionCall(*ftok->previous(), varlist, &_settings->library, 0);
if (std::find(varlist.begin(), varlist.end(), tok) != varlist.end()) {
if (value->condition == NULL)
nullPointerError(tok);
else if (_settings->isEnabled("warning"))
nullPointerError(tok, tok->str(), value->condition, value->inconclusive);
}
continue;
}
// Pointer dereference.
bool unknown = false;
if (!isPointerDeRef(tok,unknown))
continue;
if (value->condition == NULL)
nullPointerError(tok);
else if (_settings->isEnabled("warning"))
nullPointerError(tok, tok->str(), value->condition, value->inconclusive);
} }
} }