CLI: Added --environment flag
This commit is contained in:
parent
1a35241aa2
commit
d96fb577cd
8
Makefile
8
Makefile
|
@ -75,7 +75,7 @@ ifndef PREFIX
|
|||
endif
|
||||
|
||||
ifndef INCLUDE_FOR_LIB
|
||||
INCLUDE_FOR_LIB=-Ilib
|
||||
INCLUDE_FOR_LIB=-Ilib -Iexternals -Iexternals/tinyxml
|
||||
endif
|
||||
|
||||
ifndef INCLUDE_FOR_CLI
|
||||
|
@ -120,6 +120,7 @@ LIBOBJ = $(SRCDIR)/check64bit.o \
|
|||
$(SRCDIR)/checkunusedfunctions.o \
|
||||
$(SRCDIR)/checkunusedvar.o \
|
||||
$(SRCDIR)/cppcheck.o \
|
||||
$(SRCDIR)/environment.o \
|
||||
$(SRCDIR)/errorlogger.o \
|
||||
$(SRCDIR)/executionpath.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
|
||||
$(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
|
||||
|
||||
$(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
|
||||
$(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
|
||||
$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $(SRCDIR)/errorlogger.o $(SRCDIR)/errorlogger.cpp
|
||||
|
||||
|
|
|
@ -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
|
||||
else if (std::strncmp(argv[i], "--error-exitcode=", 17) == 0) {
|
||||
std::string temp = argv[i]+17;
|
||||
|
|
|
@ -33,6 +33,9 @@
|
|||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
const int DEALLOC = -1;
|
||||
const int NOALLOC = 0;
|
||||
|
||||
// Register this check class (by creating a static instance of it)
|
||||
namespace {
|
||||
CheckLeakAutoVar instance;
|
||||
|
@ -43,7 +46,7 @@ namespace {
|
|||
void VarInfo::print()
|
||||
{
|
||||
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) {
|
||||
std::string strusage;
|
||||
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)
|
||||
{
|
||||
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)
|
||||
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);
|
||||
if (type == "fopen")
|
||||
if (_settings->environment.isresource(type))
|
||||
checkmemleak.resourceLeakError(tok, varname);
|
||||
else
|
||||
checkmemleak.memleakError(tok, varname);
|
||||
//reportError(tok, Severity::error, "newleak", "New memory leak: " + 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);
|
||||
std::list<const Token *> callstack(1, tok);
|
||||
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)
|
||||
{
|
||||
const CheckMemoryLeak c(_tokenizer, _errorLogger, _settings->standards);
|
||||
c.deallocuseError(tok, varname);
|
||||
//reportError(tok, Severity::error, "newdeallocuse", "Using deallocated pointer " + 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)
|
||||
{
|
||||
if (((!cfgalloc.empty() || !cfgdealloc.empty()) && _settings->isEnabled("information")) || _settings->experimental) {
|
||||
if (_settings->isEnabled("information") && _settings->experimental) {
|
||||
reportError(tok,
|
||||
Severity::information,
|
||||
"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()
|
||||
{
|
||||
const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase();
|
||||
|
@ -198,7 +123,7 @@ void CheckLeakAutoVar::check()
|
|||
varInfo.conditionalAlloc.clear();
|
||||
|
||||
// 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()) {
|
||||
const Variable *var = symbolDatabase->getVariableFromVarId(it->first);
|
||||
if (!var ||
|
||||
|
@ -217,29 +142,18 @@ void CheckLeakAutoVar::checkScope(const Token * const startToken,
|
|||
VarInfo *varInfo,
|
||||
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;
|
||||
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
|
||||
const Token * const endToken = startToken->link();
|
||||
for (const Token *tok = startToken; tok && tok != endToken; tok = tok->next()) {
|
||||
// Deallocation and then dereferencing pointer..
|
||||
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->second == "dealloc" && !Token::Match(tok->previous(), "[;{},=] %var% =")) {
|
||||
if (var->second == DEALLOC && !Token::Match(tok->previous(), "[;{},=] %var% =")) {
|
||||
deallocUseError(tok, tok->str());
|
||||
} else if (Token::simpleMatch(tok->tokAt(-2), "= &")) {
|
||||
varInfo->erase(tok->varId());
|
||||
|
@ -252,7 +166,7 @@ void CheckLeakAutoVar::checkScope(const Token * const startToken,
|
|||
}
|
||||
|
||||
if (tok->str() == "(" && tok->previous()->isName()) {
|
||||
functionCall(tok->previous(), varInfo, "");
|
||||
functionCall(tok->previous(), varInfo, NOALLOC);
|
||||
tok = tok->link();
|
||||
continue;
|
||||
}
|
||||
|
@ -318,9 +232,9 @@ void CheckLeakAutoVar::checkScope(const Token * const startToken,
|
|||
|
||||
// allocation?
|
||||
if (Token::Match(tok->tokAt(2), "%type% (")) {
|
||||
const std::map<std::string, std::string>::const_iterator it = allocFunctions.find(tok->strAt(2));
|
||||
if (it != allocFunctions.end()) {
|
||||
alloctype[tok->varId()] = it->second;
|
||||
int i = _settings->environment.alloc(tok->strAt(2));
|
||||
if (i > 0) {
|
||||
alloctype[tok->varId()] = i;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -341,15 +255,8 @@ void CheckLeakAutoVar::checkScope(const Token * const startToken,
|
|||
if (innerTok->str() == ")")
|
||||
break;
|
||||
if (innerTok->str() == "(" && innerTok->previous()->isName()) {
|
||||
std::string dealloc;
|
||||
{
|
||||
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);
|
||||
const int deallocId = _settings->environment.dealloc(tok->str());
|
||||
functionCall(innerTok->previous(), varInfo, deallocId);
|
||||
innerTok = innerTok->link();
|
||||
}
|
||||
}
|
||||
|
@ -382,7 +289,7 @@ void CheckLeakAutoVar::checkScope(const Token * const startToken,
|
|||
old.swap(*varInfo);
|
||||
|
||||
// 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) {
|
||||
if (varInfo2.alloctype.find(it->first) == varInfo2.alloctype.end() &&
|
||||
old.alloctype.find(it->first) == old.alloctype.end()) {
|
||||
|
@ -400,13 +307,13 @@ void CheckLeakAutoVar::checkScope(const Token * const startToken,
|
|||
|
||||
// Conditional allocation/deallocation
|
||||
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);
|
||||
varInfo2.erase(it->first);
|
||||
}
|
||||
}
|
||||
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);
|
||||
varInfo1.erase(it->first);
|
||||
}
|
||||
|
@ -428,24 +335,18 @@ void CheckLeakAutoVar::checkScope(const Token * const startToken,
|
|||
|
||||
// Function call..
|
||||
else if (Token::Match(tok, "%type% (") && tok->str() != "return") {
|
||||
std::string dealloc;
|
||||
{
|
||||
const std::map<std::string, std::string>::iterator func = deallocFunctions.find(tok->str());
|
||||
if (func != deallocFunctions.end()) {
|
||||
dealloc = func->second;
|
||||
}
|
||||
}
|
||||
const int dealloc = _settings->environment.dealloc(tok->str());
|
||||
|
||||
functionCall(tok, varInfo, dealloc);
|
||||
|
||||
tok = tok->next()->link();
|
||||
|
||||
// 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());
|
||||
bool unknown = false;
|
||||
if (cfgignore.find(functionName) == cfgignore.end() &&
|
||||
cfguse.find(functionName) == cfguse.end() &&
|
||||
if (_settings->environment.ignore.find(functionName) == _settings->environment.ignore.end() &&
|
||||
_settings->environment.use.find(functionName) == _settings->environment.use.end() &&
|
||||
_tokenizer->IsScopeNoReturn(tok->tokAt(2), &unknown)) {
|
||||
if (unknown) {
|
||||
//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;
|
||||
|
||||
// Ignore function call?
|
||||
const bool ignore = bool(cfgignore.find(tok->str()) != cfgignore.end());
|
||||
//const bool use = bool(cfguse.find(tok->str()) != cfguse.end());
|
||||
const bool ignore = bool(_settings->environment.ignore.find(tok->str()) != _settings->environment.ignore.end());
|
||||
|
||||
if (ignore)
|
||||
return;
|
||||
|
@ -499,14 +399,14 @@ void CheckLeakAutoVar::functionCall(const Token *tok, VarInfo *varInfo, const st
|
|||
arg = arg->next();
|
||||
|
||||
// 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 (dealloc.empty()) {
|
||||
if (dealloc == NOALLOC) {
|
||||
// possible usage
|
||||
possibleUsage[arg->varId()] = tok->str();
|
||||
if (var->second == "dealloc" && arg->previous()->str() == "&")
|
||||
if (var->second == DEALLOC && arg->previous()->str() == "&")
|
||||
varInfo->erase(arg->varId());
|
||||
} else if (var->second == "dealloc") {
|
||||
} else if (var->second == DEALLOC) {
|
||||
CheckOther checkOther(_tokenizer, _settings, _errorLogger);
|
||||
checkOther.doubleFreeError(tok, arg->str());
|
||||
} else if (var->second != dealloc) {
|
||||
|
@ -515,10 +415,10 @@ void CheckLeakAutoVar::functionCall(const Token *tok, VarInfo *varInfo, const st
|
|||
varInfo->erase(arg->varId());
|
||||
} else {
|
||||
// deallocation
|
||||
var->second = "dealloc";
|
||||
var->second = DEALLOC;
|
||||
}
|
||||
} else if (!dealloc.empty()) {
|
||||
alloctype[arg->varId()] = "dealloc";
|
||||
} else if (dealloc != NOALLOC) {
|
||||
alloctype[arg->varId()] = DEALLOC;
|
||||
}
|
||||
} else if (Token::Match(arg, "%var% (")) {
|
||||
functionCall(arg, varInfo, dealloc);
|
||||
|
@ -530,11 +430,11 @@ void CheckLeakAutoVar::functionCall(const Token *tok, VarInfo *varInfo, const st
|
|||
void CheckLeakAutoVar::leakIfAllocated(const Token *vartok,
|
||||
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>::const_iterator var = alloctype.find(vartok->varId());
|
||||
if (var != alloctype.end() && var->second != "dealloc") {
|
||||
const std::map<unsigned int,int>::const_iterator var = alloctype.find(vartok->varId());
|
||||
if (var != alloctype.end() && var->second != DEALLOC) {
|
||||
const std::map<unsigned int, std::string>::const_iterator use = possibleUsage.find(vartok->varId());
|
||||
if (use == possibleUsage.end()) {
|
||||
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)
|
||||
{
|
||||
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 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
|
||||
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;
|
||||
|
||||
// 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
|
||||
if (used && it->second == "dealloc")
|
||||
if (used && it->second == DEALLOC)
|
||||
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);
|
||||
if (use == possibleUsage.end()) {
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
|
||||
class CPPCHECKLIB VarInfo {
|
||||
public:
|
||||
std::map<unsigned int, std::string> alloctype;
|
||||
std::map<unsigned int, int> alloctype;
|
||||
std::map<unsigned int, std::string> possibleUsage;
|
||||
std::set<unsigned int> conditionalAlloc;
|
||||
std::set<unsigned int> referenced;
|
||||
|
@ -81,20 +81,11 @@ public:
|
|||
/** @brief Run checks against the simplified token list */
|
||||
void runSimplifiedChecks(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) {
|
||||
CheckLeakAutoVar checkLeakAutoVar(tokenizer, settings, errorLogger);
|
||||
checkLeakAutoVar.parseConfigurationFile("cppcheck.cfg");
|
||||
checkLeakAutoVar.check();
|
||||
}
|
||||
|
||||
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 */
|
||||
void check();
|
||||
|
||||
|
@ -104,7 +95,7 @@ private:
|
|||
std::set<unsigned int> notzero);
|
||||
|
||||
/** 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 */
|
||||
void ret(const Token *tok, const VarInfo &varInfo);
|
||||
|
@ -112,7 +103,7 @@ private:
|
|||
/** if variable is allocated then there is a leak */
|
||||
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 deallocUseError(const Token *tok, const std::string &varname);
|
||||
void deallocReturnError(const Token *tok, const std::string &varname);
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -27,6 +27,7 @@ HEADERS += $${BASEPATH}check.h \
|
|||
$${BASEPATH}checkunusedfunctions.h \
|
||||
$${BASEPATH}checkunusedvar.h \
|
||||
$${BASEPATH}cppcheck.h \
|
||||
$${BASEPATH}environment.h \
|
||||
$${BASEPATH}errorlogger.h \
|
||||
$${BASEPATH}executionpath.h \
|
||||
$${BASEPATH}mathlib.h \
|
||||
|
@ -66,6 +67,7 @@ SOURCES += $${BASEPATH}check64bit.cpp \
|
|||
$${BASEPATH}checkunusedfunctions.cpp \
|
||||
$${BASEPATH}checkunusedvar.cpp \
|
||||
$${BASEPATH}cppcheck.cpp \
|
||||
$${BASEPATH}environment.cpp \
|
||||
$${BASEPATH}errorlogger.cpp \
|
||||
$${BASEPATH}executionpath.cpp \
|
||||
$${BASEPATH}mathlib.cpp \
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include <string>
|
||||
#include <set>
|
||||
#include "config.h"
|
||||
#include "environment.h"
|
||||
#include "suppressions.h"
|
||||
#include "standards.h"
|
||||
|
||||
|
@ -174,6 +175,9 @@ public:
|
|||
/** @brief --report-progress */
|
||||
bool reportProgress;
|
||||
|
||||
/** Environment (--environment) */
|
||||
Environment environment;
|
||||
|
||||
/** Rule */
|
||||
class CPPCHECKLIB Rule {
|
||||
public:
|
||||
|
|
|
@ -119,6 +119,7 @@ private:
|
|||
// Check for leaks..
|
||||
CheckLeakAutoVar c;
|
||||
settings.experimental = true;
|
||||
settings.addEnabled("information");
|
||||
c.runSimplifiedChecks(&tokenizer, &settings, this);
|
||||
}
|
||||
|
||||
|
|
|
@ -321,7 +321,7 @@ int main(int argc, char **argv)
|
|||
|
||||
makeConditionalVariable(fout, "CXX", "g++");
|
||||
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_TEST", "-Ilib -Icli -Iexternals -Iexternals/tinyxml");
|
||||
|
||||
|
|
Loading…
Reference in New Issue