/* * Cppcheck - A tool for static C/C++ code analysis * Copyright (C) 2007-2009 Daniel Marjamäki and Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see #include #include class Token; /** Base class for memory leaks checking */ class CheckMemoryLeak { private: const Tokenizer * const tokenizer; ErrorLogger * const errorLogger; ErrorLogger::ErrorMessage errmsg(const Token *tok, Severity::e severity, const std::string &id, const std::string &msg) const; ErrorLogger::ErrorMessage errmsg(const std::list &callstack, Severity::e severity, const std::string &id, const std::string &msg) const; public: CheckMemoryLeak(const Tokenizer *t, ErrorLogger *e) : tokenizer(t), errorLogger(e) { } /** What type of allocation are used.. the "Many" means that several types of allocation and deallocation are used */ enum AllocType { No, Malloc, gMalloc, New, NewArray, File, Fd, Pipe, Dir, Many }; void memoryLeak(const Token *tok, const char varname[], AllocType alloctype, bool all); AllocType getDeallocationType(const Token *tok, const char *varnames[]); AllocType getAllocationType(const Token *tok2) const; AllocType getReallocationType(const Token *tok2); bool isclass(const Tokenizer *_tokenizer, const Token *typestr) const; void memleakError(const Token *tok, const std::string &varname); void memleakallError(const Token *tok, const std::string &varname); void resourceLeakError(const Token *tok, const std::string &varname); void deallocDeallocError(const Token *tok, const std::string &varname); void deallocuseError(const Token *tok, const std::string &varname); void mismatchSizeError(const Token *tok, const std::string &sz); void mismatchAllocDealloc(const std::list &callstack, const std::string &varname); /** What type of allocated memory does the given function return? */ AllocType functionReturnType(const Token *tok) const; }; /** * Check function variables. * * The checking is done by looking at each function variable separately. By repeating these 4 steps over and over: * 1. locate a function variable * 2. create a simple token list that describes the usage of the function variable. * 3. simplify the token list. * 4. finally, check if the simplified token list contain any leaks. */ class CheckMemoryLeakInFunction : public Check, private CheckMemoryLeak { public: CheckMemoryLeakInFunction() : Check(), CheckMemoryLeak(0, 0) { } CheckMemoryLeakInFunction(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) : Check(tokenizer, settings, errorLogger), CheckMemoryLeak(tokenizer, errorLogger) { } void runSimplifiedChecks(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) { CheckMemoryLeakInFunction checkMemoryLeak(tokenizer, settings, errorLogger); checkMemoryLeak.check(); } #ifndef UNIT_TESTING private: #endif void check(); private: bool matchFunctionsThatReturnArg(const Token *tok, const std::string &varname); /** * Check if there is a "!var" match inside a condition * @param tok first token to match * @param varnames the varname * @param endpar if this is true the "!var" must be followed by ")" * @return true if match */ bool notvar(const Token *tok, const char *varnames[], bool endpar = false); const char * call_func(const Token *tok, std::list callstack, const char *varnames[], AllocType &alloctype, AllocType &dealloctype, bool &all, unsigned int sz); /** * Extract a new tokens list that is easier to parse than the "tokens" * @param tok start parse token * @param callstack callstack * @param varname name of variable * @param alloctype * @param dealloctype * @return Newly allocated token array. Caller needs to release reserved * memory by calling Tokenizer::deleteTokens(returnValue); */ Token *getcode(const Token *tok, std::list callstack, const char varname[], AllocType &alloctype, AllocType &dealloctype, bool classmember, bool &all, unsigned int sz); /** * Simplify code e.g. by replacing empty "{ }" with ";" * @param tok first token. The tokens list can be modified. */ void simplifycode(Token *tok, bool &all); void checkScope(const Token *Tok1, const char varname[], bool classmember, unsigned int sz); void getErrorMessages() { } std::string name() const { return "Memory leaks (function variables)"; } std::string classInfo() const { return "Is there any allocated memory when a function goes out of scope"; } }; /** * Check class variables * variables that are allocated in the constructor should be deallocated in the destructor */ class CheckMemoryLeakInClass : public Check, private CheckMemoryLeak { public: CheckMemoryLeakInClass() : Check(), CheckMemoryLeak(0,0) { } CheckMemoryLeakInClass(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) : Check(tokenizer, settings, errorLogger), CheckMemoryLeak(tokenizer, errorLogger) { } void runSimplifiedChecks(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) { CheckMemoryLeakInClass checkMemoryLeak(tokenizer, settings, errorLogger); checkMemoryLeak.check(); } #ifndef UNIT_TESTING private: #endif void check(); private: void parseClass(const Token *tok1, std::vector &classname); void variable(const char classname[], const Token *tokVarname); void getErrorMessages() { } std::string name() const { return "Memory leaks (class variables)"; } std::string classInfo() const { return "If the constructor allocate memory then the destructor must deallocate it."; } }; /** * Check class variables * variables that are allocated in the constructor should be deallocated in the destructor */ class CheckMemoryLeakStructMember : public Check, private CheckMemoryLeak { public: CheckMemoryLeakStructMember() : Check(), CheckMemoryLeak(0,0) { } CheckMemoryLeakStructMember(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) : Check(tokenizer, settings, errorLogger), CheckMemoryLeak(tokenizer, errorLogger) { } void runSimplifiedChecks(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) { CheckMemoryLeakStructMember checkMemoryLeak(tokenizer, settings, errorLogger); checkMemoryLeak.check(); } void check() { // TODO } private: void error(const Token *tok, const Severity::e severity, const std::string &id, const std::string &msg) { reportError(tok, severity, id, msg); } void error(const std::list &callstack, const Severity::e severity, const std::string &id, const std::string &msg) { reportError(callstack, severity, id, msg); } void getErrorMessages() { } std::string name() const { return "Memory leaks (struct members)"; } std::string classInfo() const { return "Don't forget to free struct members"; } }; //--------------------------------------------------------------------------- #endif