ExecutionPath: Better handling of if

This commit is contained in:
Daniel Marjamäki 2010-04-25 11:55:57 +02:00
parent 1a34e7daf6
commit eb82a89758
6 changed files with 105 additions and 19 deletions

View File

@ -1709,6 +1709,13 @@ private:
return new ExecutionPathBufferOverrun(*this); return new ExecutionPathBufferOverrun(*this);
} }
/** is other execution path equal? */
bool is_equal(const ExecutionPath *e) const
{
const ExecutionPathBufferOverrun *c = static_cast<const ExecutionPathBufferOverrun *>(e);
return (value == c->value);
}
/** @brief buffer information */ /** @brief buffer information */
const std::map<unsigned int, CheckBufferOverrun::ArrayInfo> &arrayInfo; const std::map<unsigned int, CheckBufferOverrun::ArrayInfo> &arrayInfo;

View File

@ -2722,6 +2722,13 @@ private:
{ {
} }
/** is other execution path equal? */
bool is_equal(const ExecutionPath *e) const
{
const CheckLocalLeaks *c = static_cast<const CheckLocalLeaks *>(e);
return (allocated == c->allocated && varname == c->varname);
}
/** Is variable allocated? */ /** Is variable allocated? */
bool allocated; bool allocated;

View File

@ -1691,6 +1691,13 @@ private:
/** no implementation => compiler error if used by accident */ /** no implementation => compiler error if used by accident */
void operator=(const CheckNullpointer &); void operator=(const CheckNullpointer &);
/** is other execution path equal? */
bool is_equal(const ExecutionPath *e) const
{
const CheckNullpointer *c = static_cast<const CheckNullpointer *>(e);
return (varname == c->varname && null == c->null);
}
/** variable name for this check (empty => dummy check) */ /** variable name for this check (empty => dummy check) */
const std::string varname; const std::string varname;
@ -1864,6 +1871,13 @@ private:
{ {
} }
/** is other execution path equal? */
bool is_equal(const ExecutionPath *e) const
{
const CheckUninitVar *c = static_cast<const CheckUninitVar *>(e);
return (varname == c->varname && pointer == c->pointer && array == c->array && alloc == c->alloc && strncpy_ == c->strncpy_);
}
/** variable name for this check */ /** variable name for this check */
const std::string varname; const std::string varname;

70
lib/executionpath.cpp Normal file → Executable file
View File

