- Solved FIXME: Made detection of code that is no pointer-dereference more robust, uncommented code (checknullpointer.cpp)

- Removed more indendation level counters
- Make use of symbol database more often
- Other refactorizations
This commit is contained in:
PKEuS 2012-01-21 19:55:32 +01:00
parent 87e19d2552
commit 36479499e7
6 changed files with 204 additions and 237 deletions

View File

@ -119,7 +119,8 @@ void CheckInternal::checkTokenSimpleMatchPatterns()
void CheckInternal::checkMissingPercentCharacter()
{
std::set<std::string> magics;
static std::set<std::string> magics;
if (magics.empty()) {
magics.insert("%any%");
magics.insert("%var%");
magics.insert("%type%");
@ -129,6 +130,7 @@ void CheckInternal::checkMissingPercentCharacter()
magics.insert("%varid%");
magics.insert("%or%");
magics.insert("%oror%");
}
for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) {
if (!Token::simpleMatch(tok, "Token :: Match (") && !Token::simpleMatch(tok, "Token :: findmatch ("))

View File

@ -37,7 +37,7 @@ namespace {
bool CheckNullPointer::isUpper(const std::string &str)
{
for (unsigned int i = 0; i < str.length(); ++i) {
if (str[i] >= 'a' && str[i] <= 'z')
if (std::islower(str[i]))
return false;
}
return true;
@ -234,10 +234,7 @@ bool CheckNullPointer::isPointerDeRef(const Token *tok, bool &unknown)
return false;
}
if (Token::Match(tok->previous(), "[;{}=+-/(,] %var% ["))
return true;
if (Token::Match(tok->previous(), "return %var% ["))
if (Token::Match(tok->previous(), "!!& %var% ["))
return true;
if (Token::Match(tok, "%var% ("))
@ -252,7 +249,7 @@ bool CheckNullPointer::isPointerDeRef(const Token *tok, bool &unknown)
// This is most useful in inconclusive checking
if (inconclusive) {
// Not a dereference..
if (Token::Match(tok->previous(), "[;{}(] %var% ="))
if (Token::Match(tok, "%var% ="))
return false;
// OK to delete a null
@ -261,7 +258,7 @@ bool CheckNullPointer::isPointerDeRef(const Token *tok, bool &unknown)
// OK to check if pointer is null
// OK to take address of pointer
if (Token::Match(tok->previous(), "!|& %var% )|,|&&|%oror%"))
if (Token::Match(tok->previous(), "!|& %var%"))
return false;
// OK to pass pointer to function
@ -269,7 +266,9 @@ bool CheckNullPointer::isPointerDeRef(const Token *tok, bool &unknown)
return false;
// Compare pointer
if (Token::Match(tok->previous(), "(|&&|%oror%|==|!= %var% &&|%oror%|)"))
if (Token::Match(tok->previous(), "(|&&|%oror%|==|!= %var%"))
return false;
if (Token::Match(tok, "%var% &&|%oror%|==|!=|)"))
return false;
// Taking address
@ -277,11 +276,7 @@ bool CheckNullPointer::isPointerDeRef(const Token *tok, bool &unknown)
return false;
// unknown if it's a dereference
// FIXME: Uncomment this. We just need to fix false positives
// when cppcheck source code is checked before it can
// be uncommented. We need to have better checks to
// determine when there is NOT a pointer dereference.
//unknown = true;
unknown = true;
}
// assume that it's not a dereference (no false positives)
@ -292,7 +287,7 @@ bool CheckNullPointer::isPointerDeRef(const Token *tok, bool &unknown)
// check if function can assign pointer
bool CheckNullPointer::CanFunctionAssignPointer(const Token *functiontoken, unsigned int varid) const
{
if (Token::Match(functiontoken, "if|while|sizeof"))
if (Token::Match(functiontoken, "if|while|for|switch|sizeof|catch"))
return false;
int argumentNumber = 0;
@ -434,7 +429,7 @@ void CheckNullPointer::nullPointerLinkedList()
const std::string varname(tok2->str());
// Check usage of dereferenced variable in the loop..
for (const Token *tok3 = i->classStart; tok3 && tok3 != i->classEnd; tok3 = tok3->next()) {
for (const Token *tok3 = i->classStart->next(); tok3 && tok3 != i->classEnd; tok3 = tok3->next()) {
// TODO: are there false negatives for "while ( %varid% ||"
if (Token::Match(tok3, "while ( %varid% &&|)", varid)) {
// Make sure there is a "break" or "return" inside the loop.
@ -801,25 +796,24 @@ void CheckNullPointer::nullPointerByDeRefAndChec()
void CheckNullPointer::nullPointerByCheckAndDeRef()
{
// Check if pointer is NULL and then dereference it..
const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase();
for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) {
if (Token::simpleMatch(tok, "if (") && !tok->isExpandedMacro()) {
// Check if pointer is NULL and then dereference it..
for (std::list<Scope>::const_iterator i = symbolDatabase->scopeList.begin(); i != symbolDatabase->scopeList.end(); ++i) {
if (i->type != Scope::eIf && i->type != Scope::eElseIf && i->type != Scope::eWhile)
continue;
if (!i->classDef || i->classDef->isExpandedMacro())
continue;
const Token* const tok = i->type != Scope::eElseIf ? i->classDef : i->classDef->next();
// TODO: investigate false negatives:
// - handle "while"?
// - if there are logical operators
// - if (x) { } else { ... }
// If the if-body ends with a unknown macro then bailout
{
// goto the end parenthesis
const Token *endpar = tok->next()->link();
const Token *endbody = Token::simpleMatch(endpar, ") {") ? endpar->next()->link() : 0;
if (endbody &&
Token::Match(endbody->tokAt(-3), "[;{}] %var% ;") &&
isUpper(endbody->strAt(-2)))
if (Token::Match(i->classEnd->tokAt(-3), "[;{}] %var% ;") && isUpper(i->classEnd->strAt(-2)))
continue;
}
// vartok : token for the variable
const Token *vartok = 0;
@ -851,25 +845,20 @@ void CheckNullPointer::nullPointerByCheckAndDeRef()
bool null = true;
// start token = inside the if-body
const Token *tok1 = tok->next()->link()->tokAt(2);
// indentlevel inside the if-body is 1
unsigned int indentlevel = 1;
const Token *tok1 = i->classStart;
if (Token::Match(tok, "if|while ( %var% )|&&")) {
// pointer might be null
null = false;
// start token = first token after the if/while body
tok1 = tok1->previous()->link();
tok1 = tok1 ? tok1->next() : NULL;
tok1 = i->classEnd->next();
if (!tok1)
continue;
// indentlevel at the base level is 0
indentlevel = 0;
}
unsigned int indentlevel = 0;
// Name of the pointer
const std::string &pointerName = vartok->str();
@ -972,7 +961,6 @@ void CheckNullPointer::nullPointerByCheckAndDeRef()
}
}
}
}
void CheckNullPointer::nullPointer()
@ -987,25 +975,13 @@ void CheckNullPointer::nullPointer()
/** Dereferencing null constant (simplified token list) */
void CheckNullPointer::nullConstantDereference()
{
// this is kept at 0 for all scopes that are not executing
unsigned int indentlevel = 0;
const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase();
for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) {
// start of executable scope..
if (indentlevel == 0 && Token::Match(tok, ") const| {"))
indentlevel = 1;
else if (indentlevel >= 1) {
if (tok->str() == "{")
++indentlevel;
else if (tok->str() == "}") {
if (indentlevel <= 2)
indentlevel = 0;
else
--indentlevel;
}
for (std::list<Scope>::const_iterator i = symbolDatabase->scopeList.begin(); i != symbolDatabase->scopeList.end(); ++i) {
if (i->type != Scope::eFunction || !i->classStart)
continue;
for (const Token *tok = i->classStart; tok != i->classEnd; tok = tok->next()) {
if (tok->str() == "(" && Token::Match(tok->previous(), "sizeof|decltype|typeid"))
tok = tok->link();
@ -1015,7 +991,7 @@ void CheckNullPointer::nullConstantDereference()
}
}
else if (indentlevel > 0 && Token::Match(tok->previous(), "[={};] %var% (")) {
else if (Token::Match(tok->previous(), "[={};] %var% (")) {
std::list<const Token *> var;
parseFunctionCall(*tok, var, 0);

View File

@ -599,8 +599,7 @@ void CheckOther::checkSwitchCaseFallThrough()
const char breakPattern[] = "break|continue|return|exit|goto|throw";
for (std::list<Scope>::const_iterator i = symbolDatabase->scopeList.begin(); i != symbolDatabase->scopeList.end(); ++i) {
const Token* const tok = i->classDef;
if (i->type != Scope::eSwitch || !tok) // Find the beginning of a switch
if (i->type != Scope::eSwitch || !i->classStart) // Find the beginning of a switch
continue;
// Check the contents of the switch statement
@ -609,7 +608,7 @@ void CheckOther::checkSwitchCaseFallThrough()
std::stack<Token *> scopenest;
bool justbreak = true;
bool firstcase = true;
for (const Token *tok2 = tok->next()->link()->tokAt(2); tok2; tok2 = tok2->next()) {
for (const Token *tok2 = i->classStart; tok2 != i->classEnd; tok2 = tok2->next()) {
if (Token::simpleMatch(tok2, "if (")) {
tok2 = tok2->next()->link()->next();
if (tok2->link() == NULL) {
@ -827,11 +826,11 @@ void CheckOther::checkAssignmentInAssert()
const Token *endTok = tok ? tok->next()->link() : NULL;
while (tok && endTok) {
const Token* varTok = Token::findmatch(tok->tokAt(2), "%var% --|++|+=|-=|*=|/=|&=|^=|=", endTok);
if (varTok) {
assignmentInAssertError(tok, varTok->str());
} else if (NULL != (varTok = Token::findmatch(tok->tokAt(2), "--|++ %var%", endTok))) {
assignmentInAssertError(tok, varTok->strAt(1));
for (tok = tok->tokAt(2); tok != endTok; tok = tok->next()) {
if (tok->isName() && (tok->next()->isAssignmentOp() || tok->next()->str() == "++" || tok->next()->str() == "--"))
assignmentInAssertError(tok, tok->str());
else if (Token::Match(tok, "--|++ %var%"))
assignmentInAssertError(tok, tok->strAt(1));
}
tok = Token::findmatch(endTok->next(), assertPattern);
@ -1638,7 +1637,7 @@ void CheckOther::checkUnreachableCode()
// that the goto jump was intended to skip some code on the first loop iteration.
bool labelInFollowingLoop = false;
if (labelName && Token::Match(secondBreak, "while|do|for")) {
const Token *scope = Token::findmatch(secondBreak, "{");
const Token *scope = Token::findsimplematch(secondBreak, "{");
if (scope) {
for (const Token *tokIter = scope; tokIter != scope->link() && tokIter; tokIter = tokIter->next()) {
if (Token::Match(tokIter, "[;{}] %any% :") && labelName->str() == tokIter->strAt(1)) {
@ -2270,24 +2269,12 @@ void CheckOther::checkMisusedScopedObject()
const SymbolDatabase * const symbolDatabase = _tokenizer->getSymbolDatabase();
std::list<Scope>::const_iterator scope;
for (scope = symbolDatabase->scopeList.begin(); scope != symbolDatabase->scopeList.end(); ++scope) {
for (std::list<Scope>::const_iterator scope = symbolDatabase->scopeList.begin(); scope != symbolDatabase->scopeList.end(); ++scope) {
// only check functions
if (scope->type != Scope::eFunction)
continue;
unsigned int depth = 0;
for (const Token *tok = scope->classStart; tok; tok = tok->next()) {
if (tok->str() == "{") {
++depth;
} else if (tok->str() == "}") {
if (depth <= 1)
break;
--depth;
}
for (const Token *tok = scope->classStart; tok && tok != scope->classEnd; tok = tok->next()) {
if (Token::Match(tok, "[;{}] %var% (")
&& Token::simpleMatch(tok->linkAt(2), ") ;")
&& symbolDatabase->isClassOrStruct(tok->next()->str())
@ -2484,15 +2471,15 @@ void CheckOther::checkDuplicateBranch()
//-----------------------------------------------------------------------------
void CheckOther::checkDoubleFree()
{
std::set<int> freedVariables;
std::set<int> closeDirVariables;
std::set<unsigned int> freedVariables;
std::set<unsigned int> closeDirVariables;
for (const Token* tok = _tokenizer->tokens(); tok; tok = tok->next()) {
// Keep track of any variables passed to "free()", "g_free()" or "closedir()",
// and report an error if the same variable is passed twice.
if (Token::Match(tok, "free|g_free|closedir ( %var% )")) {
int var = tok->tokAt(2)->varId();
unsigned int var = tok->tokAt(2)->varId();
if (var) {
if (Token::Match(tok, "free|g_free")) {
if (freedVariables.find(var) != freedVariables.end())
@ -2512,7 +2499,7 @@ void CheckOther::checkDoubleFree()
// and report an error if the same variable is delete'd twice.
else if (Token::Match(tok, "delete %var% ;") || Token::Match(tok, "delete [ ] %var% ;")) {
int varIdx = (tok->strAt(1) == "[") ? 3 : 1;
int var = tok->tokAt(varIdx)->varId();
unsigned int var = tok->tokAt(varIdx)->varId();
if (var) {
if (freedVariables.find(var) != freedVariables.end())
doubleFreeError(tok, tok->tokAt(varIdx)->str());
@ -2531,7 +2518,7 @@ void CheckOther::checkDoubleFree()
else if (Token::Match(tok, "%var% (") && !Token::Match(tok, "printf|sprintf|snprintf|fprintf")) {
for (const Token* tok2 = tok->tokAt(2); tok2 != tok->linkAt(1); tok2 = tok2->next()) {
if (Token::Match(tok2, "%var%")) {
int var = tok2->varId();
unsigned int var = tok2->varId();
if (var) {
freedVariables.erase(var);
closeDirVariables.erase(var);
@ -2542,7 +2529,7 @@ void CheckOther::checkDoubleFree()
// If a pointer is assigned a new value, remove it from the set of previously freed variables
else if (Token::Match(tok, "%var% =")) {
int var = tok->varId();
unsigned int var = tok->varId();
if (var) {
freedVariables.erase(var);
closeDirVariables.erase(var);

View File

@ -79,7 +79,8 @@ std::string Settings::addEnabled(const std::string &str)
bool handled = false;
std::set<std::string> id;
static std::set<std::string> id;
if (id.empty()) {
id.insert("style");
id.insert("performance");
id.insert("portability");
@ -89,6 +90,7 @@ std::string Settings::addEnabled(const std::string &str)
#ifndef NDEBUG
id.insert("internal");
#endif
}
if (str == "all") {
std::set<std::string>::const_iterator it;

View File

@ -83,15 +83,15 @@ const Token* TemplateSimplifier::hasComplicatedSyntaxErrorsInTemplates(Token *to
}
// skip executing scopes (ticket #1984)..
if (Token::simpleMatch(tok, "; {"))
else if (Token::simpleMatch(tok, "; {"))
tok = tok->next()->link();
// skip executing scopes (ticket #3183)..
if (Token::simpleMatch(tok, "( {"))
else if (Token::simpleMatch(tok, "( {"))
tok = tok->next()->link();
// skip executing scopes (ticket #1985)..
if (Token::simpleMatch(tok, "try {")) {
else if (Token::simpleMatch(tok, "try {")) {
tok = tok->next()->link();
while (Token::simpleMatch(tok, "} catch (")) {
tok = tok->linkAt(2);

View File

@ -2392,7 +2392,7 @@ bool Tokenizer::hasEnumsWithTypedef()
for (const Token *tok = _tokens; tok; tok = tok->next()) {
if (Token::Match(tok, "enum %var% {")) {
tok = tok->tokAt(2);
const Token *tok2 = Token::findmatch(tok, "typedef", tok->link());
const Token *tok2 = Token::findsimplematch(tok, "typedef", tok->link());
if (tok2) {
syntaxError(tok2);
return true;