Cppcheck
checkmemoryleak.cpp
Go to the documentation of this file.
00001 /*
00002  * Cppcheck - A tool for static C/C++ code analysis
00003  * Copyright (C) 2007-2013 Daniel Marjamäki and Cppcheck team.
00004  *
00005  * This program is free software: you can redistribute it and/or modify
00006  * it under the terms of the GNU General Public License as published by
00007  * the Free Software Foundation, either version 3 of the License, or
00008  * (at your option) any later version.
00009  *
00010  * This program is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  * GNU General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU General Public License
00016  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
00017  */
00018 
00019 
00020 #include "checkmemoryleak.h"
00021 #include "symboldatabase.h"
00022 #include "mathlib.h"
00023 #include "tokenize.h"
00024 
00025 #include <algorithm>
00026 #include <cstring>
00027 #include <cstdlib>
00028 #include <sstream>
00029 #include <set>
00030 #include <stack>
00031 
00032 //---------------------------------------------------------------------------
00033 
00034 // Register this check class (by creating a static instance of it)
00035 namespace {
00036     CheckMemoryLeakInFunction instance1;
00037     CheckMemoryLeakInClass instance2;
00038     CheckMemoryLeakStructMember instance3;
00039     CheckMemoryLeakNoVar instance4;
00040 }
00041 
00042 /**
00043  * Count function parameters
00044  * \param tok Function name token before the '('
00045  */
00046 static unsigned int countParameters(const Token *tok)
00047 {
00048     tok = tok->tokAt(2);
00049     if (tok->str() == ")")
00050         return 0;
00051 
00052     unsigned int numpar = 1;
00053     while (NULL != (tok = tok->nextArgument()))
00054         numpar++;
00055 
00056     return numpar;
00057 }
00058 
00059 
00060 /** List of functions that can be ignored when searching for memory leaks.
00061  * These functions don't take the address of the given pointer
00062  * This list needs to be alphabetically sorted so we can run bsearch on it.
00063  * This list contains function names with const parameters e.g.: atof(const char *)
00064  * Reference: http://www.aquaphoenix.com/ref/gnu_c_library/libc_492.html#SEC492
00065  */
00066 static const char * const call_func_white_list[] = {
00067     "_open", "_wopen", "access", "adjtime", "asctime", "asctime_r", "asprintf", "assert"
00068     , "atof", "atoi", "atol", "chdir", "chmod", "chown"
00069     , "clearerr", "creat", "ctime", "ctime_r", "delete", "execl", "execle"
00070     , "execlp", "execv", "execve", "fchmod", "fclose", "fcntl"
00071     , "fdatasync", "feof", "ferror", "fflush", "fgetc", "fgetpos", "fgets"
00072     , "flock", "fmemopen", "fnmatch", "fopen", "fopencookie", "for", "fprintf", "fputc", "fputs", "fread", "free"
00073     , "freopen", "fscanf", "fseek", "fseeko", "fsetpos", "fstat", "fsync", "ftell", "ftello"
00074     , "ftruncate", "fwrite", "getc", "getenv","getgrnam", "gethostbyaddr", "gethostbyname", "getnetbyname"
00075     , "getopt", "getopt_long", "getprotobyname", "getpwnam", "gets", "getservbyname", "getservbyport"
00076     , "glob", "gmtime", "gmtime_r", "if", "index", "inet_addr", "inet_aton", "inet_network", "initgroups", "ioctl"
00077     , "link", "localtime", "localtime_r"
00078     , "lockf", "lseek", "lstat", "mblen", "mbstowcs", "mbtowc", "memchr", "memcmp", "memcpy", "memmove", "memset"
00079     , "mkdir", "mkfifo", "mknod", "mkstemp"
00080     , "obstack_printf", "obstack_vprintf", "open", "opendir", "parse_printf_format", "pathconf"
00081     , "perror", "popen" ,"posix_fadvise", "posix_fallocate", "pread"
00082     , "printf", "psignal", "puts", "pwrite", "qsort", "read", "readahead", "readdir", "readdir_r"
00083     , "readlink", "readv"
00084     , "realloc", "regcomp", "remove", "rename", "return", "rewind", "rewinddir", "rindex"
00085     , "rmdir" ,"scandir", "scanf", "seekdir"
00086     , "setbuf", "setbuffer", "sethostname", "setlinebuf", "setlocale" ,"setvbuf", "sizeof" ,"snprintf", "sprintf", "sscanf"
00087     , "stat", "stpcpy", "strcasecmp", "strcat", "strchr", "strcmp", "strcoll"
00088     , "strcpy", "strcspn", "strdup", "stricmp", "strlen", "strncasecmp", "strncat", "strncmp"
00089     , "strncpy", "strpbrk","strrchr", "strspn", "strstr", "strtod", "strtok", "strtol", "strtoul", "strxfrm", "switch"
00090     , "symlink", "sync_file_range", "system", "telldir", "tempnam", "time", "typeid", "unlink"
00091     , "utime", "utimes", "vasprintf", "vfprintf", "vfscanf", "vprintf"
00092     , "vscanf", "vsnprintf", "vsprintf", "vsscanf", "while", "wordexp","write", "writev"
00093 };
00094 
00095 extern "C"
00096 {
00097     int call_func_white_list_compare(const void *a, const void *b);
00098 
00099     int call_func_white_list_compare(const void *a, const void *b)
00100     {
00101         return std::strcmp((const char *)a, *(const char * const *)b);
00102     }
00103 }
00104 
00105 //---------------------------------------------------------------------------
00106 
00107 bool CheckMemoryLeak::isclass(const Token *tok, unsigned int varid) const
00108 {
00109     if (tok->isStandardType())
00110         return false;
00111 
00112     const Variable * var = tokenizer->getSymbolDatabase()->getVariableFromVarId(varid);
00113 
00114     // return false if the type is a simple record type without side effects
00115     // a type that has no side effects (no constructors and no members with constructors)
00116     /** @todo false negative: check base class for side effects */
00117     /** @todo false negative: check constructors for side effects */
00118     if (var && var->typeScope() && var->typeScope()->numConstructors == 0 &&
00119         (var->typeScope()->varlist.empty() || var->type()->needInitialization == Type::True) &&
00120         var->type()->derivedFrom.empty())
00121         return false;
00122 
00123     return true;
00124 }
00125 //---------------------------------------------------------------------------
00126 
00127 CheckMemoryLeak::AllocType CheckMemoryLeak::getAllocationType(const Token *tok2, unsigned int varid, std::list<const Function*> *callstack) const
00128 {
00129     // What we may have...
00130     //     * var = (char *)malloc(10);
00131     //     * var = new char[10];
00132     //     * var = strdup("hello");
00133     //     * var = strndup("hello", 3);
00134     if (tok2 && tok2->str() == "(") {
00135         tok2 = tok2->link();
00136         tok2 = tok2 ? tok2->next() : NULL;
00137     }
00138     if (! tok2)
00139         return No;
00140     if (! tok2->isName())
00141         return No;
00142 
00143     if (!Token::Match(tok2, "%type%|%var% ::|. %type%")) {
00144         // Does tok2 point on "malloc", "strdup" or "kmalloc"..
00145         static const char * const mallocfunc[] = {
00146             "malloc",
00147             "calloc",
00148             "strdup",
00149             "strndup",
00150             "kmalloc",
00151             "kzalloc",
00152             "kcalloc"
00153         };
00154         for (unsigned int i = 0; i < sizeof(mallocfunc)/sizeof(*mallocfunc); i++) {
00155             if (tok2->str() == mallocfunc[i])
00156                 return Malloc;
00157         }
00158 
00159         // Using realloc..
00160         if (varid && Token::Match(tok2, "realloc ( %any% ,") && tok2->tokAt(2)->varId() != varid)
00161             return Malloc;
00162 
00163         // Does tok2 point on "g_malloc", "g_strdup", ..
00164         static const char * const gmallocfunc[] = {
00165             "g_new",
00166             "g_new0",
00167             "g_try_new",
00168             "g_try_new0",
00169             "g_malloc",
00170             "g_malloc0",
00171             "g_try_malloc",
00172             "g_try_malloc0",
00173             "g_strdup",
00174             "g_strndup",
00175             "g_strdup_printf"
00176         };
00177         for (unsigned int i = 0; i < sizeof(gmallocfunc)/sizeof(*gmallocfunc); i++) {
00178             if (tok2->str() == gmallocfunc[i])
00179                 return gMalloc;
00180         }
00181 
00182         if (Token::Match(tok2, "new struct| %type% [;()]") ||
00183             Token::Match(tok2, "new ( std :: nothrow ) struct| %type% [;()]") ||
00184             Token::Match(tok2, "new ( nothrow ) struct| %type% [;()]"))
00185             return New;
00186 
00187         if (Token::Match(tok2, "new struct| %type% [") ||
00188             Token::Match(tok2, "new ( std :: nothrow ) struct| %type% [") ||
00189             Token::Match(tok2, "new ( nothrow ) struct| %type% ["))
00190             return NewArray;
00191 
00192         if (Token::Match(tok2, "fopen|tmpfile|g_fopen ("))
00193             return File;
00194 
00195         if (standards.posix) {
00196             if (Token::Match(tok2, "open|openat|creat|mkstemp|mkostemp (")) {
00197                 // simple sanity check of function parameters..
00198                 // TODO: Make such check for all these functions
00199                 unsigned int num = countParameters(tok2);
00200                 if (tok2->str() == "open" && num != 2 && num != 3)
00201                     return No;
00202 
00203                 // is there a user function with this name?
00204                 if (tokenizer && Token::findmatch(tokenizer->tokens(), ("%type% *|&| " + tok2->str()).c_str()))
00205                     return No;
00206                 return Fd;
00207             }
00208 
00209             if (Token::simpleMatch(tok2, "popen ("))
00210                 return Pipe;
00211 
00212             if (Token::Match(tok2, "opendir|fdopendir ("))
00213                 return Dir;
00214         }
00215 
00216     }
00217 
00218     while (Token::Match(tok2,"%type%|%var% ::|. %type%"))
00219         tok2 = tok2->tokAt(2);
00220 
00221     // User function
00222     const Function* func = tok2->function();
00223     if (func == NULL)
00224         return No;
00225 
00226     // Prevent recursion
00227     if (callstack && std::find(callstack->begin(), callstack->end(), func) != callstack->end())
00228         return No;
00229 
00230     std::list<const Function*> cs;
00231     if (!callstack)
00232         callstack = &cs;
00233 
00234     callstack->push_back(func);
00235     return functionReturnType(func, callstack);
00236 }
00237 
00238 
00239 
00240 
00241 CheckMemoryLeak::AllocType CheckMemoryLeak::getReallocationType(const Token *tok2, unsigned int varid) const
00242 {
00243     // What we may have...
00244     //     * var = (char *)realloc(..;
00245     if (tok2 && tok2->str() == "(") {
00246         tok2 = tok2->link();
00247         tok2 = tok2 ? tok2->next() : NULL;
00248     }
00249     if (! tok2)
00250         return No;
00251 
00252     if (varid > 0 && ! Token::Match(tok2, "%var% ( %varid% [,)]", varid))
00253         return No;
00254 
00255     if (tok2->str() == "realloc")
00256         return Malloc;
00257 
00258     // GTK memory reallocation..
00259     if (Token::Match(tok2, "g_realloc|g_try_realloc|g_renew|g_try_renew"))
00260         return gMalloc;
00261 
00262     return No;
00263 }
00264 
00265 
00266 CheckMemoryLeak::AllocType CheckMemoryLeak::getDeallocationType(const Token *tok, unsigned int varid) const
00267 {
00268     if (Token::Match(tok, "delete %varid% ;", varid))
00269         return New;
00270 
00271     if (Token::Match(tok, "delete [ ] %varid% ;", varid))
00272         return NewArray;
00273 
00274     if (Token::Match(tok, "delete ( %varid% ) ;", varid))
00275         return New;
00276 
00277     if (Token::Match(tok, "delete [ ] ( %varid% ) ;", varid))
00278         return NewArray;
00279 
00280     if (tok && tok->str() == "::")
00281         tok = tok->next();
00282 
00283     if (Token::Match(tok, "free|kfree ( %varid% ) [;:]", varid) ||
00284         Token::Match(tok, "free|kfree ( %varid% -", varid) ||
00285         Token::Match(tok, "realloc ( %varid% , 0 ) ;", varid))
00286         return Malloc;
00287 
00288     if (Token::Match(tok, "g_free ( %varid% ) ;", varid) ||
00289         Token::Match(tok, "g_free ( %varid% -", varid))
00290         return gMalloc;
00291 
00292     if (Token::Match(tok, "fclose ( %varid% )", varid) ||
00293         Token::simpleMatch(tok, "fcloseall ( )"))
00294         return File;
00295 
00296     if (Token::Match(tok, "close ( %varid% )", varid))
00297         return Fd;
00298 
00299     if (Token::Match(tok, "pclose ( %varid% )", varid))
00300         return Pipe;
00301 
00302     if (Token::Match(tok, "closedir ( %varid% )", varid))
00303         return Dir;
00304 
00305     return No;
00306 }
00307 
00308 CheckMemoryLeak::AllocType CheckMemoryLeak::getDeallocationType(const Token *tok, const std::string &varname) const
00309 {
00310     if (Token::Match(tok, std::string("delete " + varname + " [,;]").c_str()))
00311         return New;
00312 
00313     if (Token::Match(tok, std::string("delete [ ] " + varname + " [,;]").c_str()))
00314         return NewArray;
00315 
00316     if (Token::Match(tok, std::string("delete ( " + varname + " ) [,;]").c_str()))
00317         return New;
00318 
00319     if (Token::Match(tok, std::string("delete [ ] ( " + varname + " ) [,;]").c_str()))
00320         return NewArray;
00321 
00322     if (Token::simpleMatch(tok, std::string("free ( " + varname + " ) ;").c_str()) ||
00323         Token::simpleMatch(tok, std::string("kfree ( " + varname + " ) ;").c_str()) ||
00324         Token::simpleMatch(tok, std::string("realloc ( " + varname + " , 0 ) ;").c_str()))
00325         return Malloc;
00326 
00327     if (Token::simpleMatch(tok, std::string("g_free ( " + varname + " ) ;").c_str()))
00328         return gMalloc;
00329 
00330     if (Token::simpleMatch(tok, std::string("fclose ( " + varname + " )").c_str()) ||
00331         Token::simpleMatch(tok, "fcloseall ( )"))
00332         return File;
00333 
00334     if (Token::simpleMatch(tok, std::string("close ( " + varname + " )").c_str()))
00335         return Fd;
00336 
00337     if (Token::simpleMatch(tok, std::string("pclose ( " + varname + " )").c_str()))
00338         return Pipe;
00339 
00340     if (Token::simpleMatch(tok, std::string("closedir ( " + varname + " )").c_str()))
00341         return Dir;
00342 
00343     return No;
00344 }
00345 
00346 //--------------------------------------------------------------------------
00347 
00348 
00349 //--------------------------------------------------------------------------
00350 
00351 void CheckMemoryLeak::memoryLeak(const Token *tok, const std::string &varname, AllocType alloctype)
00352 {
00353     if (alloctype == CheckMemoryLeak::File ||
00354         alloctype == CheckMemoryLeak::Pipe ||
00355         alloctype == CheckMemoryLeak::Fd   ||
00356         alloctype == CheckMemoryLeak::Dir)
00357         resourceLeakError(tok, varname);
00358     else
00359         memleakError(tok, varname);
00360 }
00361 //---------------------------------------------------------------------------
00362 
00363 
00364 void CheckMemoryLeak::reportErr(const Token *tok, Severity::SeverityType severity, const std::string &id, const std::string &msg) const
00365 {
00366     std::list<const Token *> callstack;
00367 
00368     if (tok)
00369         callstack.push_back(tok);
00370 
00371     reportErr(callstack, severity, id, msg);
00372 }
00373 
00374 void CheckMemoryLeak::reportErr(const std::list<const Token *> &callstack, Severity::SeverityType severity, const std::string &id, const std::string &msg) const
00375 {
00376     const ErrorLogger::ErrorMessage errmsg(callstack, tokenizer?&tokenizer->list:0, severity, id, msg, false);
00377 
00378     if (errorLogger)
00379         errorLogger->reportErr(errmsg);
00380     else
00381         Check::reportError(errmsg);
00382 }
00383 
00384 void CheckMemoryLeak::memleakError(const Token *tok, const std::string &varname) const
00385 {
00386     reportErr(tok, Severity::error, "memleak", "Memory leak: " + varname);
00387 }
00388 
00389 void CheckMemoryLeak::memleakUponReallocFailureError(const Token *tok, const std::string &varname) const
00390 {
00391     reportErr(tok, Severity::error, "memleakOnRealloc", "Common realloc mistake: \'" + varname + "\' nulled but not freed upon failure");
00392 }
00393 
00394 void CheckMemoryLeak::resourceLeakError(const Token *tok, const std::string &varname) const
00395 {
00396     std::string errmsg("Resource leak");
00397     if (!varname.empty())
00398         errmsg += ": " + varname;
00399     reportErr(tok, Severity::error, "resourceLeak", errmsg);
00400 }
00401 
00402 void CheckMemoryLeak::deallocDeallocError(const Token *tok, const std::string &varname) const
00403 {
00404     reportErr(tok, Severity::error, "deallocDealloc", "Deallocating a deallocated pointer: " + varname);
00405 }
00406 
00407 void CheckMemoryLeak::deallocuseError(const Token *tok, const std::string &varname) const
00408 {
00409     reportErr(tok, Severity::error, "deallocuse", "Dereferencing '" + varname + "' after it is deallocated / released");
00410 }
00411 
00412 void CheckMemoryLeak::mismatchSizeError(const Token *tok, const std::string &sz) const
00413 {
00414     reportErr(tok, Severity::error, "mismatchSize", "The given size " + sz + " is mismatching");
00415 }
00416 
00417 void CheckMemoryLeak::mismatchAllocDealloc(const std::list<const Token *> &callstack, const std::string &varname) const
00418 {
00419     reportErr(callstack, Severity::error, "mismatchAllocDealloc", "Mismatching allocation and deallocation: " + varname);
00420 }
00421 
00422 CheckMemoryLeak::AllocType CheckMemoryLeak::functionReturnType(const Function* func, std::list<const Function*> *callstack) const
00423 {
00424     if (!func || !func->hasBody)
00425         return No;
00426 
00427     // Get return pointer..
00428     unsigned int varid = 0;
00429     unsigned int indentlevel = 0;
00430     for (const Token *tok2 = func->functionScope->classStart; tok2 != func->functionScope->classEnd; tok2 = tok2->next()) {
00431         if (tok2->str() == "{")
00432             ++indentlevel;
00433         else if (tok2->str() == "}") {
00434             if (indentlevel <= 1)
00435                 return No;
00436             --indentlevel;
00437         }
00438         if (Token::Match(tok2, "return %var% ;")) {
00439             if (indentlevel != 1)
00440                 return No;
00441             varid = tok2->next()->varId();
00442             break;
00443         } else if (tok2->str() == "return") {
00444             AllocType allocType = getAllocationType(tok2->next(), 0, callstack);
00445             if (allocType != No)
00446                 return allocType;
00447         }
00448     }
00449 
00450     // Not returning pointer value..
00451     if (varid == 0)
00452         return No;
00453 
00454     if (this != NULL) {
00455         // If variable is not local then alloctype shall be "No"
00456         // Todo: there can be false negatives about mismatching allocation/deallocation.
00457         //       => Generate "alloc ; use ;" if variable is not local?
00458         const Variable *var = tokenizer->getSymbolDatabase()->getVariableFromVarId(varid);
00459         if (!var || !var->isLocal() || var->isStatic())
00460             return No;
00461     }
00462 
00463     // Check if return pointer is allocated..
00464     AllocType allocType = No;
00465     for (const Token* tok = func->functionScope->classStart; tok != func->functionScope->classEnd; tok = tok->next()) {
00466         if (Token::Match(tok, "%varid% =", varid)) {
00467             allocType = getAllocationType(tok->tokAt(2), varid, callstack);
00468         }
00469         if (Token::Match(tok, "= %varid% ;", varid)) {
00470             return No;
00471         }
00472         if (Token::Match(tok, "static %type% * %varid% [;{}=]", varid)) {
00473             return No;
00474         }
00475         if (Token::Match(tok, "[(,] %varid% [,)]", varid)) {
00476             return No;
00477         }
00478         if (tok->str() == "return")
00479             return allocType;
00480     }
00481 
00482     return allocType;
00483 }
00484 
00485 
00486 const char *CheckMemoryLeak::functionArgAlloc(const Function *func, unsigned int targetpar, AllocType &allocType) const
00487 {
00488     allocType = No;
00489 
00490     if (!func || !func->functionScope)
00491         return "";
00492 
00493     std::list<Variable>::const_iterator arg = func->argumentList.begin();
00494     for (; arg != func->argumentList.end(); ++arg) {
00495         if (arg->index() == targetpar-1)
00496             break;
00497     }
00498     if (arg == func->argumentList.end())
00499         return "";
00500 
00501     // Is **
00502     if (!arg->isPointer())
00503         return "";
00504     const Token* tok = arg->typeEndToken();
00505     tok = tok->previous();
00506     if (tok->str() != "*")
00507         return "";
00508 
00509     // Check if pointer is allocated.
00510     int realloc = 0;
00511     for (tok = func->functionScope->classStart; tok && tok != func->functionScope->classEnd; tok = tok->next()) {
00512         if (tok->varId() == arg->varId()) {
00513             if (Token::Match(tok->tokAt(-3), "free ( * %var% )")) {
00514                 realloc = 1;
00515                 allocType = No;
00516             } else if (Token::Match(tok->previous(), "* %var% =")) {
00517                 allocType = getAllocationType(tok->tokAt(2), arg->varId());
00518                 if (allocType == No) {
00519                     allocType = getReallocationType(tok->tokAt(2), arg->varId());
00520                 }
00521                 if (allocType != No) {
00522                     if (realloc)
00523                         return "realloc";
00524                     return "alloc";
00525                 }
00526             } else {
00527                 // unhandled variable usage: bailout
00528                 return "";
00529             }
00530         }
00531     }
00532 
00533     return "";
00534 }
00535 
00536 
00537 void CheckMemoryLeakInFunction::parse_noreturn()
00538 {
00539     if (noreturn.empty()) {
00540         noreturn.insert("exit");
00541         noreturn.insert("_exit");
00542         noreturn.insert("_Exit");
00543         noreturn.insert("abort");
00544         noreturn.insert("err");
00545         noreturn.insert("verr");
00546         noreturn.insert("errx");
00547         noreturn.insert("verrx");
00548         noreturn.insert("ExitProcess");
00549         noreturn.insert("ExitThread");
00550         noreturn.insert("pthread_exit");
00551     }
00552 
00553     // only check functions
00554     const std::size_t functions = symbolDatabase->functionScopes.size();
00555     for (std::size_t i = 0; i < functions; ++i) {
00556         const Scope * scope = symbolDatabase->functionScopes[i];
00557 
00558         // parse this function to check if it contains an "exit" call..
00559         bool isNoreturn = false;
00560         for (const Token *tok2 = scope->classStart->next(); tok2 != scope->classEnd; tok2 = tok2->next()) {
00561             if (Token::Match(tok2->previous(), "[;{}] exit (")) {
00562                 isNoreturn = true;
00563                 break;
00564             }
00565         }
00566 
00567         // This function is not a noreturn function
00568         if (isNoreturn)
00569             noreturn.insert(scope->className);
00570         else
00571             notnoreturn.insert(scope->className);
00572     }
00573 }
00574 
00575 
00576 bool CheckMemoryLeakInFunction::notvar(const Token *tok, unsigned int varid, bool endpar)
00577 {
00578     const std::string end(endpar ? " &&|)" : " [;)&|]");
00579     return bool(Token::Match(tok, ("! %varid%" + end).c_str(), varid) ||
00580                 Token::Match(tok, ("! ( %varid% )" + end).c_str(), varid));
00581 }
00582 
00583 
00584 
00585 bool CheckMemoryLeakInFunction::test_white_list(const std::string &funcname)
00586 {
00587     return (std::bsearch(funcname.c_str(), call_func_white_list,
00588                          sizeof(call_func_white_list) / sizeof(call_func_white_list[0]),
00589                          sizeof(call_func_white_list[0]), call_func_white_list_compare) != NULL);
00590 }
00591 
00592 const char * CheckMemoryLeakInFunction::call_func(const Token *tok, std::list<const Token *> callstack, const unsigned int varid, AllocType &alloctype, AllocType &dealloctype, bool &allocpar, unsigned int sz)
00593 {
00594     if (test_white_list(tok->str())) {
00595         if (tok->str() == "asprintf" ||
00596             tok->str() == "delete" ||
00597             tok->str() == "fclose" ||
00598             tok->str() == "for" ||
00599             tok->str() == "free" ||
00600             tok->str() == "if" ||
00601             tok->str() == "realloc" ||
00602             tok->str() == "return" ||
00603             tok->str() == "switch" ||
00604             tok->str() == "while") {
00605             return 0;
00606         }
00607 
00608         // is the varid a parameter?
00609         for (const Token *tok2 = tok->tokAt(2); tok2 != tok->linkAt(1); tok2 = tok2->next()) {
00610             if (tok2->str() == "(") {
00611                 tok2 = tok2->nextArgument();
00612                 if (!tok2)
00613                     break;
00614             }
00615             if (tok2->varId() == varid) {
00616                 if (tok->strAt(-1) == ".")
00617                     return "use";
00618                 else if (tok2->strAt(1) == "=")
00619                     return "assign";
00620                 else
00621                     return "use_";
00622             }
00623         }
00624 
00625         return 0;
00626     }
00627 
00628     if (noreturn.find(tok->str()) != noreturn.end() && tok->strAt(-1) != "=")
00629         return "exit";
00630 
00631     if (varid > 0 && (getAllocationType(tok, varid) != No || getReallocationType(tok, varid) != No || getDeallocationType(tok, varid) != No))
00632         return 0;
00633 
00634     if (callstack.size() > 2)
00635         return "dealloc_";
00636 
00637     const std::string& funcname(tok->str());
00638     for (std::list<const Token *>::const_iterator it = callstack.begin(); it != callstack.end(); ++it) {
00639         if ((*it) && (*it)->str() == funcname)
00640             return "recursive";
00641     }
00642     callstack.push_back(tok);
00643 
00644     // lock/unlock..
00645     if (varid == 0) {
00646         const Function* func = tok->function();
00647         if (!func || !func->hasBody)
00648             return 0;
00649 
00650         Token *ftok = getcode(func->functionScope->classStart->next(), callstack, 0, alloctype, dealloctype, false, 1);
00651         simplifycode(ftok);
00652         const char *ret = 0;
00653         if (Token::simpleMatch(ftok, "; alloc ; }"))
00654             ret = "alloc";
00655         else if (Token::simpleMatch(ftok, "; dealloc ; }"))
00656             ret = "dealloc";
00657         TokenList::deleteTokens(ftok);
00658         return ret;
00659     }
00660 
00661     // how many parameters is there in the function call?
00662     unsigned int numpar = countParameters(tok);
00663     if (numpar == 0) {
00664         // Taking return value => it is not a noreturn function
00665         if (tok->strAt(-1) == "=")
00666             return NULL;
00667 
00668         // Function is not noreturn
00669         if (notnoreturn.find(funcname) != notnoreturn.end())
00670             return NULL;
00671 
00672         return "callfunc";
00673     }
00674 
00675     unsigned int par = 0;
00676 
00677     const bool dot(tok->previous()->str() == ".");
00678     const bool eq(tok->previous()->str() == "=");
00679 
00680     const Token *functok = tok;
00681 
00682     tok = Token::findsimplematch(tok, "(");
00683     if (tok)
00684         tok = tok->next();
00685 
00686     for (; tok; tok = tok->nextArgument()) {
00687         ++par;
00688         if (varid > 0 && Token::Match(tok, "%varid% [,()]", varid)) {
00689             if (dot)
00690                 return "use";
00691 
00692             const Function* function = functok->function();
00693             if (!function)
00694                 return "use";
00695 
00696             // how many parameters does the function want?
00697             if (numpar != function->argCount()) // TODO: Handle default parameters
00698                 return "recursive";
00699 
00700             const Variable* param = function->getArgumentVar(par-1);
00701             if (!param || !param->nameToken())
00702                 return "use";
00703             if (!function->functionScope)
00704                 return "use";
00705             Token *func = getcode(function->functionScope->classStart->next(), callstack, param->varId(), alloctype, dealloctype, false, sz);
00706             //simplifycode(func);
00707             const Token *func_ = func;
00708             while (func_ && func_->str() == ";")
00709                 func_ = func_->next();
00710 
00711             const char *ret = 0;
00712             /** @todo handle "goto" */
00713             if (Token::findsimplematch(func_, "dealloc"))
00714                 ret = "dealloc";
00715             else if (Token::findsimplematch(func_, "use"))
00716                 ret = "use";
00717             else if (Token::findsimplematch(func_, "&use"))
00718                 ret = "&use";
00719 
00720             TokenList::deleteTokens(func);
00721             return ret;
00722         }
00723         if (varid > 0 && Token::Match(tok, "& %varid% [,()]", varid)) {
00724             const Function *func = functok->function();
00725             if (func == 0)
00726                 continue;
00727             AllocType a;
00728             const char *ret = functionArgAlloc(func, par, a);
00729 
00730             if (a != No) {
00731                 if (alloctype == No)
00732                     alloctype = a;
00733                 else if (alloctype != a)
00734                     alloctype = Many;
00735                 allocpar = true;
00736                 return ret;
00737             }
00738         }
00739         if (varid > 0 && Token::Match(tok, "%varid% . %var% [,)]", varid))
00740             return "use";
00741     }
00742     return (eq || _settings->experimental) ? 0 : "callfunc";
00743 }
00744 
00745 
00746 static void addtoken(Token **rettail, const Token *tok, const std::string &str)
00747 {
00748     (*rettail)->insertToken(str);
00749     (*rettail) = (*rettail)->next();
00750     (*rettail)->linenr(tok->linenr());
00751     (*rettail)->fileIndex(tok->fileIndex());
00752 }
00753 
00754 
00755 Token *CheckMemoryLeakInFunction::getcode(const Token *tok, std::list<const Token *> callstack, const unsigned int varid, CheckMemoryLeak::AllocType &alloctype, CheckMemoryLeak::AllocType &dealloctype, bool classmember, unsigned int sz)
00756 {
00757     // variables whose value depends on if(!var). If one of these variables
00758     // is used in a if-condition then generate "ifv" instead of "if".
00759     std::set<unsigned int> extravar;
00760 
00761     // The first token should be ";"
00762     Token* rethead = new Token(0);
00763     rethead->str(";");
00764     rethead->linenr(tok->linenr());
00765     rethead->fileIndex(tok->fileIndex());
00766     Token* rettail = rethead;
00767 
00768     int indentlevel = 0;
00769     int parlevel = 0;
00770     for (; tok; tok = tok->next()) {
00771         if (tok->str() == "{") {
00772             addtoken(&rettail, tok, "{");
00773             ++indentlevel;
00774         } else if (tok->str() == "}") {
00775             addtoken(&rettail, tok, "}");
00776             if (indentlevel <= 0)
00777                 break;
00778             --indentlevel;
00779         }
00780 
00781         else if (tok->str() == "(")
00782             ++parlevel;
00783         else if (tok->str() == ")")
00784             --parlevel;
00785 
00786         if (parlevel == 0 && tok->str() == ";")
00787             addtoken(&rettail, tok, ";");
00788 
00789         // Start of new statement.. check if the statement has anything interesting
00790         if (varid > 0 && parlevel == 0 && Token::Match(tok, "[;{}]")) {
00791             if (Token::Match(tok->next(), "[{};]"))
00792                 continue;
00793 
00794             // function calls are interesting..
00795             const Token *tok2 = tok;
00796             while (Token::Match(tok2->next(), "%var% ."))
00797                 tok2 = tok2->tokAt(2);
00798             if (Token::Match(tok2->next(), "%var% ("))
00799                 ;
00800 
00801             else if (Token::Match(tok->next(), "continue|break|return|throw|goto|do|else"))
00802                 ;
00803 
00804             else {
00805                 const Token *skipToToken = 0;
00806 
00807                 // scan statement for interesting keywords / varid
00808                 for (tok2 = tok->next(); tok2; tok2 = tok2->next()) {
00809                     if (tok2->str() == ";") {
00810                         // nothing interesting found => skip this statement
00811                         skipToToken = tok2->previous();
00812                         break;
00813                     }
00814 
00815                     if (tok2->varId() == varid ||
00816                         tok2->str() == ":" || tok2->str() == "{" || tok2->str() == "}") {
00817                         break;
00818                     }
00819                 }
00820 
00821                 if (skipToToken) {
00822                     tok = skipToToken;
00823                     continue;
00824                 }
00825             }
00826         }
00827 
00828         if (varid == 0) {
00829             if (!callstack.empty() && Token::Match(tok, "[;{}] __cppcheck_lock|__cppcheck_unlock ( ) ;")) {
00830                 // Type of leak = Resource leak
00831                 alloctype = dealloctype = CheckMemoryLeak::File;
00832 
00833                 if (tok->next()->str() == "__cppcheck_lock") {
00834                     addtoken(&rettail, tok, "alloc");
00835                 } else {
00836                     addtoken(&rettail, tok, "dealloc");
00837                 }
00838 
00839                 tok = tok->tokAt(3);
00840                 continue;
00841             }
00842 
00843             if (Token::simpleMatch(tok, "if (")) {
00844                 addtoken(&rettail, tok, "if");
00845                 tok = tok->next()->link();
00846                 continue;
00847             }
00848         } else {
00849 
00850             if (Token::Match(tok, "%varid% = close ( %varid% )", varid)) {
00851                 addtoken(&rettail, tok, "dealloc");
00852                 addtoken(&rettail, tok, ";");
00853                 addtoken(&rettail, tok, "assign");
00854                 addtoken(&rettail, tok, ";");
00855                 tok = tok->tokAt(5);
00856                 continue;
00857             }
00858 
00859             // var = strcpy|.. ( var ,
00860             if (Token::Match(tok, "[;{}] %varid% = memcpy|memmove|memset|strcpy|strncpy|strcat|strncat ( %varid% ,", varid)) {
00861                 tok = tok->linkAt(4);
00862                 continue;
00863             }
00864 
00865             if (Token::Match(tok->previous(), "[(;{}] %varid% =", varid) ||
00866                 Token::Match(tok, "asprintf|vasprintf ( & %varid% ,", varid)) {
00867                 CheckMemoryLeak::AllocType alloc;
00868 
00869                 if (Token::Match(tok, "asprintf|vasprintf (")) {
00870                     // todo: check how the return value is used.
00871                     if (!Token::Match(tok->previous(), "[;{}]")) {
00872                         TokenList::deleteTokens(rethead);
00873                         return 0;
00874                     }
00875                     alloc = Malloc;
00876                     tok = tok->next()->link();
00877                 } else {
00878                     alloc = getAllocationType(tok->tokAt(2), varid);
00879                 }
00880                 //bool realloc = false;
00881 
00882                 if (sz > 1 &&
00883                     Token::Match(tok->tokAt(2), "malloc ( %num% )") &&
00884                     (MathLib::toLongNumber(tok->strAt(4)) % long(sz)) != 0) {
00885                     mismatchSizeError(tok->tokAt(4), tok->strAt(4));
00886                 }
00887 
00888                 if (alloc == CheckMemoryLeak::No) {
00889                     alloc = getReallocationType(tok->tokAt(2), varid);
00890                     if (alloc != CheckMemoryLeak::No) {
00891                         addtoken(&rettail, tok, "realloc");
00892                         addtoken(&rettail, tok, ";");
00893                         //TODO: this assignment is redundant, should be fixed
00894                         //realloc = true;
00895                         tok = tok->tokAt(2);
00896                         if (Token::Match(tok, "%var% ("))
00897                             tok = tok->next()->link();
00898                         continue;
00899                     }
00900                 }
00901 
00902                 // don't check classes..
00903                 if (alloc == CheckMemoryLeak::New) {
00904                     if (Token::Match(tok->tokAt(2), "new struct| %type% [(;]")) {
00905                         const int offset = tok->strAt(3) == "struct" ? 1 : 0;
00906                         if (isclass(tok->tokAt(3 + offset), varid)) {
00907                             alloc = No;
00908                         }
00909                     } else if (Token::Match(tok->tokAt(2), "new ( nothrow ) struct| %type%")) {
00910                         const int offset = tok->strAt(6) == "struct" ? 1 : 0;
00911                         if (isclass(tok->tokAt(6 + offset), varid)) {
00912                             alloc = No;
00913                         }
00914                     } else if (Token::Match(tok->tokAt(2), "new ( std :: nothrow ) struct| %type%")) {
00915                         const int offset = tok->strAt(8) == "struct" ? 1 : 0;
00916                         if (isclass(tok->tokAt(8 + offset), varid)) {
00917                             alloc = No;
00918                         }
00919                     }
00920 
00921                     if (alloc == No && alloctype == No)
00922                         alloctype = CheckMemoryLeak::New;
00923                 }
00924 
00925                 if (alloc != No) {
00926                     //if (! realloc)
00927                     addtoken(&rettail, tok, "alloc");
00928 
00929                     if (alloctype != No && alloctype != alloc)
00930                         alloc = Many;
00931 
00932                     if (alloc != Many && dealloctype != No && dealloctype != Many && dealloctype != alloc) {
00933                         callstack.push_back(tok);
00934                         mismatchAllocDealloc(callstack, Token::findmatch(_tokenizer->tokens(), "%varid%", varid)->str());
00935                         callstack.pop_back();
00936                     }
00937 
00938                     alloctype = alloc;
00939 
00940                     if (Token::Match(tok, "%var% = %type% (")) {
00941                         tok = tok->linkAt(3);
00942                         continue;
00943                     }
00944                 }
00945 
00946                 // assignment..
00947                 else {
00948                     // is the pointer in rhs?
00949                     bool rhs = false;
00950                     bool trailingSemicolon = false;
00951                     bool used = false;
00952                     for (const Token *tok2 = tok->next(); tok2; tok2 = tok2->next()) {
00953                         if (tok2->str() == ";") {
00954                             trailingSemicolon = true;
00955                             if (rhs)
00956                                 tok = tok2;
00957                             break;
00958                         }
00959 
00960                         if (!used) {
00961                             if (Token::Match(tok2, "[=+(,] %varid%", varid)) {
00962                                 if (!rhs && Token::Match(tok2, "[(,]")) {
00963                                     used = true;
00964                                     addtoken(&rettail, tok, "use");
00965                                     addtoken(&rettail, tok, ";");
00966                                 }
00967                                 rhs = true;
00968                             }
00969                         }
00970                     }
00971 
00972                     if (!used) {
00973                         if (!rhs)
00974                             addtoken(&rettail, tok, "assign");
00975                         else {
00976                             addtoken(&rettail, tok, "use_");
00977                             if (trailingSemicolon)
00978                                 addtoken(&rettail, tok, ";");
00979                         }
00980                     }
00981                     continue;
00982                 }
00983             }
00984 
00985             if (Token::Match(tok->previous(), "[;{})=|] ::| %var%")) {
00986                 if (Token::Match(tok, "%varid% ?", varid))
00987                     tok = tok->tokAt(2);
00988 
00989                 AllocType dealloc = getDeallocationType(tok, varid);
00990 
00991                 if (dealloc != No && tok->str() == "fcloseall" && alloctype != dealloc)
00992                     //TODO: this assignment is redundant, should be fixed
00993                     /*dealloc = No*/;
00994 
00995                 else if (dealloc != No) {
00996                     addtoken(&rettail, tok, "dealloc");
00997 
00998                     if (dealloctype != No && dealloctype != dealloc)
00999                         dealloc = Many;
01000 
01001                     if (dealloc != Many && alloctype != No && alloctype != Many && alloctype != dealloc) {
01002                         callstack.push_back(tok);
01003                         mismatchAllocDealloc(callstack, Token::findmatch(_tokenizer->tokens(), "%varid%", varid)->str());
01004                         callstack.pop_back();
01005                     }
01006                     dealloctype = dealloc;
01007 
01008                     if (tok->strAt(2) == "(")
01009                         tok = tok->linkAt(2);
01010                     continue;
01011                 }
01012             }
01013 
01014             // if else switch
01015             if (Token::simpleMatch(tok, "if (")) {
01016                 if (alloctype == Fd) {
01017                     if (Token::Match(tok, "if ( 0|-1 <=|< %varid% )", varid) ||
01018                         Token::Match(tok, "if ( %varid% != -1 )", varid)) {
01019                         addtoken(&rettail, tok, "if(var)");
01020                         tok = tok->next()->link();
01021                         continue;
01022                     } else if (Token::Match(tok, "if ( %varid% == -1 )", varid) ||
01023                                Token::Match(tok, "if ( %varid% < 0 )", varid)) {
01024                         addtoken(&rettail, tok, "if(!var)");
01025                         tok = tok->next()->link();
01026                         continue;
01027                     }
01028                 }
01029 
01030                 if (Token::Match(tok, "if ( %varid% )", varid)) {
01031                     addtoken(&rettail, tok, "if(var)");
01032 
01033                     // Make sure the "use" will not be added
01034                     tok = tok->next()->link();
01035                     continue;
01036                 } else if (Token::simpleMatch(tok, "if (") && notvar(tok->tokAt(2), varid, true)) {
01037                     addtoken(&rettail, tok, "if(!var)");
01038 
01039                     // parse the if-body.
01040                     // if a variable is assigned then add variable to "extravar".
01041                     for (const Token *tok2 = tok->next()->link()->tokAt(2); tok2; tok2 = tok2->next()) {
01042                         if (tok2->str() == "{")
01043                             tok2 = tok2->link();
01044                         else if (tok2->str() == "}")
01045                             break;
01046                         else if (Token::Match(tok2, "%var% ="))
01047                             extravar.insert(tok2->varId());
01048                     }
01049 
01050                     tok = tok->next()->link();
01051                     continue;
01052                 } else {
01053                     // Check if the condition depends on var or extravar somehow..
01054                     bool dep = false;
01055                     const Token* const end = tok->linkAt(1);
01056                     for (const Token *tok2 = tok->next(); tok2 != end; tok2 = tok2->next()) {
01057                         if (Token::Match(tok2, "close|pclose|fclose|closedir ( %varid% )", varid)) {
01058                             addtoken(&rettail, tok, "dealloc");
01059                             addtoken(&rettail, tok, ";");
01060                             dep = true;
01061                             break;
01062                         } else if (alloctype == Fd && Token::Match(tok2, "%varid% !=|>=", varid)) {
01063                             dep = true;
01064                         } else if (Token::Match(tok2, "! %varid%", varid)) {
01065                             dep = true;
01066                         } else if (Token::Match(tok2, "%var% (") && !test_white_list(tok2->str())) {
01067                             bool use = false;
01068                             for (const Token *tok3 = tok2->tokAt(2); tok3; tok3 = tok3->nextArgument()) {
01069                                 if (Token::Match(tok3->previous(), "(|, &| %varid% ,|)", varid)) {
01070                                     use = true;
01071                                     break;
01072                                 }
01073                             }
01074                             if (use) {
01075                                 addtoken(&rettail, tok, "use");
01076                                 addtoken(&rettail, tok, ";");
01077                                 dep = false;
01078                                 break;
01079                             }
01080                         } else if (tok2->varId() && extravar.find(tok2->varId()) != extravar.end()) {
01081                             dep = true;
01082                         } else if (tok2->varId() == varid && tok2->next()->isConstOp())
01083                             dep = true;
01084                     }
01085 
01086                     if (Token::Match(tok, "if ( ! %varid% &&", varid)) {
01087                         addtoken(&rettail, tok, "if(!var)");
01088                     } else if (tok->next() &&
01089                                tok->next()->link() &&
01090                                Token::Match(tok->next()->link()->tokAt(-3), "&& ! %varid%", varid)) {
01091                         addtoken(&rettail, tok, "if(!var)");
01092                     } else {
01093                         addtoken(&rettail, tok, (dep ? "ifv" : "if"));
01094                     }
01095 
01096                     tok = tok->next()->link();
01097                     continue;
01098                 }
01099             }
01100         }
01101 
01102         if ((tok->str() == "else") || (tok->str() == "switch")) {
01103             addtoken(&rettail, tok, tok->str());
01104             if (Token::simpleMatch(tok, "switch ("))
01105                 tok = tok->next()->link();
01106             continue;
01107         }
01108 
01109         if ((tok->str() == "case")) {
01110             addtoken(&rettail, tok, "case");
01111             addtoken(&rettail, tok, ";");
01112             if (Token::Match(tok, "case %any% :"))
01113                 tok = tok->tokAt(2);
01114             continue;
01115         }
01116 
01117         if ((tok->str() == "default")) {
01118             addtoken(&rettail, tok, "default");
01119             addtoken(&rettail, tok, ";");
01120             continue;
01121         }
01122 
01123         // Loops..
01124         else if ((tok->str() == "for") || (tok->str() == "while")) {
01125             const Token* const end = tok->linkAt(1);
01126 
01127             if (Token::simpleMatch(tok, "while ( true )") ||
01128                 Token::simpleMatch(tok, "for ( ; ; )")) {
01129                 addtoken(&rettail, tok, "while1");
01130                 tok = end;
01131                 continue;
01132             }
01133 
01134             else if (varid && getDeallocationType(tok->tokAt(2), varid) != No) {
01135                 addtoken(&rettail, tok, "dealloc");
01136                 addtoken(&rettail, tok, ";");
01137             }
01138 
01139             else if (alloctype == Fd && varid) {
01140                 if (Token::Match(tok, "while ( 0 <= %varid% )", varid) ||
01141                     Token::Match(tok, "while ( %varid% != -1 )", varid)) {
01142                     addtoken(&rettail, tok, "while(var)");
01143                     tok = end;
01144                     continue;
01145                 } else if (Token::Match(tok, "while ( %varid% == -1 )", varid) ||
01146                            Token::Match(tok, "while ( %varid% < 0 )", varid)) {
01147                     addtoken(&rettail, tok, "while(!var)");
01148                     tok = end;
01149                     continue;
01150                 }
01151             }
01152 
01153             else if (varid && Token::Match(tok, "while ( %varid% )", varid)) {
01154                 addtoken(&rettail, tok, "while(var)");
01155                 tok = end;
01156                 continue;
01157             } else if (varid && Token::simpleMatch(tok, "while (") && notvar(tok->tokAt(2), varid, true)) {
01158                 addtoken(&rettail, tok, "while(!var)");
01159                 tok = end;
01160                 continue;
01161             }
01162 
01163             addtoken(&rettail, tok, "loop");
01164 
01165             if (varid > 0) {
01166                 for (const Token *tok2 = tok->tokAt(2); tok2 && tok2 != end; tok2 = tok2->next()) {
01167                     if (notvar(tok2, varid)) {
01168                         addtoken(&rettail, tok2, "!var");
01169                         break;
01170                     }
01171                 }
01172             }
01173 
01174             continue;
01175         }
01176         if ((tok->str() == "do")) {
01177             addtoken(&rettail, tok, "do");
01178             continue;
01179         }
01180 
01181         // continue / break..
01182         else if (tok->str() == "continue") {
01183             addtoken(&rettail, tok, "continue");
01184         } else if (tok->str() == "break") {
01185             addtoken(&rettail, tok, "break");
01186         } else if (tok->str() == "goto") {
01187             addtoken(&rettail, tok, "goto");
01188         }
01189 
01190         // Return..
01191         else if (tok->str() == "return") {
01192             addtoken(&rettail, tok, "return");
01193             if (varid == 0) {
01194                 addtoken(&rettail, tok, ";");
01195                 while (tok && tok->str() != ";")
01196                     tok = tok->next();
01197                 if (!tok)
01198                     break;
01199                 continue;
01200             }
01201 
01202             // Returning a auto_ptr of this allocated variable..
01203             if (Token::simpleMatch(tok->next(), "std :: auto_ptr <")) {
01204                 const Token *tok2 = tok->linkAt(4);
01205                 if (Token::Match(tok2, "> ( %varid% )", varid)) {
01206                     addtoken(&rettail, tok, "use");
01207                     tok = tok2->tokAt(3);
01208                 }
01209             }
01210 
01211             else if (varid && Token::Match(tok, "return strcpy|strncpy|memcpy ( %varid%", varid)) {
01212                 addtoken(&rettail, tok, "use");
01213                 tok = tok->tokAt(2);
01214             }
01215 
01216             else {
01217                 bool use = false;
01218 
01219                 std::stack<const Token *> f;
01220 
01221                 for (const Token *tok2 = tok->next(); tok2; tok2 = tok2->next()) {
01222                     if (tok2->str() == ";") {
01223                         tok = tok2;
01224                         break;
01225                     }
01226 
01227                     if (tok2->str() == "(")
01228                         f.push(tok2->previous());
01229                     else if (!f.empty() && tok2->str() == ")")
01230                         f.pop();
01231 
01232                     if (tok2->varId() == varid) {
01233                         // Read data..
01234                         if (!Token::Match(tok2->previous(), "&|(") &&
01235                             tok2->strAt(1) == "[") {
01236                         } else if (f.empty() ||
01237                                    !test_white_list(f.top()->str()) ||
01238                                    getDeallocationType(f.top(),varid)) {
01239                             use = true;
01240                         }
01241                     }
01242                 }
01243                 if (use)
01244                     addtoken(&rettail, tok, "use");
01245                 addtoken(&rettail, tok, ";");
01246             }
01247         }
01248 
01249         // throw..
01250         else if (Token::Match(tok, "try|throw|catch")) {
01251             addtoken(&rettail, tok, tok->str());
01252             if (tok->strAt(1) == "(")
01253                 tok = tok->next()->link();
01254         }
01255 
01256         // Assignment..
01257         if (varid) {
01258             if (Token::simpleMatch(tok, "= {")) {
01259                 const Token* const end2 = tok->linkAt(1);
01260                 bool use = false;
01261                 for (const Token *tok2 = tok; tok2 != end2; tok2 = tok2->next()) {
01262                     if (tok2->varId() == varid) {
01263                         use = true;
01264                         break;
01265                     }
01266                 }
01267 
01268                 if (use) {
01269                     addtoken(&rettail, tok, "use");
01270                     addtoken(&rettail, tok, ";");
01271                     tok = tok->next()->link();
01272                     continue;
01273                 }
01274             }
01275 
01276             if (Token::Match(tok, "& %var% = %varid% ;", varid)) {
01277                 while (rethead->next())
01278                     rethead->deleteNext();
01279                 return rethead;
01280             }
01281             if (Token::Match(tok, "[)=] %varid% [+;)]", varid) ||
01282                 (Token::Match(tok, "%var% + %varid%", varid) &&
01283                  tok->strAt(3) != "[" &&
01284                  tok->strAt(3) != ".") ||
01285                 Token::Match(tok, "<< %varid% ;", varid) ||
01286                 Token::Match(tok, "= strcpy|strcat|memmove|memcpy ( %varid% ,", varid) ||
01287                 Token::Match(tok, "[;{}] %var% [ %varid% ]", varid)) {
01288                 addtoken(&rettail, tok, "use");
01289             } else if (Token::Match(tok->previous(), ";|{|}|=|(|,|%cop% %varid% [", varid) ||
01290                        Token::Match(tok->previous(), ";|{|}|=|(|,|%cop% %varid% .", varid)) {
01291                 // warning is written for "dealloc ; use_ ;".
01292                 // but this use doesn't affect the leak-checking
01293                 addtoken(&rettail, tok, "use_");
01294             }
01295         }
01296 
01297         // Investigate function calls..
01298         if (Token::Match(tok, "%var% (")) {
01299             // A function call should normally be followed by ";"
01300             if (Token::simpleMatch(tok->next()->link(), ") {")) {
01301                 if (!Token::Match(tok, "if|for|while|switch")) {
01302                     addtoken(&rettail, tok, "exit");
01303                     addtoken(&rettail, tok, ";");
01304                     tok = tok->next()->link();
01305                     continue;
01306                 }
01307             }
01308 
01309             // Calling setjmp / longjmp => bail out
01310             else if (Token::Match(tok, "setjmp|longjmp")) {
01311                 while (rethead->next())
01312                     rethead->deleteNext();
01313                 return rethead;
01314             }
01315 
01316             // Inside class function.. if the var is passed as a parameter then
01317             // just add a "::use"
01318             // The "::use" means that a member function was probably called but it wasn't analysed further
01319             else if (classmember) {
01320                 if (noreturn.find(tok->str()) != noreturn.end())
01321                     addtoken(&rettail, tok, "exit");
01322 
01323                 else if (!test_white_list(tok->str())) {
01324                     const Token* const end2 = tok->linkAt(1);
01325                     for (const Token *tok2 = tok->tokAt(2); tok2 != end2; tok2 = tok2->next()) {
01326                         if (tok2->varId() == varid) {
01327                             addtoken(&rettail, tok, "::use");
01328                             break;
01329                         }
01330                     }
01331                 }
01332             }
01333 
01334             else {
01335                 if (varid > 0 && Token::Match(tok, "%var% ( close|fclose|pclose ( %varid% ) ) ;", varid)) {
01336                     addtoken(&rettail, tok, "dealloc");
01337                     tok = tok->next()->link();
01338                     continue;
01339                 }
01340 
01341                 bool allocpar = false;
01342                 const char *str = call_func(tok, callstack, varid, alloctype, dealloctype, allocpar, sz);
01343                 if (str) {
01344                     if (allocpar) {
01345                         addtoken(&rettail, tok, str);
01346                         tok = tok->next()->link();
01347                     } else if (varid == 0 || str != std::string("alloc")) {
01348                         addtoken(&rettail, tok, str);
01349                     } else if (Token::Match(tok->tokAt(-2), "%varid% =", varid)) {
01350                         addtoken(&rettail, tok, str);
01351                     }
01352                 } else if (varid > 0 &&
01353                            getReallocationType(tok, varid) != No &&
01354                            tok->tokAt(2)->varId() == varid) {
01355                     addtoken(&rettail, tok, "if");
01356                     addtoken(&rettail, tok, "{");
01357                     addtoken(&rettail, tok, "dealloc");
01358                     addtoken(&rettail, tok, ";");
01359                     addtoken(&rettail, tok, "}");
01360                     tok = tok->next()->link();
01361                     continue;
01362                 }
01363             }
01364         }
01365 
01366         // Callback..
01367         if (Token::Match(tok, "( *| %var%") && Token::simpleMatch(tok->link(),") (")) {
01368             const Token *tok2 = tok->next();
01369             if (tok2->str() == "*")
01370                 tok2 = tok2->next();
01371             tok2 = tok2->next();
01372 
01373             while (Token::Match(tok2, ". %var%"))
01374                 tok2 = tok2->tokAt(2);
01375 
01376             if (Token::simpleMatch(tok2, ") (")) {
01377                 for (; tok2; tok2 = tok2->next()) {
01378                     if (Token::Match(tok2, "[;{]"))
01379                         break;
01380                     else if (tok2->varId() == varid) {
01381                         addtoken(&rettail, tok, "use");
01382                         break;
01383                     }
01384                 }
01385             }
01386         }
01387 
01388         // Linux lists..
01389         if (varid > 0 && Token::Match(tok, "[=(,] & %varid% [.[,)]", varid)) {
01390             addtoken(&rettail, tok, "&use");
01391         }
01392     }
01393 
01394     for (Token *tok1 = rethead; tok1; tok1 = tok1->next()) {
01395         if (Token::simpleMatch(tok1, "callfunc alloc ;")) {
01396             tok1->deleteThis();
01397             tok1->insertToken("use");
01398             tok1->insertToken(";");
01399         }
01400     }
01401 
01402     return rethead;
01403 }
01404 
01405 
01406 
01407 
01408 
01409 
01410 void CheckMemoryLeakInFunction::simplifycode(Token *tok) const
01411 {
01412     {
01413         // Replace "throw" that is not in a try block with "return"
01414         int indentlevel = 0;
01415         int trylevel = -1;
01416         for (Token *tok2 = tok; tok2; tok2 = tok2->next()) {
01417             if (tok2->str() == "{")
01418                 ++indentlevel;
01419             else if (tok2->str() == "}") {
01420                 --indentlevel;
01421                 if (indentlevel <= trylevel)
01422                     trylevel = -1;
01423             } else if (trylevel == -1 && tok2->str() == "try")
01424                 trylevel = indentlevel;
01425             else if (trylevel == -1 && tok2->str() == "throw")
01426                 tok2->str("return");
01427         }
01428     }
01429 
01430     // Insert extra ";"
01431     for (Token *tok2 = tok; tok2; tok2 = tok2->next()) {
01432         if (!tok2->previous() || Token::Match(tok2->previous(), "[;{}]")) {
01433             if (Token::Match(tok2, "assign|callfunc|use assign|callfunc|use|}")) {
01434                 tok2->insertToken(";");
01435             }
01436         }
01437     }
01438 
01439     // remove redundant braces..
01440     for (Token *start = tok; start; start = start->next()) {
01441         if (Token::simpleMatch(start, "; {")) {
01442             // the "link" doesn't work here. Find the end brace..
01443             unsigned int indent = 0;
01444             for (Token *end = start; end; end = end->next()) {
01445                 if (end->str() == "{")
01446                     ++indent;
01447                 else if (end->str() == "}") {
01448                     if (indent <= 1) {
01449                         // If the start/end braces are redundant, delete them
01450                         if (indent == 1 && Token::Match(end->previous(), "[;{}] } %any%")) {
01451                             start->deleteNext();
01452                             end->deleteThis();
01453                         }
01454                         break;
01455                     }
01456                     --indent;
01457                 }
01458             }
01459         }
01460     }
01461 
01462     // reduce the code..
01463     // it will be reduced in N passes. When a pass completes without any
01464     // simplifications the loop is done.
01465     bool done = false;
01466     while (! done) {
01467         //tok->printOut("simplifycode loop..");
01468         done = true;
01469 
01470         // reduce callfunc
01471         for (Token *tok2 = tok; tok2; tok2 = tok2->next()) {
01472             if (tok2->str() == "callfunc") {
01473                 if (!Token::Match(tok2->previous(), "[;{}] callfunc ; }"))
01474                     tok2->deleteThis();
01475             }
01476         }
01477 
01478         // If the code starts with "if return ;" then remove it
01479         if (Token::Match(tok, ";| if return ;")) {
01480             tok->deleteNext();
01481             tok->deleteThis();
01482             if (tok->str() == "return")
01483                 tok->deleteThis();
01484             if (tok->strAt(1) == "else")
01485                 tok->deleteNext();
01486         }
01487 
01488         // simplify "while1" contents..
01489         for (Token *tok2 = tok; tok2; tok2 = tok2->next()) {
01490             if (Token::simpleMatch(tok2, "while1 {")) {
01491                 unsigned int innerIndentlevel = 0;
01492                 for (Token *tok3 = tok2->tokAt(2); tok3; tok3 = tok3->next()) {
01493                     if (tok3->str() == "{")
01494                         ++innerIndentlevel;
01495                     else if (tok3->str() == "}") {
01496                         if (innerIndentlevel == 0)
01497                             break;
01498                         --innerIndentlevel;
01499                     }
01500                     while (innerIndentlevel == 0 && Token::Match(tok3, "[{};] if|ifv|else { continue ; }")) {
01501                         tok3->deleteNext(5);
01502                         if (tok3->strAt(1) == "else")
01503                             tok3->deleteNext();
01504                     }
01505                 }
01506 
01507                 if (Token::simpleMatch(tok2, "while1 { if { dealloc ; return ; } }")) {
01508                     tok2->str(";");
01509                     tok2->deleteNext(3);
01510                     tok2->tokAt(4)->deleteNext(2);
01511                 }
01512             }
01513         }
01514 
01515         // Main inner simplification loop
01516         for (Token *tok2 = tok; tok2; tok2 = tok2 ? tok2->next() : NULL) {
01517             // Delete extra ";"
01518             while (Token::Match(tok2, "[;{}] ;")) {
01519                 tok2->deleteNext();
01520                 done = false;
01521             }
01522 
01523             // Replace "{ }" with ";"
01524             if (Token::simpleMatch(tok2->next(), "{ }")) {
01525                 tok2->deleteNext(2);
01526                 tok2->insertToken(";");
01527                 done = false;
01528             }
01529 
01530             // Delete braces around a single instruction..
01531             if (Token::Match(tok2->next(), "{ %var% ; }")) {
01532                 tok2->deleteNext();
01533                 tok2->tokAt(2)->deleteNext();
01534                 done = false;
01535             }
01536             if (Token::Match(tok2->next(), "{ %var% %var% ; }")) {
01537                 tok2->deleteNext();
01538                 tok2->tokAt(3)->deleteNext();
01539                 done = false;
01540             }
01541 
01542             // Reduce "if if|callfunc" => "if"
01543             else if (Token::Match(tok2, "if if|callfunc")) {
01544                 tok2->deleteNext();
01545                 done = false;
01546             }
01547 
01548             // outer/inner if blocks. Remove outer condition..
01549             else if (Token::Match(tok2->next(), "if|if(var) { if return use ; }")) {
01550                 tok2->deleteNext(2);
01551                 tok2->tokAt(4)->deleteNext();
01552                 done = false;
01553             }
01554 
01555             else if (tok2->next() && tok2->next()->str() == "if") {
01556                 // Delete empty if that is not followed by an else
01557                 if (Token::Match(tok2->next(), "if ; !!else")) {
01558                     tok2->deleteNext();
01559                     done = false;
01560                 }
01561 
01562                 // Reduce "if X ; else X ;" => "X ;"
01563                 else if (Token::Match(tok2->next(), "if %var% ; else %var% ;") &&
01564                          tok2->strAt(2) == tok2->strAt(5)) {
01565                     tok2->deleteNext(4);
01566                     done = false;
01567                 }
01568 
01569                 // Reduce "if continue ; if continue ;" => "if continue ;"
01570                 else if (Token::simpleMatch(tok2->next(), "if continue ; if continue ;")) {
01571                     tok2->deleteNext(3);
01572                     done = false;
01573                 }
01574 
01575                 // Reduce "if return ; alloc ;" => "alloc ;"
01576                 else if (Token::Match(tok2, "[;{}] if return ; alloc|return ;")) {
01577                     tok2->deleteNext(3);
01578                     done = false;
01579                 }
01580 
01581                 // "[;{}] if alloc ; else return ;" => "[;{}] alloc ;"
01582                 else if (Token::Match(tok2, "[;{}] if alloc ; else return ;")) {
01583                     // Remove "if"
01584                     tok2->deleteNext();
01585                     // Remove "; else return"
01586                     tok2->next()->deleteNext(3);
01587                     done = false;
01588                 }
01589 
01590                 // Reduce "if ; else %var% ;" => "if %var% ;"
01591                 else if (Token::Match(tok2->next(), "if ; else %var% ;")) {
01592                     tok2->next()->deleteNext(2);
01593                     done = false;
01594                 }
01595 
01596                 // Reduce "if ; else" => "if"
01597                 else if (Token::simpleMatch(tok2->next(), "if ; else")) {
01598                     tok2->next()->deleteNext(2);
01599                     done = false;
01600                 }
01601 
01602                 // Reduce "if return ; else|if return|continue ;" => "if return ;"
01603                 else if (Token::Match(tok2->next(), "if return ; else|if return|continue|break ;")) {
01604                     tok2->tokAt(3)->deleteNext(3);
01605                     done = false;
01606                 }
01607 
01608                 // Reduce "if continue|break ; else|if return ;" => "if return ;"
01609                 else if (Token::Match(tok2->next(), "if continue|break ; if|else return ;")) {
01610                     tok2->next()->deleteNext(3);
01611                     done = false;
01612                 }
01613 
01614                 // Remove "else" after "if continue|break|return"
01615                 else if (Token::Match(tok2->next(), "if continue|break|return ; else")) {
01616                     tok2->tokAt(3)->deleteNext();
01617                     done = false;
01618                 }
01619 
01620                 // Delete "if { dealloc|assign|use ; return ; }"
01621                 else if (Token::Match(tok2, "[;{}] if { dealloc|assign|use ; return ; }") &&
01622                          !Token::findmatch(tok, "if {| alloc ;")) {
01623                     tok2->deleteNext(7);
01624                     if (tok2->strAt(1) == "else")
01625                         tok2->deleteNext();
01626                     done = false;
01627                 }
01628 
01629                 // Remove "if { dealloc ; callfunc ; } !!else|return"
01630                 else if (Token::Match(tok2->next(), "if { dealloc|assign ; callfunc ; }") &&
01631                          !Token::Match(tok2->tokAt(8), "else|return")) {
01632                     tok2->deleteNext(7);
01633                     done = false;
01634                 }
01635 
01636                 continue;
01637             }
01638 
01639             // Reduce "alloc while(!var) alloc ;" => "alloc ;"
01640             if (Token::Match(tok2, "[;{}] alloc ; while(!var) alloc ;")) {
01641                 tok2->deleteNext(3);
01642                 done = false;
01643             }
01644 
01645             // Reduce "ifv return;" => "if return use;"
01646             if (Token::simpleMatch(tok2, "ifv return ;")) {
01647                 tok2->str("if");
01648                 tok2->next()->insertToken("use");
01649                 done = false;
01650             }
01651 
01652             // Reduce "if(var) dealloc ;" and "if(var) use ;" that is not followed by an else..
01653             if (Token::Match(tok2, "[;{}] if(var) assign|dealloc|use ; !!else")) {
01654                 tok2->deleteNext();
01655                 done = false;
01656             }
01657 
01658             // Reduce "; if(!var) alloc ; !!else" => "; dealloc ; alloc ;"
01659             if (Token::Match(tok2, "; if(!var) alloc ; !!else")) {
01660                 // Remove the "if(!var)"
01661                 tok2->deleteNext();
01662 
01663                 // Insert "dealloc ;" before the "alloc ;"
01664                 tok2->insertToken(";");
01665                 tok2->insertToken("dealloc");
01666 
01667                 done = false;
01668             }
01669 
01670             // Reduce "if(!var) exit ;" => ";"
01671             if (Token::simpleMatch(tok2, "; if(!var) exit ;")) {
01672                 tok2->deleteNext(2);
01673                 done = false;
01674             }
01675 
01676             // Reduce "if* ;"..
01677             if (Token::Match(tok2->next(), "if(var)|if(!var)|ifv ;")) {
01678                 // Followed by else..
01679                 if (tok2->strAt(3) == "else") {
01680                     tok2 = tok2->next();
01681                     if (tok2->str() == "if(var)")
01682                         tok2->str("if(!var)");
01683                     else if (tok2->str() == "if(!var)")
01684                         tok2->str("if(var)");
01685 
01686                     // remove the "; else"
01687                     tok2->deleteNext(2);
01688                 } else {
01689                     // remove the "if*"
01690                     tok2->deleteNext();
01691                 }
01692                 done = false;
01693             }
01694 
01695             // Reduce "else ;" => ";"
01696             if (Token::simpleMatch(tok2->next(), "else ;")) {
01697                 tok2->deleteNext();
01698                 done = false;
01699             }
01700 
01701             // Reduce "while1 continue| ;" => "use ;"
01702             if (Token::Match(tok2, "while1 if| continue| ;")) {
01703                 tok2->str("use");
01704                 while (tok2->strAt(1) != ";")
01705                     tok2->deleteNext();
01706                 done = false;
01707             }
01708 
01709             // Reduce "while1 if break ;" => ";"
01710             if (Token::simpleMatch(tok2, "while1 if break ;")) {
01711                 tok2->str(";");
01712                 tok2->deleteNext(2);
01713                 done = false;
01714             }
01715 
01716             // Delete if block: "alloc; if return use ;"
01717             if (Token::Match(tok2, "alloc ; if return use ; !!else")) {
01718                 tok2->deleteNext(4);
01719                 done = false;
01720             }
01721 
01722             // Reduce "alloc|dealloc|use|callfunc ; exit ;" => "; exit ;"
01723             if (Token::Match(tok2, "[;{}] alloc|dealloc|use|callfunc ; exit ;")) {
01724                 tok2->deleteNext();
01725                 done = false;
01726             }
01727 
01728             // Reduce "alloc|dealloc|use ; if(var) exit ;"
01729             if (Token::Match(tok2, "alloc|dealloc|use ; if(var) exit ;")) {
01730                 tok2->deleteThis();
01731                 done = false;
01732             }
01733 
01734             // Remove "if exit ;"
01735             if (Token::simpleMatch(tok2, "if exit ;")) {
01736                 tok2->deleteNext();
01737                 tok2->deleteThis();
01738                 done = false;
01739             }
01740 
01741             // Remove the "if break|continue ;" that follows "dealloc ; alloc ;"
01742             if (! _settings->experimental && Token::Match(tok2, "dealloc ; alloc ; if break|continue ;")) {
01743                 tok2->tokAt(3)->deleteNext(2);
01744                 done = false;
01745             }
01746 
01747             // if break ; break ; => break ;
01748             if (Token::Match(tok2->previous(), "[;{}] if break ; break ;")) {
01749                 tok2->deleteNext(3);
01750                 done = false;
01751             }
01752 
01753             // Reduce "do { dealloc ; alloc ; } while(var) ;" => ";"
01754             if (Token::simpleMatch(tok2->next(), "do { dealloc ; alloc ; } while(var) ;")) {
01755                 tok2->deleteNext(8);
01756                 done = false;
01757             }
01758 
01759             // Reduce "do { alloc ; } " => "alloc ;"
01760             /** @todo If the loop "do { alloc ; }" can be executed twice, reduce it to "loop alloc ;" */
01761             if (Token::simpleMatch(tok2->next(), "do { alloc ; }")) {
01762                 tok2->deleteNext(2);
01763                 tok2->tokAt(2)->deleteNext();
01764                 done = false;
01765             }
01766 
01767             // Reduce "loop break ; => ";"
01768             if (Token::Match(tok2->next(), "loop break|continue ;")) {
01769                 tok2->deleteNext(2);
01770                 done = false;
01771             }
01772 
01773             // Reduce "loop|do ;" => ";"
01774             if (Token::Match(tok2, "loop|do ;")) {
01775                 tok2->deleteThis();
01776                 done = false;
01777             }
01778 
01779             // Reduce "loop if break|continue ; !!else" => ";"
01780             if (Token::Match(tok2->next(), "loop if break|continue ; !!else")) {
01781                 tok2->deleteNext(3);
01782                 done = false;
01783             }
01784 
01785             // Reduce "loop { if break|continue ; !!else" => "loop {"
01786             if (Token::Match(tok2, "loop { if break|continue ; !!else")) {
01787                 tok2->next()->deleteNext(3);
01788                 done = false;
01789             }
01790 
01791             // Replace "do ; loop ;" with ";"
01792             if (Token::simpleMatch(tok2, "; loop ;")) {
01793                 tok2->deleteNext(2);
01794                 done = false;
01795             }
01796 
01797             // Replace "loop loop .." with "loop .."
01798             if (Token::simpleMatch(tok2, "loop loop")) {
01799                 tok2->deleteThis();
01800                 done = false;
01801             }
01802 
01803             // Replace "loop if return ;" with "if return ;"
01804             if (Token::simpleMatch(tok2->next(), "loop if return")) {
01805                 tok2->deleteNext();
01806                 done = false;
01807             }
01808 
01809             // Reduce "loop|while1 { dealloc ; alloc ; }"
01810             if (Token::Match(tok2, "loop|while1 { dealloc ; alloc ; }")) {
01811                 // delete "{"
01812                 tok2->deleteNext();
01813                 // delete "loop|while1"
01814                 tok2->deleteThis();
01815 
01816                 // delete "}"
01817                 tok2->tokAt(3)->deleteNext();
01818 
01819                 done = false;
01820             }
01821 
01822             // loop { use ; callfunc ; }  =>  use ;
01823             // assume that the "callfunc" is not noreturn
01824             if (Token::simpleMatch(tok2, "loop { use ; callfunc ; }")) {
01825                 tok2->deleteNext(6);
01826                 tok2->str("use");
01827                 tok2->insertToken(";");
01828                 done = false;
01829             }
01830 
01831             // Delete if block in "alloc ; if(!var) return ;"
01832             if (Token::simpleMatch(tok2, "alloc ; if(!var) return ;")) {
01833                 tok2->deleteNext(3);
01834                 done = false;
01835             }
01836 
01837             // Reduce "[;{}] return use ; %var%" => "[;{}] return use ;"
01838             if (Token::Match(tok2, "[;{}] return use ; %var%")) {
01839                 tok2->tokAt(3)->deleteNext();
01840                 done = false;
01841             }
01842 
01843             // Reduce "if(var) return use ;" => "return use ;"
01844             if (Token::Match(tok2->next(), "if(var) return use ; !!else")) {
01845                 tok2->deleteNext();
01846                 done = false;
01847             }
01848 
01849             // malloc - realloc => alloc ; dealloc ; alloc ;
01850             // Reduce "[;{}] alloc ; dealloc ; alloc ;" => "[;{}] alloc ;"
01851             if (Token::Match(tok2, "[;{}] alloc ; dealloc ; alloc ;")) {
01852                 tok2->deleteNext(4);
01853                 done = false;
01854             }
01855 
01856             // use; dealloc; => dealloc;
01857             if (Token::Match(tok2, "[;{}] use ; dealloc ;")) {
01858                 tok2->deleteNext(2);
01859                 done = false;
01860             }
01861 
01862             // use use => use
01863             while (Token::simpleMatch(tok2, "use use")) {
01864                 tok2->deleteNext();
01865                 done = false;
01866             }
01867 
01868             // use use_ => use
01869             if (Token::simpleMatch(tok2, "use use_")) {
01870                 tok2->deleteNext();
01871                 done = false;
01872             }
01873 
01874             // use_ use => use
01875             if (Token::simpleMatch(tok2, "use_ use")) {
01876                 tok2->deleteThis();
01877                 done = false;
01878             }
01879 
01880             // use & use => use
01881             while (Token::simpleMatch(tok2, "use & use")) {
01882                 tok2->deleteNext(2);
01883                 done = false;
01884             }
01885 
01886             // & use use => use
01887             while (Token::simpleMatch(tok2, "& use use")) {
01888                 tok2->deleteThis();
01889                 tok2->deleteThis();
01890                 done = false;
01891             }
01892 
01893             // use; if| use; => use;
01894             while (Token::Match(tok2, "[;{}] use ; if| use ;")) {
01895                 Token *t = tok2->tokAt(2);
01896                 t->deleteNext(2+(t->str()=="if" ? 1 : 0));
01897                 done = false;
01898             }
01899 
01900             // Delete first part in "use ; return use ;"
01901             if (Token::Match(tok2, "[;{}] use ; return use ;")) {
01902                 tok2->deleteNext(2);
01903                 done = false;
01904             }
01905 
01906             // try/catch
01907             if (Token::simpleMatch(tok2, "try ; catch exit ;")) {
01908                 tok2->deleteNext(3);
01909                 tok2->deleteThis();
01910                 done = false;
01911             }
01912 
01913             // Delete second case in "case ; case ;"
01914             while (Token::simpleMatch(tok2, "case ; case ;")) {
01915                 tok2->deleteNext(2);
01916                 done = false;
01917             }
01918 
01919             // Replace switch with if (if not complicated)
01920             if (Token::simpleMatch(tok2, "switch {")) {
01921                 // Right now, I just handle if there are a few case and perhaps a default.
01922                 bool valid = false;
01923                 bool incase = false;
01924                 for (const Token * _tok = tok2->tokAt(2); _tok; _tok = _tok->next()) {
01925                     if (_tok->str() == "{")
01926                         break;
01927 
01928                     else if (_tok->str() == "}") {
01929                         valid = true;
01930                         break;
01931                     }
01932 
01933                     else if (_tok->str() == "switch")
01934                         break;
01935 
01936                     else if (_tok->str() == "loop")
01937                         break;
01938 
01939                     else if (incase && _tok->str() == "case")
01940                         break;
01941 
01942                     else if (Token::Match(_tok, "return !!;"))
01943                         break;
01944 
01945                     if (Token::Match(_tok, "if return|break use| ;"))
01946                         _tok = _tok->tokAt(2);
01947 
01948                     incase |= (_tok->str() == "case");
01949                     incase &= (_tok->str() != "break" && _tok->str() != "return");
01950                 }
01951 
01952                 if (!incase && valid) {
01953                     done = false;
01954                     tok2->str(";");
01955                     tok2->deleteNext();
01956                     tok2 = tok2->next();
01957                     bool first = true;
01958                     while (Token::Match(tok2, "case|default")) {
01959                         const bool def(tok2->str() == "default");
01960                         tok2->str(first ? "if" : "}");
01961                         if (first) {
01962                             first = false;
01963                             tok2->insertToken("{");
01964                         } else {
01965                             // Insert "else [if] {
01966                             tok2->insertToken("{");
01967                             if (! def)
01968                                 tok2->insertToken("if");
01969                             tok2->insertToken("else");
01970                             tok2 = tok2->next();
01971                         }
01972                         while (tok2) {
01973                             if (tok2->str() == "}")
01974                                 break;
01975                             if (Token::Match(tok2, "break|return ;"))
01976                                 break;
01977                             if (Token::Match(tok2, "if return|break use| ;"))
01978                                 tok2 = tok2->tokAt(2);
01979                             else
01980                                 tok2 = tok2->next();
01981                         }
01982                         if (Token::simpleMatch(tok2, "break ;")) {
01983                             tok2->str(";");
01984                             tok2 = tok2->tokAt(2);
01985                         } else if (tok2 && tok2->str() == "return") {
01986                             tok2 = tok2->tokAt(2);
01987                         }
01988                     }
01989                 }
01990             }
01991         }
01992 
01993         // If "--all" is given, remove all "callfunc"..
01994         if (done && _settings->experimental) {
01995             for (Token *tok2 = tok; tok2; tok2 = tok2->next()) {
01996                 if (tok2->str() == "callfunc") {
01997                     tok2->deleteThis();
01998                     done = false;
01999                 }
02000             }
02001         }
02002     }
02003 }
02004 
02005 
02006 
02007 
02008 
02009 const Token *CheckMemoryLeakInFunction::findleak(const Token *tokens)
02010 {
02011     const Token *result;
02012 
02013     if ((result = Token::findsimplematch(tokens, "loop alloc ;")) != NULL) {
02014         return result;
02015     }
02016 
02017     if (Token::Match(tokens, "alloc ; if|if(var)|ifv break|continue|return ;")) {
02018         return tokens->tokAt(3);
02019     }
02020 
02021     if ((result = Token::findmatch(tokens, "alloc ; if|if(var)|ifv return ;")) != NULL) {
02022         return result->tokAt(3);
02023     }
02024 
02025     if ((result = Token::findmatch(tokens, "alloc ; alloc|assign|return callfunc| ;")) != NULL) {
02026         return result->tokAt(2);
02027     }
02028 
02029     if ((result = Token::findsimplematch(tokens, "; alloc ; if assign ;")) != NULL) {
02030         return result->tokAt(4);
02031     }
02032 
02033     if (((result = Token::findsimplematch(tokens, "; alloc ; if dealloc ; }")) != NULL) &&
02034         !result->tokAt(7)) {
02035         return result->tokAt(6);
02036     }
02037 
02038     if ((result = Token::findsimplematch(tokens, "alloc ; }")) != NULL) {
02039         if (result->tokAt(3) == NULL)
02040             return result->tokAt(2);
02041     }
02042 
02043     // No deallocation / usage => report leak at the last token
02044     if (!Token::findmatch(tokens, "dealloc|use")) {
02045         const Token *last = tokens;
02046         while (last->next())
02047             last = last->next();
02048 
02049         // not a leak if exit is called before the end of the function
02050         if (!Token::Match(last->tokAt(-2), "exit|callfunc ; }"))
02051             return last;
02052     }
02053 
02054     return NULL;
02055 }
02056 
02057 
02058 
02059 
02060 
02061 
02062 // Check for memory leaks for a function variable.
02063 void CheckMemoryLeakInFunction::checkScope(const Token *Tok1, const std::string &varname, unsigned int varid, bool classmember, unsigned int sz)
02064 {
02065     std::list<const Token *> callstack;
02066 
02067     AllocType alloctype = No;
02068     AllocType dealloctype = No;
02069 
02070     const Token *result;
02071 
02072     Token *tok = getcode(Tok1, callstack, varid, alloctype, dealloctype, classmember, sz);
02073     //tok->printOut((std::string("Checkmemoryleak: getcode result for: ") + varname).c_str());
02074 
02075     const bool use_addr = bool(Token::findsimplematch(tok, "&use") != NULL);
02076 
02077     // Simplify the code and check if freed memory is used..
02078     for (Token *tok2 = tok; tok2; tok2 = tok2->next()) {
02079         while (Token::Match(tok2, "[;{}] ;"))
02080             tok2->deleteNext();
02081     }
02082     if ((result = Token::findmatch(tok, "[;{}] dealloc ; use_ ;")) != NULL) {
02083         deallocuseError(result->tokAt(3), varname);
02084     }
02085 
02086     // Replace "&use" with "use". Replace "use_" with ";"
02087     for (Token *tok2 = tok; tok2; tok2 = tok2->next()) {
02088         if (tok2->str() == "&use")
02089             tok2->str("use");
02090         else if (tok2->str() == "use_")
02091             tok2->str(";");
02092         else if (Token::simpleMatch(tok2, "loop use_ {"))
02093             tok2->deleteNext();
02094         else if (tok2->str() == "::use")    // Some kind of member function usage. Not analyzed very well.
02095             tok2->str("use");
02096         else if (tok2->str() == "recursive")
02097             tok2->str("use");
02098         else if (tok2->str() == "dealloc_")
02099             tok2->str("dealloc");
02100         else if (tok2->str() == "realloc") {
02101             tok2->str("dealloc");
02102             tok2->insertToken("alloc");
02103             tok2->insertToken(";");
02104         }
02105     }
02106 
02107     // If the variable is not allocated at all => no memory leak
02108     if (Token::findsimplematch(tok, "alloc") == 0) {
02109         TokenList::deleteTokens(tok);
02110         return;
02111     }
02112 
02113     simplifycode(tok);
02114 
02115     if (_settings->debug && _settings->_verbose) {
02116         tok->printOut(("Checkmemoryleak: simplifycode result for: " + varname).c_str());
02117     }
02118 
02119     // If the variable is not allocated at all => no memory leak
02120     if (Token::findsimplematch(tok, "alloc") == 0) {
02121         TokenList::deleteTokens(tok);
02122         return;
02123     }
02124 
02125     /** @todo handle "goto" */
02126     if (Token::findsimplematch(tok, "goto")) {
02127         TokenList::deleteTokens(tok);
02128         return;
02129     }
02130 
02131     if ((result = findleak(tok)) != NULL) {
02132         memoryLeak(result, varname, alloctype);
02133     }
02134 
02135     else if (!use_addr && (result = Token::findsimplematch(tok, "dealloc ; dealloc ;")) != NULL) {
02136         deallocDeallocError(result->tokAt(2), varname);
02137     }
02138 
02139     // detect cases that "simplifycode" don't handle well..
02140     else if (_settings->debugwarnings) {
02141         Token *first = tok;
02142         while (first && first->str() == ";")
02143             first = first->next();
02144 
02145         bool noerr = false;
02146         noerr |= Token::simpleMatch(first, "alloc ; }");
02147         noerr |= Token::simpleMatch(first, "alloc ; dealloc ; }");
02148         noerr |= Token::simpleMatch(first, "alloc ; return use ; }");
02149         noerr |= Token::simpleMatch(first, "alloc ; use ; }");
02150         noerr |= Token::simpleMatch(first, "alloc ; use ; return ; }");
02151         noerr |= Token::simpleMatch(first, "alloc ; dealloc ; return ; }");
02152         noerr |= Token::simpleMatch(first, "if alloc ; dealloc ; }");
02153         noerr |= Token::simpleMatch(first, "if alloc ; return use ; }");
02154         noerr |= Token::simpleMatch(first, "if alloc ; use ; }");
02155         noerr |= Token::simpleMatch(first, "alloc ; ifv return ; dealloc ; }");
02156         noerr |= Token::simpleMatch(first, "alloc ; if return ; dealloc; }");
02157 
02158         // Unhandled case..
02159         if (!noerr && tok) {
02160             std::ostringstream errmsg;
02161             errmsg << "inconclusive leak of " << varname << ": ";
02162             errmsg << tok->stringifyList(false, false, false, false, false, 0, 0);
02163             reportError(first, Severity::debug, "debug", errmsg.str());
02164         }
02165     }
02166 
02167     TokenList::deleteTokens(tok);
02168 }
02169 //---------------------------------------------------------------------------
02170 
02171 
02172 
02173 
02174 
02175 //---------------------------------------------------------------------------
02176 // Check for memory leaks due to improper realloc() usage.
02177 //   Below, "a" may be set to null without being freed if realloc() cannot
02178 //   allocate the requested memory:
02179 //     a = malloc(10); a = realloc(a, 100);
02180 //---------------------------------------------------------------------------
02181 static bool isNoArgument(const SymbolDatabase* symbolDatabase, unsigned int varid)
02182 {
02183     const Variable* var = symbolDatabase->getVariableFromVarId(varid);
02184     return var && !var->isArgument();
02185 }
02186 
02187 void CheckMemoryLeakInFunction::checkReallocUsage()
02188 {
02189     // only check functions
02190     const std::size_t functions = symbolDatabase->functionScopes.size();
02191     for (std::size_t i = 0; i < functions; ++i) {
02192         const Scope * scope = symbolDatabase->functionScopes[i];
02193 
02194         // Search for the "var = realloc(var, 100" pattern within this function
02195         for (const Token *tok = scope->classStart->next(); tok != scope->classEnd; tok = tok->next()) {
02196             if (tok->varId() > 0 &&
02197                 Token::Match(tok, "%var% = realloc|g_try_realloc ( %var% , %any%") &&
02198                 tok->varId() == tok->tokAt(4)->varId() &&
02199                 isNoArgument(symbolDatabase, tok->varId())) {
02200                 // Check that another copy of the pointer wasn't saved earlier in the function
02201                 if (Token::findmatch(scope->classStart, "%var% = %varid% ;", tok, tok->varId()) ||
02202                     Token::findmatch(scope->classStart, "[{};] %varid% = %var% [;=]", tok, tok->varId()))
02203                     continue;
02204 
02205                 const Token* tokEndRealloc = tok->linkAt(3);
02206                 // Check that the allocation isn't followed immediately by an 'if (!var) { error(); }' that might handle failure
02207                 if (Token::Match(tokEndRealloc->next(), "; if ( ! %varid% ) {", tok->varId())) {
02208                     const Token* tokEndBrace = tokEndRealloc->linkAt(7);
02209                     if (tokEndBrace && Token::simpleMatch(tokEndBrace->tokAt(-2), ") ;") &&
02210                         Token::Match(tokEndBrace->linkAt(-2)->tokAt(-2), "{|}|; %var% ("))
02211                         continue;
02212                 }
02213 
02214                 memleakUponReallocFailureError(tok, tok->str());
02215             } else if (tok->next()->varId() > 0 &&
02216                        (Token::Match(tok, "* %var% = realloc|g_try_realloc ( * %var% , %any%") &&
02217                         tok->next()->varId() == tok->tokAt(6)->varId()) &&
02218                        isNoArgument(symbolDatabase, tok->next()->varId())) {
02219                 // Check that another copy of the pointer wasn't saved earlier in the function
02220                 if (Token::findmatch(scope->classStart, "%var% = * %varid% ;", tok, tok->next()->varId()) ||
02221                     Token::findmatch(scope->classStart, "[{};] * %varid% = %var% [;=]", tok, tok->next()->varId()))
02222                     continue;
02223 
02224                 const Token* tokEndRealloc = tok->linkAt(4);
02225                 // Check that the allocation isn't followed immediately by an 'if (!var) { error(); }' that might handle failure
02226                 if (Token::Match(tokEndRealloc->next(), "; if ( ! * %varid% ) {", tok->next()->varId())) {
02227                     const Token* tokEndBrace = tokEndRealloc->linkAt(8);
02228                     if (tokEndBrace && Token::simpleMatch(tokEndBrace->tokAt(-2), ") ;") &&
02229                         Token::Match(tokEndBrace->linkAt(-2)->tokAt(-2), "{|}|; %var% ("))
02230                         continue;
02231                 }
02232                 memleakUponReallocFailureError(tok->next(), tok->strAt(1));
02233             }
02234         }
02235     }
02236 }
02237 //---------------------------------------------------------------------------
02238 
02239 
02240 
02241 
02242 
02243 
02244 //---------------------------------------------------------------------------
02245 // Checks for memory leaks inside function..
02246 //---------------------------------------------------------------------------
02247 
02248 static bool isInMemberFunc(const Scope* scope)
02249 {
02250     while (scope->nestedIn && !scope->functionOf)
02251         scope = scope->nestedIn;
02252 
02253     return (scope->functionOf != 0);
02254 }
02255 
02256 void CheckMemoryLeakInFunction::check()
02257 {
02258     // fill the "noreturn"
02259     parse_noreturn();
02260 
02261     // Check locking/unlocking of global resources..
02262     const std::size_t functions = symbolDatabase->functionScopes.size();
02263     for (std::size_t i = 0; i < functions; ++i) {
02264         const Scope * scope = symbolDatabase->functionScopes[i];
02265 
02266         checkScope(scope->classStart->next(), "", 0, scope->functionOf != NULL, 1);
02267     }
02268 
02269     // Check variables..
02270     for (unsigned int i = 0; i < symbolDatabase->getVariableListSize(); i++) {
02271         const Variable* var = symbolDatabase->getVariableFromVarId(i);
02272         if (!var || (!var->isLocal() && !var->isArgument()) || var->isStatic() || !var->scope())
02273             continue;
02274 
02275         if (var->isReference())
02276             continue;
02277 
02278         if (!var->isPointer() && var->typeStartToken()->str() != "int")
02279             continue;
02280 
02281         // check for known class without implementation (forward declaration)
02282         if (var->isPointer() && var->type() && !var->typeScope())
02283             continue;
02284 
02285         unsigned int sz = _tokenizer->sizeOfType(var->typeStartToken());
02286         if (sz < 1)
02287             sz = 1;
02288 
02289         if (var->isArgument())
02290             checkScope(var->scope()->classStart->next(), var->name(), i, isInMemberFunc(var->scope()), sz);
02291         else
02292             checkScope(var->nameToken(), var->name(), i, isInMemberFunc(var->scope()), sz);
02293     }
02294 }
02295 //---------------------------------------------------------------------------
02296 
02297 
02298 
02299 
02300 
02301 
02302 
02303 
02304 
02305 
02306 
02307 
02308 
02309 
02310 
02311 
02312 
02313 
02314 
02315 
02316 
02317 
02318 
02319 
02320 
02321 
02322 
02323 
02324 
02325 //---------------------------------------------------------------------------
02326 // Checks for memory leaks in classes..
02327 //---------------------------------------------------------------------------
02328 
02329 
02330 
02331 void CheckMemoryLeakInClass::check()
02332 {
02333     const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase();
02334 
02335     // only check classes and structures
02336     const std::size_t classes = symbolDatabase->classAndStructScopes.size();
02337     for (std::size_t i = 0; i < classes; ++i) {
02338         const Scope * scope = symbolDatabase->classAndStructScopes[i];
02339         std::list<Variable>::const_iterator var;
02340         for (var = scope->varlist.begin(); var != scope->varlist.end(); ++var) {
02341             if (!var->isStatic() && var->isPointer()) {
02342                 // allocation but no deallocation of private variables in public function..
02343                 const Token *tok = var->typeStartToken();
02344                 if (tok->isStandardType()) {
02345                     if (var->isPrivate())
02346                         checkPublicFunctions(&(*scope), var->nameToken());
02347 
02348                     variable(&(*scope), var->nameToken());
02349                 }
02350 
02351                 // known class?
02352                 else if (var->type()) {
02353                     // not derived?
02354                     if (var->type()->derivedFrom.empty()) {
02355                         if (var->isPrivate())
02356                             checkPublicFunctions(&(*scope), var->nameToken());
02357 
02358                         variable(&(*scope), var->nameToken());
02359                     }
02360                 }
02361             }
02362         }
02363     }
02364 }
02365 
02366 
02367 void CheckMemoryLeakInClass::variable(const Scope *scope, const Token *tokVarname)
02368 {
02369     const std::string& varname = tokVarname->str();
02370     const unsigned int varid = tokVarname->varId();
02371     const std::string& classname = scope->className;
02372 
02373     // Check if member variable has been allocated and deallocated..
02374     CheckMemoryLeak::AllocType Alloc = CheckMemoryLeak::No;
02375     CheckMemoryLeak::AllocType Dealloc = CheckMemoryLeak::No;
02376 
02377     bool allocInConstructor = false;
02378     bool deallocInDestructor = false;
02379 
02380     // Inspect member functions
02381     std::list<Function>::const_iterator func;
02382     for (func = scope->functionList.begin(); func != scope->functionList.end(); ++func) {
02383         const bool constructor = func->type == Function::eConstructor;
02384         const bool destructor = func->type == Function::eDestructor;
02385         if (!func->hasBody) {
02386             if (destructor) { // implementation for destructor is not seen => assume it deallocates all variables properly
02387                 deallocInDestructor = true;
02388                 Dealloc = CheckMemoryLeak::Many;
02389             }
02390             continue;
02391         }
02392         bool body = false;
02393         const Token *end = func->functionScope->classEnd;
02394         for (const Token *tok = func->arg->link(); tok != end; tok = tok->next()) {
02395             if (tok == func->functionScope->classStart)
02396                 body = true;
02397             else {
02398                 if (!body) {
02399                     if (!Token::Match(tok, ":|, %varid% (", varid))
02400                         continue;
02401                 }
02402 
02403                 // Allocate..
02404                 if (!body || Token::Match(tok, "%varid% =", varid)) {
02405                     // var1 = var2 = ...
02406                     // bail out
02407                     if (tok->strAt(-1) == "=")
02408                         return;
02409 
02410                     // Foo::var1 = ..
02411                     // bail out when not same class
02412                     if (tok->strAt(-1) == "::" &&
02413                         tok->strAt(-2) != scope->className)
02414                         return;
02415 
02416                     AllocType alloc = getAllocationType(tok->tokAt(body ? 2 : 3), 0);
02417                     if (alloc != CheckMemoryLeak::No) {
02418                         if (constructor)
02419                             allocInConstructor = true;
02420 
02421                         if (Alloc != No && Alloc != alloc)
02422                             alloc = CheckMemoryLeak::Many;
02423 
02424                         std::list<const Token *> callstack;
02425                         if (alloc != CheckMemoryLeak::Many && Dealloc != CheckMemoryLeak::No && Dealloc != CheckMemoryLeak::Many && Dealloc != alloc) {
02426                             callstack.push_back(tok);
02427                             mismatchAllocDealloc(callstack, classname + "::" + varname);
02428                         }
02429 
02430                         Alloc = alloc;
02431                     }
02432                 }
02433 
02434                 if (!body)
02435                     continue;
02436 
02437                 // Deallocate..
02438                 AllocType dealloc = getDeallocationType(tok, varname);
02439                 if (dealloc == No) {
02440                     std::string temp = scope->className + " :: " + varname;
02441                     dealloc = getDeallocationType(tok, temp);
02442                 }
02443                 if (dealloc == No) {
02444                     std::string temp = "this . " + varname;
02445                     dealloc = getDeallocationType(tok, temp);
02446                 }
02447                 // some usage in the destructor => assume it's related
02448                 // to deallocation
02449                 if (destructor && tok->str() == varname)
02450                     dealloc = CheckMemoryLeak::Many;
02451                 if (dealloc != CheckMemoryLeak::No) {
02452                     if (destructor)
02453                         deallocInDestructor = true;
02454 
02455                     // several types of allocation/deallocation?
02456                     if (Dealloc != CheckMemoryLeak::No && Dealloc != dealloc)
02457                         dealloc = CheckMemoryLeak::Many;
02458 
02459                     std::list<const Token *> callstack;
02460                     if (dealloc != CheckMemoryLeak::Many && Alloc != CheckMemoryLeak::No &&  Alloc != Many && Alloc != dealloc) {
02461                         callstack.push_back(tok);
02462                         mismatchAllocDealloc(callstack, classname + "::" + varname);
02463                     }
02464 
02465                     Dealloc = dealloc;
02466                 }
02467 
02468                 // Function call .. possible deallocation
02469                 else if (Token::Match(tok->previous(), "[{};] %var% (")) {
02470                     if (!CheckMemoryLeakInFunction::test_white_list(tok->str())) {
02471                         return;
02472                     }
02473                 }
02474             }
02475         }
02476     }
02477 
02478     if (allocInConstructor && !deallocInDestructor) {
02479         unsafeClassError(tokVarname, classname, classname + "::" + varname /*, Alloc*/);
02480     } else if (Alloc != CheckMemoryLeak::No && Dealloc == CheckMemoryLeak::No) {
02481         unsafeClassError(tokVarname, classname, classname + "::" + varname /*, Alloc*/);
02482     }
02483 }
02484 
02485 void CheckMemoryLeakInClass::unsafeClassError(const Token *tok, const std::string &classname, const std::string &varname)
02486 {
02487     reportError(tok, Severity::style, "unsafeClassCanLeak",
02488                 "Class '" + classname + "' is unsafe, '" + varname + "' can leak by wrong usage.\n"
02489                 "The class '" + classname + "' is unsafe, wrong usage can cause memory/resource leaks for '" + varname + "'. This can for instance be fixed by adding proper cleanup in the destructor.");
02490 }
02491 
02492 
02493 void CheckMemoryLeakInClass::checkPublicFunctions(const Scope *scope, const Token *classtok)
02494 {
02495     // Check that public functions deallocate the pointers that they allocate.
02496     // There is no checking how these functions are used and therefore it
02497     // isn't established if there is real leaks or not.
02498     if (!_settings->isEnabled("warning"))
02499         return;
02500 
02501     const unsigned int varid = classtok->varId();
02502     if (varid == 0) {
02503         _tokenizer->getSymbolDatabase()->debugMessage(classtok, "CheckMemoryInClass::checkPublicFunctions found variable \'" + classtok->str() + "\' with varid 0");
02504         return;
02505     }
02506 
02507     // Parse public functions..
02508     // If they allocate member variables, they should also deallocate
02509     std::list<Function>::const_iterator func;
02510 
02511     for (func = scope->functionList.begin(); func != scope->functionList.end(); ++func) {
02512         if ((func->type == Function::eFunction || func->type == Function::eOperatorEqual) &&
02513             func->access == Public && func->hasBody) {
02514             const Token *tok2 = func->token;
02515             while (tok2->str() != "{")
02516                 tok2 = tok2->next();
02517             if (Token::Match(tok2, "{|}|; %varid% =", varid)) {
02518                 const CheckMemoryLeak::AllocType alloc = getAllocationType(tok2->tokAt(3), varid);
02519                 if (alloc != CheckMemoryLeak::No)
02520                     publicAllocationError(tok2, tok2->strAt(1));
02521             } else if (Token::Match(tok2, "{|}|; %type% :: %varid% =", varid) &&
02522                        tok2->next()->str() == scope->className) {
02523                 const CheckMemoryLeak::AllocType alloc = getAllocationType(tok2->tokAt(5), varid);
02524                 if (alloc != CheckMemoryLeak::No)
02525                     publicAllocationError(tok2, tok2->strAt(3));
02526             }
02527         }
02528     }
02529 }
02530 
02531 void CheckMemoryLeakInClass::publicAllocationError(const Token *tok, const std::string &varname)
02532 {
02533     reportError(tok, Severity::warning, "publicAllocationError", "Possible leak in public function. The pointer '" + varname + "' is not deallocated before it is allocated.");
02534 }
02535 
02536 
02537 void CheckMemoryLeakStructMember::check()
02538 {
02539     const SymbolDatabase* symbolDatabase = _tokenizer->getSymbolDatabase();
02540     for (unsigned int i = 0; i < symbolDatabase->getVariableListSize(); i++) {
02541         const Variable* var = symbolDatabase->getVariableFromVarId(i);
02542         if (!var || !var->isLocal() || var->isStatic())
02543             continue;
02544         if (var->typeEndToken()->isStandardType())
02545             continue;
02546         checkStructVariable(var);
02547     }
02548 }
02549 
02550 bool CheckMemoryLeakStructMember::isMalloc(const Variable *variable)
02551 {
02552     const unsigned int varid(variable->varId());
02553     bool alloc = false;
02554     for (const Token *tok2 = variable->nameToken(); tok2 != variable->scope()->classEnd; tok2 = tok2->next()) {
02555         if (Token::Match(tok2, "= %varid% [;=]", varid)) {
02556             return false;
02557         } else if (Token::Match(tok2, "%varid% = malloc|kmalloc (", varid)) {
02558             alloc = true;
02559         }
02560     }
02561     return alloc;
02562 }
02563 
02564 
02565 void CheckMemoryLeakStructMember::checkStructVariable(const Variable * const variable)
02566 {
02567     // This should be in the CheckMemoryLeak base class
02568     static std::set<std::string> ignoredFunctions;
02569     if (ignoredFunctions.empty()) {
02570         ignoredFunctions.insert("if");
02571         ignoredFunctions.insert("for");
02572         ignoredFunctions.insert("while");
02573         ignoredFunctions.insert("malloc");
02574     }
02575 
02576     // Is struct variable a pointer?
02577     if (variable->isPointer()) {
02578         // Check that variable is allocated with malloc
02579         if (!isMalloc(variable))
02580             return;
02581     } else if (!_tokenizer->isC()) {
02582         // For non-C code a destructor might cleanup members
02583         return;
02584     }
02585 
02586     // Check struct..
02587     unsigned int indentlevel2 = 0;
02588     for (const Token *tok2 = variable->nameToken(); tok2 != variable->scope()->classEnd; tok2 = tok2->next()) {
02589         if (tok2->str() == "{")
02590             ++indentlevel2;
02591 
02592         else if (tok2->str() == "}") {
02593             if (indentlevel2 == 0)
02594                 break;
02595             --indentlevel2;
02596         }
02597 
02598         // Unknown usage of struct
02599         /** @todo Check how the struct is used. Only bail out if necessary */
02600         else if (Token::Match(tok2, "[(,] %varid% [,)]", variable->varId()))
02601             break;
02602 
02603         // Struct member is allocated => check if it is also properly deallocated..
02604         else if (Token::Match(tok2->previous(), "[;{}] %varid% . %var% = malloc|strdup|kmalloc (", variable->varId())) {
02605             const unsigned int structid(variable->varId());
02606             const unsigned int structmemberid(tok2->tokAt(2)->varId());
02607 
02608             // This struct member is allocated.. check that it is deallocated
02609             unsigned int indentlevel3 = indentlevel2;
02610             for (const Token *tok3 = tok2; tok3; tok3 = tok3->next()) {
02611                 if (tok3->str() == "{")
02612                     ++indentlevel3;
02613 
02614                 else if (tok3->str() == "}") {
02615                     if (indentlevel3 == 0) {
02616                         memoryLeak(tok3, variable->name() + "." + tok2->strAt(2), Malloc);
02617                         break;
02618                     }
02619                     --indentlevel3;
02620                 }
02621 
02622                 // Deallocating the struct member..
02623                 else if (Token::Match(tok3, "free|kfree ( %var% . %varid% )", structmemberid)) {
02624                     // If the deallocation happens at the base level, don't check this member anymore
02625                     if (indentlevel3 == 0)
02626                         break;
02627 
02628                     // deallocating and then returning from function in a conditional block =>
02629                     // skip ahead out of the block
02630                     bool ret = false;
02631                     while (tok3) {
02632                         if (tok3->str() == "return")
02633                             ret = true;
02634                         else if (tok3->str() == "{" || tok3->str() == "}")
02635                             break;
02636                         tok3 = tok3->next();
02637                     }
02638                     if (!ret || !tok3 || tok3->str() != "}")
02639                         break;
02640                     --indentlevel3;
02641                     continue;
02642                 }
02643 
02644                 // Deallocating the struct..
02645                 else if (indentlevel2 == 0 && Token::Match(tok3, "free|kfree ( %varid% )", structid)) {
02646                     memoryLeak(tok3, variable->name() + "." + tok2->strAt(2), Malloc);
02647                     break;
02648                 }
02649 
02650                 // failed allocation => skip code..
02651                 else if (Token::Match(tok3, "if ( ! %var% . %varid% )", structmemberid)) {
02652                     // Goto the ")"
02653                     tok3 = tok3->next()->link();
02654 
02655                     // make sure we have ") {".. it should be
02656                     if (!Token::simpleMatch(tok3, ") {"))
02657                         break;
02658 
02659                     // Goto the "}"
02660                     tok3 = tok3->next()->link();
02661                 }
02662 
02663                 // succeeded allocation
02664                 else if (Token::Match(tok3, "if ( %var% . %varid% ) {", structmemberid)) {
02665                     // goto the ")"
02666                     tok3 = tok3->next()->link();
02667 
02668                     // check if the variable is deallocated or returned..
02669                     unsigned int indentlevel4 = 0;
02670                     for (const Token *tok4 = tok3; tok4; tok4 = tok4->next()) {
02671                         if (tok4->str() == "{")
02672                             ++indentlevel4;
02673                         else if (tok4->str() == "}") {
02674                             --indentlevel4;
02675                             if (indentlevel4 == 0)
02676                                 break;
02677                         } else if (Token::Match(tok4, "free|kfree ( %var% . %varid% )", structmemberid)) {
02678                             break;
02679                         }
02680                     }
02681 
02682                     // was there a proper deallocation?
02683                     if (indentlevel4 > 0)
02684                         break;
02685                 }
02686 
02687                 // Returning from function..
02688                 else if (tok3->str() == "return") {
02689                     // Returning from function without deallocating struct member?
02690                     if (!Token::Match(tok3, "return %varid% ;", structid) &&
02691                         !Token::Match(tok3, "return & %varid% .", structid)) {
02692                         memoryLeak(tok3, variable->name() + "." + tok2->strAt(2), Malloc);
02693                     }
02694                     break;
02695                 }
02696 
02697                 // struct assignment..
02698                 else if (Token::Match(tok3, "= %varid% ;", structid)) {
02699                     break;
02700                 } else if (Token::Match(tok3, "= %var% . %varid% ;", structmemberid)) {
02701                     break;
02702                 }
02703 
02704                 // goto isn't handled well.. bail out even though there might be leaks
02705                 else if (tok3->str() == "goto")
02706                     break;
02707 
02708                 // using struct in a function call..
02709                 else if (Token::Match(tok3, "%var% (")) {
02710                     // Calling non-function / function that doesn't deallocate?
02711                     if (ignoredFunctions.find(tok3->str()) != ignoredFunctions.end())
02712                         continue;
02713 
02714                     // Check if the struct is used..
02715                     bool deallocated = false;
02716                     const Token* const end4 = tok3->linkAt(1);
02717                     for (const Token *tok4 = tok3; tok4 != end4; tok4 = tok4->next()) {
02718                         if (Token::Match(tok4, "[(,] &| %varid% [,)]", structid)) {
02719                             /** @todo check if the function deallocates the memory */
02720                             deallocated = true;
02721                             break;
02722                         }
02723 
02724                         if (Token::Match(tok4, "[(,] &| %varid% . %var% [,)]", structid)) {
02725                             /** @todo check if the function deallocates the memory */
02726                             deallocated = true;
02727                             break;
02728                         }
02729                     }
02730 
02731                     if (deallocated)
02732                         break;
02733                 }
02734             }
02735         }
02736     }
02737 }
02738 
02739 
02740 
02741 #include "checkuninitvar.h" // CheckUninitVar::analyse
02742 
02743 void CheckMemoryLeakNoVar::check()
02744 {
02745     std::set<std::string> uvarFunctions;
02746     {
02747         const CheckUninitVar c(_tokenizer, _settings, _errorLogger);
02748         c.analyse(_tokenizer->tokens(), uvarFunctions);
02749     }
02750 
02751     const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase();
02752 
02753     // only check functions
02754     const std::size_t functions = symbolDatabase->functionScopes.size();
02755     for (std::size_t i = 0; i < functions; ++i) {
02756         const Scope * scope = symbolDatabase->functionScopes[i];
02757 
02758         // goto the "}" that ends the executable scope..
02759         const Token *tok = scope->classEnd;
02760 
02761         // parse the executable scope until tok is reached...
02762         for (const Token *tok2 = tok->link(); tok2 && tok2 != tok; tok2 = tok2->next()) {
02763             // allocating memory in parameter for function call..
02764             if (Token::Match(tok2, "[(,] %var% (") && Token::Match(tok2->linkAt(2), ") [,)]")) {
02765                 const AllocType allocType = getAllocationType(tok2->next(), 0);
02766                 if (allocType != No) {
02767                     // locate outer function call..
02768                     for (const Token *tok3 = tok2; tok3; tok3 = tok3->previous()) {
02769                         if (tok3->str() == "(") {
02770                             // Is it a function call..
02771                             if (Token::Match(tok3->tokAt(-2), "[;{}] %var% (")) {
02772                                 const std::string& functionName = tok3->strAt(-1);
02773                                 if (functionName == "delete" ||
02774                                     functionName == "free" ||
02775                                     functionName == "fclose" ||
02776                                     functionName == "realloc")
02777                                     break;
02778                                 if (CheckMemoryLeakInFunction::test_white_list(functionName)) {
02779                                     functionCallLeak(tok2, tok2->strAt(1), functionName);
02780                                     break;
02781                                 }
02782                                 if (uvarFunctions.find(functionName) != uvarFunctions.end()) {
02783                                     functionCallLeak(tok2, tok2->strAt(1), functionName);
02784                                     break;
02785                                 }
02786                             }
02787                             break;
02788                         } else if (tok3->str() == ")")
02789                             tok3 = tok3->link();
02790                         else if (Token::Match(tok3, "[;{}]"))
02791                             break;
02792                     }
02793                 }
02794             }
02795         }
02796     }
02797 }
02798 
02799 void CheckMemoryLeakNoVar::functionCallLeak(const Token *loc, const std::string &alloc, const std::string &functionCall)
02800 {
02801     reportError(loc, Severity::error, "leakNoVarFunctionCall", "Allocation with " + alloc + ", " + functionCall + " doesn't release it.");
02802 }