⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 checkmemoryleak.cpp

📁 cppcheck is a static C/C++ code analyzer that checks for memory leaks, mismatching allocation-deallo
💻 CPP
📖 第 1 页 / 共 4 页
字号:
/* * Cppcheck - A tool for static C/C++ code analysis * Copyright (C) 2007-2009 Daniel Marjamäki, Reijo Tomperi, Nicolas Le Cam, * Leandro Penz, Kimmo Varis, Vesa Pikki * * 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 "checkmemoryleak.h"#include <algorithm>#include <cstring>#include <iostream>#include <sstream>//---------------------------------------------------------------------------CheckMemoryLeakClass::CheckMemoryLeakClass(const Tokenizer *tokenizer, const Settings &settings, ErrorLogger *errorLogger)        : _settings(settings){    _tokenizer = tokenizer;    _errorLogger = errorLogger;}CheckMemoryLeakClass::~CheckMemoryLeakClass(){}bool CheckMemoryLeakClass::isclass(const Token *tok){    if (tok->isStandardType())        return false;    std::ostringstream pattern;    pattern << "struct " << tok->str();    if (Token::findmatch(_tokenizer->tokens(), pattern.str().c_str()))        return false;    return true;}//---------------------------------------------------------------------------CheckMemoryLeakClass::AllocType CheckMemoryLeakClass::GetAllocationType(const Token *tok2){    // What we may have...    //     * var = (char *)malloc(10);    //     * var = new char[10];    //     * var = strdup("hello");    if (tok2 && tok2->str() == "(")    {        while (tok2 && tok2->str() != ")")            tok2 = tok2->next();        tok2 = tok2 ? tok2->next() : NULL;    }    if (! tok2)        return No;    if (! tok2->isName())        return No;    // Does tok2 point on "malloc", "strdup" or "kmalloc"..    const char *mallocfunc[] = {"malloc",                                "calloc",                                "strdup",                                "kmalloc",                                "kzalloc",                                "kcalloc",                                0                               };    for (unsigned int i = 0; mallocfunc[i]; i++)    {        if (tok2->str() == mallocfunc[i])            return Malloc;    }    // Does tok2 point on "g_malloc", "g_strdup", ..    const char *gmallocfunc[] = {"g_new",                                 "g_new0",                                 "g_try_new",                                 "g_try_new0",                                 "g_malloc",                                 "g_malloc0",                                 "g_try_malloc",                                 "g_try_malloc0",                                 "g_strdup",                                 "g_strndup",                                 0                                };    for (unsigned int i = 0; gmallocfunc[i]; i++)    {        if (tok2->str() == gmallocfunc[i])            return gMalloc;    }    if (Token::Match(tok2, "new %type% [;(]"))        return New;    if (Token::Match(tok2, "new %type% ["))        return NewArray;    if (Token::Match(tok2, "fopen ("))        return FOPEN;    if (Token::Match(tok2, "popen ("))        return POPEN;    // Userdefined allocation function..    std::list<AllocFunc>::const_iterator it = _listAllocFunc.begin();    while (it != _listAllocFunc.end())    {        if (tok2->str() == it->funcname)            return it->alloctype;        ++it;    }    return No;}CheckMemoryLeakClass::AllocType CheckMemoryLeakClass::GetReallocationType(const Token *tok2){    // What we may have...    //     * var = (char *)realloc(..;    if (tok2 && tok2->str() == "(")    {        while (tok2 && tok2->str() != ")")            tok2 = tok2->next();        tok2 = tok2 ? tok2->next() : NULL;    }    if (! tok2)        return No;    if (Token::Match(tok2, "realloc"))        return Malloc;    // GTK memory reallocation..    if (Token::Match(tok2, "g_realloc|g_try_realloc|g_renew|g_try_renew"))        return gMalloc;    return No;}CheckMemoryLeakClass::AllocType CheckMemoryLeakClass::GetDeallocationType(const Token *tok, const char *varnames[]){    int i = 0;    std::string names;    while (varnames[i])    {        if (i > 0)            names += " . ";        names += varnames[i];        i++;    }    if (Token::simpleMatch(tok, std::string("delete " + names + " ;").c_str()))        return New;    if (Token::simpleMatch(tok, std::string("delete [ ] " + names + " ;").c_str()))        return NewArray;    if (Token::simpleMatch(tok, std::string("delete ( " + names + " ) ;").c_str()))        return New;    if (Token::simpleMatch(tok, std::string("delete [ ] ( " + names + " ) ;").c_str()))        return NewArray;    if (Token::simpleMatch(tok, std::string("free ( " + names + " ) ;").c_str()) ||        Token::simpleMatch(tok, std::string("kfree ( " + names + " ) ;").c_str()))    {        return Malloc;    }    if (Token::simpleMatch(tok, std::string("g_free ( " + names + " ) ;").c_str()))        return gMalloc;    if (Token::simpleMatch(tok, std::string("fclose ( " + names + " )").c_str()))        return FOPEN;    if (Token::simpleMatch(tok, std::string("pclose ( " + names + " )").c_str()))        return POPEN;    return No;}//--------------------------------------------------------------------------const char * CheckMemoryLeakClass::call_func(const Token *tok, std::list<const Token *> callstack, const char *varnames[], AllocType &alloctype, AllocType &dealloctype, bool &all, unsigned int sz){    // Keywords that are not function calls..    if (Token::Match(tok, "if|for|while|return|switch"))        return 0;    // String functions that are not allocating nor deallocating memory..    if (Token::Match(tok, "strcpy|strncpy|strcat|strncat|strcmp|strncmp|strcasecmp|stricmp|sprintf|strchr|strrchr|strstr"))        return 0;    // Memory functions that are not allocating nor deallocating memory..    if (Token::Match(tok, "memset|memcpy|memmove|memchr"))        return 0;    // I/O functions that are not allocating nor deallocating memory..    if (Token::Match(tok, "fgets|fgetc|fputs|fputc|printf"))        return 0;    // Convert functions that are not allocating nor deallocating memory..    if (Token::Match(tok, "atoi|atof|atol|strtol|strtoul|strtod"))        return 0;    // This is not an unknown function neither    if (tok->str() == "delete")        return 0;    if (GetAllocationType(tok) != No || GetReallocationType(tok) != No || GetDeallocationType(tok, varnames) != No)        return 0;    if (callstack.size() > 2)        return "dealloc_";    const std::string funcname(tok->str());    for (std::list<const Token *>::const_iterator it = callstack.begin(); it != callstack.end(); ++it)    {        if ((*it)->str() == funcname)            return "recursive";    }    callstack.push_back(tok);    int par = 1;    int parlevel = 0;    std::string pattern = "[,()] ";    for (int i = 0; varnames[i]; i++)    {        if (i > 0)            pattern += " . ";        pattern += varnames[i];    }    pattern += " [,()]";    for (; tok; tok = tok->next())    {        if (tok->str() == "(")            ++parlevel;        else if (tok->str() == ")")        {            --parlevel;            if (parlevel < 1)            {                return _settings._showAll ? 0 : "callfunc";            }        }        if (parlevel == 1)        {            if (tok->str() == ",")                ++par;            if (Token::Match(tok, pattern.c_str()))            {                const Token *ftok = _tokenizer->GetFunctionTokenByName(funcname.c_str());                const char *parname = Tokenizer::getParameterName(ftok, par);                if (! parname)                    return "recursive";                // Check if the function deallocates the variable..                while (ftok && (ftok->str() != "{"))                    ftok = ftok->next();                Token *func = getcode(ftok->tokAt(1), callstack, parname, alloctype, dealloctype, false, all, sz);                simplifycode(func, all);                const Token *func_ = func;                while (func_ && func_->str() == ";")                    func_ = func_->next();                const char *ret = 0;                // TODO : "goto" isn't handled well                if (Token::findmatch(func_, "dealloc"))                    ret = "dealloc";                else if (Token::findmatch(func_, "use"))                    ret = "use";                else if (Token::findmatch(func_, "&use"))                    ret = "&use";                Tokenizer::deleteTokens(func);                return ret;            }        }    }    return NULL;}//--------------------------------------------------------------------------void CheckMemoryLeakClass::MemoryLeak(const Token *tok, const char varname[], AllocType alloctype, bool all){    if (alloctype == CheckMemoryLeakClass::FOPEN ||        alloctype == CheckMemoryLeakClass::POPEN)        _errorLogger->resourceLeak(_tokenizer, tok, varname);    else if (all)        _errorLogger->memleakall(_tokenizer, tok, varname);    else        _errorLogger->memleak(_tokenizer, tok, varname);}//---------------------------------------------------------------------------bool CheckMemoryLeakClass::MatchFunctionsThatReturnArg(const Token *tok, const std::string &varname){    return Token::Match(tok, std::string("; " + varname + " = strcat|memcpy|memmove|strcpy ( " + varname + " ,").c_str());}bool CheckMemoryLeakClass::notvar(const Token *tok, const char *varnames[], bool endpar){    std::string varname;    for (int i = 0; varnames[i]; i++)    {        if (i > 0)            varname += " . ";        varname += varnames[i];    }    const std::string end(endpar ? " )" : " [;)&|]");    return bool(Token::Match(tok, std::string("! " + varname + end).c_str()) ||                Token::simpleMatch(tok, std::string("! ( " + varname + " )" + end).c_str()) ||                Token::Match(tok, std::string("0 == " + varname + end).c_str()) ||                Token::simpleMatch(tok, std::string(varname + " == 0" + end).c_str()));}Token *CheckMemoryLeakClass::getcode(const Token *tok, std::list<const Token *> callstack, const char varname[], AllocType &alloctype, AllocType &dealloctype, bool classmember, bool &all, unsigned int sz){    const char *varnames[2];    varnames[0] = varname;    varnames[1] = 0;    std::string varnameStr = varname;    Token *rethead = 0, *rettail = 0;#define addtoken(_str)                  \    {                                       \        if (rettail)                        \        {                                   \            rettail->insertToken(_str);     \            rettail = rettail->next();      \        }                                   \        else                                \        {                                   \            rethead = new Token;            \            rettail = rethead;              \            rettail->str(_str);             \        }                                   \                                            \        rettail->linenr( tok->linenr() );   \        rettail->fileIndex( tok->fileIndex() ); \    }    // The first token should be ";"    addtoken(";");    bool isloop = false;    int indentlevel = 0;    int parlevel = 0;    for (; tok; tok = tok->next())    {        if (tok->str() == "{")        {            addtoken("{");            ++indentlevel;        }        else if (tok->str() == "}")        {            addtoken("}");            if (indentlevel <= 0)                break;            --indentlevel;        }        if (tok->str() == "(")            ++parlevel;        else if (tok->str() == ")")            --parlevel;        isloop &= (parlevel > 0);        if (parlevel == 0 && tok->str() == ";")            addtoken(";");        if (Token::Match(tok->previous(), std::string("[(;{}] " + varnameStr + " =").c_str()))        {            AllocType alloc = GetAllocationType(tok->tokAt(2));            bool realloc = false;            if (sz > 1 &&                Token::Match(tok->tokAt(2), "malloc ( %num% )") &&                (std::atoi(tok->strAt(4)) % sz) != 0)            {                _errorLogger->mismatchSize(_tokenizer, tok->tokAt(4), tok->strAt(4));            }            if (alloc == No)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -