cppcheck/lib/executionpath.cpp

315 lines
8.9 KiB
C++
Raw Normal View History

2009-12-14 20:30:31 +01:00
/*
* Cppcheck - A tool for static C/C++ code analysis
* Copyright (C) 2007-2009 Daniel Marjamäki and Cppcheck team.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "executionpath.h"
#include "token.h"
#include <memory>
2009-12-25 19:45:21 +01:00
// default : bail out if the condition is has variable handling
2009-12-25 20:50:23 +01:00
bool ExecutionPath::parseCondition(const Token &tok, std::list<ExecutionPath *> & checks)
2009-12-25 19:45:21 +01:00
{
2010-04-02 02:21:53 +02:00
if(Token::Match(tok.tokAt(-3), "!!else if ("))
2009-12-25 20:50:23 +01:00
{
++ifinfo;
}
2009-12-25 19:45:21 +01:00
unsigned int parlevel = 0;
2010-04-02 02:21:53 +02:00
for(const Token *tok2 = &tok; tok2; tok2 = tok2->next())
2009-12-25 19:45:21 +01:00
{
2010-04-02 02:21:53 +02:00
if(tok2->str() == "(")
2009-12-25 19:45:21 +01:00
++parlevel;
2010-04-02 02:21:53 +02:00
else if(tok2->str() == ")")
2009-12-25 19:45:21 +01:00
{
2010-04-02 02:21:53 +02:00
if(parlevel == 0)
2009-12-25 19:45:21 +01:00
break;
--parlevel;
}
2010-04-02 02:21:53 +02:00
else if(Token::Match(tok2, ";{}"))
2009-12-25 19:45:21 +01:00
break;
2010-04-02 02:21:53 +02:00
if(tok2->varId() != 0)
2009-12-25 19:45:21 +01:00
{
2010-04-02 02:21:53 +02:00
if(ifinfo > 1)
2009-12-25 20:50:23 +01:00
return true;
else
bailOutVar(checks, tok2->varId());
2009-12-25 19:45:21 +01:00
}
}
return false;
}
static const Token *checkExecutionPaths_(const Token *tok, std::list<ExecutionPath *> &checks)
2009-12-14 20:30:31 +01:00
{
2010-04-02 02:21:53 +02:00
if(!tok || tok->str() == "}" || checks.empty())
2010-01-08 21:54:24 +01:00
return 0;
2009-12-14 20:30:31 +01:00
const std::auto_ptr<ExecutionPath> check(checks.front()->copy());
2010-04-02 02:21:53 +02:00
for(; tok; tok = tok->next())
2009-12-14 20:30:31 +01:00
{
2010-04-02 02:21:53 +02:00
if(tok->str() == "}")
2009-12-14 20:30:31 +01:00
return 0;
2010-04-02 02:21:53 +02:00
if(Token::simpleMatch(tok, "while ("))
{
// parse condition
2010-04-02 02:21:53 +02:00
if(checks.size() > 10 || check->parseCondition(*tok->tokAt(2), checks))
{
ExecutionPath::bailOut(checks);
return 0;
}
// skip "while (fgets()!=NULL)"
2010-04-02 02:21:53 +02:00
if(Token::simpleMatch(tok, "while ( fgets ("))
{
const Token *tok2 = tok->tokAt(3)->link();
2010-04-02 02:21:53 +02:00
if(Token::simpleMatch(tok2, ") ) {"))
{
tok = tok2->tokAt(2)->link();
2010-04-02 02:21:53 +02:00
if(!tok)
break;
continue;
}
}
}
// for/while/switch/do .. bail out
2010-04-02 02:21:53 +02:00
if(Token::Match(tok, "for|while|switch|do"))
2009-12-14 20:30:31 +01:00
{
// goto {
const Token *tok2 = tok->next();
2010-04-02 02:21:53 +02:00
if(tok2 && tok2->str() == "(")
tok2 = tok2->link();
2010-04-02 02:21:53 +02:00
if(tok2 && tok2->str() == ")")
tok2 = tok2->next();
2010-04-02 02:21:53 +02:00
if(!tok2 || tok2->str() != "{")
{
ExecutionPath::bailOut(checks);
return 0;
}
// skip { .. }
tok2 = tok2->link();
// if "do { .. } while ( .." , goto end of while..
2010-04-02 02:21:53 +02:00
if(Token::simpleMatch(tok, "do {") && Token::simpleMatch(tok2, "} while ("))
tok2 = tok2->tokAt(2)->link();
// bail out all variables if the scope contains a "return"
// bail out all variables used in this for/while/switch/do
2010-04-02 02:21:53 +02:00
for(; tok && tok != tok2; tok = tok->next())
{
2010-04-02 02:21:53 +02:00
if(tok->str() == "return")
ExecutionPath::bailOut(checks);
2010-04-02 02:21:53 +02:00
if(tok->varId())
ExecutionPath::bailOutVar(checks, tok->varId());
}
continue;
2009-12-14 20:30:31 +01:00
}
// .. ) { ... } => bail out
2010-04-02 02:21:53 +02:00
if(Token::simpleMatch(tok, ") {"))
{
ExecutionPath::bailOut(checks);
return 0;
}
2010-04-02 02:21:53 +02:00
if(Token::Match(tok, "abort|exit ("))
{
ExecutionPath::bailOut(checks);
return 0;
}
2009-12-21 18:17:35 +01:00
// don't parse into "struct type { .."
2010-04-02 02:21:53 +02:00
if(Token::Match(tok, "struct|union|class %type% {|:"))
{
2010-04-02 02:21:53 +02:00
while(tok && tok->str() != "{" && tok->str() != ";")
tok = tok->next();
tok = tok ? tok->link() : 0;
}
2009-12-21 18:17:35 +01:00
2010-04-02 02:21:53 +02:00
if(Token::Match(tok, "= {"))
2009-12-14 20:30:31 +01:00
{
// GCC struct initialization.. bail out
2010-04-02 02:21:53 +02:00
if(Token::Match(tok->tokAt(2), ". %var% ="))
{
ExecutionPath::bailOut(checks);
return 0;
}
2009-12-14 20:30:31 +01:00
tok = tok->next()->link();
2010-04-02 02:21:53 +02:00
if(!tok)
2009-12-14 20:30:31 +01:00
{
ExecutionPath::bailOut(checks);
return 0;
}
continue;
}
// ; { ... }
2010-04-02 02:21:53 +02:00
if(Token::Match(tok->previous(), "[;{}] {"))
{
const Token *tokerr = checkExecutionPaths_(tok->next(), checks);
2010-04-02 02:21:53 +02:00
if(tokerr)
{
ExecutionPath::bailOut(checks);
return tokerr;
}
tok = tok->link();
continue;
}
2010-04-02 02:21:53 +02:00
if(tok->str() == "if")
2009-12-14 20:30:31 +01:00
{
std::list<ExecutionPath *> newchecks;
2010-04-02 02:21:53 +02:00
while(tok->str() == "if")
2009-12-14 20:30:31 +01:00
{
// goto "("
tok = tok->next();
2009-12-25 19:45:21 +01:00
// parse condition
2010-04-02 02:21:53 +02:00
if(checks.size() > 10 || check->parseCondition(*tok->next(), checks))
2009-12-14 20:30:31 +01:00
{
ExecutionPath::bailOut(checks);
ExecutionPath::bailOut(newchecks);
2009-12-25 19:45:21 +01:00
return 0;
2009-12-14 20:30:31 +01:00
}
2009-12-25 19:45:21 +01:00
// goto ")"
tok = tok ? tok->link() : 0;
2009-12-14 20:30:31 +01:00
// goto "{"
tok = tok ? tok->next() : 0;
2010-04-02 02:21:53 +02:00
if(!Token::simpleMatch(tok, "{"))
{
ExecutionPath::bailOut(checks);
ExecutionPath::bailOut(newchecks);
2009-12-14 20:30:31 +01:00
return 0;
}
2009-12-14 20:30:31 +01:00
// Recursively check into the if ..
{
std::list<ExecutionPath *> c;
std::list<ExecutionPath *>::iterator it;
2010-04-02 02:21:53 +02:00
for(it = checks.begin(); it != checks.end(); ++it)
2009-12-14 20:30:31 +01:00
c.push_back((*it)->copy());
const Token *tokerr = checkExecutionPaths_(tok->next(), c);
2010-04-02 02:21:53 +02:00
if(tokerr)
{
ExecutionPath::bailOut(c);
ExecutionPath::bailOut(newchecks);
2009-12-14 20:30:31 +01:00
return tokerr;
}
2010-04-02 02:21:53 +02:00
while(!c.empty())
2009-12-14 20:30:31 +01:00
{
newchecks.push_back(c.back());
c.pop_back();
}
}
// goto "}"
tok = tok->link();
// there is no else => break out
2010-04-02 02:21:53 +02:00
if(Token::Match(tok, "} !!else"))
2009-12-14 20:30:31 +01:00
break;
// parse next "if"..
tok = tok->tokAt(2);
2010-04-02 02:21:53 +02:00
if(tok->str() == "if")
2009-12-14 20:30:31 +01:00
continue;
// there is no "if"..
const Token *tokerr = checkExecutionPaths_(tok->next(), checks);
2010-04-02 02:21:53 +02:00
if(tokerr)
{
ExecutionPath::bailOut(newchecks);
2009-12-14 20:30:31 +01:00
return tokerr;
}
2009-12-14 20:30:31 +01:00
tok = tok->link();
2010-04-02 02:21:53 +02:00
if(!tok)
{
ExecutionPath::bailOut(newchecks);
2009-12-14 20:30:31 +01:00
return 0;
}
2009-12-14 20:30:31 +01:00
}
std::list<ExecutionPath *>::iterator it;
2010-04-02 02:21:53 +02:00
for(it = newchecks.begin(); it != newchecks.end(); ++it)
checks.push_back(*it);
2009-12-14 20:30:31 +01:00
}
{
bool foundError = false;
tok = check->parse(*tok, foundError, checks);
2010-04-02 02:21:53 +02:00
if(checks.empty())
2009-12-14 20:30:31 +01:00
return 0;
2010-04-02 02:21:53 +02:00
else if(foundError)
2009-12-14 20:30:31 +01:00
return tok;
}
// return/throw ends all execution paths
2010-04-02 02:21:53 +02:00
if(tok->str() == "return" || tok->str() == "throw")
2009-12-14 20:30:31 +01:00
{
ExecutionPath::bailOut(checks);
}
}
return 0;
}
void checkExecutionPaths(const Token *tok, ExecutionPath *c)
{
2010-04-02 02:21:53 +02:00
for(; tok; tok = tok->next())
{
2010-04-02 02:21:53 +02:00
if(tok->str() != ")")
continue;
// Start of implementation..
2010-04-02 02:21:53 +02:00
if(Token::Match(tok, ") const| {"))
{
// goto the "{"
tok = tok->next();
2010-04-02 02:21:53 +02:00
if(tok->str() == "const")
tok = tok->next();
std::list<ExecutionPath *> checks;
checks.push_back(c->copy());
checkExecutionPaths_(tok, checks);
c->end(checks, tok->link());
2010-04-02 02:21:53 +02:00
while(!checks.empty())
{
delete checks.back();
checks.pop_back();
}
// skip this scope - it has been checked
tok = tok->link();
}
}
}