Merge branch 'master' of https://github.com/danmar/cppcheck
This commit is contained in:
commit
fa04273473
2
Makefile
2
Makefile
|
@ -362,7 +362,7 @@ $(SRCDIR)/tokenize.o: lib/tokenize.cpp lib/tokenize.h lib/errorlogger.h lib/conf
|
||||||
$(SRCDIR)/tokenlist.o: lib/tokenlist.cpp lib/tokenlist.h lib/config.h lib/token.h lib/valueflow.h lib/mathlib.h lib/path.h lib/preprocessor.h lib/settings.h lib/library.h lib/suppressions.h lib/standards.h lib/timer.h lib/errorlogger.h
|
$(SRCDIR)/tokenlist.o: lib/tokenlist.cpp lib/tokenlist.h lib/config.h lib/token.h lib/valueflow.h lib/mathlib.h lib/path.h lib/preprocessor.h lib/settings.h lib/library.h lib/suppressions.h lib/standards.h lib/timer.h lib/errorlogger.h
|
||||||
$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CFG) $(CXXFLAGS) -c -o $(SRCDIR)/tokenlist.o $(SRCDIR)/tokenlist.cpp
|
$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CFG) $(CXXFLAGS) -c -o $(SRCDIR)/tokenlist.o $(SRCDIR)/tokenlist.cpp
|
||||||
|
|
||||||
$(SRCDIR)/valueflow.o: lib/valueflow.cpp lib/valueflow.h lib/token.h lib/config.h lib/mathlib.h
|
$(SRCDIR)/valueflow.o: lib/valueflow.cpp lib/valueflow.h lib/errorlogger.h lib/config.h lib/suppressions.h lib/mathlib.h lib/settings.h lib/library.h lib/path.h lib/standards.h lib/timer.h lib/symboldatabase.h lib/token.h lib/tokenlist.h
|
||||||
$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CFG) $(CXXFLAGS) -c -o $(SRCDIR)/valueflow.o $(SRCDIR)/valueflow.cpp
|
$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CFG) $(CXXFLAGS) -c -o $(SRCDIR)/valueflow.o $(SRCDIR)/valueflow.cpp
|
||||||
|
|
||||||
cli/cmdlineparser.o: cli/cmdlineparser.cpp cli/cmdlineparser.h lib/cppcheck.h lib/config.h lib/settings.h lib/library.h lib/path.h lib/mathlib.h lib/suppressions.h lib/standards.h lib/timer.h lib/errorlogger.h lib/checkunusedfunctions.h lib/check.h lib/token.h lib/valueflow.h lib/tokenize.h lib/tokenlist.h cli/filelister.h
|
cli/cmdlineparser.o: cli/cmdlineparser.cpp cli/cmdlineparser.h lib/cppcheck.h lib/config.h lib/settings.h lib/library.h lib/path.h lib/mathlib.h lib/suppressions.h lib/standards.h lib/timer.h lib/errorlogger.h lib/checkunusedfunctions.h lib/check.h lib/token.h lib/valueflow.h lib/tokenize.h lib/tokenlist.h cli/filelister.h
|
||||||
|
|
|
@ -112,7 +112,7 @@ the latest sources in a zip or tgz archive</a> from the github website.</p>
|
||||||
</ul>
|
</ul>
|
||||||
<h2 id="other">Other</h2>
|
<h2 id="other">Other</h2>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="daca2-report/daca2.html">DACA2 - Scanning Debian with latest Cppcheck</a></li>
|
<li>DACA2 - Scanning Debian with Cppcheck. Version: <a href="daca2-cppcheck1.63/daca2.html">1.63</a> / <a href="daca2-report/daca2.html">head</a></li>
|
||||||
<li><a href="coverage_report/">Coverage report</a></li>
|
<li><a href="coverage_report/">Coverage report</a></li>
|
||||||
<li><a href="cpd.txt">CPD report (duplicate code)</a></li>
|
<li><a href="cpd.txt">CPD report (duplicate code)</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
|
@ -468,7 +468,7 @@ void CheckClass::initializeVarList(const Function &func, std::list<const Functio
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (level == 0 && Token::Match(ftok, "%var% {") && ftok->str() != "const" && Token::Match(ftok->next()->link()->next(), ",|{|%type%")) {
|
} else if (level == 0 && Token::Match(ftok, "%var% {") && ftok->str() != "const" && Token::Match(ftok->next()->link()->next(), "%type%|,|{")) {
|
||||||
initVar(ftok->str(), scope, usage);
|
initVar(ftok->str(), scope, usage);
|
||||||
ftok = ftok->linkAt(1);
|
ftok = ftok->linkAt(1);
|
||||||
} else if (level != 0 && Token::Match(ftok, "%var% =")) // assignment in the initializer: var(value = x)
|
} else if (level != 0 && Token::Match(ftok, "%var% =")) // assignment in the initializer: var(value = x)
|
||||||
|
|
|
@ -22,6 +22,8 @@
|
||||||
#include "symboldatabase.h"
|
#include "symboldatabase.h"
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <set>
|
#include <set>
|
||||||
|
#include <cstring>
|
||||||
|
#include <cctype>
|
||||||
|
|
||||||
// Register this check class (by creating a static instance of it).
|
// Register this check class (by creating a static instance of it).
|
||||||
// Disabled in release builds
|
// Disabled in release builds
|
||||||
|
@ -48,6 +50,34 @@ void CheckInternal::checkTokenMatchPatterns()
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char *p = pattern.c_str();
|
||||||
|
while (*p) {
|
||||||
|
while (*p && std::isspace(*p))
|
||||||
|
p++;
|
||||||
|
const char *start = p;
|
||||||
|
while (*p && !std::isspace(*p))
|
||||||
|
p++;
|
||||||
|
const char *end = p - 1;
|
||||||
|
if (start < end && !(*start == '[' && *end == ']')) {
|
||||||
|
bool cmd = (*start=='%' && std::isalpha(*(start+1)));
|
||||||
|
// check multicompare pattern..
|
||||||
|
for (const char *s = start; s != end; s++) {
|
||||||
|
if (*s == '|') {
|
||||||
|
if (!(*(s+1) == '%' && std::isalpha(*(s+2)))) {
|
||||||
|
cmd = false;
|
||||||
|
} else if (!cmd &&
|
||||||
|
std::strncmp(s+1,"%op%",4)!=0 &&
|
||||||
|
std::strncmp(s+1,"%or%",4)!=0 &&
|
||||||
|
std::strncmp(s+1,"%cop%",5)!=0 &&
|
||||||
|
std::strncmp(s+1,"%var%",5)!=0 &&
|
||||||
|
std::strncmp(s+1,"%oror%",6)!=0) {
|
||||||
|
multiComparePatternError(tok, pattern, funcname);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Check for signs of complex patterns
|
// Check for signs of complex patterns
|
||||||
if (pattern.find_first_of("[|%") != std::string::npos)
|
if (pattern.find_first_of("[|%") != std::string::npos)
|
||||||
continue;
|
continue;
|
||||||
|
@ -245,6 +275,13 @@ void CheckInternal::checkRedundantNextPrevious()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CheckInternal::multiComparePatternError(const Token* tok, const std::string& pattern, const std::string &funcname)
|
||||||
|
{
|
||||||
|
reportError(tok, Severity::error, "multiComparePatternError",
|
||||||
|
"Bad multicompare pattern (a %cmd% must be first unless it is %or%,%op%,%cop%,%var%,%oror%) inside Token::" + funcname + "() call: \"" + pattern + "\""
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
void CheckInternal::simplePatternError(const Token* tok, const std::string& pattern, const std::string &funcname)
|
void CheckInternal::simplePatternError(const Token* tok, const std::string& pattern, const std::string &funcname)
|
||||||
{
|
{
|
||||||
reportError(tok, Severity::warning, "simplePatternError",
|
reportError(tok, Severity::warning, "simplePatternError",
|
||||||
|
|
|
@ -73,6 +73,7 @@ public:
|
||||||
void checkRedundantNextPrevious();
|
void checkRedundantNextPrevious();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void multiComparePatternError(const Token *tok, const std::string &pattern, const std::string &funcname);
|
||||||
void simplePatternError(const Token *tok, const std::string &pattern, const std::string &funcname);
|
void simplePatternError(const Token *tok, const std::string &pattern, const std::string &funcname);
|
||||||
void complexPatternError(const Token *tok, const std::string &pattern, const std::string &funcname);
|
void complexPatternError(const Token *tok, const std::string &pattern, const std::string &funcname);
|
||||||
void missingPercentCharacterError(const Token *tok, const std::string &pattern, const std::string &funcname);
|
void missingPercentCharacterError(const Token *tok, const std::string &pattern, const std::string &funcname);
|
||||||
|
@ -81,6 +82,7 @@ private:
|
||||||
|
|
||||||
void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const {
|
void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const {
|
||||||
CheckInternal c(0, settings, errorLogger);
|
CheckInternal c(0, settings, errorLogger);
|
||||||
|
c.multiComparePatternError(0, ";|%type%", "Match");
|
||||||
c.simplePatternError(0, "class {", "Match");
|
c.simplePatternError(0, "class {", "Match");
|
||||||
c.complexPatternError(0, "%type% ( )", "Match");
|
c.complexPatternError(0, "%type% ( )", "Match");
|
||||||
c.missingPercentCharacterError(0, "%num", "Match");
|
c.missingPercentCharacterError(0, "%num", "Match");
|
||||||
|
|
|
@ -2158,8 +2158,10 @@ void CheckOther::checkZeroDivision()
|
||||||
std::list<ValueFlow::Value>::const_iterator it;
|
std::list<ValueFlow::Value>::const_iterator it;
|
||||||
for (it = values.begin(); it != values.end(); ++it) {
|
for (it = values.begin(); it != values.end(); ++it) {
|
||||||
if (it->intvalue == 0) {
|
if (it->intvalue == 0) {
|
||||||
if (!it->link || _settings->isEnabled("warning"))
|
if (it->condition == NULL)
|
||||||
zerodivError(tok);
|
zerodivError(tok);
|
||||||
|
else if (_settings->isEnabled("warning"))
|
||||||
|
zerodivcondError(it->condition,tok);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2176,6 +2178,11 @@ void CheckOther::checkZeroDivisionOrUselessCondition()
|
||||||
{
|
{
|
||||||
if (!_settings->isEnabled("warning"))
|
if (!_settings->isEnabled("warning"))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
// Use experimental checking instead based on value flow analysis
|
||||||
|
if (_settings->valueFlow)
|
||||||
|
return;
|
||||||
|
|
||||||
const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase();
|
const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase();
|
||||||
const std::size_t numberOfFunctions = symbolDatabase->functionScopes.size();
|
const std::size_t numberOfFunctions = symbolDatabase->functionScopes.size();
|
||||||
for (std::size_t functionIndex = 0; functionIndex < numberOfFunctions; ++functionIndex) {
|
for (std::size_t functionIndex = 0; functionIndex < numberOfFunctions; ++functionIndex) {
|
||||||
|
@ -2297,6 +2304,24 @@ void CheckOther::checkZeroDivisionOrUselessCondition()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: this utility function should probably be moved to some common file
|
||||||
|
static std::string astStringify(const Token *top)
|
||||||
|
{
|
||||||
|
const Token *start = top;
|
||||||
|
while (start->astOperand1() && start->astOperand2())
|
||||||
|
start = start->astOperand1();
|
||||||
|
const Token *end = top;
|
||||||
|
while (end->astOperand1() && end->astOperand2())
|
||||||
|
end = end->astOperand2();
|
||||||
|
std::string str;
|
||||||
|
for (const Token *tok = start; tok && tok != end; tok = tok->next()) {
|
||||||
|
str += tok->str();
|
||||||
|
if (Token::Match(tok, "%var%|%num% %var%|%num%"))
|
||||||
|
str += " ";
|
||||||
|
}
|
||||||
|
return str + end->str();
|
||||||
|
}
|
||||||
|
|
||||||
void CheckOther::zerodivcondError(const Token *tokcond, const Token *tokdiv)
|
void CheckOther::zerodivcondError(const Token *tokcond, const Token *tokdiv)
|
||||||
{
|
{
|
||||||
std::list<const Token *> callstack;
|
std::list<const Token *> callstack;
|
||||||
|
@ -2307,9 +2332,13 @@ void CheckOther::zerodivcondError(const Token *tokcond, const Token *tokdiv)
|
||||||
callstack.push_back(tokdiv);
|
callstack.push_back(tokdiv);
|
||||||
}
|
}
|
||||||
std::string condition;
|
std::string condition;
|
||||||
if (Token::Match(tokcond, "%num% <|<=")) {
|
if (!tokcond) {
|
||||||
|
// getErrorMessages
|
||||||
|
} else if (Token::Match(tokcond, "%num% <|<=")) {
|
||||||
condition = tokcond->strAt(2) + ((tokcond->strAt(1) == "<") ? ">" : ">=") + tokcond->str();
|
condition = tokcond->strAt(2) + ((tokcond->strAt(1) == "<") ? ">" : ">=") + tokcond->str();
|
||||||
} else if (tokcond) {
|
} else if (tokcond->isComparisonOp()) {
|
||||||
|
condition = astStringify(tokcond);
|
||||||
|
} else {
|
||||||
if (tokcond->str() == "!")
|
if (tokcond->str() == "!")
|
||||||
condition = tokcond->next()->str() + "==0";
|
condition = tokcond->next()->str() + "==0";
|
||||||
else
|
else
|
||||||
|
|
|
@ -98,8 +98,12 @@ public:
|
||||||
|
|
||||||
class ArgumentChecks {
|
class ArgumentChecks {
|
||||||
public:
|
public:
|
||||||
ArgumentChecks() {
|
ArgumentChecks() :
|
||||||
notbool = notnull = notuninit = formatstr = strz = false;
|
notbool(false),
|
||||||
|
notnull(false),
|
||||||
|
notuninit(false),
|
||||||
|
formatstr(false),
|
||||||
|
strz(false) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool notbool;
|
bool notbool;
|
||||||
|
|
|
@ -2023,7 +2023,7 @@ bool Function::isImplicitlyVirtual(bool defaultVal) const
|
||||||
bool Function::isImplicitlyVirtual_rec(const ::Type* baseType, bool& safe) const
|
bool Function::isImplicitlyVirtual_rec(const ::Type* baseType, bool& safe) const
|
||||||
{
|
{
|
||||||
// check each base class
|
// check each base class
|
||||||
for (unsigned int i = 0; i < baseType->derivedFrom.size(); ++i) {
|
for (std::size_t i = 0; i < baseType->derivedFrom.size(); ++i) {
|
||||||
// check if base class exists in database
|
// check if base class exists in database
|
||||||
if (baseType->derivedFrom[i].type && baseType->derivedFrom[i].type->classScope) {
|
if (baseType->derivedFrom[i].type && baseType->derivedFrom[i].type->classScope) {
|
||||||
const Scope *parent = baseType->derivedFrom[i].type->classScope;
|
const Scope *parent = baseType->derivedFrom[i].type->classScope;
|
||||||
|
@ -2055,9 +2055,11 @@ bool Function::isImplicitlyVirtual_rec(const ::Type* baseType, bool& safe) const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!baseType->derivedFrom[i].type->derivedFrom.empty())
|
if (!baseType->derivedFrom[i].type->derivedFrom.empty()) {
|
||||||
if (isImplicitlyVirtual_rec(baseType->derivedFrom[i].type, safe))
|
// avoid endless recursion, see #5289 Crash: Stack overflow in isImplicitlyVirtual_rec when checking SVN
|
||||||
|
if ((baseType != baseType->derivedFrom[i].type) && isImplicitlyVirtual_rec(baseType->derivedFrom[i].type, safe))
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// unable to find base class so assume it has no virtual function
|
// unable to find base class so assume it has no virtual function
|
||||||
safe = false;
|
safe = false;
|
||||||
|
|
|
@ -65,6 +65,10 @@ public:
|
||||||
} needInitialization;
|
} needInitialization;
|
||||||
|
|
||||||
struct BaseInfo {
|
struct BaseInfo {
|
||||||
|
BaseInfo() :
|
||||||
|
type(NULL), nameTok(NULL), access(Public), isVirtual(false) {
|
||||||
|
}
|
||||||
|
|
||||||
std::string name;
|
std::string name;
|
||||||
const Type* type;
|
const Type* type;
|
||||||
const Token* nameTok;
|
const Token* nameTok;
|
||||||
|
@ -73,6 +77,10 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
struct FriendInfo {
|
struct FriendInfo {
|
||||||
|
FriendInfo() :
|
||||||
|
nameStart(NULL), nameEnd(NULL), type(NULL) {
|
||||||
|
}
|
||||||
|
|
||||||
const Token* nameStart;
|
const Token* nameStart;
|
||||||
const Token* nameEnd;
|
const Token* nameEnd;
|
||||||
std::string name;
|
std::string name;
|
||||||
|
|
|
@ -620,7 +620,7 @@ bool TemplateSimplifier::instantiateMatch(const Token *instance, const std::stri
|
||||||
if (patternAfter) {
|
if (patternAfter) {
|
||||||
const Token *tok = instance;
|
const Token *tok = instance;
|
||||||
unsigned int indentlevel = 0;
|
unsigned int indentlevel = 0;
|
||||||
for (tok = instance; tok && (tok->str() != ">" || indentlevel > 0); tok = tok->next()) {
|
for (tok = instance; tok && (tok->str() != ">" || indentlevel > 0) && (tok->str() != ">>" || indentlevel > 1); tok = tok->next()) {
|
||||||
if (Token::Match(tok, "[<,] %var% <") && templateParameters(tok->tokAt(2)) > 0)
|
if (Token::Match(tok, "[<,] %var% <") && templateParameters(tok->tokAt(2)) > 0)
|
||||||
++indentlevel;
|
++indentlevel;
|
||||||
if (indentlevel > 0 && tok->str() == ">")
|
if (indentlevel > 0 && tok->str() == ">")
|
||||||
|
|
|
@ -206,6 +206,7 @@ void Token::deleteThis()
|
||||||
_function = _next->_function;
|
_function = _next->_function;
|
||||||
_variable = _next->_variable;
|
_variable = _next->_variable;
|
||||||
_originalName = _next->_originalName;
|
_originalName = _next->_originalName;
|
||||||
|
values = _next->values;
|
||||||
if (_link)
|
if (_link)
|
||||||
_link->link(this);
|
_link->link(this);
|
||||||
|
|
||||||
|
@ -229,6 +230,7 @@ void Token::deleteThis()
|
||||||
_function = _previous->_function;
|
_function = _previous->_function;
|
||||||
_variable = _previous->_variable;
|
_variable = _previous->_variable;
|
||||||
_originalName = _previous->_originalName;
|
_originalName = _previous->_originalName;
|
||||||
|
values = _previous->values;
|
||||||
if (_link)
|
if (_link)
|
||||||
_link->link(this);
|
_link->link(this);
|
||||||
|
|
||||||
|
|
|
@ -370,6 +370,7 @@ Token * Tokenizer::deleteInvalidTypedef(Token *typeDef)
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Space {
|
struct Space {
|
||||||
|
Space() : classEnd(NULL), isNamespace(false) { }
|
||||||
std::string className;
|
std::string className;
|
||||||
const Token * classEnd;
|
const Token * classEnd;
|
||||||
bool isNamespace;
|
bool isNamespace;
|
||||||
|
@ -1605,7 +1606,7 @@ bool Tokenizer::tokenize(std::istream &code,
|
||||||
list.createAst();
|
list.createAst();
|
||||||
|
|
||||||
if (_settings->valueFlow)
|
if (_settings->valueFlow)
|
||||||
ValueFlow::setValues(list.front());
|
ValueFlow::setValues(&list, _errorLogger, _settings);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -7531,23 +7532,23 @@ bool Tokenizer::duplicateDefinition(Token ** tokPtr, const Token * name) const
|
||||||
|
|
||||||
class EnumValue {
|
class EnumValue {
|
||||||
public:
|
public:
|
||||||
EnumValue() {
|
EnumValue() :
|
||||||
name = 0;
|
name(NULL),
|
||||||
value = 0;
|
value(NULL),
|
||||||
start = 0;
|
start(NULL),
|
||||||
end = 0;
|
end(NULL) {
|
||||||
}
|
}
|
||||||
EnumValue(const EnumValue &ev) {
|
EnumValue(const EnumValue &ev) :
|
||||||
name = ev.name;
|
name(ev.name),
|
||||||
value = ev.value;
|
value(ev.value),
|
||||||
start = ev.start;
|
start(ev.start),
|
||||||
end = ev.end;
|
end(ev.end) {
|
||||||
}
|
}
|
||||||
EnumValue(Token *name_, Token *value_, Token *start_, Token *end_) {
|
EnumValue(Token *name_, Token *value_, Token *start_, Token *end_) :
|
||||||
name = name_;
|
name(name_),
|
||||||
value = value_;
|
value(value_),
|
||||||
start = start_;
|
start(start_),
|
||||||
end = end_;
|
end(end_) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void simplify(const std::map<std::string, EnumValue> &enumValues) {
|
void simplify(const std::map<std::string, EnumValue> &enumValues) {
|
||||||
|
|
|
@ -17,20 +17,47 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "valueflow.h"
|
#include "valueflow.h"
|
||||||
#include "token.h"
|
#include "errorlogger.h"
|
||||||
#include "mathlib.h"
|
#include "mathlib.h"
|
||||||
|
#include "settings.h"
|
||||||
|
#include "symboldatabase.h"
|
||||||
|
#include "token.h"
|
||||||
|
#include "tokenlist.h"
|
||||||
|
|
||||||
static void valueFlowBeforeCondition(Token *tokens)
|
#include <iostream>
|
||||||
|
|
||||||
|
|
||||||
|
static void printvalues(const Token *tok)
|
||||||
{
|
{
|
||||||
for (Token *tok = tokens; tok; tok = tok->next()) {
|
if (tok->values.empty())
|
||||||
|
std::cout << "empty";
|
||||||
|
for (std::list<ValueFlow::Value>::const_iterator it = tok->values.begin(); it != tok->values.end(); ++it)
|
||||||
|
std::cout << " " << (it->intvalue);
|
||||||
|
std::cout << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void bailout(TokenList *tokenlist, ErrorLogger *errorLogger, const Token *tok, const std::string &what)
|
||||||
|
{
|
||||||
|
std::list<ErrorLogger::ErrorMessage::FileLocation> callstack;
|
||||||
|
callstack.push_back(ErrorLogger::ErrorMessage::FileLocation(tok,tokenlist));
|
||||||
|
ErrorLogger::ErrorMessage errmsg(callstack, Severity::debug, "ValueFlow bailout: " + what, "valueFlowBailout", false);
|
||||||
|
errorLogger->reportErr(errmsg);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void valueFlowBeforeCondition(TokenList *tokenlist, ErrorLogger *errorLogger, const Settings *settings)
|
||||||
|
{
|
||||||
|
for (Token *tok = tokenlist->front(); tok; tok = tok->next()) {
|
||||||
unsigned int varid;
|
unsigned int varid;
|
||||||
MathLib::bigint num;
|
MathLib::bigint num;
|
||||||
|
const Variable *var;
|
||||||
if (Token::Match(tok, "==|!=|>=|<=") && tok->astOperand1() && tok->astOperand2()) {
|
if (Token::Match(tok, "==|!=|>=|<=") && tok->astOperand1() && tok->astOperand2()) {
|
||||||
if (tok->astOperand1()->isName() && tok->astOperand2()->isNumber()) {
|
if (tok->astOperand1()->isName() && tok->astOperand2()->isNumber()) {
|
||||||
varid = tok->astOperand1()->varId();
|
varid = tok->astOperand1()->varId();
|
||||||
|
var = tok->astOperand1()->variable();
|
||||||
num = MathLib::toLongNumber(tok->astOperand2()->str());
|
num = MathLib::toLongNumber(tok->astOperand2()->str());
|
||||||
} else if (tok->astOperand1()->isNumber() && tok->astOperand2()->isName()) {
|
} else if (tok->astOperand1()->isNumber() && tok->astOperand2()->isName()) {
|
||||||
varid = tok->astOperand2()->varId();
|
varid = tok->astOperand2()->varId();
|
||||||
|
var = tok->astOperand2()->variable();
|
||||||
num = MathLib::toLongNumber(tok->astOperand1()->str());
|
num = MathLib::toLongNumber(tok->astOperand1()->str());
|
||||||
} else {
|
} else {
|
||||||
continue;
|
continue;
|
||||||
|
@ -38,9 +65,11 @@ static void valueFlowBeforeCondition(Token *tokens)
|
||||||
} else if (Token::Match(tok->previous(), "if|while ( %var% %oror%|&&|)") ||
|
} else if (Token::Match(tok->previous(), "if|while ( %var% %oror%|&&|)") ||
|
||||||
Token::Match(tok, "%oror%|&& %var% %oror%|&&|)")) {
|
Token::Match(tok, "%oror%|&& %var% %oror%|&&|)")) {
|
||||||
varid = tok->next()->varId();
|
varid = tok->next()->varId();
|
||||||
|
var = tok->next()->variable();
|
||||||
num = 0;
|
num = 0;
|
||||||
} else if (tok->str() == "!" && tok->astOperand1() && tok->astOperand1()->isName()) {
|
} else if (tok->str() == "!" && tok->astOperand1() && tok->astOperand1()->isName()) {
|
||||||
varid = tok->astOperand1()->varId();
|
varid = tok->astOperand1()->varId();
|
||||||
|
var = tok->astOperand1()->variable();
|
||||||
num = 0;
|
num = 0;
|
||||||
} else {
|
} else {
|
||||||
continue;
|
continue;
|
||||||
|
@ -49,27 +78,112 @@ static void valueFlowBeforeCondition(Token *tokens)
|
||||||
if (varid == 0U)
|
if (varid == 0U)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
// bailout: global variables
|
||||||
|
if (var && var->isGlobal()) {
|
||||||
|
if (settings->debugwarnings)
|
||||||
|
bailout(tokenlist, errorLogger, tok, "global variable " + var->nameToken()->str());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
struct ValueFlow::Value val;
|
struct ValueFlow::Value val;
|
||||||
val.link = tok;
|
val.condition = tok;
|
||||||
val.intvalue = num;
|
val.intvalue = num;
|
||||||
|
|
||||||
for (Token *tok2 = tok->previous(); tok2; tok2 = tok2->previous()) {
|
for (Token *tok2 = tok->previous(); ; tok2 = tok2->previous()) {
|
||||||
if (tok2->varId() == varid)
|
if (!tok2) {
|
||||||
|
if (settings->debugwarnings) {
|
||||||
|
std::list<ErrorLogger::ErrorMessage::FileLocation> callstack;
|
||||||
|
callstack.push_back(ErrorLogger::ErrorMessage::FileLocation(tok,tokenlist));
|
||||||
|
ErrorLogger::ErrorMessage errmsg(callstack, Severity::debug, "iterated too far", "debugValueFlowBeforeCondition", false);
|
||||||
|
errorLogger->reportErr(errmsg);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tok2->varId() == varid) {
|
||||||
|
// bailout: assignment
|
||||||
|
if (Token::Match(tok2, "%var% =")) {
|
||||||
|
if (settings->debugwarnings)
|
||||||
|
bailout(tokenlist, errorLogger, tok2, "assignment of " + tok2->str());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
tok2->values.push_back(val);
|
tok2->values.push_back(val);
|
||||||
if (tok2->str() == "{") {
|
if (var && tok2 == var->nameToken())
|
||||||
if (!Token::simpleMatch(tok2->previous(), ") {"))
|
|
||||||
break;
|
|
||||||
if (!Token::simpleMatch(tok2->previous()->link()->previous(), "if ("))
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (tok2->str() == "}") {
|
||||||
|
if (settings->debugwarnings)
|
||||||
|
bailout(tokenlist, errorLogger, tok2, "variable " + var->nameToken()->str() + " stopping on }");
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ValueFlow::setValues(Token *tokens)
|
static void valueFlowSubFunction(TokenList *tokenlist, ErrorLogger *errorLogger, const Settings *settings)
|
||||||
{
|
{
|
||||||
for (Token *tok = tokens; tok; tok = tok->next())
|
std::list<ValueFlow::Value> argvalues;
|
||||||
|
for (Token *tok = tokenlist->front(); tok; tok = tok->next()) {
|
||||||
|
if (Token::Match(tok, "[(,] %var% [,)]") && !tok->next()->values.empty())
|
||||||
|
argvalues = tok->next()->values;
|
||||||
|
else if (Token::Match(tok, "[(,] %num% [,)]")) {
|
||||||
|
ValueFlow::Value val;
|
||||||
|
val.condition = 0;
|
||||||
|
val.intvalue = MathLib::toLongNumber(tok->next()->str());
|
||||||
|
argvalues.clear();
|
||||||
|
argvalues.push_back(val);
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Token * const argumentToken = tok->next();
|
||||||
|
|
||||||
|
// is this a function call?
|
||||||
|
const Token *ftok = tok;
|
||||||
|
while (ftok && ftok->str() != "(")
|
||||||
|
ftok = ftok->astParent();
|
||||||
|
if (!ftok || !ftok->astOperand1() || !ftok->astOperand2() || !ftok->astOperand1()->function())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Get argument nr
|
||||||
|
unsigned int argnr = 0;
|
||||||
|
for (const Token *argtok = ftok->next(); argtok && argtok != argumentToken; argtok = argtok->nextArgument())
|
||||||
|
++ argnr;
|
||||||
|
|
||||||
|
// Get function argument, and check if parameter is passed by value
|
||||||
|
const Function * const function = ftok->astOperand1()->function();
|
||||||
|
const Variable * const arg = function ? function->getArgumentVar(argnr) : NULL;
|
||||||
|
if (!Token::Match(arg ? arg->typeStartToken() : NULL, "const| %type% %var% ,|)"))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Function scope..
|
||||||
|
const Scope * const functionScope = function ? function->functionScope : NULL;
|
||||||
|
if (!functionScope)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Set value in function scope..
|
||||||
|
const unsigned int varid2 = arg->nameToken()->varId();
|
||||||
|
for (const Token *tok2 = functionScope->classStart->next(); tok2 != functionScope->classEnd; tok2 = tok2->next()) {
|
||||||
|
if (Token::Match(tok2, "%cop%|return %varid%", varid2)) {
|
||||||
|
tok2 = tok2->next();
|
||||||
|
std::list<ValueFlow::Value> &values = const_cast<Token*>(tok2)->values;
|
||||||
|
values.insert(values.begin(), argvalues.begin(), argvalues.end());
|
||||||
|
} else if (tok2->varId() == varid2 || tok2->str() == "{") {
|
||||||
|
if (settings->debugwarnings)
|
||||||
|
bailout(tokenlist, errorLogger, tok2, "parameter " + arg->nameToken()->str());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ValueFlow::setValues(TokenList *tokenlist, ErrorLogger *errorLogger, const Settings *settings)
|
||||||
|
{
|
||||||
|
for (Token *tok = tokenlist->front(); tok; tok = tok->next())
|
||||||
tok->values.clear();
|
tok->values.clear();
|
||||||
|
|
||||||
valueFlowBeforeCondition(tokens);
|
valueFlowBeforeCondition(tokenlist, errorLogger, settings);
|
||||||
|
valueFlowSubFunction(tokenlist, errorLogger, settings);
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,15 +22,17 @@
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
class Token;
|
class Token;
|
||||||
|
class TokenList;
|
||||||
|
class ErrorLogger;
|
||||||
|
class Settings;
|
||||||
|
|
||||||
namespace ValueFlow {
|
namespace ValueFlow {
|
||||||
|
|
||||||
struct Value {
|
struct Value {
|
||||||
const Token *link;
|
const Token *condition;
|
||||||
long long intvalue;
|
long long intvalue;
|
||||||
};
|
};
|
||||||
|
|
||||||
void setValues(Token *tokens);
|
void setValues(TokenList *tokenlist, ErrorLogger *errorLogger, const Settings *settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // valueflowH
|
#endif // valueflowH
|
||||||
|
|
|
@ -40,6 +40,7 @@ private:
|
||||||
TEST_CASE(unknownPattern)
|
TEST_CASE(unknownPattern)
|
||||||
TEST_CASE(redundantNextPrevious)
|
TEST_CASE(redundantNextPrevious)
|
||||||
TEST_CASE(internalError)
|
TEST_CASE(internalError)
|
||||||
|
TEST_CASE(invalidMultiCompare);
|
||||||
}
|
}
|
||||||
|
|
||||||
void check(const char code[]) {
|
void check(const char code[]) {
|
||||||
|
@ -222,7 +223,9 @@ private:
|
||||||
" const Token *tok;\n"
|
" const Token *tok;\n"
|
||||||
" Token::Match(tok, \"foo|%type|bar\");\n"
|
" Token::Match(tok, \"foo|%type|bar\");\n"
|
||||||
"}");
|
"}");
|
||||||
ASSERT_EQUALS("[test.cpp:3]: (error) Missing percent end character in Token::Match() pattern: \"foo|%type|bar\"\n", errout.str());
|
ASSERT_EQUALS("[test.cpp:3]: (error) Bad multicompare pattern (a %cmd% must be first unless it is %or%,%op%,%cop%,%var%,%oror%) inside Token::Match() call: \"foo|%type|bar\"\n"
|
||||||
|
"[test.cpp:3]: (error) Missing percent end character in Token::Match() pattern: \"foo|%type|bar\"\n"
|
||||||
|
, errout.str());
|
||||||
|
|
||||||
// Make sure we don't take %or% for a broken %oror%
|
// Make sure we don't take %or% for a broken %oror%
|
||||||
check("void f() {\n"
|
check("void f() {\n"
|
||||||
|
@ -312,6 +315,27 @@ private:
|
||||||
"};");
|
"};");
|
||||||
ASSERT_EQUALS("", errout.str());
|
ASSERT_EQUALS("", errout.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void invalidMultiCompare() {
|
||||||
|
// #5310
|
||||||
|
check("void f() {\n"
|
||||||
|
" const Token *tok;\n"
|
||||||
|
" Token::Match(tok, \";|%type%\");\n"
|
||||||
|
"}");
|
||||||
|
ASSERT_EQUALS("[test.cpp:3]: (error) Bad multicompare pattern (a %cmd% must be first unless it is %or%,%op%,%cop%,%var%,%oror%) inside Token::Match() call: \";|%type%\"\n", errout.str());
|
||||||
|
|
||||||
|
check("void f() {\n"
|
||||||
|
" const Token *tok;\n"
|
||||||
|
" Token::Match(tok, \";|%oror%\");\n"
|
||||||
|
"}");
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
|
||||||
|
check("void f() {\n" // The %var%|%num% works..
|
||||||
|
" const Token *tok;\n"
|
||||||
|
" Token::Match(tok, \"%var%|%num%\");\n"
|
||||||
|
"}");
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
REGISTER_TEST(TestInternal)
|
REGISTER_TEST(TestInternal)
|
||||||
|
|
|
@ -135,6 +135,7 @@ private:
|
||||||
TEST_CASE(template40); // #5055 - template specialization outside struct
|
TEST_CASE(template40); // #5055 - template specialization outside struct
|
||||||
TEST_CASE(template41); // #4710 - const in instantiation not handled perfectly
|
TEST_CASE(template41); // #4710 - const in instantiation not handled perfectly
|
||||||
TEST_CASE(template42); // #4878 - variadic templates
|
TEST_CASE(template42); // #4878 - variadic templates
|
||||||
|
TEST_CASE(template43); // #5097 - assert due to '>>' not treated as end of template instantiation
|
||||||
TEST_CASE(template_unhandled);
|
TEST_CASE(template_unhandled);
|
||||||
TEST_CASE(template_default_parameter);
|
TEST_CASE(template_default_parameter);
|
||||||
TEST_CASE(template_default_type);
|
TEST_CASE(template_default_type);
|
||||||
|
@ -2367,6 +2368,19 @@ private:
|
||||||
tok(code);
|
tok(code);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void template43() { // #5097 - Assert due to '>>' in 'B<A<C>>' not being treated as end of template instantation
|
||||||
|
const char code[] = "template <typename T> struct C { };"
|
||||||
|
"template <typename T> struct D { static int f() { return C<T>::f(); } };"
|
||||||
|
"template <typename T> inline int f2() { return D<T>::f(); }"
|
||||||
|
"template <typename T> int f1(int x, T *) { int id = f2<T>(); return id; }"
|
||||||
|
"template <> struct C < B < A >> {"
|
||||||
|
" static int f() {"
|
||||||
|
" return f1 < B < A >> (0, reinterpret_cast< B<A> *>(E<void *>::Int(-1)));"
|
||||||
|
" }"
|
||||||
|
"};";
|
||||||
|
tok(code); // Don't assert
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void template_default_parameter() {
|
void template_default_parameter() {
|
||||||
{
|
{
|
||||||
|
|
|
@ -1760,6 +1760,19 @@ private:
|
||||||
"};");
|
"};");
|
||||||
ASSERT(db && db->findScopeByName("Deri") && db->findScopeByName("Deri")->functionList.front().isImplicitlyVirtual(false)); // Default false, but we saw "virtual" -> true
|
ASSERT(db && db->findScopeByName("Deri") && db->findScopeByName("Deri")->functionList.front().isImplicitlyVirtual(false)); // Default false, but we saw "virtual" -> true
|
||||||
}
|
}
|
||||||
|
// #5289
|
||||||
|
{
|
||||||
|
GET_SYMBOL_DB("template<>\n"
|
||||||
|
"class Bar<void, void> {\n"
|
||||||
|
"};\n"
|
||||||
|
"template<typename K, typename V, int KeySize>\n"
|
||||||
|
"class Bar : private Bar<void, void> {\n"
|
||||||
|
" void foo() {\n"
|
||||||
|
" }\n"
|
||||||
|
"};");
|
||||||
|
ASSERT(db && db->findScopeByName("Bar") && !db->findScopeByName("Bar")->functionList.front().isImplicitlyVirtual(false));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void garbage() {
|
void garbage() {
|
||||||
|
|
|
@ -34,7 +34,8 @@ public:
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void run() {
|
void run() {
|
||||||
valueFlowBeforeCondition();
|
TEST_CASE(valueFlowBeforeCondition);
|
||||||
|
TEST_CASE(valueFlowSubFunction);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool testValueOfX(const char code[], unsigned int linenr, int value) {
|
bool testValueOfX(const char code[], unsigned int linenr, int value) {
|
||||||
|
@ -53,19 +54,71 @@ private:
|
||||||
if (it->intvalue == value)
|
if (it->intvalue == value)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void bailout(const char code[]) {
|
||||||
|
Settings settings;
|
||||||
|
settings.valueFlow = true; // temporary flag
|
||||||
|
settings.debugwarnings = true;
|
||||||
|
|
||||||
|
// Tokenize..
|
||||||
|
Tokenizer tokenizer(&settings, this);
|
||||||
|
std::istringstream istr(code);
|
||||||
|
errout.str("");
|
||||||
|
tokenizer.tokenize(istr, "test.cpp");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void valueFlowBeforeCondition() {
|
void valueFlowBeforeCondition() {
|
||||||
const char code[] = "void f(int x) {\n"
|
const char code[] = "void f(int x) {\n"
|
||||||
" int a = x;\n"
|
" int a = x;\n"
|
||||||
" if (x == 123) {}\n"
|
" if (x == 123) {}\n"
|
||||||
"}";
|
"}";
|
||||||
ASSERT_EQUALS(true, testValueOfX(code, 2U, 123));
|
ASSERT_EQUALS(true, testValueOfX(code, 2U, 123));
|
||||||
|
|
||||||
|
// bailout: if/else/etc
|
||||||
|
bailout("void f(int x) {\n"
|
||||||
|
" if (x != 123) { b = x; }\n"
|
||||||
|
" if (x == 123) {}\n"
|
||||||
|
"}");
|
||||||
|
ASSERT_EQUALS("[test.cpp:2]: (debug) ValueFlow bailout: variable x stopping on }\n", errout.str());
|
||||||
|
|
||||||
|
// bailout: assignment
|
||||||
|
bailout("void f(int x) {\n"
|
||||||
|
" x = y;\n"
|
||||||
|
" if (x == 123) {}\n"
|
||||||
|
"}");
|
||||||
|
ASSERT_EQUALS("[test.cpp:2]: (debug) ValueFlow bailout: assignment of x\n", errout.str());
|
||||||
|
|
||||||
|
// bailout: global variables
|
||||||
|
bailout("int x;\n"
|
||||||
|
"void f() {\n"
|
||||||
|
" int a = x;\n"
|
||||||
|
" if (x == 123) {}\n"
|
||||||
|
"}");
|
||||||
|
ASSERT_EQUALS("[test.cpp:4]: (debug) ValueFlow bailout: global variable x\n", errout.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
void valueFlowSubFunction() {
|
||||||
|
const char *code;
|
||||||
|
|
||||||
|
code = "void f1(int x) { return x; }\n"
|
||||||
|
"void f2(int x) {\n"
|
||||||
|
" f1(123);\n"
|
||||||
|
"}";
|
||||||
|
ASSERT_EQUALS(true, testValueOfX(code, 1U, 123));
|
||||||
|
|
||||||
|
code = "void f1(int x) { return x; }\n"
|
||||||
|
"void f2(int x) {\n"
|
||||||
|
" f1(x);\n"
|
||||||
|
" if (x==0){}\n"
|
||||||
|
"}";
|
||||||
|
ASSERT_EQUALS(true, testValueOfX(code, 1U, 0));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -31,13 +31,6 @@ def readdate(data):
|
||||||
return None
|
return None
|
||||||
datepos = datepos + 1
|
datepos = datepos + 1
|
||||||
|
|
||||||
if os.path.isfile(os.path.expanduser('~/aws-debian.pem')):
|
|
||||||
subprocess.call(['scp',
|
|
||||||
'-i',
|
|
||||||
os.path.expanduser('~/aws-debian.pem'),
|
|
||||||
'admin@ec2-54-201-59-232.us-west-2.compute.amazonaws.com:daca2/results-*.txt',
|
|
||||||
os.path.expanduser('~/daca2/')])
|
|
||||||
|
|
||||||
path = '.'
|
path = '.'
|
||||||
if len(sys.argv) == 2:
|
if len(sys.argv) == 2:
|
||||||
path = sys.argv[1]
|
path = sys.argv[1]
|
||||||
|
|
Loading…
Reference in New Issue