diff --git a/Makefile b/Makefile index b8c07a3a3..4928a3d69 100644 --- a/Makefile +++ b/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 diff --git a/cli/cmdlineparser.cpp b/cli/cmdlineparser.cpp index 195e3a9c2..07fcbf5ac 100644 --- a/cli/cmdlineparser.cpp +++ b/cli/cmdlineparser.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; diff --git a/lib/checkleakautovar.cpp b/lib/checkleakautovar.cpp index 89b44108e..364c97b96 100644 --- a/lib/checkleakautovar.cpp +++ b/lib/checkleakautovar.cpp @@ -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::const_iterator it; + std::map::const_iterator it; for (it = alloctype.begin(); it != alloctype.end(); ++it) { std::string strusage; std::map::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::const_iterator it; + std::map::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 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::iterator it = varInfo.alloctype.begin(); + std::map::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 notzero) { - std::map &alloctype = varInfo->alloctype; + std::map &alloctype = varInfo->alloctype; std::map &possibleUsage = varInfo->possibleUsage; const std::set conditionalAlloc(varInfo->conditionalAlloc); - // Allocation functions. key = function name, value = allocation type - std::map allocFunctions(cfgalloc); - allocFunctions["malloc"] = "malloc"; - allocFunctions["strdup"] = "malloc"; - allocFunctions["fopen"] = "fopen"; - - // Deallocation functions. key = function name, value = allocation type - std::map 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::iterator var = alloctype.find(tok->varId()); + const std::map::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::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::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::const_iterator it; + std::map::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::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 &alloctype = varInfo->alloctype; + std::map &alloctype = varInfo->alloctype; std::map &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::iterator var = alloctype.find(arg->varId()); + const std::map::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 &alloctype = varInfo.alloctype; + const std::map &alloctype = varInfo.alloctype; const std::map &possibleUsage = varInfo.possibleUsage; - const std::map::const_iterator var = alloctype.find(vartok->varId()); - if (var != alloctype.end() && var->second != "dealloc") { + const std::map::const_iterator var = alloctype.find(vartok->varId()); + if (var != alloctype.end() && var->second != DEALLOC) { const std::map::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 &alloctype = varInfo.alloctype; + const std::map &alloctype = varInfo.alloctype; const std::map &possibleUsage = varInfo.possibleUsage; const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase(); - for (std::map::const_iterator it = alloctype.begin(); it != alloctype.end(); ++it) { + for (std::map::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::const_iterator use = possibleUsage.find(varid); if (use == possibleUsage.end()) { diff --git a/lib/checkleakautovar.h b/lib/checkleakautovar.h index eb896b5fd..1b43b73c5 100644 --- a/lib/checkleakautovar.h +++ b/lib/checkleakautovar.h @@ -28,7 +28,7 @@ class CPPCHECKLIB VarInfo { public: - std::map alloctype; + std::map alloctype; std::map possibleUsage; std::set conditionalAlloc; std::set 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 cfgalloc; - std::map cfgdealloc; - std::set cfgignore; - std::set cfguse; - std::set cfgnoreturn; - - void parseConfigurationFile(const std::string &filename); - /** check for leaks in all scopes */ void check(); @@ -104,7 +95,7 @@ private: std::set 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); diff --git a/lib/environment.cpp b/lib/environment.cpp new file mode 100644 index 000000000..5f0f4b4ed --- /dev/null +++ b/lib/environment.cpp @@ -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 . + */ + +#include "environment.h" +#include + +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; +} diff --git a/lib/environment.h b/lib/environment.h new file mode 100644 index 000000000..d2772b259 --- /dev/null +++ b/lib/environment.h @@ -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 . + */ + +#ifndef ENVIRONMENT_H +#define ENVIRONMENT_H + +#include +#include +#include + +/// @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 use; + std::set ignore; + std::set noreturn; + +private: + int allocid; + std::map _alloc; // allocation functions + std::map _dealloc; // deallocation functions + + int getid(const std::map &data, const std::string &name) const { + const std::map::const_iterator it = data.find(name); + return (it == data.end()) ? 0 : it->second; + } +}; + +/// @} + +#endif // PATH_H_INCLUDED diff --git a/lib/lib.pri b/lib/lib.pri index f395f0935..2620c9e4f 100644 --- a/lib/lib.pri +++ b/lib/lib.pri @@ -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 \ diff --git a/lib/settings.h b/lib/settings.h index fcd8c478d..ad51fc714 100644 --- a/lib/settings.h +++ b/lib/settings.h @@ -24,6 +24,7 @@ #include #include #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: diff --git a/test/testleakautovar.cpp b/test/testleakautovar.cpp index 436f90f7c..f10f8a20d 100644 --- a/test/testleakautovar.cpp +++ b/test/testleakautovar.cpp @@ -119,6 +119,7 @@ private: // Check for leaks.. CheckLeakAutoVar c; settings.experimental = true; + settings.addEnabled("information"); c.runSimplifiedChecks(&tokenizer, &settings, this); } diff --git a/tools/dmake.cpp b/tools/dmake.cpp index adf3a5f45..47841b3b8 100644 --- a/tools/dmake.cpp +++ b/tools/dmake.cpp @@ -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");