Remove ExecutionPath from CheckNullPointer
This commit is contained in:
parent
f3f7e6d302
commit
1d7bb05faf
|
@ -19,7 +19,6 @@
|
|||
|
||||
//---------------------------------------------------------------------------
|
||||
#include "checknullpointer.h"
|
||||
#include "executionpath.h"
|
||||
#include "mathlib.h"
|
||||
#include "symboldatabase.h"
|
||||
#include <cctype>
|
||||
|
@ -1038,212 +1037,6 @@ void CheckNullPointer::nullPointerDefaultArgument()
|
|||
/// @{
|
||||
|
||||
|
||||
/**
|
||||
* @brief %Check for null pointer usage (using ExecutionPath)
|
||||
*/
|
||||
|
||||
class Nullpointer : public ExecutionPath {
|
||||
public:
|
||||
/** Startup constructor */
|
||||
Nullpointer(Check *c, const SymbolDatabase* symbolDatabase_, const Library *lib) : ExecutionPath(c, 0), symbolDatabase(symbolDatabase_), library(lib), null(false) {
|
||||
}
|
||||
|
||||
private:
|
||||
const SymbolDatabase* symbolDatabase;
|
||||
const Library *library;
|
||||
|
||||
/** Create checking of specific variable: */
|
||||
Nullpointer(Check *c, const unsigned int id, const std::string &name, const SymbolDatabase* symbolDatabase_, const Library *lib)
|
||||
: ExecutionPath(c, id),
|
||||
symbolDatabase(symbolDatabase_),
|
||||
library(lib),
|
||||
varname(name),
|
||||
null(false) {
|
||||
}
|
||||
|
||||
/** Copy this check */
|
||||
ExecutionPath *copy() {
|
||||
return new Nullpointer(*this);
|
||||
}
|
||||
|
||||
/** no implementation => compiler error if used by accident */
|
||||
void operator=(const Nullpointer &);
|
||||
|
||||
/** is other execution path equal? */
|
||||
bool is_equal(const ExecutionPath *e) const {
|
||||
const Nullpointer *c = static_cast<const Nullpointer *>(e);
|
||||
return (varname == c->varname && null == c->null);
|
||||
}
|
||||
|
||||
/** variable name for this check (empty => dummy check) */
|
||||
const std::string varname;
|
||||
|
||||
/** is this variable null? */
|
||||
bool null;
|
||||
|
||||
/** variable is set to null */
|
||||
static void setnull(std::list<ExecutionPath *> &checks, const unsigned int varid, bool null) {
|
||||
std::list<ExecutionPath *>::iterator it;
|
||||
for (it = checks.begin(); it != checks.end(); ++it) {
|
||||
Nullpointer *c = dynamic_cast<Nullpointer *>(*it);
|
||||
if (c && c->varId == varid)
|
||||
c->null = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Dereferencing variable. Check if it is safe (if the variable is null there's an error)
|
||||
* @param checks Checks
|
||||
* @param tok token where dereferencing happens
|
||||
*/
|
||||
static void dereference(std::list<ExecutionPath *> &checks, const Token *tok) {
|
||||
const unsigned int varid(tok->varId());
|
||||
|
||||
std::list<ExecutionPath *>::iterator it;
|
||||
for (it = checks.begin(); it != checks.end(); ++it) {
|
||||
Nullpointer *c = dynamic_cast<Nullpointer *>(*it);
|
||||
if (c && c->varId == varid && c->null) {
|
||||
for (const Token *tok2 = tok; tok2 && tok2->str() != ";"; tok2 = tok2->previous()) {
|
||||
// Checking that pointer is not NULL
|
||||
if (Token::Match(tok2, "return|=|[|(|,|&& %varid% )| &&", varid))
|
||||
return;
|
||||
if (Token::Match(tok2, "return|=|[|(|,|%oror% ! %varid% )| %oror%", varid))
|
||||
return;
|
||||
}
|
||||
|
||||
CheckNullPointer *checkNullPointer = dynamic_cast<CheckNullPointer *>(c->owner);
|
||||
if (checkNullPointer) {
|
||||
checkNullPointer->nullPointerError(tok, c->varname);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** parse tokens */
|
||||
const Token *parse(const Token &tok, std::list<ExecutionPath *> &checks) const {
|
||||
if (tok.varId() != 0) {
|
||||
// Pointer declaration declaration?
|
||||
const Variable *var = tok.variable();
|
||||
if (var && var->isPointer() && var->nameToken() == &tok)
|
||||
checks.push_back(new Nullpointer(owner, var->declarationId(), var->name(), symbolDatabase, library));
|
||||
}
|
||||
|
||||
if (Token::simpleMatch(&tok, "try {")) {
|
||||
// Bail out all used variables
|
||||
const Token* tok2 = &tok;
|
||||
const Token* endtok = tok.linkAt(1);
|
||||
for (; tok2 && tok2 != endtok; tok2 = tok2->next()) {
|
||||
if (tok2->varId())
|
||||
bailOutVar(checks,tok2->varId());
|
||||
}
|
||||
return tok2;
|
||||
}
|
||||
|
||||
if (Token::Match(&tok, "%var% (")) {
|
||||
if (tok.str() == "sizeof" || tok.str() == "typeid")
|
||||
return tok.next()->link();
|
||||
|
||||
// parse usage..
|
||||
std::list<const Token *> var;
|
||||
CheckNullPointer::parseFunctionCall(tok, var, library, 0);
|
||||
for (std::list<const Token *>::const_iterator it = var.begin(); it != var.end(); ++it)
|
||||
dereference(checks, *it);
|
||||
}
|
||||
|
||||
else if (Token::simpleMatch(&tok, "( 0 &&"))
|
||||
return tok.link();
|
||||
|
||||
if (tok.varId() != 0) {
|
||||
// unknown: if isPointerDeRef fails to determine if there
|
||||
// is a dereference this will be set to true.
|
||||
bool unknown = owner->inconclusiveFlag();
|
||||
bool deref = CheckNullPointer::isPointerDeRef(&tok, unknown);
|
||||
|
||||
if (deref)
|
||||
dereference(checks, &tok);
|
||||
else if (unknown && owner->inconclusiveFlag())
|
||||
dereference(checks, &tok);
|
||||
if (Token::Match(tok.previous(), "[;{}=] %var% ="))
|
||||
setnull(checks, tok.varId(), Token::simpleMatch(tok.tokAt(2), "0 ;"));
|
||||
else if (!deref &&
|
||||
(!tok.previous()->isOp() || tok.previous()->str() == "&") &&
|
||||
(!tok.next()->isConstOp() || tok.next()->str() == ">>"))
|
||||
bailOutVar(checks, tok.varId()); // If its possible that the pointers value changes, bail out.
|
||||
}
|
||||
|
||||
else if (tok.str() == "delete") {
|
||||
const Token *ret = tok.next();
|
||||
if (Token::simpleMatch(ret, "[ ]"))
|
||||
ret = ret->tokAt(2);
|
||||
if (Token::Match(ret, "%var% ;"))
|
||||
return ret->next();
|
||||
}
|
||||
|
||||
else if (tok.str() == "return") {
|
||||
bool unknown = owner->inconclusiveFlag();
|
||||
const Token* tok2 = &tok;
|
||||
for (; tok2 && tok2->str() != ";"; tok2 = tok2->next()) {
|
||||
if (tok2->varId()) {
|
||||
if (CheckNullPointer::isPointerDeRef(tok2, unknown) || unknown)
|
||||
dereference(checks, tok2);
|
||||
}
|
||||
|
||||
// If return statement contains "?" then assume there
|
||||
// is no dangours dereferencing later
|
||||
if (tok2->str() == "?") {
|
||||
while (tok2 && tok2->str() != ";")
|
||||
tok2 = tok2->next();
|
||||
return tok2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return &tok;
|
||||
}
|
||||
|
||||
/** parse condition. @sa ExecutionPath::parseCondition */
|
||||
bool parseCondition(const Token &tok, std::list<ExecutionPath *> &checks) {
|
||||
for (const Token *tok2 = &tok; tok2; tok2 = tok2->next()) {
|
||||
if (tok2->str() == "(" || tok2->str() == ")" || tok2->str() == "&&" || tok2->str() == "||" || tok2->str() == "?")
|
||||
break;
|
||||
bool unknown = owner->inconclusiveFlag();
|
||||
if (tok2->varId() && (CheckNullPointer::isPointerDeRef(tok2, unknown) || unknown))
|
||||
dereference(checks, tok2);
|
||||
}
|
||||
|
||||
if (Token::Match(&tok, "!| %var% (")) {
|
||||
std::list<const Token *> var;
|
||||
CheckNullPointer::parseFunctionCall(tok.str() == "!" ? *tok.next() : tok, var, library, 0);
|
||||
for (std::list<const Token *>::const_iterator it = var.begin(); it != var.end(); ++it)
|
||||
dereference(checks, *it);
|
||||
}
|
||||
|
||||
return ExecutionPath::parseCondition(tok, checks);
|
||||
}
|
||||
|
||||
|
||||
void parseLoopBody(const Token *tok, std::list<ExecutionPath *> &checks) const {
|
||||
while (tok) {
|
||||
if (Token::Match(tok, "{|}|return|goto|break|if"))
|
||||
return;
|
||||
const Token *next = parse(*tok, checks);
|
||||
if (next)
|
||||
tok = tok->next();
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
/// @}
|
||||
|
||||
|
||||
void CheckNullPointer::executionPaths()
|
||||
{
|
||||
// Check for null pointer errors..
|
||||
Nullpointer c(this, _tokenizer->getSymbolDatabase(), &_settings->library);
|
||||
checkExecutionPaths(_tokenizer->getSymbolDatabase(), &c);
|
||||
}
|
||||
|
||||
void CheckNullPointer::nullPointerError(const Token *tok)
|
||||
{
|
||||
reportError(tok, Severity::error, "nullPointer", "Null pointer dereference");
|
||||
|
|
|
@ -56,7 +56,6 @@ public:
|
|||
void runSimplifiedChecks(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) {
|
||||
CheckNullPointer checkNullPointer(tokenizer, settings, errorLogger);
|
||||
checkNullPointer.nullConstantDereference();
|
||||
checkNullPointer.executionPaths();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -95,9 +94,6 @@ public:
|
|||
/** @brief dereferencing null constant (after Tokenizer::simplifyKnownVariables) */
|
||||
void nullConstantDereference();
|
||||
|
||||
/** @brief new type of check: check execution paths */
|
||||
void executionPaths();
|
||||
|
||||
void nullPointerError(const Token *tok); // variable name unknown / doesn't exist
|
||||
void nullPointerError(const Token *tok, const std::string &varname, bool inconclusive=false);
|
||||
void nullPointerError(const Token *tok, const std::string &varname, const Token* nullcheck, bool inconclusive = false);
|
||||
|
|
|
@ -113,7 +113,6 @@ private:
|
|||
"TestSimplifyTokens instead.\nstr1="+str1+"\nstr2="+str2).c_str());
|
||||
|
||||
checkNullPointer.nullConstantDereference();
|
||||
//checkNullPointer.executionPaths();
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue