CLI: Added --environment flag

This commit is contained in:
Daniel Marjamäki 2013-07-02 07:18:19 +02:00
parent 1a35241aa2
commit d96fb577cd
10 changed files with 224 additions and 158 deletions

View File

@ -75,7 +75,7 @@ ifndef PREFIX
endif endif
ifndef INCLUDE_FOR_LIB ifndef INCLUDE_FOR_LIB
INCLUDE_FOR_LIB=-Ilib INCLUDE_FOR_LIB=-Ilib -Iexternals -Iexternals/tinyxml
endif endif
ifndef INCLUDE_FOR_CLI ifndef INCLUDE_FOR_CLI
@ -120,6 +120,7 @@ LIBOBJ = $(SRCDIR)/check64bit.o \
$(SRCDIR)/checkunusedfunctions.o \ $(SRCDIR)/checkunusedfunctions.o \
$(SRCDIR)/checkunusedvar.o \ $(SRCDIR)/checkunusedvar.o \
$(SRCDIR)/cppcheck.o \ $(SRCDIR)/cppcheck.o \
$(SRCDIR)/environment.o \
$(SRCDIR)/errorlogger.o \ $(SRCDIR)/errorlogger.o \
$(SRCDIR)/executionpath.o \ $(SRCDIR)/executionpath.o \
$(SRCDIR)/mathlib.o \ $(SRCDIR)/mathlib.o \
@ -285,7 +286,7 @@ $(SRCDIR)/checknullpointer.o: lib/checknullpointer.cpp lib/checknullpointer.h li
$(SRCDIR)/checkobsoletefunctions.o: lib/checkobsoletefunctions.cpp lib/checkobsoletefunctions.h lib/config.h lib/check.h lib/token.h lib/tokenize.h lib/errorlogger.h lib/suppressions.h lib/tokenlist.h lib/settings.h lib/standards.h lib/symboldatabase.h lib/mathlib.h $(SRCDIR)/checkobsoletefunctions.o: lib/checkobsoletefunctions.cpp lib/checkobsoletefunctions.h lib/config.h lib/check.h lib/token.h lib/tokenize.h lib/errorlogger.h lib/suppressions.h lib/tokenlist.h lib/settings.h lib/standards.h lib/symboldatabase.h lib/mathlib.h
$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $(SRCDIR)/checkobsoletefunctions.o $(SRCDIR)/checkobsoletefunctions.cpp $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $(SRCDIR)/checkobsoletefunctions.o $(SRCDIR)/checkobsoletefunctions.cpp
$(SRCDIR)/checkother.o: lib/checkother.cpp lib/checkother.h lib/config.h lib/check.h lib/token.h lib/tokenize.h lib/errorlogger.h lib/suppressions.h lib/tokenlist.h lib/settings.h lib/standards.h lib/mathlib.h lib/symboldatabase.h $(SRCDIR)/checkother.o: lib/checkother.cpp lib/checkother.h lib/config.h lib/check.h lib/token.h lib/tokenize.h lib/errorlogger.h lib/suppressions.h lib/tokenlist.h lib/settings.h lib/standards.h lib/mathlib.h lib/symboldatabase.h lib/templatesimplifier.h
$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $(SRCDIR)/checkother.o $(SRCDIR)/checkother.cpp $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $(SRCDIR)/checkother.o $(SRCDIR)/checkother.cpp
$(SRCDIR)/checkpostfixoperator.o: lib/checkpostfixoperator.cpp lib/checkpostfixoperator.h lib/config.h lib/check.h lib/token.h lib/tokenize.h lib/errorlogger.h lib/suppressions.h lib/tokenlist.h lib/settings.h lib/standards.h lib/symboldatabase.h lib/mathlib.h $(SRCDIR)/checkpostfixoperator.o: lib/checkpostfixoperator.cpp lib/checkpostfixoperator.h lib/config.h lib/check.h lib/token.h lib/tokenize.h lib/errorlogger.h lib/suppressions.h lib/tokenlist.h lib/settings.h lib/standards.h lib/symboldatabase.h lib/mathlib.h
@ -309,6 +310,9 @@ $(SRCDIR)/checkunusedvar.o: lib/checkunusedvar.cpp lib/checkunusedvar.h lib/conf
$(SRCDIR)/cppcheck.o: lib/cppcheck.cpp lib/cppcheck.h lib/config.h lib/settings.h lib/suppressions.h lib/standards.h lib/errorlogger.h lib/checkunusedfunctions.h lib/check.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/preprocessor.h lib/path.h lib/timer.h $(SRCDIR)/cppcheck.o: lib/cppcheck.cpp lib/cppcheck.h lib/config.h lib/settings.h lib/suppressions.h lib/standards.h lib/errorlogger.h lib/checkunusedfunctions.h lib/check.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/preprocessor.h lib/path.h lib/timer.h
$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $(SRCDIR)/cppcheck.o $(SRCDIR)/cppcheck.cpp $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $(SRCDIR)/cppcheck.o $(SRCDIR)/cppcheck.cpp
$(SRCDIR)/environment.o: lib/environment.cpp lib/environment.h
$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $(SRCDIR)/environment.o $(SRCDIR)/environment.cpp
$(SRCDIR)/errorlogger.o: lib/errorlogger.cpp lib/errorlogger.h lib/config.h lib/suppressions.h lib/path.h lib/cppcheck.h lib/settings.h lib/standards.h lib/checkunusedfunctions.h lib/check.h lib/token.h lib/tokenize.h lib/tokenlist.h $(SRCDIR)/errorlogger.o: lib/errorlogger.cpp lib/errorlogger.h lib/config.h lib/suppressions.h lib/path.h lib/cppcheck.h lib/settings.h lib/standards.h lib/checkunusedfunctions.h lib/check.h lib/token.h lib/tokenize.h lib/tokenlist.h
$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $(SRCDIR)/errorlogger.o $(SRCDIR)/errorlogger.cpp $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $(SRCDIR)/errorlogger.o $(SRCDIR)/errorlogger.cpp

