Branch data Line data Source code
1 : : /*
2 : : * Cppcheck - A tool for static C/C++ code analysis
3 : : * Copyright (C) 2007-2013 Daniel Marjamäki and Cppcheck team.
4 : : *
5 : : * This program is free software: you can redistribute it and/or modify
6 : : * it under the terms of the GNU General Public License as published by
7 : : * the Free Software Foundation, either version 3 of the License, or
8 : : * (at your option) any later version.
9 : : *
10 : : * This program is distributed in the hope that it will be useful,
11 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 : : * GNU General Public License for more details.
14 : : *
15 : : * You should have received a copy of the GNU General Public License
16 : : * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 : : */
18 : :
19 : :
20 : : #include "checkmemoryleak.h"
21 : : #include "symboldatabase.h"
22 : : #include "mathlib.h"
23 : : #include "tokenize.h"
24 : :
25 : : #include <algorithm>
26 : : #include <cstring>
27 : : #include <cstdlib>
28 : : #include <sstream>
29 : : #include <set>
30 : : #include <stack>
31 : :
32 : : //---------------------------------------------------------------------------
33 : :
34 : : // Register this check class (by creating a static instance of it)
35 : : namespace {
36 : 45 : CheckMemoryLeakInFunction instance1;
37 : 45 : CheckMemoryLeakInClass instance2;
38 : 45 : CheckMemoryLeakStructMember instance3;
39 : 45 : CheckMemoryLeakNoVar instance4;
40 : : }
41 : :
42 : : /**
43 : : * Count function parameters
44 : : * \param tok Function name token before the '('
45 : : */
46 : 5580 : static unsigned int countParameters(const Token *tok)
47 : : {
48 : 5580 : tok = tok->tokAt(2);
49 [ + + ]: 5580 : if (tok->str() == ")")
50 : 1485 : return 0;
51 : :
52 : 4095 : unsigned int numpar = 1;
53 [ + + ]: 5760 : while (NULL != (tok = tok->nextArgument()))
54 : 1665 : numpar++;
55 : :
56 : 5580 : return numpar;
57 : : }
58 : :
59 : :
60 : : /** List of functions that can be ignored when searching for memory leaks.
61 : : * These functions don't take the address of the given pointer
62 : : * This list needs to be alphabetically sorted so we can run bsearch on it.
63 : : * This list contains function names with const parameters e.g.: atof(const char *)
64 : : * Reference: http://www.aquaphoenix.com/ref/gnu_c_library/libc_492.html#SEC492
65 : : */
66 : : static const char * const call_func_white_list[] = {
67 : : "_open", "_wopen", "access", "adjtime", "asctime", "asctime_r", "asprintf", "assert"
68 : : , "atof", "atoi", "atol", "chdir", "chmod", "chown"
69 : : , "clearerr", "creat", "ctime", "ctime_r", "delete", "execl", "execle"
70 : : , "execlp", "execv", "execve", "fchmod", "fclose", "fcntl"
71 : : , "fdatasync", "feof", "ferror", "fflush", "fgetc", "fgetpos", "fgets"
72 : : , "flock", "fmemopen", "fnmatch", "fopen", "fopencookie", "for", "fprintf", "fputc", "fputs", "fread", "free"
73 : : , "freopen", "fscanf", "fseek", "fseeko", "fsetpos", "fstat", "fsync", "ftell", "ftello"
74 : : , "ftruncate", "fwrite", "getc", "getenv","getgrnam", "gethostbyaddr", "gethostbyname", "getnetbyname"
75 : : , "getopt", "getopt_long", "getprotobyname", "getpwnam", "gets", "getservbyname", "getservbyport"
76 : : , "glob", "gmtime", "gmtime_r", "if", "index", "inet_addr", "inet_aton", "inet_network", "initgroups", "ioctl"
77 : : , "link", "localtime", "localtime_r"
78 : : , "lockf", "lseek", "lstat", "mblen", "mbstowcs", "mbtowc", "memchr", "memcmp", "memcpy", "memmove", "memset"
79 : : , "mkdir", "mkfifo", "mknod", "mkstemp"
80 : : , "obstack_printf", "obstack_vprintf", "open", "opendir", "parse_printf_format", "pathconf"
81 : : , "perror", "popen" ,"posix_fadvise", "posix_fallocate", "pread"
82 : : , "printf", "psignal", "puts", "pwrite", "qsort", "read", "readahead", "readdir", "readdir_r"
83 : : , "readlink", "readv"
84 : : , "realloc", "regcomp", "remove", "rename", "return", "rewind", "rewinddir", "rindex"
85 : : , "rmdir" ,"scandir", "scanf", "seekdir"
86 : : , "setbuf", "setbuffer", "sethostname", "setlinebuf", "setlocale" ,"setvbuf", "sizeof" ,"snprintf", "sprintf", "sscanf"
87 : : , "stat", "stpcpy", "strcasecmp", "strcat", "strchr", "strcmp", "strcoll"
88 : : , "strcpy", "strcspn", "strdup", "stricmp", "strlen", "strncasecmp", "strncat", "strncmp"
89 : : , "strncpy", "strpbrk","strrchr", "strspn", "strstr", "strtod", "strtok", "strtol", "strtoul", "strxfrm", "switch"
90 : : , "symlink", "sync_file_range", "system", "telldir", "tempnam", "time", "typeid", "unlink"
91 : : , "utime", "utimes", "vasprintf", "vfprintf", "vfscanf", "vprintf"
92 : : , "vscanf", "vsnprintf", "vsprintf", "vsscanf", "while", "wordexp","write", "writev"
93 : : };
94 : :
95 : : extern "C"
96 : : {
97 : : int call_func_white_list_compare(const void *a, const void *b);
98 : :
99 : 340308 : int call_func_white_list_compare(const void *a, const void *b)
100 : : {
101 : 340308 : return std::strcmp((const char *)a, *(const char * const *)b);
102 : : }
103 : : }
104 : :
105 : : //---------------------------------------------------------------------------
106 : :
107 : 765 : bool CheckMemoryLeak::isclass(const Token *tok, unsigned int varid) const
108 : : {
109 [ + + ]: 765 : if (tok->isStandardType())
110 : 270 : return false;
111 : :
112 : 495 : const Variable * var = tokenizer->getSymbolDatabase()->getVariableFromVarId(varid);
113 : :
114 : : // return false if the type is a simple record type without side effects
115 : : // a type that has no side effects (no constructors and no members with constructors)
116 : : /** @todo false negative: check base class for side effects */
117 : : /** @todo false negative: check constructors for side effects */
118 [ + - ][ + + ]: 990 : if (var && var->typeScope() && var->typeScope()->numConstructors == 0 &&
[ + + + +
+ - + - ]
[ + + ]
119 : 270 : (var->typeScope()->varlist.empty() || var->type()->needInitialization == Type::True) &&
120 : 225 : var->type()->derivedFrom.empty())
121 : 225 : return false;
122 : :
123 : 765 : return true;
124 : : }
125 : : //---------------------------------------------------------------------------
126 : :
127 : 27621 : CheckMemoryLeak::AllocType CheckMemoryLeak::getAllocationType(const Token *tok2, unsigned int varid, std::list<const Function*> *callstack) const
128 : : {
129 : : // What we may have...
130 : : // * var = (char *)malloc(10);
131 : : // * var = new char[10];
132 : : // * var = strdup("hello");
133 : : // * var = strndup("hello", 3);
134 [ + - ][ - + ]: 27621 : if (tok2 && tok2->str() == "(") {
[ - + ]
135 : 0 : tok2 = tok2->link();
136 [ # # ]: 0 : tok2 = tok2 ? tok2->next() : NULL;
137 : : }
138 [ - + ]: 27621 : if (! tok2)
139 : 0 : return No;
140 [ + + ]: 27621 : if (! tok2->isName())
141 : 1620 : return No;
142 : :
143 [ + + ]: 26001 : if (!Token::Match(tok2, "%type%|%var% ::|. %type%")) {
144 : : // Does tok2 point on "malloc", "strdup" or "kmalloc"..
145 : : static const char * const mallocfunc[] = {
146 : : "malloc",
147 : : "calloc",
148 : : "strdup",
149 : : "strndup",
150 : : "kmalloc",
151 : : "kzalloc",
152 : : "kcalloc"
153 : : };
154 [ + + ]: 164016 : for (unsigned int i = 0; i < sizeof(mallocfunc)/sizeof(*mallocfunc); i++) {
155 [ + + ]: 144486 : if (tok2->str() == mallocfunc[i])
156 : 6381 : return Malloc;
157 : : }
158 : :
159 : : // Using realloc..
160 [ + + ][ + + ]: 19530 : if (varid && Token::Match(tok2, "realloc ( %any% ,") && tok2->tokAt(2)->varId() != varid)
[ + + ][ + + ]
161 : 360 : return Malloc;
162 : :
163 : : // Does tok2 point on "g_malloc", "g_strdup", ..
164 : : static const char * const gmallocfunc[] = {
165 : : "g_new",
166 : : "g_new0",
167 : : "g_try_new",
168 : : "g_try_new0",
169 : : "g_malloc",
170 : : "g_malloc0",
171 : : "g_try_malloc",
172 : : "g_try_malloc0",
173 : : "g_strdup",
174 : : "g_strndup",
175 : : "g_strdup_printf"
176 : : };
177 [ + + ]: 229860 : for (unsigned int i = 0; i < sizeof(gmallocfunc)/sizeof(*gmallocfunc); i++) {
178 [ + + ]: 210780 : if (tok2->str() == gmallocfunc[i])
179 : 90 : return gMalloc;
180 : : }
181 : :
182 [ + + + + : 53370 : if (Token::Match(tok2, "new struct| %type% [;()]") ||
+ + ][ + + ]
183 : 17235 : Token::Match(tok2, "new ( std :: nothrow ) struct| %type% [;()]") ||
184 : 17055 : Token::Match(tok2, "new ( nothrow ) struct| %type% [;()]"))
185 : 2160 : return New;
186 : :
187 [ + + + + : 38970 : if (Token::Match(tok2, "new struct| %type% [") ||
+ + ][ + + ]
188 : 11115 : Token::Match(tok2, "new ( std :: nothrow ) struct| %type% [") ||
189 : 10935 : Token::Match(tok2, "new ( nothrow ) struct| %type% ["))
190 : 6030 : return NewArray;
191 : :
192 [ + + ]: 10890 : if (Token::Match(tok2, "fopen|tmpfile|g_fopen ("))
193 : 900 : return File;
194 : :
195 [ + + ]: 9990 : if (standards.posix) {
196 [ + + ]: 9855 : if (Token::Match(tok2, "open|openat|creat|mkstemp|mkostemp (")) {
197 : : // simple sanity check of function parameters..
198 : : // TODO: Make such check for all these functions
199 : 1080 : unsigned int num = countParameters(tok2);
200 [ + + ][ + + ]: 1080 : if (tok2->str() == "open" && num != 2 && num != 3)
[ + - ][ + + ]
201 : 135 : return No;
202 : :
203 : : // is there a user function with this name?
204 [ + - ][ + - ]: 945 : if (tokenizer && Token::findmatch(tokenizer->tokens(), ("%type% *|&| " + tok2->str()).c_str()))
[ + - ][ + - ]
[ - + ][ + - ]
[ - + ][ # # ]
205 : 0 : return No;
206 : 945 : return Fd;
207 : : }
208 : :
209 [ + + ]: 8775 : if (Token::simpleMatch(tok2, "popen ("))
210 : 135 : return Pipe;
211 : :
212 [ + + ]: 8640 : if (Token::Match(tok2, "opendir|fdopendir ("))
213 : 360 : return Dir;
214 : : }
215 : :
216 : : }
217 : :
218 [ + + ]: 8595 : while (Token::Match(tok2,"%type%|%var% ::|. %type%"))
219 : 90 : tok2 = tok2->tokAt(2);
220 : :
221 : : // User function
222 : 8505 : const Function* func = tok2->function();
223 [ + + ]: 8505 : if (func == NULL)
224 : 5355 : return No;
225 : :
226 : : // Prevent recursion
227 [ + + ][ + + ]: 3150 : if (callstack && std::find(callstack->begin(), callstack->end(), func) != callstack->end())
[ + + ]
228 : 360 : return No;
229 : :
230 : 2790 : std::list<const Function*> cs;
231 [ + + ]: 2790 : if (!callstack)
232 : 2700 : callstack = &cs;
233 : :
234 [ + - ]: 2790 : callstack->push_back(func);
235 [ + - ]: 27621 : return functionReturnType(func, callstack);
236 : : }
237 : :
238 : :
239 : :
240 : :
241 : 14490 : CheckMemoryLeak::AllocType CheckMemoryLeak::getReallocationType(const Token *tok2, unsigned int varid) const
242 : : {
243 : : // What we may have...
244 : : // * var = (char *)realloc(..;
245 [ + - ][ - + ]: 14490 : if (tok2 && tok2->str() == "(") {
[ - + ]
246 : 0 : tok2 = tok2->link();
247 [ # # ]: 0 : tok2 = tok2 ? tok2->next() : NULL;
248 : : }
249 [ - + ]: 14490 : if (! tok2)
250 : 0 : return No;
251 : :
252 [ + - ][ + + ]: 14490 : if (varid > 0 && ! Token::Match(tok2, "%var% ( %varid% [,)]", varid))
[ + + ]
253 : 12060 : return No;
254 : :
255 [ + + ]: 2430 : if (tok2->str() == "realloc")
256 : 675 : return Malloc;
257 : :
258 : : // GTK memory reallocation..
259 [ - + ]: 1755 : if (Token::Match(tok2, "g_realloc|g_try_realloc|g_renew|g_try_renew"))
260 : 0 : return gMalloc;
261 : :
262 : 14490 : return No;
263 : : }
264 : :
265 : :
266 : 63940 : CheckMemoryLeak::AllocType CheckMemoryLeak::getDeallocationType(const Token *tok, unsigned int varid) const
267 : : {
268 [ + + ]: 63940 : if (Token::Match(tok, "delete %varid% ;", varid))
269 : 765 : return New;
270 : :
271 [ + + ]: 63175 : if (Token::Match(tok, "delete [ ] %varid% ;", varid))
272 : 3060 : return NewArray;
273 : :
274 [ - + ]: 60115 : if (Token::Match(tok, "delete ( %varid% ) ;", varid))
275 : 0 : return New;
276 : :
277 [ + + ]: 60115 : if (Token::Match(tok, "delete [ ] ( %varid% ) ;", varid))
278 : 45 : return NewArray;
279 : :
280 [ + - ][ + + ]: 60070 : if (tok && tok->str() == "::")
[ + + ]
281 : 45 : tok = tok->next();
282 : :
283 [ + + + + : 175530 : if (Token::Match(tok, "free|kfree ( %varid% ) [;:]", varid) ||
+ + ][ + + ]
284 : 57775 : Token::Match(tok, "free|kfree ( %varid% -", varid) ||
285 : 57685 : Token::Match(tok, "realloc ( %varid% , 0 ) ;", varid))
286 : 2475 : return Malloc;
287 : :
288 [ + + - + ]: 115145 : if (Token::Match(tok, "g_free ( %varid% ) ;", varid) ||
[ + + ]
289 : 57550 : Token::Match(tok, "g_free ( %varid% -", varid))
290 : 45 : return gMalloc;
291 : :
292 [ + + + + ]: 114560 : if (Token::Match(tok, "fclose ( %varid% )", varid) ||
[ + + ]
293 : 57010 : Token::simpleMatch(tok, "fcloseall ( )"))
294 : 765 : return File;
295 : :
296 [ + + ]: 56785 : if (Token::Match(tok, "close ( %varid% )", varid))
297 : 585 : return Fd;
298 : :
299 [ + + ]: 56200 : if (Token::Match(tok, "pclose ( %varid% )", varid))
300 : 135 : return Pipe;
301 : :
302 [ + + ]: 56065 : if (Token::Match(tok, "closedir ( %varid% )", varid))
303 : 90 : return Dir;
304 : :
305 : 63940 : return No;
306 : : }
307 : :
308 : 108900 : CheckMemoryLeak::AllocType CheckMemoryLeak::getDeallocationType(const Token *tok, const std::string &varname) const
309 : : {
310 [ + - ][ + - ]: 108900 : if (Token::Match(tok, std::string("delete " + varname + " [,;]").c_str()))
[ + - ][ + - ]
[ + + ]
311 : 450 : return New;
312 : :
313 [ + - ][ + - ]: 108450 : if (Token::Match(tok, std::string("delete [ ] " + varname + " [,;]").c_str()))
[ + - ][ + - ]
[ + + ]
314 : 810 : return NewArray;
315 : :
316 [ + - ][ + - ]: 107640 : if (Token::Match(tok, std::string("delete ( " + varname + " ) [,;]").c_str()))
[ + - ][ + - ]
[ + + ]
317 : 45 : return New;
318 : :
319 [ + - ][ + - ]: 107595 : if (Token::Match(tok, std::string("delete [ ] ( " + varname + " ) [,;]").c_str()))
[ + - ][ + - ]
[ - + ]
320 : 0 : return NewArray;
321 : :
322 [ + - ][ + - ]: 429750 : if (Token::simpleMatch(tok, std::string("free ( " + varname + " ) ;").c_str()) ||
[ + - ][ + - ]
[ + + ][ + - ]
[ - + ][ + - ]
[ + - ][ + - ]
[ + + ][ # # ]
[ # # ]
323 [ + - ][ + - ]: 214875 : Token::simpleMatch(tok, std::string("kfree ( " + varname + " ) ;").c_str()) ||
[ + - ][ + - ]
[ + + ][ + - ]
[ + + ][ + - ]
[ # # ][ # # ]
324 [ + - ][ + - ]: 214875 : Token::simpleMatch(tok, std::string("realloc ( " + varname + " , 0 ) ;").c_str()))
[ + - ][ + - ]
[ + + ][ + - ]
[ + + ][ + - ]
[ # # ][ # # ]
325 : 315 : return Malloc;
326 : :
327 [ + - ][ + - ]: 107280 : if (Token::simpleMatch(tok, std::string("g_free ( " + varname + " ) ;").c_str()))
[ + - ][ + - ]
[ - + ]
328 : 0 : return gMalloc;
329 : :
330 [ + - ][ + - ]: 214560 : if (Token::simpleMatch(tok, std::string("fclose ( " + varname + " )").c_str()) ||
[ + - ][ + - ]
[ + - ][ - + ]
[ + - ][ + - ]
[ + - ][ - + ]
[ # # ][ # # ]
331 [ + - ]: 107280 : Token::simpleMatch(tok, "fcloseall ( )"))
332 : 0 : return File;
333 : :
334 [ + - ][ + - ]: 107280 : if (Token::simpleMatch(tok, std::string("close ( " + varname + " )").c_str()))
[ + - ][ + - ]
[ - + ]
335 : 0 : return Fd;
336 : :
337 [ + - ][ + - ]: 107280 : if (Token::simpleMatch(tok, std::string("pclose ( " + varname + " )").c_str()))
[ + - ][ + - ]
[ - + ]
338 : 0 : return Pipe;
339 : :
340 [ + - ][ + - ]: 107280 : if (Token::simpleMatch(tok, std::string("closedir ( " + varname + " )").c_str()))
[ + - ][ + - ]
[ - + ]
341 : 0 : return Dir;
342 : :
343 : 108900 : return No;
344 : : }
345 : :
346 : : //--------------------------------------------------------------------------
347 : :
348 : :
349 : : //--------------------------------------------------------------------------
350 : :
351 : 5391 : void CheckMemoryLeak::memoryLeak(const Token *tok, const std::string &varname, AllocType alloctype)
352 : : {
353 [ + + ][ + - ]: 5391 : if (alloctype == CheckMemoryLeak::File ||
[ + + ][ + + ]
354 : : alloctype == CheckMemoryLeak::Pipe ||
355 : : alloctype == CheckMemoryLeak::Fd ||
356 : : alloctype == CheckMemoryLeak::Dir)
357 : 630 : resourceLeakError(tok, varname);
358 : : else
359 : 4761 : memleakError(tok, varname);
360 : 5391 : }
361 : : //---------------------------------------------------------------------------
362 : :
363 : :
364 : 8262 : void CheckMemoryLeak::reportErr(const Token *tok, Severity::SeverityType severity, const std::string &id, const std::string &msg) const
365 : : {
366 : 8262 : std::list<const Token *> callstack;
367 : :
368 [ + + ]: 8262 : if (tok)
369 [ + - ]: 7992 : callstack.push_back(tok);
370 : :
371 [ + - ]: 8262 : reportErr(callstack, severity, id, msg);
372 : 8262 : }
373 : :
374 : 8982 : void CheckMemoryLeak::reportErr(const std::list<const Token *> &callstack, Severity::SeverityType severity, const std::string &id, const std::string &msg) const
375 : : {
376 [ + + ]: 8982 : const ErrorLogger::ErrorMessage errmsg(callstack, tokenizer?&tokenizer->list:0, severity, id, msg, false);
377 : :
378 [ + - ]: 8982 : if (errorLogger)
379 [ + - ]: 8982 : errorLogger->reportErr(errmsg);
380 : : else
381 [ # # ]: 8982 : Check::reportError(errmsg);
382 : 8982 : }
383 : :
384 : 6552 : void CheckMemoryLeak::memleakError(const Token *tok, const std::string &varname) const
385 : : {
386 [ + - ][ + - ]: 6552 : reportErr(tok, Severity::error, "memleak", "Memory leak: " + varname);
[ + - ]
387 : 6552 : }
388 : :
389 : 450 : void CheckMemoryLeak::memleakUponReallocFailureError(const Token *tok, const std::string &varname) const
390 : : {
391 [ + - ][ + - ]: 450 : reportErr(tok, Severity::error, "memleakOnRealloc", "Common realloc mistake: \'" + varname + "\' nulled but not freed upon failure");
[ + - ][ + - ]
[ + - ]
392 : 450 : }
393 : :
394 : 675 : void CheckMemoryLeak::resourceLeakError(const Token *tok, const std::string &varname) const
395 : : {
396 [ + - ]: 675 : std::string errmsg("Resource leak");
397 [ + - ][ + - ]: 675 : if (!varname.empty())
398 [ + - ][ + - ]: 675 : errmsg += ": " + varname;
[ + - ]
399 [ + - ][ + - ]: 675 : reportErr(tok, Severity::error, "resourceLeak", errmsg);
[ + - ]
400 : 675 : }
401 : :
402 : 90 : void CheckMemoryLeak::deallocDeallocError(const Token *tok, const std::string &varname) const
403 : : {
404 [ + - ][ + - ]: 90 : reportErr(tok, Severity::error, "deallocDealloc", "Deallocating a deallocated pointer: " + varname);
[ + - ]
405 : 90 : }
406 : :
407 : 405 : void CheckMemoryLeak::deallocuseError(const Token *tok, const std::string &varname) const
408 : : {
409 [ + - ][ + - ]: 405 : reportErr(tok, Severity::error, "deallocuse", "Dereferencing '" + varname + "' after it is deallocated / released");
[ + - ][ + - ]
[ + - ]
410 : 405 : }
411 : :
412 : 90 : void CheckMemoryLeak::mismatchSizeError(const Token *tok, const std::string &sz) const
413 : : {
414 [ + - ][ + - ]: 90 : reportErr(tok, Severity::error, "mismatchSize", "The given size " + sz + " is mismatching");
[ + - ][ + - ]
[ + - ]
415 : 90 : }
416 : :
417 : 720 : void CheckMemoryLeak::mismatchAllocDealloc(const std::list<const Token *> &callstack, const std::string &varname) const
418 : : {
419 [ + - ][ + - ]: 720 : reportErr(callstack, Severity::error, "mismatchAllocDealloc", "Mismatching allocation and deallocation: " + varname);
[ + - ]
420 : 720 : }
421 : :
422 : 2970 : CheckMemoryLeak::AllocType CheckMemoryLeak::functionReturnType(const Function* func, std::list<const Function*> *callstack) const
423 : : {
424 [ + - ][ - + ]: 2970 : if (!func || !func->hasBody)
425 : 0 : return No;
426 : :
427 : : // Get return pointer..
428 : 2970 : unsigned int varid = 0;
429 : 2970 : unsigned int indentlevel = 0;
430 [ + + ]: 32805 : for (const Token *tok2 = func->functionScope->classStart; tok2 != func->functionScope->classEnd; tok2 = tok2->next()) {
431 [ + + ]: 31410 : if (tok2->str() == "{")
432 : 3510 : ++indentlevel;
433 [ + + ]: 27900 : else if (tok2->str() == "}") {
434 [ - + ]: 450 : if (indentlevel <= 1)
435 : 0 : return No;
436 : 450 : --indentlevel;
437 : : }
438 [ + + ]: 31410 : if (Token::Match(tok2, "return %var% ;")) {
439 [ + + ]: 900 : if (indentlevel != 1)
440 : 90 : return No;
441 : 810 : varid = tok2->next()->varId();
442 : 810 : break;
443 [ + + ]: 30510 : } else if (tok2->str() == "return") {
444 : 1260 : AllocType allocType = getAllocationType(tok2->next(), 0, callstack);
445 [ + + ]: 1260 : if (allocType != No)
446 : 675 : return allocType;
447 : : }
448 : : }
449 : :
450 : : // Not returning pointer value..
451 [ + + ]: 2205 : if (varid == 0)
452 : 1395 : return No;
453 : :
454 [ + + ]: 810 : if (this != NULL) {
455 : : // If variable is not local then alloctype shall be "No"
456 : : // Todo: there can be false negatives about mismatching allocation/deallocation.
457 : : // => Generate "alloc ; use ;" if variable is not local?
458 : 765 : const Variable *var = tokenizer->getSymbolDatabase()->getVariableFromVarId(varid);
459 [ + - ][ + + ]: 765 : if (!var || !var->isLocal() || var->isStatic())
[ + + ][ + + ]
460 : 180 : return No;
461 : : }
462 : :
463 : : // Check if return pointer is allocated..
464 : 630 : AllocType allocType = No;
465 [ + - ]: 9045 : for (const Token* tok = func->functionScope->classStart; tok != func->functionScope->classEnd; tok = tok->next()) {
466 [ + + ]: 9045 : if (Token::Match(tok, "%varid% =", varid)) {
467 : 720 : allocType = getAllocationType(tok->tokAt(2), varid, callstack);
468 : : }
469 [ + + ]: 9045 : if (Token::Match(tok, "= %varid% ;", varid)) {
470 : 90 : return No;
471 : : }
472 [ - + ]: 8955 : if (Token::Match(tok, "static %type% * %varid% [;{}=]", varid)) {
473 : 0 : return No;
474 : : }
475 [ + + ]: 8955 : if (Token::Match(tok, "[(,] %varid% [,)]", varid)) {
476 : 90 : return No;
477 : : }
478 [ + + ]: 8865 : if (tok->str() == "return")
479 : 450 : return allocType;
480 : : }
481 : :
482 : 2970 : return allocType;
483 : : }
484 : :
485 : :
486 : 405 : const char *CheckMemoryLeak::functionArgAlloc(const Function *func, unsigned int targetpar, AllocType &allocType) const
487 : : {
488 : 405 : allocType = No;
489 : :
490 [ + - ][ - + ]: 405 : if (!func || !func->functionScope)
491 : 0 : return "";
492 : :
493 : 405 : std::list<Variable>::const_iterator arg = func->argumentList.begin();
494 [ + - ]: 450 : for (; arg != func->argumentList.end(); ++arg) {
495 [ + + ]: 450 : if (arg->index() == targetpar-1)
496 : 405 : break;
497 : : }
498 [ - + ]: 405 : if (arg == func->argumentList.end())
499 : 0 : return "";
500 : :
501 : : // Is **
502 [ - + ]: 405 : if (!arg->isPointer())
503 : 0 : return "";
504 : 405 : const Token* tok = arg->typeEndToken();
505 : 405 : tok = tok->previous();
506 [ - + ]: 405 : if (tok->str() != "*")
507 : 0 : return "";
508 : :
509 : : // Check if pointer is allocated.
510 : 405 : int realloc = 0;
511 [ + - ][ + + ]: 3015 : for (tok = func->functionScope->classStart; tok && tok != func->functionScope->classEnd; tok = tok->next()) {
[ + + ]
512 [ + + ]: 2925 : if (tok->varId() == arg->varId()) {
513 [ + + ]: 450 : if (Token::Match(tok->tokAt(-3), "free ( * %var% )")) {
514 : 90 : realloc = 1;
515 : 90 : allocType = No;
516 [ + + ]: 360 : } else if (Token::Match(tok->previous(), "* %var% =")) {
517 : 270 : allocType = getAllocationType(tok->tokAt(2), arg->varId());
518 [ + + ]: 270 : if (allocType == No) {
519 : 45 : allocType = getReallocationType(tok->tokAt(2), arg->varId());
520 : : }
521 [ + + ]: 270 : if (allocType != No) {
522 [ + + ]: 225 : if (realloc)
523 : 90 : return "realloc";
524 : 135 : return "alloc";
525 : : }
526 : : } else {
527 : : // unhandled variable usage: bailout
528 : 90 : return "";
529 : : }
530 : : }
531 : : }
532 : :
533 : 405 : return "";
534 : : }
535 : :
536 : :
537 : 16666 : void CheckMemoryLeakInFunction::parse_noreturn()
538 : : {
539 [ + - ]: 16666 : if (noreturn.empty()) {
540 [ + - ][ + - ]: 16666 : noreturn.insert("exit");
[ + - ]
541 [ + - ][ + - ]: 16666 : noreturn.insert("_exit");
[ + - ]
542 [ + - ][ + - ]: 16666 : noreturn.insert("_Exit");
[ + - ]
543 [ + - ][ + - ]: 16666 : noreturn.insert("abort");
[ + - ]
544 [ + - ][ + - ]: 16666 : noreturn.insert("err");
[ + - ]
545 [ + - ][ + - ]: 16666 : noreturn.insert("verr");
[ + - ]
546 [ + - ][ + - ]: 16666 : noreturn.insert("errx");
[ + - ]
547 [ + - ][ + - ]: 16666 : noreturn.insert("verrx");
[ + - ]
548 [ + - ][ + - ]: 16666 : noreturn.insert("ExitProcess");
[ + - ]
549 [ + - ][ + - ]: 16666 : noreturn.insert("ExitThread");
[ + - ]
550 [ + - ][ + - ]: 16666 : noreturn.insert("pthread_exit");
[ + - ]
551 : : }
552 : :
553 : : // only check functions
554 : 16666 : const std::size_t functions = symbolDatabase->functionScopes.size();
555 [ + + ]: 30542 : for (std::size_t i = 0; i < functions; ++i) {
556 : 13876 : const Scope * scope = symbolDatabase->functionScopes[i];
557 : :
558 : : // parse this function to check if it contains an "exit" call..
559 : 13876 : bool isNoreturn = false;
560 [ + + ]: 342919 : for (const Token *tok2 = scope->classStart->next(); tok2 != scope->classEnd; tok2 = tok2->next()) {
561 [ + + ]: 329538 : if (Token::Match(tok2->previous(), "[;{}] exit (")) {
562 : 495 : isNoreturn = true;
563 : 495 : break;
564 : : }
565 : : }
566 : :
567 : : // This function is not a noreturn function
568 [ + + ]: 13876 : if (isNoreturn)
569 : 495 : noreturn.insert(scope->className);
570 : : else
571 : 13381 : notnoreturn.insert(scope->className);
572 : : }
573 : 16666 : }
574 : :
575 : :
576 : 14040 : bool CheckMemoryLeakInFunction::notvar(const Token *tok, unsigned int varid, bool endpar)
577 : : {
578 [ + + ][ + - ]: 14040 : const std::string end(endpar ? " &&|)" : " [;)&|]");
579 [ + - ][ + - ]: 28080 : return bool(Token::Match(tok, ("! %varid%" + end).c_str(), varid) ||
[ + - ][ + - ]
[ + - ][ # # ]
580 [ + + ][ + - ]: 28080 : Token::Match(tok, ("! ( %varid% )" + end).c_str(), varid));
[ + - ][ + - ]
[ - + ][ + + ]
[ + - ][ # # ]
581 : : }
582 : :
583 : :
584 : :
585 : 48141 : bool CheckMemoryLeakInFunction::test_white_list(const std::string &funcname)
586 : : {
587 : 48141 : return (std::bsearch(funcname.c_str(), call_func_white_list,
588 : : sizeof(call_func_white_list) / sizeof(call_func_white_list[0]),
589 : 48141 : sizeof(call_func_white_list[0]), call_func_white_list_compare) != NULL);
590 : : }
591 : :
592 : 37026 : 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)
593 : : {
594 [ + + ]: 37026 : if (test_white_list(tok->str())) {
595 [ + + + + : 162000 : if (tok->str() == "asprintf" ||
+ + + - +
+ + - + +
+ - + - -
+ ][ + + ]
596 : 19260 : tok->str() == "delete" ||
597 : 19215 : tok->str() == "fclose" ||
598 : 18225 : tok->str() == "for" ||
599 : 18225 : tok->str() == "free" ||
600 : 14715 : tok->str() == "if" ||
601 : 14715 : tok->str() == "realloc" ||
602 : 12780 : tok->str() == "return" ||
603 : 12780 : tok->str() == "switch" ||
604 : 12780 : tok->str() == "while") {
605 : 6525 : return 0;
606 : : }
607 : :
608 : : // is the varid a parameter?
609 [ + + ]: 25245 : for (const Token *tok2 = tok->tokAt(2); tok2 != tok->linkAt(1); tok2 = tok2->next()) {
610 [ + + ]: 21960 : if (tok2->str() == "(") {
611 : 90 : tok2 = tok2->nextArgument();
612 [ + + ]: 90 : if (!tok2)
613 : 45 : break;
614 : : }
615 [ + + ]: 21915 : if (tok2->varId() == varid) {
616 [ + + ]: 9450 : if (tok->strAt(-1) == ".")
617 : 45 : return "use";
618 [ + + ]: 9405 : else if (tok2->strAt(1) == "=")
619 : 45 : return "assign";
620 : : else
621 : 9360 : return "use_";
622 : : }
623 : : }
624 : :
625 : 3330 : return 0;
626 : : }
627 : :
628 [ + + ][ + + ]: 17721 : if (noreturn.find(tok->str()) != noreturn.end() && tok->strAt(-1) != "=")
[ + + ]
629 : 1620 : return "exit";
630 : :
631 [ + + ][ + + ]: 16101 : if (varid > 0 && (getAllocationType(tok, varid) != No || getReallocationType(tok, varid) != No || getDeallocationType(tok, varid) != No))
[ + - ][ + + ]
[ + + ]
632 : 720 : return 0;
633 : :
634 [ - + ]: 15381 : if (callstack.size() > 2)
635 : 0 : return "dealloc_";
636 : :
637 : 15381 : const std::string& funcname(tok->str());
638 [ + + ]: 16686 : for (std::list<const Token *>::const_iterator it = callstack.begin(); it != callstack.end(); ++it) {
639 [ + + ][ + + ]: 1395 : if ((*it) && (*it)->str() == funcname)
[ + + ]
640 : 90 : return "recursive";
641 : : }
642 : 15291 : callstack.push_back(tok);
643 : :
644 : : // lock/unlock..
645 [ + + ]: 15291 : if (varid == 0) {
646 : 10791 : const Function* func = tok->function();
647 [ + + ][ - + ]: 10791 : if (!func || !func->hasBody)
648 : 8811 : return 0;
649 : :
650 [ + - ]: 1980 : Token *ftok = getcode(func->functionScope->classStart->next(), callstack, 0, alloctype, dealloctype, false, 1);
651 : 1980 : simplifycode(ftok);
652 : 1980 : const char *ret = 0;
653 [ - + ]: 1980 : if (Token::simpleMatch(ftok, "; alloc ; }"))
654 : 0 : ret = "alloc";
655 [ - + ]: 1980 : else if (Token::simpleMatch(ftok, "; dealloc ; }"))
656 : 0 : ret = "dealloc";
657 : 1980 : TokenList::deleteTokens(ftok);
658 : 1980 : return ret;
659 : : }
660 : :
661 : : // how many parameters is there in the function call?
662 : 4500 : unsigned int numpar = countParameters(tok);
663 [ + + ]: 4500 : if (numpar == 0) {
664 : : // Taking return value => it is not a noreturn function
665 [ + + ]: 1395 : if (tok->strAt(-1) == "=")
666 : 450 : return NULL;
667 : :
668 : : // Function is not noreturn
669 [ + + ]: 945 : if (notnoreturn.find(funcname) != notnoreturn.end())
670 : 45 : return NULL;
671 : :
672 : 900 : return "callfunc";
673 : : }
674 : :
675 : 3105 : unsigned int par = 0;
676 : :
677 : 3105 : const bool dot(tok->previous()->str() == ".");
678 : 3105 : const bool eq(tok->previous()->str() == "=");
679 : :
680 : 3105 : const Token *functok = tok;
681 : :
682 : 3105 : tok = Token::findsimplematch(tok, "(");
683 [ + - ]: 3105 : if (tok)
684 : 3105 : tok = tok->next();
685 : :
686 [ + + ]: 5175 : for (; tok; tok = tok->nextArgument()) {
687 : 3645 : ++par;
688 [ + - ][ + + ]: 3645 : if (varid > 0 && Token::Match(tok, "%varid% [,()]", varid)) {
[ + + ]
689 [ + + ]: 1305 : if (dot)
690 : 180 : return "use";
691 : :
692 : 1125 : const Function* function = functok->function();
693 [ + + ]: 1125 : if (!function)
694 : 585 : return "use";
695 : :
696 : : // how many parameters does the function want?
697 [ - + ]: 540 : if (numpar != function->argCount()) // TODO: Handle default parameters
698 : 0 : return "recursive";
699 : :
700 : 540 : const Variable* param = function->getArgumentVar(par-1);
701 [ + - ][ + + ]: 540 : if (!param || !param->nameToken())
[ + + ]
702 : 45 : return "use";
703 [ - + ]: 495 : if (!function->functionScope)
704 : 0 : return "use";
705 [ + - ]: 495 : Token *func = getcode(function->functionScope->classStart->next(), callstack, param->varId(), alloctype, dealloctype, false, sz);
706 : : //simplifycode(func);
707 : 495 : const Token *func_ = func;
708 [ + - ][ + + ]: 990 : while (func_ && func_->str() == ";")
[ + + ]
709 : 495 : func_ = func_->next();
710 : :
711 : 495 : const char *ret = 0;
712 : : /** @todo handle "goto" */
713 [ + + ]: 495 : if (Token::findsimplematch(func_, "dealloc"))
714 : 135 : ret = "dealloc";
715 [ + + ]: 360 : else if (Token::findsimplematch(func_, "use"))
716 : 45 : ret = "use";
717 [ + + ]: 315 : else if (Token::findsimplematch(func_, "&use"))
718 : 45 : ret = "&use";
719 : :
720 : 495 : TokenList::deleteTokens(func);
721 : 495 : return ret;
722 : : }
723 [ + - ][ + + ]: 2340 : if (varid > 0 && Token::Match(tok, "& %varid% [,()]", varid)) {
[ + + ]
724 : 675 : const Function *func = functok->function();
725 [ + + ]: 675 : if (func == 0)
726 : 270 : continue;
727 : : AllocType a;
728 : 405 : const char *ret = functionArgAlloc(func, par, a);
729 : :
730 [ + + ]: 405 : if (a != No) {
731 [ + + ]: 225 : if (alloctype == No)
732 : 135 : alloctype = a;
733 [ - + ]: 90 : else if (alloctype != a)
734 : 0 : alloctype = Many;
735 : 225 : allocpar = true;
736 : 225 : return ret;
737 : : }
738 : : }
739 [ + - ][ + + ]: 1845 : if (varid > 0 && Token::Match(tok, "%varid% . %var% [,)]", varid))
[ + + ]
740 : 45 : return "use";
741 : : }
742 [ + + ][ + + ]: 37026 : return (eq || _settings->experimental) ? 0 : "callfunc";
743 : : }
744 : :
745 : :
746 : 275879 : static void addtoken(Token **rettail, const Token *tok, const std::string &str)
747 : : {
748 : 275879 : (*rettail)->insertToken(str);
749 : 275879 : (*rettail) = (*rettail)->next();
750 : 275879 : (*rettail)->linenr(tok->linenr());
751 : 275879 : (*rettail)->fileIndex(tok->fileIndex());
752 : 275879 : }
753 : :
754 : :
755 : 37892 : 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)
756 : : {
757 : : // variables whose value depends on if(!var). If one of these variables
758 : : // is used in a if-condition then generate "ifv" instead of "if".
759 : 37892 : std::set<unsigned int> extravar;
760 : :
761 : : // The first token should be ";"
762 [ + - ][ + - ]: 37892 : Token* rethead = new Token(0);
763 [ + - ][ + - ]: 37892 : rethead->str(";");
[ + - ]
764 : 37892 : rethead->linenr(tok->linenr());
765 : 37892 : rethead->fileIndex(tok->fileIndex());
766 : 37892 : Token* rettail = rethead;
767 : :
768 : 37892 : int indentlevel = 0;
769 : 37892 : int parlevel = 0;
770 [ + + ]: 665524 : for (; tok; tok = tok->next()) {
771 [ + - ][ + + ]: 660529 : if (tok->str() == "{") {
772 [ + - ][ + - ]: 17856 : addtoken(&rettail, tok, "{");
[ + - ]
773 : 17856 : ++indentlevel;
774 [ + - ][ + + ]: 642673 : } else if (tok->str() == "}") {
775 [ + - ][ + - ]: 50483 : addtoken(&rettail, tok, "}");
[ + - ]
776 [ + + ]: 50483 : if (indentlevel <= 0)
777 : 32627 : break;
778 : 17856 : --indentlevel;
779 : : }
780 : :
781 [ + - ][ + + ]: 592190 : else if (tok->str() == "(")
782 : 42876 : ++parlevel;
783 [ + - ][ + + ]: 549314 : else if (tok->str() == ")")
784 : 43101 : --parlevel;
785 : :
786 [ + + ][ + - ]: 627902 : if (parlevel == 0 && tok->str() == ";")
[ + + ][ + + ]
787 [ + - ][ + - ]: 113709 : addtoken(&rettail, tok, ";");
[ + - ]
788 : :
789 : : // Start of new statement.. check if the statement has anything interesting
790 [ + + ][ + + ]: 627902 : if (varid > 0 && parlevel == 0 && Token::Match(tok, "[;{}]")) {
[ + - ][ + + ]
[ + + ]
791 [ + - ][ + + ]: 84527 : if (Token::Match(tok->next(), "[{};]"))
792 : 20011 : continue;
793 : :
794 : : // function calls are interesting..
795 : 64516 : const Token *tok2 = tok;
796 [ + - ][ + + ]: 65056 : while (Token::Match(tok2->next(), "%var% ."))
797 [ + - ]: 540 : tok2 = tok2->tokAt(2);
798 [ + - ][ + + ]: 64516 : if (Token::Match(tok2->next(), "%var% ("))
799 : : ;
800 : :
801 [ + - ][ + + ]: 42016 : else if (Token::Match(tok->next(), "continue|break|return|throw|goto|do|else"))
802 : : ;
803 : :
804 : : else {
805 : 33421 : const Token *skipToToken = 0;
806 : :
807 : : // scan statement for interesting keywords / varid
808 [ + + ]: 73336 : for (tok2 = tok->next(); tok2; tok2 = tok2->next()) {
809 [ + - ][ + + ]: 68971 : if (tok2->str() == ";") {
810 : : // nothing interesting found => skip this statement
811 : 4320 : skipToToken = tok2->previous();
812 : 4320 : break;
813 : : }
814 : :
815 [ + + ][ + + ]: 184936 : if (tok2->varId() == varid ||
[ + + ][ - + ]
[ + + ]
816 [ + - ][ + - ]: 120285 : tok2->str() == ":" || tok2->str() == "{" || tok2->str() == "}") {
[ + - ]
817 : 24736 : break;
818 : : }
819 : : }
820 : :
821 [ + + ]: 33421 : if (skipToToken) {
822 : 4320 : tok = skipToToken;
823 : 4320 : continue;
824 : : }
825 : : }
826 : : }
827 : :
828 [ + + ]: 603571 : if (varid == 0) {
829 [ + + ][ + - ]: 311163 : if (!callstack.empty() && Token::Match(tok, "[;{}] __cppcheck_lock|__cppcheck_unlock ( ) ;")) {
[ + + ][ + + ]
830 : : // Type of leak = Resource leak
831 : 90 : alloctype = dealloctype = CheckMemoryLeak::File;
832 : :
833 [ + - ][ + + ]: 90 : if (tok->next()->str() == "__cppcheck_lock") {
834 [ + - ][ + - ]: 45 : addtoken(&rettail, tok, "alloc");
[ + - ]
835 : : } else {
836 [ + - ][ + - ]: 45 : addtoken(&rettail, tok, "dealloc");
[ + - ]
837 : : }
838 : :
839 [ + - ]: 90 : tok = tok->tokAt(3);
840 : 90 : continue;
841 : : }
842 : :
843 [ + - ][ + + ]: 311073 : if (Token::simpleMatch(tok, "if (")) {
844 [ + - ][ + - ]: 4815 : addtoken(&rettail, tok, "if");
[ + - ]
845 : 4815 : tok = tok->next()->link();
846 : 4815 : continue;
847 : : }
848 : : } else {
849 : :
850 [ + - ][ + + ]: 292408 : if (Token::Match(tok, "%varid% = close ( %varid% )", varid)) {
851 [ + - ][ + - ]: 45 : addtoken(&rettail, tok, "dealloc");
[ + - ]
852 [ + - ][ + - ]: 45 : addtoken(&rettail, tok, ";");
[ + - ]
853 [ + - ][ + - ]: 45 : addtoken(&rettail, tok, "assign");
[ + - ]
854 [ + - ][ + - ]: 45 : addtoken(&rettail, tok, ";");
[ + - ]
855 [ + - ]: 45 : tok = tok->tokAt(5);
856 : 45 : continue;
857 : : }
858 : :
859 : : // var = strcpy|.. ( var ,
860 [ + - ][ + + ]: 292363 : if (Token::Match(tok, "[;{}] %varid% = memcpy|memmove|memset|strcpy|strncpy|strcat|strncat ( %varid% ,", varid)) {
861 [ + - ]: 90 : tok = tok->linkAt(4);
862 : 90 : continue;
863 : : }
864 : :
865 [ + - ][ + + ]: 568535 : if (Token::Match(tok->previous(), "[(;{}] %varid% =", varid) ||
[ + + ][ + + ]
866 [ + - ]: 276262 : Token::Match(tok, "asprintf|vasprintf ( & %varid% ,", varid)) {
867 : : CheckMemoryLeak::AllocType alloc;
868 : :
869 [ + - ][ + + ]: 16191 : if (Token::Match(tok, "asprintf|vasprintf (")) {
870 : : // todo: check how the return value is used.
871 [ + - ][ + + ]: 180 : if (!Token::Match(tok->previous(), "[;{}]")) {
872 [ + - ]: 90 : TokenList::deleteTokens(rethead);
873 : 90 : return 0;
874 : : }
875 : 90 : alloc = Malloc;
876 : 90 : tok = tok->next()->link();
877 : : } else {
878 [ + - ][ + - ]: 16011 : alloc = getAllocationType(tok->tokAt(2), varid);
879 : : }
880 : : //bool realloc = false;
881 : :
882 [ + + ][ + + ]: 18666 : if (sz > 1 &&
[ + + ][ + + ]
883 [ + - ][ + - ]: 2385 : Token::Match(tok->tokAt(2), "malloc ( %num% )") &&
884 [ + - ][ + - ]: 180 : (MathLib::toLongNumber(tok->strAt(4)) % long(sz)) != 0) {
885 [ + - ][ + - ]: 45 : mismatchSizeError(tok->tokAt(4), tok->strAt(4));
[ + - ]
886 : : }
887 : :
888 [ + + ]: 16101 : if (alloc == CheckMemoryLeak::No) {
889 [ + - ][ + - ]: 3555 : alloc = getReallocationType(tok->tokAt(2), varid);
890 [ + + ]: 3555 : if (alloc != CheckMemoryLeak::No) {
891 [ + - ][ + - ]: 540 : addtoken(&rettail, tok, "realloc");
[ + - ]
892 [ + - ][ + - ]: 540 : addtoken(&rettail, tok, ";");
[ + - ]
893 : : //TODO: this assignment is redundant, should be fixed
894 : : //realloc = true;
895 [ + - ]: 540 : tok = tok->tokAt(2);
896 [ + - ][ + - ]: 540 : if (Token::Match(tok, "%var% ("))
897 : 540 : tok = tok->next()->link();
898 : 540 : continue;
899 : : }
900 : : }
901 : :
902 : : // don't check classes..
903 [ + + ]: 15561 : if (alloc == CheckMemoryLeak::New) {
904 [ + - ][ + - ]: 810 : if (Token::Match(tok->tokAt(2), "new struct| %type% [(;]")) {
[ + + ]
905 [ + - ][ + - ]: 540 : const int offset = tok->strAt(3) == "struct" ? 1 : 0;
[ - + ]
906 [ + - ][ + - ]: 540 : if (isclass(tok->tokAt(3 + offset), varid)) {
[ + + ]
907 : 180 : alloc = No;
908 : : }
909 [ + - ][ + - ]: 270 : } else if (Token::Match(tok->tokAt(2), "new ( nothrow ) struct| %type%")) {
[ + + ]
910 [ + - ][ + - ]: 90 : const int offset = tok->strAt(6) == "struct" ? 1 : 0;
[ - + ]
911 [ + - ][ + - ]: 90 : if (isclass(tok->tokAt(6 + offset), varid)) {
[ + + ]
912 : 45 : alloc = No;
913 : : }
914 [ + - ][ + - ]: 180 : } else if (Token::Match(tok->tokAt(2), "new ( std :: nothrow ) struct| %type%")) {
[ + + ]
915 [ + - ][ + - ]: 135 : const int offset = tok->strAt(8) == "struct" ? 1 : 0;
[ - + ]
916 [ + - ][ + - ]: 135 : if (isclass(tok->tokAt(8 + offset), varid)) {
[ + + ]
917 : 45 : alloc = No;
918 : : }
919 : : }
920 : :
921 [ + + ][ + - ]: 810 : if (alloc == No && alloctype == No)
922 : 270 : alloctype = CheckMemoryLeak::New;
923 : : }
924 : :
925 [ + + ]: 15561 : if (alloc != No) {
926 : : //if (! realloc)
927 [ + - ][ + - ]: 12276 : addtoken(&rettail, tok, "alloc");
[ + - ]
928 : :
929 [ + + ][ + + ]: 12276 : if (alloctype != No && alloctype != alloc)
930 : 135 : alloc = Many;
931 : :
932 [ + + ][ + + ]: 12276 : if (alloc != Many && dealloctype != No && dealloctype != Many && dealloctype != alloc) {
[ + - ][ + + ]
933 [ + - ]: 45 : callstack.push_back(tok);
934 [ + - ][ + - ]: 45 : mismatchAllocDealloc(callstack, Token::findmatch(_tokenizer->tokens(), "%varid%", varid)->str());
935 [ + - ]: 45 : callstack.pop_back();
936 : : }
937 : :
938 : 12276 : alloctype = alloc;
939 : :
940 [ + - ][ + + ]: 12276 : if (Token::Match(tok, "%var% = %type% (")) {
941 [ + - ]: 7866 : tok = tok->linkAt(3);
942 : 7866 : continue;
943 : : }
944 : : }
945 : :
946 : : // assignment..
947 : : else {
948 : : // is the pointer in rhs?
949 : 3285 : bool rhs = false;
950 : 3285 : bool trailingSemicolon = false;
951 : 3285 : bool used = false;
952 [ + - ]: 15750 : for (const Token *tok2 = tok->next(); tok2; tok2 = tok2->next()) {
953 [ + - ][ + + ]: 15750 : if (tok2->str() == ";") {
954 : 3285 : trailingSemicolon = true;
955 [ + + ]: 3285 : if (rhs)
956 : 225 : tok = tok2;
957 : 3285 : break;
958 : : }
959 : :
960 [ + + ]: 12465 : if (!used) {
961 [ + - ][ + + ]: 12285 : if (Token::Match(tok2, "[=+(,] %varid%", varid)) {
962 [ + - ][ + - ]: 225 : if (!rhs && Token::Match(tok2, "[(,]")) {
[ + + ][ + + ]
963 : 90 : used = true;
964 [ + - ][ + - ]: 90 : addtoken(&rettail, tok, "use");
[ + - ]
965 [ + - ][ + - ]: 90 : addtoken(&rettail, tok, ";");
[ + - ]
966 : : }
967 : 225 : rhs = true;
968 : : }
969 : : }
970 : : }
971 : :
972 [ + + ]: 3285 : if (!used) {
973 [ + + ]: 3195 : if (!rhs)
974 [ + - ][ + - ]: 3060 : addtoken(&rettail, tok, "assign");
[ + - ]
975 : : else {
976 [ + - ][ + - ]: 135 : addtoken(&rettail, tok, "use_");
[ + - ]
977 [ + - ]: 135 : if (trailingSemicolon)
978 [ + - ][ + - ]: 135 : addtoken(&rettail, tok, ";");
[ + - ]
979 : : }
980 : : }
981 : 3285 : continue;
982 : : }
983 : : }
984 : :
985 [ + - ][ + + ]: 280492 : if (Token::Match(tok->previous(), "[;{})=|] ::| %var%")) {
986 [ + - ][ + + ]: 57865 : if (Token::Match(tok, "%varid% ?", varid))
987 [ + - ]: 45 : tok = tok->tokAt(2);
988 : :
989 [ + - ]: 57865 : AllocType dealloc = getDeallocationType(tok, varid);
990 : :
991 [ + + ][ + - ]: 57865 : if (dealloc != No && tok->str() == "fcloseall" && alloctype != dealloc)
[ + + ][ + + ]
[ + + ]
992 : : //TODO: this assignment is redundant, should be fixed
993 : : /*dealloc = No*/;
994 : :
995 [ + + ]: 57820 : else if (dealloc != No) {
996 [ + - ][ + - ]: 7740 : addtoken(&rettail, tok, "dealloc");
[ + - ]
997 : :
998 [ + + ][ + + ]: 7740 : if (dealloctype != No && dealloctype != dealloc)
999 : 180 : dealloc = Many;
1000 : :
1001 [ + + ][ + + ]: 7740 : if (dealloc != Many && alloctype != No && alloctype != Many && alloctype != dealloc) {
[ + + ][ + + ]
1002 [ + - ]: 450 : callstack.push_back(tok);
1003 [ + - ][ + - ]: 450 : mismatchAllocDealloc(callstack, Token::findmatch(_tokenizer->tokens(), "%varid%", varid)->str());
1004 [ + - ]: 450 : callstack.pop_back();
1005 : : }
1006 : 7740 : dealloctype = dealloc;
1007 : :
1008 [ + - ][ + - ]: 7740 : if (tok->strAt(2) == "(")
[ + + ]
1009 [ + - ]: 45 : tok = tok->linkAt(2);
1010 : 7740 : continue;
1011 : : }
1012 : : }
1013 : :
1014 : : // if else switch
1015 [ + - ][ + + ]: 272752 : if (Token::simpleMatch(tok, "if (")) {
1016 [ + + ]: 6975 : if (alloctype == Fd) {
1017 [ + - ][ + + ]: 1035 : if (Token::Match(tok, "if ( 0|-1 <=|< %varid% )", varid) ||
[ - + ][ + + ]
1018 [ + - ]: 450 : Token::Match(tok, "if ( %varid% != -1 )", varid)) {
1019 [ + - ][ + - ]: 135 : addtoken(&rettail, tok, "if(var)");
[ + - ]
1020 : 135 : tok = tok->next()->link();
1021 : 135 : continue;
1022 [ + - ][ + + ]: 810 : } else if (Token::Match(tok, "if ( %varid% == -1 )", varid) ||
[ + + ][ + + ]
1023 [ + - ]: 360 : Token::Match(tok, "if ( %varid% < 0 )", varid)) {
1024 [ + - ][ + - ]: 180 : addtoken(&rettail, tok, "if(!var)");
[ + - ]
1025 : 180 : tok = tok->next()->link();
1026 : 180 : continue;
1027 : : }
1028 : : }
1029 : :
1030 [ + - ][ + + ]: 6660 : if (Token::Match(tok, "if ( %varid% )", varid)) {
1031 [ + - ][ + - ]: 405 : addtoken(&rettail, tok, "if(var)");
[ + - ]
1032 : :
1033 : : // Make sure the "use" will not be added
1034 : 405 : tok = tok->next()->link();
1035 : 405 : continue;
1036 [ + - ][ + - ]: 6255 : } else if (Token::simpleMatch(tok, "if (") && notvar(tok->tokAt(2), varid, true)) {
[ + - ][ + - ]
[ + + ][ + + ]
1037 [ + - ][ + - ]: 855 : addtoken(&rettail, tok, "if(!var)");
[ + - ]
1038 : :
1039 : : // parse the if-body.
1040 : : // if a variable is assigned then add variable to "extravar".
1041 [ + - ][ + - ]: 3780 : for (const Token *tok2 = tok->next()->link()->tokAt(2); tok2; tok2 = tok2->next()) {
1042 [ + - ][ - + ]: 3780 : if (tok2->str() == "{")
1043 : 0 : tok2 = tok2->link();
1044 [ + - ][ + + ]: 3780 : else if (tok2->str() == "}")
1045 : 855 : break;
1046 [ + - ][ + + ]: 2925 : else if (Token::Match(tok2, "%var% ="))
1047 [ + - ]: 90 : extravar.insert(tok2->varId());
1048 : : }
1049 : :
1050 : 855 : tok = tok->next()->link();
1051 : 855 : continue;
1052 : : } else {
1053 : : // Check if the condition depends on var or extravar somehow..
1054 : 5400 : bool dep = false;
1055 [ + - ]: 5400 : const Token* const end = tok->linkAt(1);
1056 [ + + ]: 27360 : for (const Token *tok2 = tok->next(); tok2 != end; tok2 = tok2->next()) {
1057 [ + - ][ + + ]: 22500 : if (Token::Match(tok2, "close|pclose|fclose|closedir ( %varid% )", varid)) {
1058 [ + - ][ + - ]: 135 : addtoken(&rettail, tok, "dealloc");
[ + - ]
1059 [ + - ][ + - ]: 135 : addtoken(&rettail, tok, ";");
[ + - ]
1060 : 135 : dep = true;
1061 : 135 : break;
1062 [ + + ][ + - ]: 22365 : } else if (alloctype == Fd && Token::Match(tok2, "%varid% !=|>=", varid)) {
[ + + ][ + + ]
1063 : 45 : dep = true;
1064 [ + - ][ + + ]: 22320 : } else if (Token::Match(tok2, "! %varid%", varid)) {
1065 : 225 : dep = true;
1066 [ + - ][ + + ]: 22095 : } else if (Token::Match(tok2, "%var% (") && !test_white_list(tok2->str())) {
[ + - ][ + + ]
[ + + ]
1067 : 855 : bool use = false;
1068 [ + - ][ + - ]: 1305 : for (const Token *tok3 = tok2->tokAt(2); tok3; tok3 = tok3->nextArgument()) {
[ + + ]
1069 [ + - ][ + + ]: 855 : if (Token::Match(tok3->previous(), "(|, &| %varid% ,|)", varid)) {
1070 : 405 : use = true;
1071 : 405 : break;
1072 : : }
1073 : : }
1074 [ + + ]: 855 : if (use) {
1075 [ + - ][ + - ]: 405 : addtoken(&rettail, tok, "use");
[ + - ]
1076 [ + - ][ + - ]: 405 : addtoken(&rettail, tok, ";");
[ + - ]
1077 : 405 : dep = false;
1078 : 405 : break;
1079 : : }
1080 [ + + ][ + - ]: 21240 : } else if (tok2->varId() && extravar.find(tok2->varId()) != extravar.end()) {
[ + - ][ + + ]
[ + + ]
1081 : 45 : dep = true;
1082 [ + + ][ + - ]: 21195 : } else if (tok2->varId() == varid && tok2->next()->isConstOp())
[ + + ][ + + ]
1083 : 540 : dep = true;
1084 : : }
1085 : :
1086 [ + - ][ - + ]: 5400 : if (Token::Match(tok, "if ( ! %varid% &&", varid)) {
1087 [ # # ][ # # ]: 0 : addtoken(&rettail, tok, "if(!var)");
[ # # ]
1088 [ + - + - ]: 16200 : } else if (tok->next() &&
[ + + ][ + + ]
1089 : 5400 : tok->next()->link() &&
1090 [ + - ][ + - ]: 5400 : Token::Match(tok->next()->link()->tokAt(-3), "&& ! %varid%", varid)) {
1091 [ + - ][ + - ]: 90 : addtoken(&rettail, tok, "if(!var)");
[ + - ]
1092 : : } else {
1093 [ + + ][ + - ]: 5310 : addtoken(&rettail, tok, (dep ? "ifv" : "if"));
[ + - ][ + - ]
1094 : : }
1095 : :
1096 : 5400 : tok = tok->next()->link();
1097 : 5400 : continue;
1098 : : }
1099 : : }
1100 : : }
1101 : :
1102 [ + - ][ + + ]: 572035 : if ((tok->str() == "else") || (tok->str() == "switch")) {
[ + - ][ + + ]
[ + + ]
1103 [ + - ]: 1395 : addtoken(&rettail, tok, tok->str());
1104 [ + - ][ + + ]: 1395 : if (Token::simpleMatch(tok, "switch ("))
1105 : 225 : tok = tok->next()->link();
1106 : 1395 : continue;
1107 : : }
1108 : :
1109 [ + - ][ + + ]: 570640 : if ((tok->str() == "case")) {
1110 [ + - ][ + - ]: 180 : addtoken(&rettail, tok, "case");
[ + - ]
1111 [ + - ][ + - ]: 180 : addtoken(&rettail, tok, ";");
[ + - ]
1112 [ + - ][ + - ]: 180 : if (Token::Match(tok, "case %any% :"))
1113 [ + - ]: 180 : tok = tok->tokAt(2);
1114 : 180 : continue;
1115 : : }
1116 : :
1117 [ + - ][ + + ]: 570460 : if ((tok->str() == "default")) {
1118 [ + - ][ + - ]: 180 : addtoken(&rettail, tok, "default");
[ + - ]
1119 [ + - ][ + - ]: 180 : addtoken(&rettail, tok, ";");
[ + - ]
1120 : 180 : continue;
1121 : : }
1122 : :
1123 : : // Loops..
1124 [ + - ][ + + ]: 570280 : else if ((tok->str() == "for") || (tok->str() == "while")) {
[ + - ][ + + ]
[ + + ]
1125 [ + - ]: 2160 : const Token* const end = tok->linkAt(1);
1126 : :
1127 [ + - ][ + + ]: 4275 : if (Token::simpleMatch(tok, "while ( true )") ||
[ + + ][ + + ]
1128 [ + - ]: 2115 : Token::simpleMatch(tok, "for ( ; ; )")) {
1129 [ + - ][ + - ]: 225 : addtoken(&rettail, tok, "while1");
[ + - ]
1130 : 225 : tok = end;
1131 : 225 : continue;
1132 : : }
1133 : :
1134 [ + + ][ + - ]: 1935 : else if (varid && getDeallocationType(tok->tokAt(2), varid) != No) {
[ + - ][ + + ]
[ + + ]
1135 [ + - ][ + - ]: 45 : addtoken(&rettail, tok, "dealloc");
[ + - ]
1136 [ + - ][ + - ]: 45 : addtoken(&rettail, tok, ";");
[ + - ]
1137 : : }
1138 : :
1139 [ + + ][ + - ]: 1890 : else if (alloctype == Fd && varid) {
1140 [ + - ][ + + ]: 270 : if (Token::Match(tok, "while ( 0 <= %varid% )", varid) ||
[ - + ][ + + ]
1141 [ + - ]: 90 : Token::Match(tok, "while ( %varid% != -1 )", varid)) {
1142 [ + - ][ + - ]: 45 : addtoken(&rettail, tok, "while(var)");
[ + - ]
1143 : 45 : tok = end;
1144 : 45 : continue;
1145 [ + - ][ + - ]: 180 : } else if (Token::Match(tok, "while ( %varid% == -1 )", varid) ||
[ + + ][ + + ]
1146 [ + - ]: 90 : Token::Match(tok, "while ( %varid% < 0 )", varid)) {
1147 [ + - ][ + - ]: 45 : addtoken(&rettail, tok, "while(!var)");
[ + - ]
1148 : 45 : tok = end;
1149 : 45 : continue;
1150 : : }
1151 : : }
1152 : :
1153 [ + + ][ + - ]: 1755 : else if (varid && Token::Match(tok, "while ( %varid% )", varid)) {
[ + + ][ + + ]
1154 [ + - ][ + - ]: 45 : addtoken(&rettail, tok, "while(var)");
[ + - ]
1155 : 45 : tok = end;
1156 : 45 : continue;
1157 [ + + ][ + - ]: 1710 : } else if (varid && Token::simpleMatch(tok, "while (") && notvar(tok->tokAt(2), varid, true)) {
[ + + ][ + - ]
[ + - ][ + + ]
[ + + ]
1158 [ + - ][ + - ]: 90 : addtoken(&rettail, tok, "while(!var)");
[ + - ]
1159 : 90 : tok = end;
1160 : 90 : continue;
1161 : : }
1162 : :
1163 [ + - ][ + - ]: 1710 : addtoken(&rettail, tok, "loop");
[ + - ]
1164 : :
1165 [ + + ]: 1710 : if (varid > 0) {
1166 [ + - ][ + - ]: 8460 : for (const Token *tok2 = tok->tokAt(2); tok2 && tok2 != end; tok2 = tok2->next()) {
[ + + ][ + + ]
1167 [ + - ][ + + ]: 7380 : if (notvar(tok2, varid)) {
1168 [ + - ][ + - ]: 90 : addtoken(&rettail, tok2, "!var");
[ + - ]
1169 : 90 : break;
1170 : : }
1171 : : }
1172 : : }
1173 : :
1174 : 1710 : continue;
1175 : : }
1176 [ + - ][ + + ]: 568120 : if ((tok->str() == "do")) {
1177 [ + - ][ + - ]: 45 : addtoken(&rettail, tok, "do");
[ + - ]
1178 : 45 : continue;
1179 : : }
1180 : :
1181 : : // continue / break..
1182 [ + - ][ + + ]: 568075 : else if (tok->str() == "continue") {
1183 [ + - ][ + - ]: 405 : addtoken(&rettail, tok, "continue");
[ + - ]
1184 [ + - ][ + + ]: 567670 : } else if (tok->str() == "break") {
1185 [ + - ][ + - ]: 540 : addtoken(&rettail, tok, "break");
[ + - ]
1186 [ + - ][ + + ]: 567130 : } else if (tok->str() == "goto") {
1187 [ + - ][ + - ]: 180 : addtoken(&rettail, tok, "goto");
[ + - ]
1188 : : }
1189 : :
1190 : : // Return..
1191 [ + - ][ + + ]: 566950 : else if (tok->str() == "return") {
1192 [ + - ][ + - ]: 14880 : addtoken(&rettail, tok, "return");
[ + - ]
1193 [ + + ]: 14880 : if (varid == 0) {
1194 [ + - ][ + - ]: 7410 : addtoken(&rettail, tok, ";");
[ + - ]
1195 [ + - ][ + - ]: 26010 : while (tok && tok->str() != ";")
[ + + ][ + + ]
1196 : 18600 : tok = tok->next();
1197 [ - + ]: 7410 : if (!tok)
1198 : 0 : break;
1199 : 7410 : continue;
1200 : : }
1201 : :
1202 : : // Returning a auto_ptr of this allocated variable..
1203 [ + - ][ + + ]: 7470 : if (Token::simpleMatch(tok->next(), "std :: auto_ptr <")) {
1204 [ + - ]: 45 : const Token *tok2 = tok->linkAt(4);
1205 [ + - ][ + - ]: 45 : if (Token::Match(tok2, "> ( %varid% )", varid)) {
1206 [ + - ][ + - ]: 45 : addtoken(&rettail, tok, "use");
[ + - ]
1207 [ + - ]: 45 : tok = tok2->tokAt(3);
1208 : : }
1209 : : }
1210 : :
1211 [ + - ][ + - ]: 7425 : else if (varid && Token::Match(tok, "return strcpy|strncpy|memcpy ( %varid%", varid)) {
[ + + ][ + + ]
1212 [ + - ][ + - ]: 90 : addtoken(&rettail, tok, "use");
[ + - ]
1213 [ + - ]: 90 : tok = tok->tokAt(2);
1214 : : }
1215 : :
1216 : : else {
1217 : 7335 : bool use = false;
1218 : :
1219 [ + - ][ + - ]: 7335 : std::stack<const Token *> f;
[ + - ]
1220 : :
1221 [ + - ]: 13815 : for (const Token *tok2 = tok->next(); tok2; tok2 = tok2->next()) {
1222 [ + - ][ + + ]: 13815 : if (tok2->str() == ";") {
1223 : 7335 : tok = tok2;
1224 : 7335 : break;
1225 : : }
1226 : :
1227 [ + - ][ + + ]: 6480 : if (tok2->str() == "(")
1228 [ + - ]: 180 : f.push(tok2->previous());
1229 [ + - ][ + + ]: 6300 : else if (!f.empty() && tok2->str() == ")")
[ + - ][ + + ]
[ + + ]
1230 [ + - ]: 180 : f.pop();
1231 : :
1232 [ + + ]: 6480 : if (tok2->varId() == varid) {
1233 : : // Read data..
1234 [ + - ][ + + ]: 3510 : if (!Token::Match(tok2->previous(), "&|(") &&
[ + + ][ + + ]
1235 [ + - ][ + - ]: 1665 : tok2->strAt(1) == "[") {
1236 [ + - ][ + + ]: 2115 : } else if (f.empty() ||
[ + - ][ + + ]
[ + + ]
1237 [ + - ][ + - ]: 180 : !test_white_list(f.top()->str()) ||
1238 [ + - ][ + - ]: 180 : getDeallocationType(f.top(),varid)) {
1239 : 1620 : use = true;
1240 : : }
1241 : : }
1242 : : }
1243 [ + + ]: 7335 : if (use)
1244 [ + - ][ + - ]: 1575 : addtoken(&rettail, tok, "use");
[ + - ]
1245 [ + - ][ + - ]: 7335 : addtoken(&rettail, tok, ";");
[ + - ][ + - ]
1246 : : }
1247 : : }
1248 : :
1249 : : // throw..
1250 [ + - ][ + + ]: 552070 : else if (Token::Match(tok, "try|throw|catch")) {
1251 [ + - ]: 585 : addtoken(&rettail, tok, tok->str());
1252 [ + - ][ + - ]: 585 : if (tok->strAt(1) == "(")
[ + + ]
1253 : 225 : tok = tok->next()->link();
1254 : : }
1255 : :
1256 : : // Assignment..
1257 [ + + ]: 560665 : if (varid) {
1258 [ + - ][ + + ]: 263347 : if (Token::simpleMatch(tok, "= {")) {
1259 [ + - ]: 45 : const Token* const end2 = tok->linkAt(1);
1260 : 45 : bool use = false;
1261 [ + - ]: 225 : for (const Token *tok2 = tok; tok2 != end2; tok2 = tok2->next()) {
1262 [ + + ]: 225 : if (tok2->varId() == varid) {
1263 : 45 : use = true;
1264 : 45 : break;
1265 : : }
1266 : : }
1267 : :
1268 [ + - ]: 45 : if (use) {
1269 [ + - ][ + - ]: 45 : addtoken(&rettail, tok, "use");
[ + - ]
1270 [ + - ][ + - ]: 45 : addtoken(&rettail, tok, ";");
[ + - ]
1271 : 45 : tok = tok->next()->link();
1272 : 45 : continue;
1273 : : }
1274 : : }
1275 : :
1276 [ + - ][ + + ]: 263302 : if (Token::Match(tok, "& %var% = %varid% ;", varid)) {
1277 [ + + ]: 90 : while (rethead->next())
1278 [ + - ]: 45 : rethead->deleteNext();
1279 : 45 : return rethead;
1280 : : }
1281 [ + - ][ + + ]: 1313225 : if (Token::Match(tok, "[)=] %varid% [+;)]", varid) ||
[ + + ][ + + ]
[ + + ][ + - ]
[ + + ][ + + ]
[ + + ]
1282 [ + - ]: 262492 : (Token::Match(tok, "%var% + %varid%", varid) &&
1283 [ + - ][ + - ]: 180 : tok->strAt(3) != "[" &&
1284 [ + - ][ + - ]: 135 : tok->strAt(3) != ".") ||
1285 [ + - ]: 262402 : Token::Match(tok, "<< %varid% ;", varid) ||
1286 [ + - ]: 262402 : Token::Match(tok, "= strcpy|strcat|memmove|memcpy ( %varid% ,", varid) ||
1287 [ + - ]: 262357 : Token::Match(tok, "[;{}] %var% [ %varid% ]", varid)) {
1288 [ + - ][ + - ]: 990 : addtoken(&rettail, tok, "use");
[ + - ]
1289 [ + - ][ + + ]: 523994 : } else if (Token::Match(tok->previous(), ";|{|}|=|(|,|%cop% %varid% [", varid) ||
[ + + ][ + + ]
1290 [ + - ]: 261727 : Token::Match(tok->previous(), ";|{|}|=|(|,|%cop% %varid% .", varid)) {
1291 : : // warning is written for "dealloc ; use_ ;".
1292 : : // but this use doesn't affect the leak-checking
1293 [ + - ][ + - ]: 1170 : addtoken(&rettail, tok, "use_");
[ + - ]
1294 : : }
1295 : : }
1296 : :
1297 : : // Investigate function calls..
1298 [ + - ][ + + ]: 560575 : if (Token::Match(tok, "%var% (")) {
1299 : : // A function call should normally be followed by ";"
1300 [ + - ][ + + ]: 37746 : if (Token::simpleMatch(tok->next()->link(), ") {")) {
1301 [ + - ][ + - ]: 90 : if (!Token::Match(tok, "if|for|while|switch")) {
1302 [ + - ][ + - ]: 90 : addtoken(&rettail, tok, "exit");
[ + - ]
1303 [ + - ][ + - ]: 90 : addtoken(&rettail, tok, ";");
[ + - ]
1304 : 90 : tok = tok->next()->link();
1305 : 90 : continue;
1306 : : }
1307 : : }
1308 : :
1309 : : // Calling setjmp / longjmp => bail out
1310 [ + - ][ + + ]: 37656 : else if (Token::Match(tok, "setjmp|longjmp")) {
1311 [ + + ]: 945 : while (rethead->next())
1312 [ + - ]: 810 : rethead->deleteNext();
1313 : 135 : return rethead;
1314 : : }
1315 : :
1316 : : // Inside class function.. if the var is passed as a parameter then
1317 : : // just add a "::use"
1318 : : // The "::use" means that a member function was probably called but it wasn't analysed further
1319 [ + + ]: 37521 : else if (classmember) {
1320 [ + - ][ + - ]: 405 : if (noreturn.find(tok->str()) != noreturn.end())
[ + + ]
1321 [ + - ][ + - ]: 135 : addtoken(&rettail, tok, "exit");
[ + - ]
1322 : :
1323 [ + - ][ + + ]: 270 : else if (!test_white_list(tok->str())) {
1324 [ + - ]: 225 : const Token* const end2 = tok->linkAt(1);
1325 [ + - ][ + + ]: 495 : for (const Token *tok2 = tok->tokAt(2); tok2 != end2; tok2 = tok2->next()) {
1326 [ + + ]: 270 : if (tok2->varId() == varid) {
1327 [ + - ][ + - ]: 90 : addtoken(&rettail, tok, "::use");
[ + - ]
1328 : 90 : break;
1329 : : }
1330 : : }
1331 : : }
1332 : : }
1333 : :
1334 : : else {
1335 [ + + ][ + - ]: 37116 : if (varid > 0 && Token::Match(tok, "%var% ( close|fclose|pclose ( %varid% ) ) ;", varid)) {
[ + + ][ + + ]
1336 [ + - ][ + - ]: 90 : addtoken(&rettail, tok, "dealloc");
[ + - ]
1337 : 90 : tok = tok->next()->link();
1338 : 90 : continue;
1339 : : }
1340 : :
1341 : 37026 : bool allocpar = false;
1342 [ + - ][ + - ]: 37026 : const char *str = call_func(tok, callstack, varid, alloctype, dealloctype, allocpar, sz);
[ + - ]
1343 [ + + ]: 37026 : if (str) {
1344 [ + + ]: 14490 : if (allocpar) {
1345 [ + - ][ + - ]: 225 : addtoken(&rettail, tok, str);
[ + - ]
1346 : 225 : tok = tok->next()->link();
1347 [ + + ][ + - ]: 14265 : } else if (varid == 0 || str != std::string("alloc")) {
[ + - ][ + - ]
[ + + ][ + - ]
[ + + ][ + - ]
[ # # ][ # # ]
1348 [ + - ][ + - ]: 14265 : addtoken(&rettail, tok, str);
[ + - ]
1349 [ # # ][ # # ]: 0 : } else if (Token::Match(tok->tokAt(-2), "%varid% =", varid)) {
[ # # ]
1350 [ # # ][ # # ]: 0 : addtoken(&rettail, tok, str);
[ # # ]
1351 : : }
1352 [ + + ]: 28971 : } else if (varid > 0 &&
[ + + + - ]
[ + + ]
1353 [ + - ]: 6300 : getReallocationType(tok, varid) != No &&
1354 [ + - ]: 135 : tok->tokAt(2)->varId() == varid) {
1355 [ + - ][ + - ]: 135 : addtoken(&rettail, tok, "if");
[ + - ]
1356 [ + - ][ + - ]: 135 : addtoken(&rettail, tok, "{");
[ + - ]
1357 [ + - ][ + - ]: 135 : addtoken(&rettail, tok, "dealloc");
[ + - ]
1358 [ + - ][ + - ]: 135 : addtoken(&rettail, tok, ";");
[ + - ]
1359 [ + - ][ + - ]: 135 : addtoken(&rettail, tok, "}");
[ + - ]
1360 : 135 : tok = tok->next()->link();
1361 : 135 : continue;
1362 : : }
1363 : : }
1364 : : }
1365 : :
1366 : : // Callback..
1367 [ + - ][ + + ]: 560125 : if (Token::Match(tok, "( *| %var%") && Token::simpleMatch(tok->link(),") (")) {
[ + - ][ + + ]
[ + + ]
1368 : 90 : const Token *tok2 = tok->next();
1369 [ + - ][ + + ]: 90 : if (tok2->str() == "*")
1370 : 45 : tok2 = tok2->next();
1371 : 90 : tok2 = tok2->next();
1372 : :
1373 [ + - ][ - + ]: 90 : while (Token::Match(tok2, ". %var%"))
1374 [ # # ]: 0 : tok2 = tok2->tokAt(2);
1375 : :
1376 [ + - ][ + + ]: 90 : if (Token::simpleMatch(tok2, ") (")) {
1377 [ + - ]: 180 : for (; tok2; tok2 = tok2->next()) {
1378 [ + - ][ - + ]: 135 : if (Token::Match(tok2, "[;{]"))
1379 : 0 : break;
1380 [ + + ]: 135 : else if (tok2->varId() == varid) {
1381 [ + - ][ + - ]: 45 : addtoken(&rettail, tok, "use");
[ + - ]
1382 : 45 : break;
1383 : : }
1384 : : }
1385 : : }
1386 : : }
1387 : :
1388 : : // Linux lists..
1389 [ + + ][ + - ]: 560125 : if (varid > 0 && Token::Match(tok, "[=(,] & %varid% [.[,)]", varid)) {
[ + + ][ + + ]
1390 [ + - ][ + - ]: 585 : addtoken(&rettail, tok, "&use");
[ + - ]
1391 : : }
1392 : : }
1393 : :
1394 [ + + ]: 350133 : for (Token *tok1 = rethead; tok1; tok1 = tok1->next()) {
1395 [ + - ][ + + ]: 312511 : if (Token::simpleMatch(tok1, "callfunc alloc ;")) {
1396 [ + - ]: 45 : tok1->deleteThis();
1397 [ + - ][ + - ]: 45 : tok1->insertToken("use");
[ + - ]
1398 [ + - ][ + - ]: 45 : tok1->insertToken(";");
[ + - ]
1399 : : }
1400 : : }
1401 : :
1402 : 37892 : return rethead;
1403 : : }
1404 : :
1405 : :
1406 : :
1407 : :
1408 : :
1409 : :
1410 : 16956 : void CheckMemoryLeakInFunction::simplifycode(Token *tok) const
1411 : : {
1412 : : {
1413 : : // Replace "throw" that is not in a try block with "return"
1414 : 16956 : int indentlevel = 0;
1415 : 16956 : int trylevel = -1;
1416 [ + + ]: 167535 : for (Token *tok2 = tok; tok2; tok2 = tok2->next()) {
1417 [ + + ]: 150579 : if (tok2->str() == "{")
1418 : 9765 : ++indentlevel;
1419 [ + + ]: 140814 : else if (tok2->str() == "}") {
1420 : 24066 : --indentlevel;
1421 [ + + ]: 24066 : if (indentlevel <= trylevel)
1422 : 14391 : trylevel = -1;
1423 [ + + ][ + + ]: 116748 : } else if (trylevel == -1 && tok2->str() == "try")
[ + + ]
1424 : 135 : trylevel = indentlevel;
1425 [ + + ][ + + ]: 116613 : else if (trylevel == -1 && tok2->str() == "throw")
[ + + ]
1426 [ + - ][ + - ]: 45 : tok2->str("return");
[ + - ]
1427 : : }
1428 : : }
1429 : :
1430 : : // Insert extra ";"
1431 [ + + ]: 167895 : for (Token *tok2 = tok; tok2; tok2 = tok2->next()) {
1432 [ + + ][ + + ]: 150939 : if (!tok2->previous() || Token::Match(tok2->previous(), "[;{}]")) {
[ + + ]
1433 [ + + ]: 99018 : if (Token::Match(tok2, "assign|callfunc|use assign|callfunc|use|}")) {
1434 [ + - ][ + - ]: 360 : tok2->insertToken(";");
[ + - ]
1435 : : }
1436 : : }
1437 : : }
1438 : :
1439 : : // remove redundant braces..
1440 [ + + ]: 167625 : for (Token *start = tok; start; start = start->next()) {
1441 [ + + ]: 150669 : if (Token::simpleMatch(start, "; {")) {
1442 : : // the "link" doesn't work here. Find the end brace..
1443 : 135 : unsigned int indent = 0;
1444 [ + - ]: 855 : for (Token *end = start; end; end = end->next()) {
1445 [ + + ]: 720 : if (end->str() == "{")
1446 : 135 : ++indent;
1447 [ + + ]: 585 : else if (end->str() == "}") {
1448 [ + - ]: 135 : if (indent <= 1) {
1449 : : // If the start/end braces are redundant, delete them
1450 [ + - ][ + - ]: 135 : if (indent == 1 && Token::Match(end->previous(), "[;{}] } %any%")) {
[ + - ]
1451 : 135 : start->deleteNext();
1452 : 135 : end->deleteThis();
1453 : : }
1454 : 135 : break;
1455 : : }
1456 : 0 : --indent;
1457 : : }
1458 : : }
1459 : : }
1460 : : }
1461 : :
1462 : : // reduce the code..
1463 : : // it will be reduced in N passes. When a pass completes without any
1464 : : // simplifications the loop is done.
1465 : 16956 : bool done = false;
1466 [ + + ]: 53442 : while (! done) {
1467 : : //tok->printOut("simplifycode loop..");
1468 : 36486 : done = true;
1469 : :
1470 : : // reduce callfunc
1471 [ + + ]: 327240 : for (Token *tok2 = tok; tok2; tok2 = tok2->next()) {
1472 [ + + ]: 290754 : if (tok2->str() == "callfunc") {
1473 [ + + ]: 1575 : if (!Token::Match(tok2->previous(), "[;{}] callfunc ; }"))
1474 : 990 : tok2->deleteThis();
1475 : : }
1476 : : }
1477 : :
1478 : : // If the code starts with "if return ;" then remove it
1479 [ + + ]: 36486 : if (Token::Match(tok, ";| if return ;")) {
1480 : 225 : tok->deleteNext();
1481 : 225 : tok->deleteThis();
1482 [ + - ]: 225 : if (tok->str() == "return")
1483 : 225 : tok->deleteThis();
1484 [ + + ]: 225 : if (tok->strAt(1) == "else")
1485 : 90 : tok->deleteNext();
1486 : : }
1487 : :
1488 : : // simplify "while1" contents..
1489 [ + + ]: 325350 : for (Token *tok2 = tok; tok2; tok2 = tok2->next()) {
1490 [ + + ]: 288864 : if (Token::simpleMatch(tok2, "while1 {")) {
1491 : 1035 : unsigned int innerIndentlevel = 0;
1492 [ + - ]: 8595 : for (Token *tok3 = tok2->tokAt(2); tok3; tok3 = tok3->next()) {
1493 [ + + ]: 8595 : if (tok3->str() == "{")
1494 : 900 : ++innerIndentlevel;
1495 [ + + ]: 7695 : else if (tok3->str() == "}") {
1496 [ + + ]: 1935 : if (innerIndentlevel == 0)
1497 : 1035 : break;
1498 : 900 : --innerIndentlevel;
1499 : : }
1500 [ + + ][ + + ]: 7650 : while (innerIndentlevel == 0 && Token::Match(tok3, "[{};] if|ifv|else { continue ; }")) {
[ + + ]
1501 : 90 : tok3->deleteNext(5);
1502 [ - + ]: 90 : if (tok3->strAt(1) == "else")
1503 : 0 : tok3->deleteNext();
1504 : : }
1505 : : }
1506 : :
1507 [ + + ]: 1035 : if (Token::simpleMatch(tok2, "while1 { if { dealloc ; return ; } }")) {
1508 [ + - ][ + - ]: 135 : tok2->str(";");
[ + - ]
1509 : 135 : tok2->deleteNext(3);
1510 : 135 : tok2->tokAt(4)->deleteNext(2);
1511 : : }
1512 : : }
1513 : : }
1514 : :
1515 : : // Main inner simplification loop
1516 [ + - ][ + + ]: 266445 : for (Token *tok2 = tok; tok2; tok2 = tok2 ? tok2->next() : NULL) {
1517 : : // Delete extra ";"
1518 [ + + ]: 245394 : while (Token::Match(tok2, "[;{}] ;")) {
1519 : 15435 : tok2->deleteNext();
1520 : 15435 : done = false;
1521 : : }
1522 : :
1523 : : // Replace "{ }" with ";"
1524 [ + + ]: 229959 : if (Token::simpleMatch(tok2->next(), "{ }")) {
1525 : 1260 : tok2->deleteNext(2);
1526 [ + - ][ + - ]: 1260 : tok2->insertToken(";");
[ + - ]
1527 : 1260 : done = false;
1528 : : }
1529 : :
1530 : : // Delete braces around a single instruction..
1531 [ + + ]: 229959 : if (Token::Match(tok2->next(), "{ %var% ; }")) {
1532 : 4950 : tok2->deleteNext();
1533 : 4950 : tok2->tokAt(2)->deleteNext();
1534 : 4950 : done = false;
1535 : : }
1536 [ + + ]: 229959 : if (Token::Match(tok2->next(), "{ %var% %var% ; }")) {
1537 : 1170 : tok2->deleteNext();
1538 : 1170 : tok2->tokAt(3)->deleteNext();
1539 : 1170 : done = false;
1540 : : }
1541 : :
1542 : : // Reduce "if if|callfunc" => "if"
1543 [ + + ]: 228789 : else if (Token::Match(tok2, "if if|callfunc")) {
1544 : 90 : tok2->deleteNext();
1545 : 90 : done = false;
1546 : : }
1547 : :
1548 : : // outer/inner if blocks. Remove outer condition..
1549 [ + + ]: 228699 : else if (Token::Match(tok2->next(), "if|if(var) { if return use ; }")) {
1550 : 90 : tok2->deleteNext(2);
1551 : 90 : tok2->tokAt(4)->deleteNext();
1552 : 90 : done = false;
1553 : : }
1554 : :
1555 [ + + ][ + + ]: 228609 : else if (tok2->next() && tok2->next()->str() == "if") {
[ + + ]
1556 : : // Delete empty if that is not followed by an else
1557 [ + + ]: 10080 : if (Token::Match(tok2->next(), "if ; !!else")) {
1558 : 360 : tok2->deleteNext();
1559 : 360 : done = false;
1560 : : }
1561 : :
1562 : : // Reduce "if X ; else X ;" => "X ;"
1563 [ + + + + ]: 10035 : else if (Token::Match(tok2->next(), "if %var% ; else %var% ;") &&
[ + + ]
1564 : 315 : tok2->strAt(2) == tok2->strAt(5)) {
1565 : 180 : tok2->deleteNext(4);
1566 : 180 : done = false;
1567 : : }
1568 : :
1569 : : // Reduce "if continue ; if continue ;" => "if continue ;"
1570 [ + + ]: 9540 : else if (Token::simpleMatch(tok2->next(), "if continue ; if continue ;")) {
1571 : 45 : tok2->deleteNext(3);
1572 : 45 : done = false;
1573 : : }
1574 : :
1575 : : // Reduce "if return ; alloc ;" => "alloc ;"
1576 [ + + ]: 9495 : else if (Token::Match(tok2, "[;{}] if return ; alloc|return ;")) {
1577 : 180 : tok2->deleteNext(3);
1578 : 180 : done = false;
1579 : : }
1580 : :
1581 : : // "[;{}] if alloc ; else return ;" => "[;{}] alloc ;"
1582 [ + + ]: 9315 : else if (Token::Match(tok2, "[;{}] if alloc ; else return ;")) {
1583 : : // Remove "if"
1584 : 45 : tok2->deleteNext();
1585 : : // Remove "; else return"
1586 : 45 : tok2->next()->deleteNext(3);
1587 : 45 : done = false;
1588 : : }
1589 : :
1590 : : // Reduce "if ; else %var% ;" => "if %var% ;"
1591 [ + + ]: 9270 : else if (Token::Match(tok2->next(), "if ; else %var% ;")) {
1592 : 45 : tok2->next()->deleteNext(2);
1593 : 45 : done = false;
1594 : : }
1595 : :
1596 : : // Reduce "if ; else" => "if"
1597 [ + + ]: 9225 : else if (Token::simpleMatch(tok2->next(), "if ; else")) {
1598 : 180 : tok2->next()->deleteNext(2);
1599 : 180 : done = false;
1600 : : }
1601 : :
1602 : : // Reduce "if return ; else|if return|continue ;" => "if return ;"
1603 [ + + ]: 9045 : else if (Token::Match(tok2->next(), "if return ; else|if return|continue|break ;")) {
1604 : 45 : tok2->tokAt(3)->deleteNext(3);
1605 : 45 : done = false;
1606 : : }
1607 : :
1608 : : // Reduce "if continue|break ; else|if return ;" => "if return ;"
1609 [ + + ]: 9000 : else if (Token::Match(tok2->next(), "if continue|break ; if|else return ;")) {
1610 : 45 : tok2->next()->deleteNext(3);
1611 : 45 : done = false;
1612 : : }
1613 : :
1614 : : // Remove "else" after "if continue|break|return"
1615 [ + + ]: 8955 : else if (Token::Match(tok2->next(), "if continue|break|return ; else")) {
1616 : 45 : tok2->tokAt(3)->deleteNext();
1617 : 45 : done = false;
1618 : : }
1619 : :
1620 : : // Delete "if { dealloc|assign|use ; return ; }"
1621 [ + + + + ]: 10350 : else if (Token::Match(tok2, "[;{}] if { dealloc|assign|use ; return ; }") &&
[ + + ]
1622 : 1440 : !Token::findmatch(tok, "if {| alloc ;")) {
1623 : 1125 : tok2->deleteNext(7);
1624 [ + + ]: 1125 : if (tok2->strAt(1) == "else")
1625 : 90 : tok2->deleteNext();
1626 : 1125 : done = false;
1627 : : }
1628 : :
1629 : : // Remove "if { dealloc ; callfunc ; } !!else|return"
1630 [ + + + + ]: 7965 : else if (Token::Match(tok2->next(), "if { dealloc|assign ; callfunc ; }") &&
[ + + ]
1631 : 180 : !Token::Match(tok2->tokAt(8), "else|return")) {
1632 : 135 : tok2->deleteNext(7);
1633 : 135 : done = false;
1634 : : }
1635 : :
1636 : 10080 : continue;
1637 : : }
1638 : :
1639 : : // Reduce "alloc while(!var) alloc ;" => "alloc ;"
1640 [ + + ]: 219879 : if (Token::Match(tok2, "[;{}] alloc ; while(!var) alloc ;")) {
1641 : 90 : tok2->deleteNext(3);
1642 : 90 : done = false;
1643 : : }
1644 : :
1645 : : // Reduce "ifv return;" => "if return use;"
1646 [ + + ]: 219879 : if (Token::simpleMatch(tok2, "ifv return ;")) {
1647 [ + - ][ + - ]: 90 : tok2->str("if");
[ + - ]
1648 [ + - ][ + - ]: 90 : tok2->next()->insertToken("use");
[ + - ]
1649 : 90 : done = false;
1650 : : }
1651 : :
1652 : : // Reduce "if(var) dealloc ;" and "if(var) use ;" that is not followed by an else..
1653 [ + + ]: 219879 : if (Token::Match(tok2, "[;{}] if(var) assign|dealloc|use ; !!else")) {
1654 : 135 : tok2->deleteNext();
1655 : 135 : done = false;
1656 : : }
1657 : :
1658 : : // Reduce "; if(!var) alloc ; !!else" => "; dealloc ; alloc ;"
1659 [ + + ]: 219879 : if (Token::Match(tok2, "; if(!var) alloc ; !!else")) {
1660 : : // Remove the "if(!var)"
1661 : 90 : tok2->deleteNext();
1662 : :
1663 : : // Insert "dealloc ;" before the "alloc ;"
1664 [ + - ][ + - ]: 90 : tok2->insertToken(";");
[ + - ]
1665 [ + - ][ + - ]: 90 : tok2->insertToken("dealloc");
[ + - ]
1666 : :
1667 : 90 : done = false;
1668 : : }
1669 : :
1670 : : // Reduce "if(!var) exit ;" => ";"
1671 [ + + ]: 219879 : if (Token::simpleMatch(tok2, "; if(!var) exit ;")) {
1672 : 90 : tok2->deleteNext(2);
1673 : 90 : done = false;
1674 : : }
1675 : :
1676 : : // Reduce "if* ;"..
1677 [ + + ]: 219879 : if (Token::Match(tok2->next(), "if(var)|if(!var)|ifv ;")) {
1678 : : // Followed by else..
1679 [ + + ]: 675 : if (tok2->strAt(3) == "else") {
1680 : 180 : tok2 = tok2->next();
1681 [ + + ]: 180 : if (tok2->str() == "if(var)")
1682 [ + - ][ + - ]: 45 : tok2->str("if(!var)");
[ + - ]
1683 [ + + ]: 135 : else if (tok2->str() == "if(!var)")
1684 [ + - ][ + - ]: 90 : tok2->str("if(var)");
[ + - ]
1685 : :
1686 : : // remove the "; else"
1687 : 180 : tok2->deleteNext(2);
1688 : : } else {
1689 : : // remove the "if*"
1690 : 495 : tok2->deleteNext();
1691 : : }
1692 : 675 : done = false;
1693 : : }
1694 : :
1695 : : // Reduce "else ;" => ";"
1696 [ + + ]: 219879 : if (Token::simpleMatch(tok2->next(), "else ;")) {
1697 : 225 : tok2->deleteNext();
1698 : 225 : done = false;
1699 : : }
1700 : :
1701 : : // Reduce "while1 continue| ;" => "use ;"
1702 [ + + ]: 219879 : if (Token::Match(tok2, "while1 if| continue| ;")) {
1703 [ + - ][ + - ]: 135 : tok2->str("use");
[ + - ]
1704 [ + + ]: 270 : while (tok2->strAt(1) != ";")
1705 : 135 : tok2->deleteNext();
1706 : 135 : done = false;
1707 : : }
1708 : :
1709 : : // Reduce "while1 if break ;" => ";"
1710 [ + + ]: 219879 : if (Token::simpleMatch(tok2, "while1 if break ;")) {
1711 [ + - ][ + - ]: 45 : tok2->str(";");
[ + - ]
1712 : 45 : tok2->deleteNext(2);
1713 : 45 : done = false;
1714 : : }
1715 : :
1716 : : // Delete if block: "alloc; if return use ;"
1717 [ + + ]: 219879 : if (Token::Match(tok2, "alloc ; if return use ; !!else")) {
1718 : 360 : tok2->deleteNext(4);
1719 : 360 : done = false;
1720 : : }
1721 : :
1722 : : // Reduce "alloc|dealloc|use|callfunc ; exit ;" => "; exit ;"
1723 [ + + ]: 219879 : if (Token::Match(tok2, "[;{}] alloc|dealloc|use|callfunc ; exit ;")) {
1724 : 630 : tok2->deleteNext();
1725 : 630 : done = false;
1726 : : }
1727 : :
1728 : : // Reduce "alloc|dealloc|use ; if(var) exit ;"
1729 [ + + ]: 219879 : if (Token::Match(tok2, "alloc|dealloc|use ; if(var) exit ;")) {
1730 : 90 : tok2->deleteThis();
1731 : 90 : done = false;
1732 : : }
1733 : :
1734 : : // Remove "if exit ;"
1735 [ + + ]: 219879 : if (Token::simpleMatch(tok2, "if exit ;")) {
1736 : 270 : tok2->deleteNext();
1737 : 270 : tok2->deleteThis();
1738 : 270 : done = false;
1739 : : }
1740 : :
1741 : : // Remove the "if break|continue ;" that follows "dealloc ; alloc ;"
1742 [ + + ][ + + ]: 219879 : if (! _settings->experimental && Token::Match(tok2, "dealloc ; alloc ; if break|continue ;")) {
[ + + ]
1743 : 45 : tok2->tokAt(3)->deleteNext(2);
1744 : 45 : done = false;
1745 : : }
1746 : :
1747 : : // if break ; break ; => break ;
1748 [ - + ]: 219879 : if (Token::Match(tok2->previous(), "[;{}] if break ; break ;")) {
1749 : 0 : tok2->deleteNext(3);
1750 : 0 : done = false;
1751 : : }
1752 : :
1753 : : // Reduce "do { dealloc ; alloc ; } while(var) ;" => ";"
1754 [ + + ]: 219879 : if (Token::simpleMatch(tok2->next(), "do { dealloc ; alloc ; } while(var) ;")) {
1755 : 45 : tok2->deleteNext(8);
1756 : 45 : done = false;
1757 : : }
1758 : :
1759 : : // Reduce "do { alloc ; } " => "alloc ;"
1760 : : /** @todo If the loop "do { alloc ; }" can be executed twice, reduce it to "loop alloc ;" */
1761 [ + + ]: 219879 : if (Token::simpleMatch(tok2->next(), "do { alloc ; }")) {
1762 : 45 : tok2->deleteNext(2);
1763 : 45 : tok2->tokAt(2)->deleteNext();
1764 : 45 : done = false;
1765 : : }
1766 : :
1767 : : // Reduce "loop break ; => ";"
1768 [ + + ]: 219879 : if (Token::Match(tok2->next(), "loop break|continue ;")) {
1769 : 90 : tok2->deleteNext(2);
1770 : 90 : done = false;
1771 : : }
1772 : :
1773 : : // Reduce "loop|do ;" => ";"
1774 [ + + ]: 219879 : if (Token::Match(tok2, "loop|do ;")) {
1775 : 360 : tok2->deleteThis();
1776 : 360 : done = false;
1777 : : }
1778 : :
1779 : : // Reduce "loop if break|continue ; !!else" => ";"
1780 [ + + ]: 219879 : if (Token::Match(tok2->next(), "loop if break|continue ; !!else")) {
1781 : 180 : tok2->deleteNext(3);
1782 : 180 : done = false;
1783 : : }
1784 : :
1785 : : // Reduce "loop { if break|continue ; !!else" => "loop {"
1786 [ + + ]: 219879 : if (Token::Match(tok2, "loop { if break|continue ; !!else")) {
1787 : 270 : tok2->next()->deleteNext(3);
1788 : 270 : done = false;
1789 : : }
1790 : :
1791 : : // Replace "do ; loop ;" with ";"
1792 [ + + ]: 219879 : if (Token::simpleMatch(tok2, "; loop ;")) {
1793 : 90 : tok2->deleteNext(2);
1794 : 90 : done = false;
1795 : : }
1796 : :
1797 : : // Replace "loop loop .." with "loop .."
1798 [ + + ]: 219879 : if (Token::simpleMatch(tok2, "loop loop")) {
1799 : 90 : tok2->deleteThis();
1800 : 90 : done = false;
1801 : : }
1802 : :
1803 : : // Replace "loop if return ;" with "if return ;"
1804 [ + + ]: 219879 : if (Token::simpleMatch(tok2->next(), "loop if return")) {
1805 : 180 : tok2->deleteNext();
1806 : 180 : done = false;
1807 : : }
1808 : :
1809 : : // Reduce "loop|while1 { dealloc ; alloc ; }"
1810 [ + + ]: 219879 : if (Token::Match(tok2, "loop|while1 { dealloc ; alloc ; }")) {
1811 : : // delete "{"
1812 : 225 : tok2->deleteNext();
1813 : : // delete "loop|while1"
1814 : 225 : tok2->deleteThis();
1815 : :
1816 : : // delete "}"
1817 : 225 : tok2->tokAt(3)->deleteNext();
1818 : :
1819 : 225 : done = false;
1820 : : }
1821 : :
1822 : : // loop { use ; callfunc ; } => use ;
1823 : : // assume that the "callfunc" is not noreturn
1824 [ + + ]: 219879 : if (Token::simpleMatch(tok2, "loop { use ; callfunc ; }")) {
1825 : 45 : tok2->deleteNext(6);
1826 [ + - ][ + - ]: 45 : tok2->str("use");
[ + - ]
1827 [ + - ][ + - ]: 45 : tok2->insertToken(";");
[ + - ]
1828 : 45 : done = false;
1829 : : }
1830 : :
1831 : : // Delete if block in "alloc ; if(!var) return ;"
1832 [ + + ]: 219879 : if (Token::simpleMatch(tok2, "alloc ; if(!var) return ;")) {
1833 : 855 : tok2->deleteNext(3);
1834 : 855 : done = false;
1835 : : }
1836 : :
1837 : : // Reduce "[;{}] return use ; %var%" => "[;{}] return use ;"
1838 [ + + ]: 219879 : if (Token::Match(tok2, "[;{}] return use ; %var%")) {
1839 : 45 : tok2->tokAt(3)->deleteNext();
1840 : 45 : done = false;
1841 : : }
1842 : :
1843 : : // Reduce "if(var) return use ;" => "return use ;"
1844 [ + + ]: 219879 : if (Token::Match(tok2->next(), "if(var) return use ; !!else")) {
1845 : 90 : tok2->deleteNext();
1846 : 90 : done = false;
1847 : : }
1848 : :
1849 : : // malloc - realloc => alloc ; dealloc ; alloc ;
1850 : : // Reduce "[;{}] alloc ; dealloc ; alloc ;" => "[;{}] alloc ;"
1851 [ + + ]: 219879 : if (Token::Match(tok2, "[;{}] alloc ; dealloc ; alloc ;")) {
1852 : 315 : tok2->deleteNext(4);
1853 : 315 : done = false;
1854 : : }
1855 : :
1856 : : // use; dealloc; => dealloc;
1857 [ + + ]: 219879 : if (Token::Match(tok2, "[;{}] use ; dealloc ;")) {
1858 : 315 : tok2->deleteNext(2);
1859 : 315 : done = false;
1860 : : }
1861 : :
1862 : : // use use => use
1863 [ - + ]: 219879 : while (Token::simpleMatch(tok2, "use use")) {
1864 : 0 : tok2->deleteNext();
1865 : 0 : done = false;
1866 : : }
1867 : :
1868 : : // use use_ => use
1869 [ + + ]: 219879 : if (Token::simpleMatch(tok2, "use use_")) {
1870 : 45 : tok2->deleteNext();
1871 : 45 : done = false;
1872 : : }
1873 : :
1874 : : // use_ use => use
1875 [ + + ]: 219879 : if (Token::simpleMatch(tok2, "use_ use")) {
1876 : 45 : tok2->deleteThis();
1877 : 45 : done = false;
1878 : : }
1879 : :
1880 : : // use & use => use
1881 [ + + ]: 219924 : while (Token::simpleMatch(tok2, "use & use")) {
1882 : 45 : tok2->deleteNext(2);
1883 : 45 : done = false;
1884 : : }
1885 : :
1886 : : // & use use => use
1887 [ + + ]: 219924 : while (Token::simpleMatch(tok2, "& use use")) {
1888 : 45 : tok2->deleteThis();
1889 : 45 : tok2->deleteThis();
1890 : 45 : done = false;
1891 : : }
1892 : :
1893 : : // use; if| use; => use;
1894 [ + + ]: 220059 : while (Token::Match(tok2, "[;{}] use ; if| use ;")) {
1895 : 180 : Token *t = tok2->tokAt(2);
1896 [ - + ]: 180 : t->deleteNext(2+(t->str()=="if" ? 1 : 0));
1897 : 180 : done = false;
1898 : : }
1899 : :
1900 : : // Delete first part in "use ; return use ;"
1901 [ + + ]: 219879 : if (Token::Match(tok2, "[;{}] use ; return use ;")) {
1902 : 135 : tok2->deleteNext(2);
1903 : 135 : done = false;
1904 : : }
1905 : :
1906 : : // try/catch
1907 [ + + ]: 219879 : if (Token::simpleMatch(tok2, "try ; catch exit ;")) {
1908 : 45 : tok2->deleteNext(3);
1909 : 45 : tok2->deleteThis();
1910 : 45 : done = false;
1911 : : }
1912 : :
1913 : : // Delete second case in "case ; case ;"
1914 [ + + ]: 219924 : while (Token::simpleMatch(tok2, "case ; case ;")) {
1915 : 45 : tok2->deleteNext(2);
1916 : 45 : done = false;
1917 : : }
1918 : :
1919 : : // Replace switch with if (if not complicated)
1920 [ + + ]: 219879 : if (Token::simpleMatch(tok2, "switch {")) {
1921 : : // Right now, I just handle if there are a few case and perhaps a default.
1922 : 450 : bool valid = false;
1923 : 450 : bool incase = false;
1924 [ + - ]: 3690 : for (const Token * _tok = tok2->tokAt(2); _tok; _tok = _tok->next()) {
1925 [ + + ]: 3690 : if (_tok->str() == "{")
1926 : 45 : break;
1927 : :
1928 [ + + ]: 3645 : else if (_tok->str() == "}") {
1929 : 360 : valid = true;
1930 : 360 : break;
1931 : : }
1932 : :
1933 [ - + ]: 3285 : else if (_tok->str() == "switch")
1934 : 0 : break;
1935 : :
1936 [ - + ]: 3285 : else if (_tok->str() == "loop")
1937 : 0 : break;
1938 : :
1939 [ + + ][ + + ]: 3285 : else if (incase && _tok->str() == "case")
[ + + ]
1940 : 45 : break;
1941 : :
1942 [ - + ]: 3240 : else if (Token::Match(_tok, "return !!;"))
1943 : 0 : break;
1944 : :
1945 [ + + ]: 3240 : if (Token::Match(_tok, "if return|break use| ;"))
1946 : 45 : _tok = _tok->tokAt(2);
1947 : :
1948 : 3240 : incase |= (_tok->str() == "case");
1949 [ + + ][ + + ]: 3240 : incase &= (_tok->str() != "break" && _tok->str() != "return");
1950 : : }
1951 : :
1952 [ + + ][ + - ]: 450 : if (!incase && valid) {
1953 : 360 : done = false;
1954 [ + - ][ + - ]: 360 : tok2->str(";");
[ + - ]
1955 : 360 : tok2->deleteNext();
1956 : 360 : tok2 = tok2->next();
1957 : 360 : bool first = true;
1958 [ + + ]: 990 : while (Token::Match(tok2, "case|default")) {
1959 : 630 : const bool def(tok2->str() == "default");
1960 [ + + ][ + - ]: 630 : tok2->str(first ? "if" : "}");
[ + - ][ + - ]
1961 [ + + ]: 630 : if (first) {
1962 : 360 : first = false;
1963 [ + - ][ + - ]: 360 : tok2->insertToken("{");
[ + - ]
1964 : : } else {
1965 : : // Insert "else [if] {
1966 [ + - ][ + - ]: 270 : tok2->insertToken("{");
[ + - ]
1967 [ - + ]: 270 : if (! def)
1968 [ # # ][ # # ]: 0 : tok2->insertToken("if");
[ # # ]
1969 [ + - ][ + - ]: 270 : tok2->insertToken("else");
[ + - ]
1970 : 270 : tok2 = tok2->next();
1971 : : }
1972 [ + - ]: 3060 : while (tok2) {
1973 [ - + ]: 3060 : if (tok2->str() == "}")
1974 : 0 : break;
1975 [ + + ]: 3060 : if (Token::Match(tok2, "break|return ;"))
1976 : 630 : break;
1977 [ + + ]: 2430 : if (Token::Match(tok2, "if return|break use| ;"))
1978 : 45 : tok2 = tok2->tokAt(2);
1979 : : else
1980 : 2385 : tok2 = tok2->next();
1981 : : }
1982 [ + + ]: 630 : if (Token::simpleMatch(tok2, "break ;")) {
1983 [ + - ][ + - ]: 360 : tok2->str(";");
[ + - ]
1984 : 360 : tok2 = tok2->tokAt(2);
1985 [ + - ][ + - ]: 270 : } else if (tok2 && tok2->str() == "return") {
[ + - ]
1986 : 270 : tok2 = tok2->tokAt(2);
1987 : : }
1988 : : }
1989 : : }
1990 : : }
1991 : : }
1992 : :
1993 : : // If "--all" is given, remove all "callfunc"..
1994 [ + + ][ + + ]: 36486 : if (done && _settings->experimental) {
1995 [ + + ]: 5445 : for (Token *tok2 = tok; tok2; tok2 = tok2->next()) {
1996 [ - + ]: 4770 : if (tok2->str() == "callfunc") {
1997 : 0 : tok2->deleteThis();
1998 : 0 : done = false;
1999 : : }
2000 : : }
2001 : : }
2002 : : }
2003 : 16956 : }
2004 : :
2005 : :
2006 : :
2007 : :
2008 : :
2009 : 12456 : const Token *CheckMemoryLeakInFunction::findleak(const Token *tokens)
2010 : : {
2011 : : const Token *result;
2012 : :
2013 [ + + ]: 12456 : if ((result = Token::findsimplematch(tokens, "loop alloc ;")) != NULL) {
2014 : 90 : return result;
2015 : : }
2016 : :
2017 [ + + ]: 12366 : if (Token::Match(tokens, "alloc ; if|if(var)|ifv break|continue|return ;")) {
2018 : 180 : return tokens->tokAt(3);
2019 : : }
2020 : :
2021 [ + + ]: 12186 : if ((result = Token::findmatch(tokens, "alloc ; if|if(var)|ifv return ;")) != NULL) {
2022 : 585 : return result->tokAt(3);
2023 : : }
2024 : :
2025 [ + + ]: 11601 : if ((result = Token::findmatch(tokens, "alloc ; alloc|assign|return callfunc| ;")) != NULL) {
2026 : 990 : return result->tokAt(2);
2027 : : }
2028 : :
2029 [ + + ]: 10611 : if ((result = Token::findsimplematch(tokens, "; alloc ; if assign ;")) != NULL) {
2030 : 45 : return result->tokAt(4);
2031 : : }
2032 : :
2033 [ + + + - ]: 10656 : if (((result = Token::findsimplematch(tokens, "; alloc ; if dealloc ; }")) != NULL) &&
[ + + ]
2034 : 90 : !result->tokAt(7)) {
2035 : 90 : return result->tokAt(6);
2036 : : }
2037 : :
2038 [ + + ]: 10476 : if ((result = Token::findsimplematch(tokens, "alloc ; }")) != NULL) {
2039 [ + + ]: 3771 : if (result->tokAt(3) == NULL)
2040 : 3681 : return result->tokAt(2);
2041 : : }
2042 : :
2043 : : // No deallocation / usage => report leak at the last token
2044 [ + + ]: 6795 : if (!Token::findmatch(tokens, "dealloc|use")) {
2045 : 225 : const Token *last = tokens;
2046 [ + + ]: 1305 : while (last->next())
2047 : 1080 : last = last->next();
2048 : :
2049 : : // not a leak if exit is called before the end of the function
2050 [ + + ]: 225 : if (!Token::Match(last->tokAt(-2), "exit|callfunc ; }"))
2051 : 135 : return last;
2052 : : }
2053 : :
2054 : 12456 : return NULL;
2055 : : }
2056 : :
2057 : :
2058 : :
2059 : :
2060 : :
2061 : :
2062 : : // Check for memory leaks for a function variable.
2063 : 30287 : void CheckMemoryLeakInFunction::checkScope(const Token *Tok1, const std::string &varname, unsigned int varid, bool classmember, unsigned int sz)
2064 : : {
2065 : 30287 : std::list<const Token *> callstack;
2066 : :
2067 : 30287 : AllocType alloctype = No;
2068 : 30287 : AllocType dealloctype = No;
2069 : :
2070 : : const Token *result;
2071 : :
2072 [ + - ][ + - ]: 30287 : Token *tok = getcode(Tok1, callstack, varid, alloctype, dealloctype, classmember, sz);
[ + - ]
2073 : : //tok->printOut((std::string("Checkmemoryleak: getcode result for: ") + varname).c_str());
2074 : :
2075 [ + - ]: 30287 : const bool use_addr = bool(Token::findsimplematch(tok, "&use") != NULL);
2076 : :
2077 : : // Simplify the code and check if freed memory is used..
2078 [ + + ]: 238755 : for (Token *tok2 = tok; tok2; tok2 = tok2->next()) {
2079 [ + - ][ + + ]: 272956 : while (Token::Match(tok2, "[;{}] ;"))
2080 [ + - ]: 64488 : tok2->deleteNext();
2081 : : }
2082 [ + - ][ + + ]: 30287 : if ((result = Token::findmatch(tok, "[;{}] dealloc ; use_ ;")) != NULL) {
2083 [ + - ][ + - ]: 225 : deallocuseError(result->tokAt(3), varname);
2084 : : }
2085 : :
2086 : : // Replace "&use" with "use". Replace "use_" with ";"
2087 [ + + ]: 239925 : for (Token *tok2 = tok; tok2; tok2 = tok2->next()) {
2088 [ + - ][ + + ]: 209638 : if (tok2->str() == "&use")
2089 [ + - ][ + - ]: 540 : tok2->str("use");
[ + - ]
2090 [ + - ][ + + ]: 209098 : else if (tok2->str() == "use_")
2091 [ + - ][ + - ]: 10170 : tok2->str(";");
[ + - ]
2092 [ + - ][ - + ]: 198928 : else if (Token::simpleMatch(tok2, "loop use_ {"))
2093 [ # # ]: 0 : tok2->deleteNext();
2094 [ + - ][ + + ]: 198928 : else if (tok2->str() == "::use") // Some kind of member function usage. Not analyzed very well.
2095 [ + - ][ + - ]: 90 : tok2->str("use");
[ + - ]
2096 [ + - ][ - + ]: 198838 : else if (tok2->str() == "recursive")
2097 [ # # ][ # # ]: 0 : tok2->str("use");
[ # # ]
2098 [ + - ][ - + ]: 198838 : else if (tok2->str() == "dealloc_")
2099 [ # # ][ # # ]: 0 : tok2->str("dealloc");
[ # # ]
2100 [ + - ][ + + ]: 198838 : else if (tok2->str() == "realloc") {
2101 [ + - ][ + - ]: 585 : tok2->str("dealloc");
[ + - ]
2102 [ + - ][ + - ]: 585 : tok2->insertToken("alloc");
[ + - ]
2103 [ + - ][ + - ]: 585 : tok2->insertToken(";");
[ + - ]
2104 : : }
2105 : : }
2106 : :
2107 : : // If the variable is not allocated at all => no memory leak
2108 [ + - ][ + + ]: 30287 : if (Token::findsimplematch(tok, "alloc") == 0) {
2109 [ + - ]: 19091 : TokenList::deleteTokens(tok);
2110 : : return;
2111 : : }
2112 : :
2113 [ + - ]: 11196 : simplifycode(tok);
2114 : :
2115 [ - + ][ # # ]: 11196 : if (_settings->debug && _settings->_verbose) {
2116 [ # # ][ # # ]: 0 : tok->printOut(("Checkmemoryleak: simplifycode result for: " + varname).c_str());
[ # # ][ # # ]
2117 : : }
2118 : :
2119 : : // If the variable is not allocated at all => no memory leak
2120 [ + - ][ + + ]: 11196 : if (Token::findsimplematch(tok, "alloc") == 0) {
2121 [ + - ]: 225 : TokenList::deleteTokens(tok);
2122 : : return;
2123 : : }
2124 : :
2125 : : /** @todo handle "goto" */
2126 [ + - ][ - + ]: 10971 : if (Token::findsimplematch(tok, "goto")) {
2127 [ # # ]: 0 : TokenList::deleteTokens(tok);
2128 : : return;
2129 : : }
2130 : :
2131 [ + - ][ + + ]: 10971 : if ((result = findleak(tok)) != NULL) {
2132 [ + - ]: 5166 : memoryLeak(result, varname, alloctype);
2133 : : }
2134 : :
2135 [ + + ][ + - ]: 5805 : else if (!use_addr && (result = Token::findsimplematch(tok, "dealloc ; dealloc ;")) != NULL) {
[ + + ][ + + ]
2136 [ + - ][ + - ]: 45 : deallocDeallocError(result->tokAt(2), varname);
2137 : : }
2138 : :
2139 : : // detect cases that "simplifycode" don't handle well..
2140 [ - + ]: 5760 : else if (_settings->debugwarnings) {
2141 : 0 : Token *first = tok;
2142 [ # # ][ # # ]: 0 : while (first && first->str() == ";")
[ # # ][ # # ]
2143 : 0 : first = first->next();
2144 : :
2145 : 0 : bool noerr = false;
2146 [ # # ]: 0 : noerr |= Token::simpleMatch(first, "alloc ; }");
2147 [ # # ]: 0 : noerr |= Token::simpleMatch(first, "alloc ; dealloc ; }");
2148 [ # # ]: 0 : noerr |= Token::simpleMatch(first, "alloc ; return use ; }");
2149 [ # # ]: 0 : noerr |= Token::simpleMatch(first, "alloc ; use ; }");
2150 [ # # ]: 0 : noerr |= Token::simpleMatch(first, "alloc ; use ; return ; }");
2151 [ # # ]: 0 : noerr |= Token::simpleMatch(first, "alloc ; dealloc ; return ; }");
2152 [ # # ]: 0 : noerr |= Token::simpleMatch(first, "if alloc ; dealloc ; }");
2153 [ # # ]: 0 : noerr |= Token::simpleMatch(first, "if alloc ; return use ; }");
2154 [ # # ]: 0 : noerr |= Token::simpleMatch(first, "if alloc ; use ; }");
2155 [ # # ]: 0 : noerr |= Token::simpleMatch(first, "alloc ; ifv return ; dealloc ; }");
2156 [ # # ]: 0 : noerr |= Token::simpleMatch(first, "alloc ; if return ; dealloc; }");
2157 : :
2158 : : // Unhandled case..
2159 [ # # ][ # # ]: 0 : if (!noerr && tok) {
2160 [ # # ]: 0 : std::ostringstream errmsg;
2161 [ # # ][ # # ]: 0 : errmsg << "inconclusive leak of " << varname << ": ";
[ # # ]
2162 [ # # ][ # # ]: 0 : errmsg << tok->stringifyList(false, false, false, false, false, 0, 0);
[ # # ]
2163 [ # # ][ # # ]: 0 : reportError(first, Severity::debug, "debug", errmsg.str());
[ # # ][ # # ]
[ # # ][ # # ]
2164 : : }
2165 : : }
2166 : :
2167 [ + - ]: 30287 : TokenList::deleteTokens(tok);
2168 : : }
2169 : : //---------------------------------------------------------------------------
2170 : :
2171 : :
2172 : :
2173 : :
2174 : :
2175 : : //---------------------------------------------------------------------------
2176 : : // Check for memory leaks due to improper realloc() usage.
2177 : : // Below, "a" may be set to null without being freed if realloc() cannot
2178 : : // allocate the requested memory:
2179 : : // a = malloc(10); a = realloc(a, 100);
2180 : : //---------------------------------------------------------------------------
2181 : 630 : static bool isNoArgument(const SymbolDatabase* symbolDatabase, unsigned int varid)
2182 : : {
2183 : 630 : const Variable* var = symbolDatabase->getVariableFromVarId(varid);
2184 [ + - ][ + + ]: 630 : return var && !var->isArgument();
2185 : : }
2186 : :
2187 : 11536 : void CheckMemoryLeakInFunction::checkReallocUsage()
2188 : : {
2189 : : // only check functions
2190 : 11536 : const std::size_t functions = symbolDatabase->functionScopes.size();
2191 [ + + ]: 25412 : for (std::size_t i = 0; i < functions; ++i) {
2192 : 13876 : const Scope * scope = symbolDatabase->functionScopes[i];
2193 : :
2194 : : // Search for the "var = realloc(var, 100" pattern within this function
2195 [ + + ]: 347284 : for (const Token *tok = scope->classStart->next(); tok != scope->classEnd; tok = tok->next()) {
2196 [ + + + + : 388100 : if (tok->varId() > 0 &&
+ + + + ]
[ + + ]
2197 : 53522 : Token::Match(tok, "%var% = realloc|g_try_realloc ( %var% , %any%") &&
2198 : 630 : tok->varId() == tok->tokAt(4)->varId() &&
2199 : 540 : isNoArgument(symbolDatabase, tok->varId())) {
2200 : : // Check that another copy of the pointer wasn't saved earlier in the function
2201 [ + - + + ]: 990 : if (Token::findmatch(scope->classStart, "%var% = %varid% ;", tok, tok->varId()) ||
[ + + ]
2202 : 495 : Token::findmatch(scope->classStart, "[{};] %varid% = %var% [;=]", tok, tok->varId()))
2203 : 45 : continue;
2204 : :
2205 : 450 : const Token* tokEndRealloc = tok->linkAt(3);
2206 : : // Check that the allocation isn't followed immediately by an 'if (!var) { error(); }' that might handle failure
2207 [ + + ]: 450 : if (Token::Match(tokEndRealloc->next(), "; if ( ! %varid% ) {", tok->varId())) {
2208 : 225 : const Token* tokEndBrace = tokEndRealloc->linkAt(7);
2209 [ + - ]: 315 : if (tokEndBrace && Token::simpleMatch(tokEndBrace->tokAt(-2), ") ;") &&
[ + + + - ]
[ + + ]
2210 : 90 : Token::Match(tokEndBrace->linkAt(-2)->tokAt(-2), "{|}|; %var% ("))
2211 : 90 : continue;
2212 : : }
2213 : :
2214 : 360 : memleakUponReallocFailureError(tok, tok->str());
2215 [ + + + + : 386345 : } else if (tok->next()->varId() > 0 &&
+ - + + ]
[ + + ]
2216 : 53252 : (Token::Match(tok, "* %var% = realloc|g_try_realloc ( * %var% , %any%") &&
2217 : 90 : tok->next()->varId() == tok->tokAt(6)->varId()) &&
2218 : 90 : isNoArgument(symbolDatabase, tok->next()->varId())) {
2219 : : // Check that another copy of the pointer wasn't saved earlier in the function
2220 [ + - - + ]: 90 : if (Token::findmatch(scope->classStart, "%var% = * %varid% ;", tok, tok->next()->varId()) ||
[ - + ]
2221 : 45 : Token::findmatch(scope->classStart, "[{};] * %varid% = %var% [;=]", tok, tok->next()->varId()))
2222 : 0 : continue;
2223 : :
2224 : 45 : const Token* tokEndRealloc = tok->linkAt(4);
2225 : : // Check that the allocation isn't followed immediately by an 'if (!var) { error(); }' that might handle failure
2226 [ - + ]: 45 : if (Token::Match(tokEndRealloc->next(), "; if ( ! * %varid% ) {", tok->next()->varId())) {
2227 : 0 : const Token* tokEndBrace = tokEndRealloc->linkAt(8);
2228 [ # # ]: 0 : if (tokEndBrace && Token::simpleMatch(tokEndBrace->tokAt(-2), ") ;") &&
[ # # # # ]
[ # # ]
2229 : 0 : Token::Match(tokEndBrace->linkAt(-2)->tokAt(-2), "{|}|; %var% ("))
2230 : 0 : continue;
2231 : : }
2232 : 45 : memleakUponReallocFailureError(tok->next(), tok->strAt(1));
2233 : : }
2234 : : }
2235 : : }
2236 : 11536 : }
2237 : : //---------------------------------------------------------------------------
2238 : :
2239 : :
2240 : :
2241 : :
2242 : :
2243 : :
2244 : : //---------------------------------------------------------------------------
2245 : : // Checks for memory leaks inside function..
2246 : : //---------------------------------------------------------------------------
2247 : :
2248 : 16411 : static bool isInMemberFunc(const Scope* scope)
2249 : : {
2250 [ + + ][ + + ]: 34388 : while (scope->nestedIn && !scope->functionOf)
[ + + ]
2251 : 17977 : scope = scope->nestedIn;
2252 : :
2253 : 16411 : return (scope->functionOf != 0);
2254 : : }
2255 : :
2256 : 11536 : void CheckMemoryLeakInFunction::check()
2257 : : {
2258 : : // fill the "noreturn"
2259 : 11536 : parse_noreturn();
2260 : :
2261 : : // Check locking/unlocking of global resources..
2262 : 11536 : const std::size_t functions = symbolDatabase->functionScopes.size();
2263 [ + + ]: 25412 : for (std::size_t i = 0; i < functions; ++i) {
2264 : 13876 : const Scope * scope = symbolDatabase->functionScopes[i];
2265 : :
2266 [ + - ][ + - ]: 13876 : checkScope(scope->classStart->next(), "", 0, scope->functionOf != NULL, 1);
[ + - ]
2267 : : }
2268 : :
2269 : : // Check variables..
2270 [ + + ]: 41603 : for (unsigned int i = 0; i < symbolDatabase->getVariableListSize(); i++) {
2271 : 30067 : const Variable* var = symbolDatabase->getVariableFromVarId(i);
2272 [ + + ][ + + ]: 30067 : if (!var || (!var->isLocal() && !var->isArgument()) || var->isStatic() || !var->scope())
[ + + ][ + + ]
[ - + ][ + + ]
2273 : 12576 : continue;
2274 : :
2275 [ + + ]: 17491 : if (var->isReference())
2276 : 90 : continue;
2277 : :
2278 [ + + ][ + + ]: 17401 : if (!var->isPointer() && var->typeStartToken()->str() != "int")
[ + + ]
2279 : 945 : continue;
2280 : :
2281 : : // check for known class without implementation (forward declaration)
2282 [ + + ][ + + ]: 16456 : if (var->isPointer() && var->type() && !var->typeScope())
[ + + ][ + + ]
2283 : 45 : continue;
2284 : :
2285 : 16411 : unsigned int sz = _tokenizer->sizeOfType(var->typeStartToken());
2286 [ + + ]: 16411 : if (sz < 1)
2287 : 2430 : sz = 1;
2288 : :
2289 [ + + ]: 16411 : if (var->isArgument())
2290 : 2655 : checkScope(var->scope()->classStart->next(), var->name(), i, isInMemberFunc(var->scope()), sz);
2291 : : else
2292 : 13756 : checkScope(var->nameToken(), var->name(), i, isInMemberFunc(var->scope()), sz);
2293 : : }
2294 : 11536 : }
2295 : : //---------------------------------------------------------------------------
2296 : :
2297 : :
2298 : :
2299 : :
2300 : :
2301 : :
2302 : :
2303 : :
2304 : :
2305 : :
2306 : :
2307 : :
2308 : :
2309 : :
2310 : :
2311 : :
2312 : :
2313 : :
2314 : :
2315 : :
2316 : :
2317 : :
2318 : :
2319 : :
2320 : :
2321 : :
2322 : :
2323 : :
2324 : :
2325 : : //---------------------------------------------------------------------------
2326 : : // Checks for memory leaks in classes..
2327 : : //---------------------------------------------------------------------------
2328 : :
2329 : :
2330 : :
2331 : 3571 : void CheckMemoryLeakInClass::check()
2332 : : {
2333 : 3571 : const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase();
2334 : :
2335 : : // only check classes and structures
2336 : 3571 : const std::size_t classes = symbolDatabase->classAndStructScopes.size();
2337 [ + + ]: 6721 : for (std::size_t i = 0; i < classes; ++i) {
2338 : 3150 : const Scope * scope = symbolDatabase->classAndStructScopes[i];
2339 : 3150 : std::list<Variable>::const_iterator var;
2340 [ + + ]: 6435 : for (var = scope->varlist.begin(); var != scope->varlist.end(); ++var) {
2341 [ + + ][ + + ]: 3285 : if (!var->isStatic() && var->isPointer()) {
[ + + ]
2342 : : // allocation but no deallocation of private variables in public function..
2343 : 3195 : const Token *tok = var->typeStartToken();
2344 [ + + ]: 3195 : if (tok->isStandardType()) {
2345 [ + + ]: 2520 : if (var->isPrivate())
2346 : 2160 : checkPublicFunctions(&(*scope), var->nameToken());
2347 : :
2348 : 2520 : variable(&(*scope), var->nameToken());
2349 : : }
2350 : :
2351 : : // known class?
2352 [ + + ]: 675 : else if (var->type()) {
2353 : : // not derived?
2354 [ + - ]: 585 : if (var->type()->derivedFrom.empty()) {
2355 [ + + ]: 585 : if (var->isPrivate())
2356 : 495 : checkPublicFunctions(&(*scope), var->nameToken());
2357 : :
2358 : 585 : variable(&(*scope), var->nameToken());
2359 : : }
2360 : : }
2361 : : }
2362 : : }
2363 : : }
2364 : 3571 : }
2365 : :
2366 : :
2367 : 3105 : void CheckMemoryLeakInClass::variable(const Scope *scope, const Token *tokVarname)
2368 : : {
2369 : 3105 : const std::string& varname = tokVarname->str();
2370 : 3105 : const unsigned int varid = tokVarname->varId();
2371 : 3105 : const std::string& classname = scope->className;
2372 : :
2373 : : // Check if member variable has been allocated and deallocated..
2374 : 3105 : CheckMemoryLeak::AllocType Alloc = CheckMemoryLeak::No;
2375 : 3105 : CheckMemoryLeak::AllocType Dealloc = CheckMemoryLeak::No;
2376 : :
2377 : 3105 : bool allocInConstructor = false;
2378 : 3105 : bool deallocInDestructor = false;
2379 : :
2380 : : // Inspect member functions
2381 : 3105 : std::list<Function>::const_iterator func;
2382 [ + + ]: 8235 : for (func = scope->functionList.begin(); func != scope->functionList.end(); ++func) {
2383 : 5445 : const bool constructor = func->type == Function::eConstructor;
2384 : 5445 : const bool destructor = func->type == Function::eDestructor;
2385 [ + + ]: 5445 : if (!func->hasBody) {
2386 [ + - ]: 45 : if (destructor) { // implementation for destructor is not seen => assume it deallocates all variables properly
2387 : 45 : deallocInDestructor = true;
2388 : 45 : Dealloc = CheckMemoryLeak::Many;
2389 : : }
2390 : 45 : continue;
2391 : : }
2392 : 5400 : bool body = false;
2393 : 5400 : const Token *end = func->functionScope->classEnd;
2394 [ + + ]: 56385 : for (const Token *tok = func->arg->link(); tok != end; tok = tok->next()) {
2395 [ + + ]: 51300 : if (tok == func->functionScope->classStart)
2396 : 5400 : body = true;
2397 : : else {
2398 [ + + ]: 45900 : if (!body) {
2399 [ + + ]: 8550 : if (!Token::Match(tok, ":|, %varid% (", varid))
2400 : 8235 : continue;
2401 : : }
2402 : :
2403 : : // Allocate..
2404 [ + + ][ + + ]: 37665 : if (!body || Token::Match(tok, "%varid% =", varid)) {
[ + + ]
2405 : : // var1 = var2 = ...
2406 : : // bail out
2407 [ + + ]: 3285 : if (tok->strAt(-1) == "=")
2408 : 45 : return;
2409 : :
2410 : : // Foo::var1 = ..
2411 : : // bail out when not same class
2412 [ + + - + ]: 3285 : if (tok->strAt(-1) == "::" &&
[ - + ]
2413 : 45 : tok->strAt(-2) != scope->className)
2414 : 0 : return;
2415 : :
2416 [ + + ]: 3240 : AllocType alloc = getAllocationType(tok->tokAt(body ? 2 : 3), 0);
2417 [ + + ]: 3240 : if (alloc != CheckMemoryLeak::No) {
2418 [ + + ]: 2880 : if (constructor)
2419 : 2205 : allocInConstructor = true;
2420 : :
2421 [ - + ][ # # ]: 2880 : if (Alloc != No && Alloc != alloc)
2422 : 0 : alloc = CheckMemoryLeak::Many;
2423 : :
2424 : 2880 : std::list<const Token *> callstack;
2425 [ + - ][ + + ]: 2880 : if (alloc != CheckMemoryLeak::Many && Dealloc != CheckMemoryLeak::No && Dealloc != CheckMemoryLeak::Many && Dealloc != alloc) {
[ - + ][ # # ]
2426 [ # # ]: 0 : callstack.push_back(tok);
2427 [ # # ][ # # ]: 0 : mismatchAllocDealloc(callstack, classname + "::" + varname);
[ # # ][ # # ]
[ # # ]
2428 : : }
2429 : :
2430 : 2880 : Alloc = alloc;
2431 : : }
2432 : : }
2433 : :
2434 [ + + ]: 37620 : if (!body)
2435 : 315 : continue;
2436 : :
2437 : : // Deallocate..
2438 : 37305 : AllocType dealloc = getDeallocationType(tok, varname);
2439 [ + + ]: 37305 : if (dealloc == No) {
2440 [ + - ][ + - ]: 35820 : std::string temp = scope->className + " :: " + varname;
2441 [ + - ]: 35820 : dealloc = getDeallocationType(tok, temp);
2442 : : }
2443 [ + + ]: 37305 : if (dealloc == No) {
2444 : 35775 : std::string temp = "this . " + varname;
2445 [ + - ]: 35775 : dealloc = getDeallocationType(tok, temp);
2446 : : }
2447 : : // some usage in the destructor => assume it's related
2448 : : // to deallocation
2449 [ + + ][ + + ]: 37305 : if (destructor && tok->str() == varname)
[ + + ]
2450 : 1395 : dealloc = CheckMemoryLeak::Many;
2451 [ + + ]: 37305 : if (dealloc != CheckMemoryLeak::No) {
2452 [ + + ]: 3015 : if (destructor)
2453 : 2655 : deallocInDestructor = true;
2454 : :
2455 : : // several types of allocation/deallocation?
2456 [ + + ][ + + ]: 3015 : if (Dealloc != CheckMemoryLeak::No && Dealloc != dealloc)
2457 : 1260 : dealloc = CheckMemoryLeak::Many;
2458 : :
2459 : 3015 : std::list<const Token *> callstack;
2460 [ + + ][ + + ]: 3015 : if (dealloc != CheckMemoryLeak::Many && Alloc != CheckMemoryLeak::No && Alloc != Many && Alloc != dealloc) {
[ + - ][ + + ]
2461 [ + - ]: 135 : callstack.push_back(tok);
2462 [ + - ][ + - ]: 135 : mismatchAllocDealloc(callstack, classname + "::" + varname);
[ + - ][ + - ]
[ + - ]
2463 : : }
2464 : :
2465 : 3015 : Dealloc = dealloc;
2466 : : }
2467 : :
2468 : : // Function call .. possible deallocation
2469 [ + + ]: 34290 : else if (Token::Match(tok->previous(), "[{};] %var% (")) {
2470 [ + + ]: 360 : if (!CheckMemoryLeakInFunction::test_white_list(tok->str())) {
2471 : 270 : return;
2472 : : }
2473 : : }
2474 : : }
2475 : : }
2476 : : }
2477 : :
2478 [ + + ][ + + ]: 2790 : if (allocInConstructor && !deallocInDestructor) {
2479 [ + - ][ + - ]: 855 : unsafeClassError(tokVarname, classname, classname + "::" + varname /*, Alloc*/);
[ + - ]
2480 [ + + ][ + + ]: 1935 : } else if (Alloc != CheckMemoryLeak::No && Dealloc == CheckMemoryLeak::No) {
2481 [ + - ][ + - ]: 3105 : unsafeClassError(tokVarname, classname, classname + "::" + varname /*, Alloc*/);
[ + - ]
2482 : : }
2483 : : }
2484 : :
2485 : 1170 : void CheckMemoryLeakInClass::unsafeClassError(const Token *tok, const std::string &classname, const std::string &varname)
2486 : : {
2487 : : reportError(tok, Severity::style, "unsafeClassCanLeak",
2488 : : "Class '" + classname + "' is unsafe, '" + varname + "' can leak by wrong usage.\n"
2489 [ + - ][ + - ]: 1170 : "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.");
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ]
2490 : 1170 : }
2491 : :
2492 : :
2493 : 2655 : void CheckMemoryLeakInClass::checkPublicFunctions(const Scope *scope, const Token *classtok)
2494 : : {
2495 : : // Check that public functions deallocate the pointers that they allocate.
2496 : : // There is no checking how these functions are used and therefore it
2497 : : // isn't established if there is real leaks or not.
2498 [ + - ][ + - ]: 2655 : if (!_settings->isEnabled("warning"))
[ + - ][ - + ]
2499 : 0 : return;
2500 : :
2501 : 2655 : const unsigned int varid = classtok->varId();
2502 [ - + ]: 2655 : if (varid == 0) {
2503 [ # # ][ # # ]: 0 : _tokenizer->getSymbolDatabase()->debugMessage(classtok, "CheckMemoryInClass::checkPublicFunctions found variable \'" + classtok->str() + "\' with varid 0");
[ # # ]
2504 : 0 : return;
2505 : : }
2506 : :
2507 : : // Parse public functions..
2508 : : // If they allocate member variables, they should also deallocate
2509 : 2655 : std::list<Function>::const_iterator func;
2510 : :
2511 [ + + ]: 7650 : for (func = scope->functionList.begin(); func != scope->functionList.end(); ++func) {
2512 [ + + ][ + + : 6660 : if ((func->type == Function::eFunction || func->type == Function::eOperatorEqual) &&
+ + + - ]
[ + + ]
2513 : 1665 : func->access == Public && func->hasBody) {
2514 : 810 : const Token *tok2 = func->token;
2515 [ + + ]: 3690 : while (tok2->str() != "{")
2516 : 2880 : tok2 = tok2->next();
2517 [ + + ]: 810 : if (Token::Match(tok2, "{|}|; %varid% =", varid)) {
2518 : 585 : const CheckMemoryLeak::AllocType alloc = getAllocationType(tok2->tokAt(3), varid);
2519 [ + - ]: 585 : if (alloc != CheckMemoryLeak::No)
2520 : 585 : publicAllocationError(tok2, tok2->strAt(1));
2521 [ + + + - ]: 270 : } else if (Token::Match(tok2, "{|}|; %type% :: %varid% =", varid) &&
[ + + ]
2522 : 45 : tok2->next()->str() == scope->className) {
2523 : 45 : const CheckMemoryLeak::AllocType alloc = getAllocationType(tok2->tokAt(5), varid);
2524 [ + - ]: 45 : if (alloc != CheckMemoryLeak::No)
2525 : 45 : publicAllocationError(tok2, tok2->strAt(3));
2526 : : }
2527 : : }
2528 : : }
2529 : : }
2530 : :
2531 : 675 : void CheckMemoryLeakInClass::publicAllocationError(const Token *tok, const std::string &varname)
2532 : : {
2533 [ + - ][ + - ]: 675 : reportError(tok, Severity::warning, "publicAllocationError", "Possible leak in public function. The pointer '" + varname + "' is not deallocated before it is allocated.");
[ + - ][ + - ]
[ + - ]
2534 : 675 : }
2535 : :
2536 : :
2537 : 1816 : void CheckMemoryLeakStructMember::check()
2538 : : {
2539 : 1816 : const SymbolDatabase* symbolDatabase = _tokenizer->getSymbolDatabase();
2540 [ + + ]: 8438 : for (unsigned int i = 0; i < symbolDatabase->getVariableListSize(); i++) {
2541 : 6622 : const Variable* var = symbolDatabase->getVariableFromVarId(i);
2542 [ + + ][ + + ]: 6622 : if (!var || !var->isLocal() || var->isStatic())
[ - + ][ + + ]
2543 : 3621 : continue;
2544 [ + + ]: 3001 : if (var->typeEndToken()->isStandardType())
2545 : 445 : continue;
2546 : 2556 : checkStructVariable(var);
2547 : : }
2548 : 1816 : }
2549 : :
2550 : 2331 : bool CheckMemoryLeakStructMember::isMalloc(const Variable *variable)
2551 : : {
2552 : 2331 : const unsigned int varid(variable->varId());
2553 : 2331 : bool alloc = false;
2554 [ + + ]: 40725 : for (const Token *tok2 = variable->nameToken(); tok2 != variable->scope()->classEnd; tok2 = tok2->next()) {
2555 [ + + ]: 38529 : if (Token::Match(tok2, "= %varid% [;=]", varid)) {
2556 : 135 : return false;
2557 [ + + ]: 38394 : } else if (Token::Match(tok2, "%varid% = malloc|kmalloc (", varid)) {
2558 : 2196 : alloc = true;
2559 : : }
2560 : : }
2561 : 2331 : return alloc;
2562 : : }
2563 : :
2564 : :
2565 : 2556 : void CheckMemoryLeakStructMember::checkStructVariable(const Variable * const variable)
2566 : : {
2567 : : // This should be in the CheckMemoryLeak base class
2568 [ + + ][ + - ]: 2556 : static std::set<std::string> ignoredFunctions;
[ + - ][ # # ]
2569 [ + + ]: 2556 : if (ignoredFunctions.empty()) {
2570 [ + - ][ + - ]: 45 : ignoredFunctions.insert("if");
[ + - ]
2571 [ + - ][ + - ]: 45 : ignoredFunctions.insert("for");
[ + - ]
2572 [ + - ][ + - ]: 45 : ignoredFunctions.insert("while");
[ + - ]
2573 [ + - ][ + - ]: 45 : ignoredFunctions.insert("malloc");
[ + - ]
2574 : : }
2575 : :
2576 : : // Is struct variable a pointer?
2577 [ + + ]: 2556 : if (variable->isPointer()) {
2578 : : // Check that variable is allocated with malloc
2579 [ + + ]: 2331 : if (!isMalloc(variable))
2580 : 180 : return;
2581 [ + + ]: 225 : } else if (!_tokenizer->isC()) {
2582 : : // For non-C code a destructor might cleanup members
2583 : 45 : return;
2584 : : }
2585 : :
2586 : : // Check struct..
2587 : 2331 : unsigned int indentlevel2 = 0;
2588 [ + + ]: 37800 : for (const Token *tok2 = variable->nameToken(); tok2 != variable->scope()->classEnd; tok2 = tok2->next()) {
2589 [ + + ]: 35244 : if (tok2->str() == "{")
2590 : 315 : ++indentlevel2;
2591 : :
2592 [ + + ]: 34929 : else if (tok2->str() == "}") {
2593 [ - + ]: 180 : if (indentlevel2 == 0)
2594 : 0 : break;
2595 : 180 : --indentlevel2;
2596 : : }
2597 : :
2598 : : // Unknown usage of struct
2599 : : /** @todo Check how the struct is used. Only bail out if necessary */
2600 [ + + ]: 34749 : else if (Token::Match(tok2, "[(,] %varid% [,)]", variable->varId()))
2601 : 315 : break;
2602 : :
2603 : : // Struct member is allocated => check if it is also properly deallocated..
2604 [ + + ]: 34434 : else if (Token::Match(tok2->previous(), "[;{}] %varid% . %var% = malloc|strdup|kmalloc (", variable->varId())) {
2605 : 765 : const unsigned int structid(variable->varId());
2606 : 765 : const unsigned int structmemberid(tok2->tokAt(2)->varId());
2607 : :
2608 : : // This struct member is allocated.. check that it is deallocated
2609 : 765 : unsigned int indentlevel3 = indentlevel2;
2610 [ + - ]: 10890 : for (const Token *tok3 = tok2; tok3; tok3 = tok3->next()) {
2611 [ + + ]: 10125 : if (tok3->str() == "{")
2612 : 180 : ++indentlevel3;
2613 : :
2614 [ + + ]: 9945 : else if (tok3->str() == "}") {
2615 [ + + ]: 180 : if (indentlevel3 == 0) {
2616 [ + - ][ + - ]: 135 : memoryLeak(tok3, variable->name() + "." + tok2->strAt(2), Malloc);
[ + - ]
2617 : 135 : break;
2618 : : }
2619 : 45 : --indentlevel3;
2620 : : }
2621 : :
2622 : : // Deallocating the struct member..
2623 [ + + ]: 9765 : else if (Token::Match(tok3, "free|kfree ( %var% . %varid% )", structmemberid)) {
2624 : : // If the deallocation happens at the base level, don't check this member anymore
2625 [ - + ]: 45 : if (indentlevel3 == 0)
2626 : 0 : break;
2627 : :
2628 : : // deallocating and then returning from function in a conditional block =>
2629 : : // skip ahead out of the block
2630 : 45 : bool ret = false;
2631 [ + - ]: 450 : while (tok3) {
2632 [ + + ]: 450 : if (tok3->str() == "return")
2633 : 45 : ret = true;
2634 [ + - ][ + + ]: 405 : else if (tok3->str() == "{" || tok3->str() == "}")
[ + + ]
2635 : 45 : break;
2636 : 405 : tok3 = tok3->next();
2637 : : }
2638 [ + - ][ + - ]: 45 : if (!ret || !tok3 || tok3->str() != "}")
[ - + ][ - + ]
2639 : 0 : break;
2640 : 45 : --indentlevel3;
2641 : 45 : continue;
2642 : : }
2643 : :
2644 : : // Deallocating the struct..
2645 [ + + ][ + + ]: 9720 : else if (indentlevel2 == 0 && Token::Match(tok3, "free|kfree ( %varid% )", structid)) {
[ + + ]
2646 [ + - ][ + - ]: 45 : memoryLeak(tok3, variable->name() + "." + tok2->strAt(2), Malloc);
[ + - ]
2647 : 45 : break;
2648 : : }
2649 : :
2650 : : // failed allocation => skip code..
2651 [ + + ]: 9675 : else if (Token::Match(tok3, "if ( ! %var% . %varid% )", structmemberid)) {
2652 : : // Goto the ")"
2653 : 90 : tok3 = tok3->next()->link();
2654 : :
2655 : : // make sure we have ") {".. it should be
2656 [ - + ]: 90 : if (!Token::simpleMatch(tok3, ") {"))
2657 : 0 : break;
2658 : :
2659 : : // Goto the "}"
2660 : 90 : tok3 = tok3->next()->link();
2661 : : }
2662 : :
2663 : : // succeeded allocation
2664 [ + + ]: 9585 : else if (Token::Match(tok3, "if ( %var% . %varid% ) {", structmemberid)) {
2665 : : // goto the ")"
2666 : 45 : tok3 = tok3->next()->link();
2667 : :
2668 : : // check if the variable is deallocated or returned..
2669 : 45 : unsigned int indentlevel4 = 0;
2670 [ + - ]: 135 : for (const Token *tok4 = tok3; tok4; tok4 = tok4->next()) {
2671 [ + + ]: 135 : if (tok4->str() == "{")
2672 : 45 : ++indentlevel4;
2673 [ - + ]: 90 : else if (tok4->str() == "}") {
2674 : 0 : --indentlevel4;
2675 [ # # ]: 0 : if (indentlevel4 == 0)
2676 : 0 : break;
2677 [ + + ]: 90 : } else if (Token::Match(tok4, "free|kfree ( %var% . %varid% )", structmemberid)) {
2678 : 45 : break;
2679 : : }
2680 : : }
2681 : :
2682 : : // was there a proper deallocation?
2683 [ + - ]: 45 : if (indentlevel4 > 0)
2684 : 45 : break;
2685 : : }
2686 : :
2687 : : // Returning from function..
2688 [ + + ]: 9540 : else if (tok3->str() == "return") {
2689 : : // Returning from function without deallocating struct member?
2690 [ + + + + ]: 315 : if (!Token::Match(tok3, "return %varid% ;", structid) &&
[ + + ]
2691 : 90 : !Token::Match(tok3, "return & %varid% .", structid)) {
2692 [ + - ][ + - ]: 45 : memoryLeak(tok3, variable->name() + "." + tok2->strAt(2), Malloc);
[ + - ]
2693 : : }
2694 : 225 : break;
2695 : : }
2696 : :
2697 : : // struct assignment..
2698 [ + + ]: 9315 : else if (Token::Match(tok3, "= %varid% ;", structid)) {
2699 : 45 : break;
2700 [ + + ]: 9270 : } else if (Token::Match(tok3, "= %var% . %varid% ;", structmemberid)) {
2701 : 45 : break;
2702 : : }
2703 : :
2704 : : // goto isn't handled well.. bail out even though there might be leaks
2705 [ - + ]: 9225 : else if (tok3->str() == "goto")
2706 : 0 : break;
2707 : :
2708 : : // using struct in a function call..
2709 [ + + ]: 9225 : else if (Token::Match(tok3, "%var% (")) {
2710 : : // Calling non-function / function that doesn't deallocate?
2711 [ + + ]: 1215 : if (ignoredFunctions.find(tok3->str()) != ignoredFunctions.end())
2712 : 900 : continue;
2713 : :
2714 : : // Check if the struct is used..
2715 : 315 : bool deallocated = false;
2716 : 315 : const Token* const end4 = tok3->linkAt(1);
2717 [ + + ]: 855 : for (const Token *tok4 = tok3; tok4 != end4; tok4 = tok4->next()) {
2718 [ + + ]: 765 : if (Token::Match(tok4, "[(,] &| %varid% [,)]", structid)) {
2719 : : /** @todo check if the function deallocates the memory */
2720 : 135 : deallocated = true;
2721 : 135 : break;
2722 : : }
2723 : :
2724 [ + + ]: 630 : if (Token::Match(tok4, "[(,] &| %varid% . %var% [,)]", structid)) {
2725 : : /** @todo check if the function deallocates the memory */
2726 : 90 : deallocated = true;
2727 : 90 : break;
2728 : : }
2729 : : }
2730 : :
2731 [ + + ]: 315 : if (deallocated)
2732 : 225 : break;
2733 : : }
2734 : : }
2735 : : }
2736 : : }
2737 : : }
2738 : :
2739 : :
2740 : :
2741 : : #include "checkuninitvar.h" // CheckUninitVar::analyse
2742 : :
2743 : 1051 : void CheckMemoryLeakNoVar::check()
2744 : : {
2745 : 1051 : std::set<std::string> uvarFunctions;
2746 : : {
2747 [ + - ]: 1051 : const CheckUninitVar c(_tokenizer, _settings, _errorLogger);
2748 [ + - ][ + - ]: 1051 : c.analyse(_tokenizer->tokens(), uvarFunctions);
2749 : : }
2750 : :
2751 : 1051 : const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase();
2752 : :
2753 : : // only check functions
2754 : 1051 : const std::size_t functions = symbolDatabase->functionScopes.size();
2755 [ + + ]: 2192 : for (std::size_t i = 0; i < functions; ++i) {
2756 : 1141 : const Scope * scope = symbolDatabase->functionScopes[i];
2757 : :
2758 : : // goto the "}" that ends the executable scope..
2759 : 1141 : const Token *tok = scope->classEnd;
2760 : :
2761 : : // parse the executable scope until tok is reached...
2762 [ + - ][ + + ]: 29015 : for (const Token *tok2 = tok->link(); tok2 && tok2 != tok; tok2 = tok2->next()) {
[ + + ]
2763 : : // allocating memory in parameter for function call..
2764 [ + - ][ + + ]: 27874 : if (Token::Match(tok2, "[(,] %var% (") && Token::Match(tok2->linkAt(2), ") [,)]")) {
[ + - ][ + - ]
[ + - ][ + + ]
2765 [ + - ]: 225 : const AllocType allocType = getAllocationType(tok2->next(), 0);
2766 [ + - ]: 225 : if (allocType != No) {
2767 : : // locate outer function call..
2768 [ + - ]: 540 : for (const Token *tok3 = tok2; tok3; tok3 = tok3->previous()) {
2769 [ + - ][ + + ]: 315 : if (tok3->str() == "(") {
2770 : : // Is it a function call..
2771 [ + - ][ + - ]: 225 : if (Token::Match(tok3->tokAt(-2), "[;{}] %var% (")) {
[ + + ]
2772 [ + - ]: 135 : const std::string& functionName = tok3->strAt(-1);
2773 [ + - ][ + - ]: 450 : if (functionName == "delete" ||
[ + + ][ + - ]
[ - + ][ + + ]
2774 [ + - ]: 135 : functionName == "free" ||
2775 [ + - ]: 90 : functionName == "fclose" ||
2776 [ + - ]: 90 : functionName == "realloc")
2777 : 45 : break;
2778 [ + - ][ + + ]: 90 : if (CheckMemoryLeakInFunction::test_white_list(functionName)) {
2779 [ + - ][ + - ]: 45 : functionCallLeak(tok2, tok2->strAt(1), functionName);
2780 : 45 : break;
2781 : : }
2782 [ + - ][ + - ]: 45 : if (uvarFunctions.find(functionName) != uvarFunctions.end()) {
[ + - ]
2783 [ + - ][ + - ]: 45 : functionCallLeak(tok2, tok2->strAt(1), functionName);
2784 : 45 : break;
2785 : : }
2786 : : }
2787 : 90 : break;
2788 [ + - ][ - + ]: 90 : } else if (tok3->str() == ")")
2789 : 0 : tok3 = tok3->link();
2790 [ + - ][ - + ]: 90 : else if (Token::Match(tok3, "[;{}]"))
2791 : 0 : break;
2792 : : }
2793 : : }
2794 : : }
2795 : : }
2796 : 1051 : }
2797 : 1051 : }
2798 : :
2799 : 135 : void CheckMemoryLeakNoVar::functionCallLeak(const Token *loc, const std::string &alloc, const std::string &functionCall)
2800 : : {
2801 [ + - ][ + - ]: 135 : reportError(loc, Severity::error, "leakNoVarFunctionCall", "Allocation with " + alloc + ", " + functionCall + " doesn't release it.");
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ]
2802 [ + - ][ + - ]: 270 : }
|