@ -20,16 +20,12 @@
#include "executionpath.h" #include "executionpath.h"
#include "token.h" #include "token.h"
#include <memory> #include <memory>
#include <set>
// default : bail out if the condition is has variable handling // default : bail out if the condition is has variable handling
bool ExecutionPath::parseCondition(const Token &tok, std::list<ExecutionPath *> & checks) bool ExecutionPath::parseCondition(const Token &tok, std::list<ExecutionPath *> & checks)
{ {
if (Token::Match(tok.tokAt(-3), "!!else if ("))
{
++ifinfo;
}
unsigned int parlevel = 0; unsigned int parlevel = 0;
for (const Token *tok2 = &tok; tok2; tok2 = tok2->next()) for (const Token *tok2 = &tok; tok2; tok2 = tok2->next())
{ {
@ -45,10 +41,19 @@ bool ExecutionPath::parseCondition(const Token &tok, std::list<ExecutionPath *>
break; break;
if (tok2->varId() != 0) if (tok2->varId() != 0)
{ {
if (ifinfo > 1) bailOutVar(checks, tok2->varId());
return true; for (std::list<ExecutionPath *>::iterator it = checks.begin(); it != checks.end();)
else {
bailOutVar(checks, tok2->varId()); if ((*it)->varId > 0 && (*it)->numberOfIf >= 1)
{
delete *it;
checks.erase(it++);
}
else
{
++it;
}
}
} }
} }
@ -182,6 +187,9 @@ static void checkExecutionPaths_(const Token *tok, std::list<ExecutionPath *> &c
if (tok->str() == "if") if (tok->str() == "if")
{ {
// what variable ids should the numberOfIf be counted for?
std::set<unsigned int> countif;
std::list<ExecutionPath *> newchecks; std::list<ExecutionPath *> newchecks;
while (tok->str() == "if") while (tok->str() == "if")
{ {
@ -211,16 +219,41 @@ static void checkExecutionPaths_(const Token *tok, std::list<ExecutionPath *> &c
// Recursively check into the if .. // Recursively check into the if ..
{ {
std::set<unsigned int> countif2;
std::list<ExecutionPath *> c; std::list<ExecutionPath *> c;
std::list<ExecutionPath *>::iterator it; if (checks.size() == 1)
for (it = checks.begin(); it != checks.end(); ++it) c.push_back(checks.front()->copy());
c.push_back((*it)->copy()); else if (!checks.empty())
{
std::list<ExecutionPath *>::const_iterator it;
it = checks.begin();
while (++it != checks.end())
{
c.push_back((*it)->copy());
countif2.insert((*it)->varId);
}
}
checkExecutionPaths_(tok->next(), c); checkExecutionPaths_(tok->next(), c);
while (!c.empty()) while (!c.empty())
{ {
newchecks.push_back(c.back()); bool duplicate = false;
std::list<ExecutionPath *>::const_iterator it;
for (it = checks.begin(); it != checks.end(); ++it)
{
if (*(*it) == *c.back())
{
duplicate = true;
countif2.erase((*it)->varId);
break;
}
}
if (!duplicate)
newchecks.push_back(c.back());
c.pop_back(); c.pop_back();
} }
// Add countif2 ids to countif..
countif.insert(countif2.begin(), countif2.end());
} }
// goto "}" // goto "}"
@ -245,9 +278,16 @@ static void checkExecutionPaths_(const Token *tok, std::list<ExecutionPath *> &c
} }
} }
// Add newchecks to checks..
std::copy(newchecks.begin(), newchecks.end(), std::back_inserter(checks));
// Increase numberOfIf
std::list<ExecutionPath *>::iterator it; std::list<ExecutionPath *>::iterator it;
for (it = newchecks.begin(); it != newchecks.end(); ++it) for (it = checks.begin(); it != checks.end(); ++it)
checks.push_back(*it); {
if (countif.find((*it)->varId) != countif.end())
(*it)->numberOfIf++;
}
} }

View File

@ -35,11 +35,13 @@ private:
void operator=(const ExecutionPath &); void operator=(const ExecutionPath &);
protected: protected:
const unsigned int varId;
Check * const owner; Check * const owner;
/** Are two execution paths equal? */
virtual bool is_equal(const ExecutionPath *) const = 0;
public: public:
ExecutionPath(Check *c, unsigned int id) : varId(id), owner(c), ifinfo(0) ExecutionPath(Check *c, unsigned int id) : varId(id), owner(c), numberOfIf(0)
{ } { }
virtual ~ExecutionPath() virtual ~ExecutionPath()
@ -48,8 +50,10 @@ public:
/** Implement this in each derived class. This function must create a copy of the current instance */ /** Implement this in each derived class. This function must create a copy of the current instance */
virtual ExecutionPath *copy() = 0; virtual ExecutionPath *copy() = 0;
/** Some kind of if-information */ /** number of if blocks */
unsigned int ifinfo; unsigned int numberOfIf;
const unsigned int varId;
/** /**
* bail out all execution paths * bail out all execution paths
@ -109,6 +113,11 @@ public:
/** going out of scope - all execution paths end */ /** going out of scope - all execution paths end */
virtual void end(const std::list<ExecutionPath *> & /*checks*/, const Token * /*tok*/) const virtual void end(const std::list<ExecutionPath *> & /*checks*/, const Token * /*tok*/) const
{ } { }
bool operator==(const ExecutionPath &e) const
{
return bool(varId == e.varId && is_equal(&e));
}
}; };

View File

@ -1456,6 +1456,15 @@ private:
"}\n"); "}\n");
ASSERT_EQUALS("[test.cpp:6]: (error) Uninitialized variable: p\n", errout.str()); ASSERT_EQUALS("[test.cpp:6]: (error) Uninitialized variable: p\n", errout.str());
checkUninitVar("static void foo(int x)\n"
"{\n"
" int a;\n"
" if (x==1);\n"
" if (x==2);\n"
" x = a;\n"
"}\n");
ASSERT_EQUALS("[test.cpp:6]: (error) Uninitialized variable: a\n", errout.str());
checkUninitVar("int foo()\n" checkUninitVar("int foo()\n"
"{\n" "{\n"
" int i;\n" " int i;\n"