View File

@ -328,6 +328,14 @@ bool CmdLineParser::ParseFromArgs(int argc, const char* const argv[])
} }
} }
// --environment
else if (std::strncmp(argv[i], "--environment=", 14) == 0) {
if (!_settings->environment.load(argv[i]+14)) {
PrintMessage("cppcheck: Failed to load environment file '" + std::string(argv[i]+14) + "'");
return false;
}
}
// --error-exitcode=1 // --error-exitcode=1
else if (std::strncmp(argv[i], "--error-exitcode=", 17) == 0) { else if (std::strncmp(argv[i], "--error-exitcode=", 17) == 0) {
std::string temp = argv[i]+17; std::string temp = argv[i]+17;

View File

@ -33,6 +33,9 @@
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
const int DEALLOC = -1;
const int NOALLOC = 0;
// Register this check class (by creating a static instance of it) // Register this check class (by creating a static instance of it)
namespace { namespace {
CheckLeakAutoVar instance; CheckLeakAutoVar instance;
@ -43,7 +46,7 @@ namespace {
void VarInfo::print() void VarInfo::print()
{ {
std::cout << "size=" << alloctype.size() << std::endl; std::cout << "size=" << alloctype.size() << std::endl;
std::map<unsigned int, std::string>::const_iterator it; std::map<unsigned int, int>::const_iterator it;
for (it = alloctype.begin(); it != alloctype.end(); ++it) { for (it = alloctype.begin(); it != alloctype.end(); ++it) {
std::string strusage; std::string strusage;
std::map<unsigned int, std::string>::const_iterator use = possibleUsage.find(it->first); std::map<unsigned int, std::string>::const_iterator use = possibleUsage.find(it->first);
@ -58,20 +61,19 @@ void VarInfo::print()
void VarInfo::possibleUsageAll(const std::string &functionName) void VarInfo::possibleUsageAll(const std::string &functionName)
{ {
possibleUsage.clear(); possibleUsage.clear();
std::map<unsigned int, std::string>::const_iterator it; std::map<unsigned int, int>::const_iterator it;
for (it = alloctype.begin(); it != alloctype.end(); ++it) for (it = alloctype.begin(); it != alloctype.end(); ++it)
possibleUsage[it->first] = functionName; possibleUsage[it->first] = functionName;
} }
void CheckLeakAutoVar::leakError(const Token *tok, const std::string &varname, const std::string &type) void CheckLeakAutoVar::leakError(const Token *tok, const std::string &varname, int type)
{ {
const CheckMemoryLeak checkmemleak(_tokenizer, _errorLogger, _settings->standards); const CheckMemoryLeak checkmemleak(_tokenizer, _errorLogger, _settings->standards);
if (type == "fopen") if (_settings->environment.isresource(type))
checkmemleak.resourceLeakError(tok, varname); checkmemleak.resourceLeakError(tok, varname);
else else
checkmemleak.memleakError(tok, varname); checkmemleak.memleakError(tok, varname);
//reportError(tok, Severity::error, "newleak", "New memory leak: " + varname);
} }
void CheckLeakAutoVar::mismatchError(const Token *tok, const std::string &varname) void CheckLeakAutoVar::mismatchError(const Token *tok, const std::string &varname)
@ -79,14 +81,12 @@ void CheckLeakAutoVar::mismatchError(const Token *tok, const std::string &varnam
const CheckMemoryLeak c(_tokenizer, _errorLogger, _settings->standards); const CheckMemoryLeak c(_tokenizer, _errorLogger, _settings->standards);
std::list<const Token *> callstack(1, tok); std::list<const Token *> callstack(1, tok);
c.mismatchAllocDealloc(callstack, varname); c.mismatchAllocDealloc(callstack, varname);
//reportError(tok, Severity::error, "newmismatch", "New mismatching allocation and deallocation: " + varname);
} }
void CheckLeakAutoVar::deallocUseError(const Token *tok, const std::string &varname) void CheckLeakAutoVar::deallocUseError(const Token *tok, const std::string &varname)
{ {
const CheckMemoryLeak c(_tokenizer, _errorLogger, _settings->standards); const CheckMemoryLeak c(_tokenizer, _errorLogger, _settings->standards);
c.deallocuseError(tok, varname); c.deallocuseError(tok, varname);
//reportError(tok, Severity::error, "newdeallocuse", "Using deallocated pointer " + varname);
} }
void CheckLeakAutoVar::deallocReturnError(const Token *tok, const std::string &varname) void CheckLeakAutoVar::deallocReturnError(const Token *tok, const std::string &varname)
@ -96,7 +96,7 @@ void CheckLeakAutoVar::deallocReturnError(const Token *tok, const std::string &v
void CheckLeakAutoVar::configurationInfo(const Token* tok, const std::string &functionName) void CheckLeakAutoVar::configurationInfo(const Token* tok, const std::string &functionName)
{ {
if (((!cfgalloc.empty() || !cfgdealloc.empty()) && _settings->isEnabled("information")) || _settings->experimental) { if (_settings->isEnabled("information") && _settings->experimental) {
reportError(tok, reportError(tok,
Severity::information, Severity::information,
"leakconfiguration", "leakconfiguration",
@ -104,81 +104,6 @@ void CheckLeakAutoVar::configurationInfo(const Token* tok, const std::string &fu
} }
} }
void CheckLeakAutoVar::parseConfigurationFile(const std::string &filename)
{
std::ifstream fin(filename.c_str());
if (!fin.is_open())
return;
std::string line;
while (std::getline(fin,line)) {
if (line.compare(0,4,"MEM ",0,4) == 0) {
std::string f1;
enum {ALLOC, DEALLOC} type = ALLOC;
std::string::size_type pos1 = line.find_first_not_of(" ", 4U);
while (pos1 < line.size()) {
const std::string::size_type pos2 = line.find(" ", pos1);
std::string f;
if (pos2 == std::string::npos)
f = line.substr(pos1);
else
f = line.substr(pos1, pos2-pos1);
if (f1.empty())
f1 = f;
if (f == ":")
type = DEALLOC;
else if (type == ALLOC)
cfgalloc[f] = f1;
else if (type == DEALLOC)
cfgdealloc[f] = f1;
pos1 = line.find_first_not_of(" ", pos2);
}
}
else if (line.compare(0,7,"IGNORE ",0,7) == 0) {
std::string::size_type pos1 = line.find_first_not_of(" ", 7U);
while (pos1 < line.size()) {
std::string::size_type pos2 = line.find_first_of(" ", pos1);
std::string functionName;
if (pos2 == std::string::npos)
functionName = line.substr(pos1);
else
functionName = line.substr(pos1, pos2-pos1);
cfgignore.insert(functionName);
pos1 = line.find_first_not_of(" ", pos2);
}
}
else if (line.compare(0,4,"USE ",0,4) == 0) {
std::string::size_type pos1 = line.find_first_not_of(" ", 4U);
while (pos1 < line.size()) {
std::string::size_type pos2 = line.find_first_of(" ", pos1);
std::string functionName;
if (pos2 == std::string::npos)
functionName = line.substr(pos1);
else
functionName = line.substr(pos1, pos2-pos1);
cfguse.insert(functionName);
pos1 = line.find_first_not_of(" ", pos2);
}
}
else if (line.compare(0,9,"NORETURN ",0,9) == 0) {
std::string::size_type pos1 = line.find_first_not_of(" ", 9U);
while (pos1 < line.size()) {
std::string::size_type pos2 = line.find_first_of(" ", pos1);
std::string functionName;
if (pos2 == std::string::npos)
functionName = line.substr(pos1);
else
functionName = line.substr(pos1, pos2-pos1);
cfgnoreturn.insert(functionName);
pos1 = line.find_first_not_of(" ", pos2);
}
}
}
}
void CheckLeakAutoVar::check() void CheckLeakAutoVar::check()
{ {
const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase(); const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase();
@ -198,7 +123,7 @@ void CheckLeakAutoVar::check()
varInfo.conditionalAlloc.clear(); varInfo.conditionalAlloc.clear();
// Clear reference arguments from varInfo.. // Clear reference arguments from varInfo..
std::map<unsigned int, std::string>::iterator it = varInfo.alloctype.begin(); std::map<unsigned int, int>::iterator it = varInfo.alloctype.begin();
while (it != varInfo.alloctype.end()) { while (it != varInfo.alloctype.end()) {
const Variable *var = symbolDatabase->getVariableFromVarId(it->first); const Variable *var = symbolDatabase->getVariableFromVarId(it->first);
if (!var || if (!var ||
@ -217,29 +142,18 @@ void CheckLeakAutoVar::checkScope(const Token * const startToken,
VarInfo *varInfo, VarInfo *varInfo,
std::set<unsigned int> notzero) std::set<unsigned int> notzero)
{ {
std::map<unsigned int, std::string> &alloctype = varInfo->alloctype; std::map<unsigned int, int> &alloctype = varInfo->alloctype;
std::map<unsigned int, std::string> &possibleUsage = varInfo->possibleUsage; std::map<unsigned int, std::string> &possibleUsage = varInfo->possibleUsage;
const std::set<unsigned int> conditionalAlloc(varInfo->conditionalAlloc); const std::set<unsigned int> conditionalAlloc(varInfo->conditionalAlloc);
// Allocation functions. key = function name, value = allocation type
std::map<std::string, std::string> allocFunctions(cfgalloc);
allocFunctions["malloc"] = "malloc";
allocFunctions["strdup"] = "malloc";
allocFunctions["fopen"] = "fopen";
// Deallocation functions. key = function name, value = allocation type
std::map<std::string, std::string> deallocFunctions(cfgdealloc);
deallocFunctions["free"] = "malloc";
deallocFunctions["fclose"] = "fopen";
// Parse all tokens // Parse all tokens
const Token * const endToken = startToken->link(); const Token * const endToken = startToken->link();
for (const Token *tok = startToken; tok && tok != endToken; tok = tok->next()) { for (const Token *tok = startToken; tok && tok != endToken; tok = tok->next()) {
// Deallocation and then dereferencing pointer.. // Deallocation and then dereferencing pointer..
if (tok->varId() > 0) { if (tok->varId() > 0) {
const std::map<unsigned int, std::string>::iterator var = alloctype.find(tok->varId()); const std::map<unsigned int, int>::iterator var = alloctype.find(tok->varId());
if (var != alloctype.end()) { if (var != alloctype.end()) {
if (var->second == "dealloc" && !Token::Match(tok->previous(), "[;{},=] %var% =")) { if (var->second == DEALLOC && !Token::Match(tok->previous(), "[;{},=] %var% =")) {
deallocUseError(tok, tok->str()); deallocUseError(tok, tok->str());
} else if (Token::simpleMatch(tok->tokAt(-2), "= &")) { } else if (Token::simpleMatch(tok->tokAt(-2), "= &")) {
varInfo->erase(tok->varId()); varInfo->erase(tok->varId());
@ -252,7 +166,7 @@ void CheckLeakAutoVar::checkScope(const Token * const startToken,
} }
if (tok->str() == "(" && tok->previous()->isName()) { if (tok->str() == "(" && tok->previous()->isName()) {
functionCall(tok->previous(), varInfo, ""); functionCall(tok->previous(), varInfo, NOALLOC);
tok = tok->link(); tok = tok->link();
continue; continue;
} }
@ -318,9 +232,9 @@ void CheckLeakAutoVar::checkScope(const Token * const startToken,
// allocation? // allocation?
if (Token::Match(tok->tokAt(2), "%type% (")) { if (Token::Match(tok->tokAt(2), "%type% (")) {
const std::map<std::string, std::string>::const_iterator it = allocFunctions.find(tok->strAt(2)); int i = _settings->environment.alloc(tok->strAt(2));
if (it != allocFunctions.end()) { if (i > 0) {
alloctype[tok->varId()] = it->second; alloctype[tok->varId()] = i;
} }
} }
@ -341,15 +255,8 @@ void CheckLeakAutoVar::checkScope(const Token * const startToken,
if (innerTok->str() == ")") if (innerTok->str() == ")")
break; break;
if (innerTok->str() == "(" && innerTok->previous()->isName()) { if (innerTok->str() == "(" && innerTok->previous()->isName()) {
std::string dealloc; const int deallocId = _settings->environment.dealloc(tok->str());
{ functionCall(innerTok->previous(), varInfo, deallocId);
const std::map<std::string, std::string>::iterator func = deallocFunctions.find(tok->str());
if (func != deallocFunctions.end()) {
dealloc = func->second;
}
}
functionCall(innerTok->previous(), varInfo, dealloc);
innerTok = innerTok->link(); innerTok = innerTok->link();
} }
} }
@ -382,7 +289,7 @@ void CheckLeakAutoVar::checkScope(const Token * const startToken,
old.swap(*varInfo); old.swap(*varInfo);
// Conditional allocation in varInfo1 // Conditional allocation in varInfo1
std::map<unsigned int, std::string>::const_iterator it; std::map<unsigned int, int>::const_iterator it;
for (it = varInfo1.alloctype.begin(); it != varInfo1.alloctype.end(); ++it) { for (it = varInfo1.alloctype.begin(); it != varInfo1.alloctype.end(); ++it) {
if (varInfo2.alloctype.find(it->first) == varInfo2.alloctype.end() && if (varInfo2.alloctype.find(it->first) == varInfo2.alloctype.end() &&
old.alloctype.find(it->first) == old.alloctype.end()) { old.alloctype.find(it->first) == old.alloctype.end()) {
@ -400,13 +307,13 @@ void CheckLeakAutoVar::checkScope(const Token * const startToken,
// Conditional allocation/deallocation // Conditional allocation/deallocation
for (it = varInfo1.alloctype.begin(); it != varInfo1.alloctype.end(); ++it) { for (it = varInfo1.alloctype.begin(); it != varInfo1.alloctype.end(); ++it) {
if (it->second == "dealloc" && conditionalAlloc.find(it->first) != conditionalAlloc.end()) { if (it->second == DEALLOC && conditionalAlloc.find(it->first) != conditionalAlloc.end()) {
varInfo->conditionalAlloc.erase(it->first); varInfo->conditionalAlloc.erase(it->first);
varInfo2.erase(it->first); varInfo2.erase(it->first);
} }
} }
for (it = varInfo2.alloctype.begin(); it != varInfo2.alloctype.end(); ++it) { for (it = varInfo2.alloctype.begin(); it != varInfo2.alloctype.end(); ++it) {
if (it->second == "dealloc" && conditionalAlloc.find(it->first) != conditionalAlloc.end()) { if (it->second == DEALLOC && conditionalAlloc.find(it->first) != conditionalAlloc.end()) {
varInfo->conditionalAlloc.erase(it->first); varInfo->conditionalAlloc.erase(it->first);
varInfo1.erase(it->first); varInfo1.erase(it->first);
} }
@ -428,24 +335,18 @@ void CheckLeakAutoVar::checkScope(const Token * const startToken,
// Function call.. // Function call..
else if (Token::Match(tok, "%type% (") && tok->str() != "return") { else if (Token::Match(tok, "%type% (") && tok->str() != "return") {
std::string dealloc; const int dealloc = _settings->environment.dealloc(tok->str());
{
const std::map<std::string, std::string>::iterator func = deallocFunctions.find(tok->str());
if (func != deallocFunctions.end()) {
dealloc = func->second;
}
}
functionCall(tok, varInfo, dealloc); functionCall(tok, varInfo, dealloc);
tok = tok->next()->link(); tok = tok->next()->link();
// Handle scopes that might be noreturn // Handle scopes that might be noreturn
if (dealloc.empty() && Token::simpleMatch(tok, ") ; }")) { if (dealloc == NOALLOC && Token::simpleMatch(tok, ") ; }")) {
const std::string &functionName(tok->link()->previous()->str()); const std::string &functionName(tok->link()->previous()->str());
bool unknown = false; bool unknown = false;
if (cfgignore.find(functionName) == cfgignore.end() && if (_settings->environment.ignore.find(functionName) == _settings->environment.ignore.end() &&
cfguse.find(functionName) == cfguse.end() && _settings->environment.use.find(functionName) == _settings->environment.use.end() &&
_tokenizer->IsScopeNoReturn(tok->tokAt(2), &unknown)) { _tokenizer->IsScopeNoReturn(tok->tokAt(2), &unknown)) {
if (unknown) { if (unknown) {
//const std::string &functionName(tok->link()->previous()->str()); //const std::string &functionName(tok->link()->previous()->str());
@ -478,14 +379,13 @@ void CheckLeakAutoVar::checkScope(const Token * const startToken,
} }
} }
void CheckLeakAutoVar::functionCall(const Token *tok, VarInfo *varInfo, const std::string &dealloc) void CheckLeakAutoVar::functionCall(const Token *tok, VarInfo *varInfo, const int dealloc)
{ {
std::map<unsigned int, std::string> &alloctype = varInfo->alloctype; std::map<unsigned int, int> &alloctype = varInfo->alloctype;
std::map<unsigned int, std::string> &possibleUsage = varInfo->possibleUsage; std::map<unsigned int, std::string> &possibleUsage = varInfo->possibleUsage;
// Ignore function call? // Ignore function call?
const bool ignore = bool(cfgignore.find(tok->str()) != cfgignore.end()); const bool ignore = bool(_settings->environment.ignore.find(tok->str()) != _settings->environment.ignore.end());
//const bool use = bool(cfguse.find(tok->str()) != cfguse.end());
if (ignore) if (ignore)
return; return;
@ -499,14 +399,14 @@ void CheckLeakAutoVar::functionCall(const Token *tok, VarInfo *varInfo, const st
arg = arg->next(); arg = arg->next();
// Is variable allocated? // Is variable allocated?
const std::map<unsigned int,std::string>::iterator var = alloctype.find(arg->varId()); const std::map<unsigned int,int>::iterator var = alloctype.find(arg->varId());
if (var != alloctype.end()) { if (var != alloctype.end()) {
if (dealloc.empty()) { if (dealloc == NOALLOC) {
// possible usage // possible usage
possibleUsage[arg->varId()] = tok->str(); possibleUsage[arg->varId()] = tok->str();
if (var->second == "dealloc" && arg->previous()->str() == "&") if (var->second == DEALLOC && arg->previous()->str() == "&")
varInfo->erase(arg->varId()); varInfo->erase(arg->varId());
} else if (var->second == "dealloc") { } else if (var->second == DEALLOC) {
CheckOther checkOther(_tokenizer, _settings, _errorLogger); CheckOther checkOther(_tokenizer, _settings, _errorLogger);
checkOther.doubleFreeError(tok, arg->str()); checkOther.doubleFreeError(tok, arg->str());
} else if (var->second != dealloc) { } else if (var->second != dealloc) {
@ -515,10 +415,10 @@ void CheckLeakAutoVar::functionCall(const Token *tok, VarInfo *varInfo, const st
varInfo->erase(arg->varId()); varInfo->erase(arg->varId());
} else { } else {
// deallocation // deallocation
var->second = "dealloc"; var->second = DEALLOC;
} }
} else if (!dealloc.empty()) { } else if (dealloc != NOALLOC) {
alloctype[arg->varId()] = "dealloc"; alloctype[arg->varId()] = DEALLOC;
} }
} else if (Token::Match(arg, "%var% (")) { } else if (Token::Match(arg, "%var% (")) {
functionCall(arg, varInfo, dealloc); functionCall(arg, varInfo, dealloc);
@ -530,11 +430,11 @@ void CheckLeakAutoVar::functionCall(const Token *tok, VarInfo *varInfo, const st
void CheckLeakAutoVar::leakIfAllocated(const Token *vartok, void CheckLeakAutoVar::leakIfAllocated(const Token *vartok,
const VarInfo &varInfo) const VarInfo &varInfo)
{ {
const std::map<unsigned int, std::string> &alloctype = varInfo.alloctype; const std::map<unsigned int, int> &alloctype = varInfo.alloctype;
const std::map<unsigned int, std::string> &possibleUsage = varInfo.possibleUsage; const std::map<unsigned int, std::string> &possibleUsage = varInfo.possibleUsage;
const std::map<unsigned int,std::string>::const_iterator var = alloctype.find(vartok->varId()); const std::map<unsigned int,int>::const_iterator var = alloctype.find(vartok->varId());
if (var != alloctype.end() && var->second != "dealloc") { if (var != alloctype.end() && var->second != DEALLOC) {
const std::map<unsigned int, std::string>::const_iterator use = possibleUsage.find(vartok->varId()); const std::map<unsigned int, std::string>::const_iterator use = possibleUsage.find(vartok->varId());
if (use == possibleUsage.end()) { if (use == possibleUsage.end()) {
leakError(vartok, vartok->str(), var->second); leakError(vartok, vartok->str(), var->second);
@ -546,13 +446,13 @@ void CheckLeakAutoVar::leakIfAllocated(const Token *vartok,
void CheckLeakAutoVar::ret(const Token *tok, const VarInfo &varInfo) void CheckLeakAutoVar::ret(const Token *tok, const VarInfo &varInfo)
{ {
const std::map<unsigned int, std::string> &alloctype = varInfo.alloctype; const std::map<unsigned int, int> &alloctype = varInfo.alloctype;
const std::map<unsigned int, std::string> &possibleUsage = varInfo.possibleUsage; const std::map<unsigned int, std::string> &possibleUsage = varInfo.possibleUsage;
const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase(); const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase();
for (std::map<unsigned int, std::string>::const_iterator it = alloctype.begin(); it != alloctype.end(); ++it) { for (std::map<unsigned int, int>::const_iterator it = alloctype.begin(); it != alloctype.end(); ++it) {
// don't warn if variable is conditionally allocated // don't warn if variable is conditionally allocated
if (it->second != "dealloc" && varInfo.conditionalAlloc.find(it->first) != varInfo.conditionalAlloc.end()) if (it->second != DEALLOC && varInfo.conditionalAlloc.find(it->first) != varInfo.conditionalAlloc.end())
continue; continue;
// don't warn if there is a reference of the variable // don't warn if there is a reference of the variable
@ -577,10 +477,10 @@ void CheckLeakAutoVar::ret(const Token *tok, const VarInfo &varInfo)
} }
// return deallocated pointer // return deallocated pointer
if (used && it->second == "dealloc") if (used && it->second == DEALLOC)
deallocReturnError(tok, var->name()); deallocReturnError(tok, var->name());
else if (!used && it->second != "dealloc") { else if (!used && it->second != DEALLOC) {
const std::map<unsigned int, std::string>::const_iterator use = possibleUsage.find(varid); const std::map<unsigned int, std::string>::const_iterator use = possibleUsage.find(varid);
if (use == possibleUsage.end()) { if (use == possibleUsage.end()) {

View File

@ -28,7 +28,7 @@
class CPPCHECKLIB VarInfo { class CPPCHECKLIB VarInfo {
public: public:
std::map<unsigned int, std::string> alloctype; std::map<unsigned int, int> alloctype;
std::map<unsigned int, std::string> possibleUsage; std::map<unsigned int, std::string> possibleUsage;
std::set<unsigned int> conditionalAlloc; std::set<unsigned int> conditionalAlloc;
std::set<unsigned int> referenced; std::set<unsigned int> referenced;
@ -81,20 +81,11 @@ public:
/** @brief Run checks against the simplified token list */ /** @brief Run checks against the simplified token list */
void runSimplifiedChecks(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) { void runSimplifiedChecks(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) {
CheckLeakAutoVar checkLeakAutoVar(tokenizer, settings, errorLogger); CheckLeakAutoVar checkLeakAutoVar(tokenizer, settings, errorLogger);
checkLeakAutoVar.parseConfigurationFile("cppcheck.cfg");
checkLeakAutoVar.check(); checkLeakAutoVar.check();
} }
private: private:
std::map<std::string,std::string> cfgalloc;
std::map<std::string,std::string> cfgdealloc;
std::set<std::string> cfgignore;
std::set<std::string> cfguse;
std::set<std::string> cfgnoreturn;
void parseConfigurationFile(const std::string &filename);
/** check for leaks in all scopes */ /** check for leaks in all scopes */
void check(); void check();
@ -104,7 +95,7 @@ private:
std::set<unsigned int> notzero); std::set<unsigned int> notzero);
/** parse function call */ /** parse function call */
void functionCall(const Token *tok, VarInfo *varInfo, const std::string &dealloc); void functionCall(const Token *tok, VarInfo *varInfo, const int dealloc);
/** return. either "return" or end of variable scope is seen */ /** return. either "return" or end of variable scope is seen */
void ret(const Token *tok, const VarInfo &varInfo); void ret(const Token *tok, const VarInfo &varInfo);
@ -112,7 +103,7 @@ private:
/** if variable is allocated then there is a leak */ /** if variable is allocated then there is a leak */
void leakIfAllocated(const Token *vartok, const VarInfo &varInfo); void leakIfAllocated(const Token *vartok, const VarInfo &varInfo);
void leakError(const Token* tok, const std::string &varname, const std::string &type); void leakError(const Token* tok, const std::string &varname, int type);
void mismatchError(const Token* tok, const std::string &varname); void mismatchError(const Token* tok, const std::string &varname);
void deallocUseError(const Token *tok, const std::string &varname); void deallocUseError(const Token *tok, const std::string &varname);
void deallocReturnError(const Token *tok, const std::string &varname); void deallocReturnError(const Token *tok, const std::string &varname);

79
lib/environment.cpp Normal file
View File

@ -0,0 +1,79 @@
/*
* Cppcheck - A tool for static C/C++ code analysis
* Copyright (C) 2007-2013 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 "environment.h"
#include <tinyxml2.h>
Environment::Environment() : allocid(0)
{
while (!ismemory(++allocid));
_alloc["malloc"] = allocid;
_alloc["calloc"] = allocid;
_alloc["strdup"] = allocid;
_alloc["strndup"] = allocid;
_dealloc["free"] = allocid;
while (!isresource(++allocid));
_alloc["fopen"] = allocid;
_dealloc["fclose"] = allocid;
}
Environment::Environment(const Environment &env) : use(env.use), ignore(env.ignore), noreturn(env.noreturn), allocid(env.allocid), _alloc(env._alloc), _dealloc(env._dealloc)
{
}
Environment::~Environment() { }
bool Environment::load(const char path[])
{
tinyxml2::XMLDocument doc;
const tinyxml2::XMLError error = doc.LoadFile(path);
if (error != tinyxml2::XML_NO_ERROR)
return false;
const tinyxml2::XMLElement * const rootnode = doc.FirstChildElement();
if (strcmp(rootnode->Value(),"def") != 0)
return false;
for (const tinyxml2::XMLElement *node = rootnode->FirstChildElement(); node; node = node->NextSiblingElement()) {
if (strcmp(node->Value(),"memory")==0) {
while (!ismemory(++allocid));
for (const tinyxml2::XMLElement *memorynode = node->FirstChildElement(); memorynode; memorynode = memorynode->NextSiblingElement()) {
if (strcmp(memorynode->Value(),"alloc")==0)
_alloc[node->GetText()] = allocid;
else if (strcmp(memorynode->Value(),"dealloc")==0)
_dealloc[node->GetText()] = allocid;
else if (strcmp(node->Value(),"use")==0)
use.insert(node->GetText());
else
return false;
}
}
else if (strcmp(node->Value(),"ignore")==0)
ignore.insert(node->GetText());
else if (strcmp(node->Value(),"noreturn")==0)
noreturn.insert(node->GetText());
else
return false;
}
return true;
}

77
lib/environment.h Normal file
View File

@ -0,0 +1,77 @@
/*
* Cppcheck - A tool for static C/C++ code analysis
* Copyright (C) 2007-2013 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/>.
*/
#ifndef ENVIRONMENT_H
#define ENVIRONMENT_H
#include <map>
#include <set>
#include <string>
/// @addtogroup Core
/// @{
/**
* @brief Environment definitions handling
*/
class Environment {
public:
Environment();
Environment(const Environment &);
~Environment();
bool load(const char path[]);
/** get allocation id for function (by name) */
int alloc(const std::string &name) const {
return getid(_alloc, name);
}
/** get deallocation id for function (by name) */
int dealloc(const std::string &name) const {
return getid(_dealloc, name);
}
/** is allocation type memory? */
static bool ismemory(int id) {
return ((id > 0) && ((id & 1) == 0));
}
/** is allocation type resource? */
static bool isresource(int id) {
return ((id > 0) && ((id & 1) == 1));
}
std::set<std::string> use;
std::set<std::string> ignore;
std::set<std::string> noreturn;
private:
int allocid;
std::map<std::string, int> _alloc; // allocation functions
std::map<std::string, int> _dealloc; // deallocation functions
int getid(const std::map<std::string,int> &data, const std::string &name) const {
const std::map<std::string,int>::const_iterator it = data.find(name);
return (it == data.end()) ? 0 : it->second;
}
};
/// @}
#endif // PATH_H_INCLUDED

View File

@ -27,6 +27,7 @@ HEADERS += $${BASEPATH}check.h \
$${BASEPATH}checkunusedfunctions.h \ $${BASEPATH}checkunusedfunctions.h \
$${BASEPATH}checkunusedvar.h \ $${BASEPATH}checkunusedvar.h \
$${BASEPATH}cppcheck.h \ $${BASEPATH}cppcheck.h \
$${BASEPATH}environment.h \
$${BASEPATH}errorlogger.h \ $${BASEPATH}errorlogger.h \
$${BASEPATH}executionpath.h \ $${BASEPATH}executionpath.h \
$${BASEPATH}mathlib.h \ $${BASEPATH}mathlib.h \
@ -66,6 +67,7 @@ SOURCES += $${BASEPATH}check64bit.cpp \
$${BASEPATH}checkunusedfunctions.cpp \ $${BASEPATH}checkunusedfunctions.cpp \
$${BASEPATH}checkunusedvar.cpp \ $${BASEPATH}checkunusedvar.cpp \
$${BASEPATH}cppcheck.cpp \ $${BASEPATH}cppcheck.cpp \
$${BASEPATH}environment.cpp \
$${BASEPATH}errorlogger.cpp \ $${BASEPATH}errorlogger.cpp \
$${BASEPATH}executionpath.cpp \ $${BASEPATH}executionpath.cpp \
$${BASEPATH}mathlib.cpp \ $${BASEPATH}mathlib.cpp \

View File

@ -24,6 +24,7 @@
#include <string> #include <string>
#include <set> #include <set>
#include "config.h" #include "config.h"
#include "environment.h"
#include "suppressions.h" #include "suppressions.h"
#include "standards.h" #include "standards.h"
@ -174,6 +175,9 @@ public:
/** @brief --report-progress */ /** @brief --report-progress */
bool reportProgress; bool reportProgress;
/** Environment (--environment) */
Environment environment;
/** Rule */ /** Rule */
class CPPCHECKLIB Rule { class CPPCHECKLIB Rule {
public: public:

View File

@ -119,6 +119,7 @@ private:
// Check for leaks.. // Check for leaks..
CheckLeakAutoVar c; CheckLeakAutoVar c;
settings.experimental = true; settings.experimental = true;
settings.addEnabled("information");
c.runSimplifiedChecks(&tokenizer, &settings, this); c.runSimplifiedChecks(&tokenizer, &settings, this);
} }

View File

@ -321,7 +321,7 @@ int main(int argc, char **argv)
makeConditionalVariable(fout, "CXX", "g++"); makeConditionalVariable(fout, "CXX", "g++");
makeConditionalVariable(fout, "PREFIX", "/usr"); makeConditionalVariable(fout, "PREFIX", "/usr");
makeConditionalVariable(fout, "INCLUDE_FOR_LIB", "-Ilib"); makeConditionalVariable(fout, "INCLUDE_FOR_LIB", "-Ilib -Iexternals -Iexternals/tinyxml");
makeConditionalVariable(fout, "INCLUDE_FOR_CLI", "-Ilib -Iexternals -Iexternals/tinyxml"); makeConditionalVariable(fout, "INCLUDE_FOR_CLI", "-Ilib -Iexternals -Iexternals/tinyxml");
makeConditionalVariable(fout, "INCLUDE_FOR_TEST", "-Ilib -Icli -Iexternals -Iexternals/tinyxml"); makeConditionalVariable(fout, "INCLUDE_FOR_TEST", "-Ilib -Icli -Iexternals -Iexternals/tinyxml");