Cppcheck
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
checkmemoryleak.h
Go to the documentation of this file.
1 /*
2  * Cppcheck - A tool for static C/C++ code analysis
3  * Copyright (C) 2007-2014 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 #ifndef checkmemoryleakH
21 #define checkmemoryleakH
22 //---------------------------------------------------------------------------
23 
24 /**
25  * @file
26  *
27  * %Check for memory leaks
28  *
29  * The checking is split up into three specialized classes.
30  * - CheckMemoryLeakInFunction can detect when a function variable is allocated but not deallocated properly.
31  * - CheckMemoryLeakInClass can detect when a class variable is allocated but not deallocated properly.
32  * - CheckMemoryLeakStructMember checks allocation/deallocation of structs and struct members
33  */
34 
35 #include "config.h"
36 #include "check.h"
37 
38 #include <list>
39 #include <string>
40 
41 class Scope;
42 class Function;
43 class Variable;
44 
45 /// @addtogroup Core
46 /// @{
47 
48 /** @brief Base class for memory leaks checking */
50 private:
51  /** For access to the tokens */
52  const Tokenizer * const tokenizer;
53 
54  /** ErrorLogger used to report errors */
56 
57  /** Enabled standards */
58  const Settings * const settings1;
59 
60  /** Disable the default constructors */
62 
63  /** Disable the default constructors */
65 
66  /** disable assignment operator */
67  void operator=(const CheckMemoryLeak &);
68 
69  /**
70  * Report error. Similar with the function Check::reportError
71  * @param location the token where the error occurs
72  * @param severity the severity of the bug
73  * @param id type of message
74  * @param msg text
75  */
76  void reportErr(const Token *location, Severity::SeverityType severity, const std::string &id, const std::string &msg) const;
77 
78  /**
79  * Report error. Similar with the function Check::reportError
80  * @param callstack callstack of error
81  * @param severity the severity of the bug
82  * @param id type of message
83  * @param msg text
84  */
85  void reportErr(const std::list<const Token *> &callstack, Severity::SeverityType severity, const std::string &id, const std::string &msg) const;
86 
87 public:
89  : tokenizer(t), errorLogger(e), settings1(s) {
90  }
91 
92  /** @brief What type of allocation are used.. the "Many" means that several types of allocation and deallocation are used */
93  enum AllocType { No, Malloc, New, NewArray, File, Fd, Pipe, OtherMem, OtherRes, Many };
94 
95  void memoryLeak(const Token *tok, const std::string &varname, AllocType alloctype);
96 
97  /**
98  * @brief Get type of deallocation at given position
99  * @param tok position
100  * @param varname variable name
101  * @return type of deallocation
102  */
103  AllocType getDeallocationType(const Token *tok, const std::string &varname) const;
104 
105  /**
106  * @brief Get type of deallocation at given position
107  * @param tok position
108  * @param varid variable id
109  * @return type of deallocation
110  */
111  AllocType getDeallocationType(const Token *tok, unsigned int varid) const;
112 
113  /**
114  * @brief Get type of allocation at given position
115  */
116  AllocType getAllocationType(const Token *tok2, unsigned int varid, std::list<const Function*> *callstack = NULL) const;
117 
118  /**
119  * @brief Get type of reallocation at given position
120  */
121  static AllocType getReallocationType(const Token *tok2, unsigned int varid);
122 
123  /**
124  * @brief Is a typename the name of a class?
125  * @param tok type token
126  * @param varid variable id
127  * @return true if the type name is the name of a class
128  */
129  bool isclass(const Token *tok, unsigned int varid) const;
130 
131  /**
132  * Report that there is a memory leak (new/malloc/etc)
133  * @param tok token where memory is leaked
134  * @param varname name of variable
135  */
136  void memleakError(const Token *tok, const std::string &varname) const;
137 
138  /**
139  * Report that there is a resource leak (fopen/popen/etc)
140  * @param tok token where resource is leaked
141  * @param varname name of variable
142  */
143  void resourceLeakError(const Token *tok, const std::string &varname) const;
144 
145  /**
146  * @brief Report error: deallocating a deallocated pointer
147  * @param tok token where error occurs
148  * @param varname name of variable
149  */
150  void deallocDeallocError(const Token *tok, const std::string &varname) const;
151  void deallocuseError(const Token *tok, const std::string &varname) const;
152  void mismatchSizeError(const Token *tok, const std::string &sz) const;
153  void mismatchAllocDealloc(const std::list<const Token *> &callstack, const std::string &varname) const;
154  void memleakUponReallocFailureError(const Token *tok, const std::string &varname) const;
155 
156  /** What type of allocated memory does the given function return? */
157  AllocType functionReturnType(const Function* func, std::list<const Function*> *callstack = NULL) const;
158 
159  /** Function allocates pointed-to argument (a la asprintf)? */
160  const char *functionArgAlloc(const Function *func, unsigned int targetpar, AllocType &allocType) const;
161 };
162 
163 /// @}
164 
165 
166 
167 /// @addtogroup Checks
168 /// @{
169 
170 
171 /**
172  * @brief %CheckMemoryLeakInFunction detects when a function variable is allocated but not deallocated properly.
173  *
174  * The checking is done by looking at each function variable separately. By repeating these 4 steps over and over:
175  * -# locate a function variable
176  * -# create a simple token list that describes the usage of the function variable.
177  * -# simplify the token list.
178  * -# finally, check if the simplified token list contain any leaks.
179  */
180 
182 public:
183  /** @brief This constructor is used when registering this class */
184  CheckMemoryLeakInFunction() : Check(myName()), CheckMemoryLeak(0, 0, 0), symbolDatabase(NULL) {
185  }
186 
187  /** @brief This constructor is used when running checks */
188  CheckMemoryLeakInFunction(const Tokenizer *tokenizr, const Settings *settings, ErrorLogger *errLog)
189  : Check(myName(), tokenizr, settings, errLog), CheckMemoryLeak(tokenizr, errLog, settings) {
190  // get the symbol database
191  if (tokenizr)
192  symbolDatabase = tokenizr->getSymbolDatabase();
193  else
194  symbolDatabase = 0;
195  }
196 
197  /** @brief run all simplified checks */
198  void runSimplifiedChecks(const Tokenizer *tokenizr, const Settings *settings, ErrorLogger *errLog) {
199  CheckMemoryLeakInFunction checkMemoryLeak(tokenizr, settings, errLog);
200  checkMemoryLeak.checkReallocUsage();
201  checkMemoryLeak.check();
202  }
203 
204  /** @brief Unit testing : testing the white list */
205  static bool test_white_list(const std::string &funcname);
206  static bool test_white_list_with_lib(const std::string &funcname, const Settings *settings);
207 
208  /** @brief Perform checking */
209  void check();
210 
211  /**
212  * Checking for a memory leak caused by improper realloc usage.
213  */
214  void checkReallocUsage();
215 
216  /**
217  * @brief %Check if there is a "!var" match inside a condition
218  * @param tok first token to match
219  * @param varid variable id
220  * @param endpar if this is true the "!var" must be followed by ")"
221  * @return true if match
222  */
223  static bool notvar(const Token *tok, unsigned int varid, bool endpar = false);
224 
225  /**
226  * Inspect a function call. the call_func and getcode are recursive
227  * @param tok token where the function call occurs
228  * @param callstack callstack
229  * @param varid variable id to check
230  * @param alloctype if memory is allocated, this indicates the type of allocation
231  * @param dealloctype if memory is deallocated, this indicates the type of deallocation
232  * @param allocpar if function allocates varid parameter
233  * @param sz not used by call_func - see getcode
234  * @return These are the possible return values:
235  * - NULL : no significant code
236  * - "recursive" : recursive function
237  * - "alloc" : the function returns allocated memory
238  * - "dealloc" : the function deallocates the variable
239  * - "dealloc_"
240  * - "use" : the variable is used (unknown usage of the variable => the checking bails out)
241  * - "callfunc" : a function call with unknown side effects
242  * - "&use"
243  */
244  const char * call_func(const Token *tok, std::list<const Token *> callstack, const unsigned int varid, AllocType &alloctype, AllocType &dealloctype, bool &allocpar, unsigned int sz);
245 
246  /**
247  * Extract a new tokens list that is easier to parse than the "_tokenizer->tokens()", the
248  * extracted tokens list describes how the given variable is used.
249  * The getcode and call_func are recursive
250  * @param tok start parse token
251  * @param callstack callstack
252  * @param varid variable id
253  * @param alloctype keep track of what type of allocation is used
254  * @param dealloctype keeps track of what type of deallocation is used
255  * @param classmember should be set if the inspected function is a class member
256  * @param sz size of type, used to check for mismatching size of allocation. for example "int *a;" => the sz is "sizeof(int)"
257  * @return Newly allocated token array. Caller needs to release reserved
258  * memory by calling TokenList::deleteTokens(returnValue);
259  * Returned tokens:
260  * - "alloc" : the variable is allocated
261  * - "assign" : the variable is assigned a new value
262  * - "break" : corresponds to "break"
263  * - "callfunc" : a function call with unknown side effects
264  * - "continue" : corresponds to "continue"
265  * - "dealloc" : the variable is deallocated
266  * - "goto" : corresponds to a "goto"
267  * - "if" : there is an "if"
268  * - "if(var)" : corresponds with "if ( var != 0 )"
269  * - "if(!var)" : corresponds with "if ( var == 0 )"
270  * - "ifv" : the variable is used in some way in a "if"
271  * - "loop" : corresponds to either a "for" or a "while"
272  * - "realloc" : the variable is reallocated
273  * - "return" : corresponds to a "return"
274  * - "use" : unknown usage -> bail out checking of this execution path
275  * - "&use" : the address of the variable is taken
276  * - "::use" : calling member function of class
277  * - "use_" : content of variable is accessed (used to warn access after dealloc)
278  */
279  Token *getcode(const Token *tok, std::list<const Token *> callstack, const unsigned int varid, AllocType &alloctype, AllocType &dealloctype, bool classmember, unsigned int sz);
280 
281  /**
282  * Simplify code e.g. by replacing empty "{ }" with ";"
283  * @param tok first token. The tokens list can be modified.
284  */
285  void simplifycode(Token *tok) const;
286 
287  static const Token *findleak(const Token *tokens);
288 
289  /**
290  * Checking the variable varname
291  * @param Tok1 start token
292  * @param varname name of variable (for error messages)
293  * @param varid variable id
294  * @param classmember is the scope inside a class member function
295  * @param sz size of type.. if the variable is a "int *" then sz should be "sizeof(int)"
296  */
297  void checkScope(const Token *Tok1, const std::string &varname, unsigned int varid, bool classmember, unsigned int sz);
298 
299  /** parse tokens to see what functions are "noreturn" */
300  void parse_noreturn();
301 
302 private:
303  /** Report all possible errors (for the --errorlist) */
304  void getErrorMessages(ErrorLogger *e, const Settings *settings) const {
305  CheckMemoryLeakInFunction c(0, settings, e);
306 
307  c.memleakError(0, "varname");
308  c.resourceLeakError(0, "varname");
309 
310  c.deallocDeallocError(0, "varname");
311  c.deallocuseError(0, "varname");
312  c.mismatchSizeError(0, "sz");
313  std::list<const Token *> callstack;
314  c.mismatchAllocDealloc(callstack, "varname");
315  c.memleakUponReallocFailureError(0, "varname");
316  }
317 
318  /**
319  * Get name of class (--doc)
320  * @return name of class
321  */
322  static std::string myName() {
323  return "Memory leaks (function variables)";
324  }
325 
326  /**
327  * Get class information (--doc)
328  * @return Wiki formatted information about this class
329  */
330  std::string classInfo() const {
331  return "Is there any allocated memory when a function goes out of scope\n";
332  }
333 
334  /** Function names for functions that are "noreturn" */
335  std::set<std::string> noreturn;
336 
337  /** Function names for functions that are not "noreturn" */
338  std::set<std::string> notnoreturn;
339 
341 };
342 
343 
344 
345 /**
346  * @brief %Check class variables, variables that are allocated in the constructor should be deallocated in the destructor
347  */
348 
350 public:
351  CheckMemoryLeakInClass() : Check(myName()), CheckMemoryLeak(0, 0, 0) {
352  }
353 
354  CheckMemoryLeakInClass(const Tokenizer *tokenizr, const Settings *settings, ErrorLogger *errLog)
355  : Check(myName(), tokenizr, settings, errLog), CheckMemoryLeak(tokenizr, errLog, settings) {
356  }
357 
358  void runSimplifiedChecks(const Tokenizer *tokenizr, const Settings *settings, ErrorLogger *errLog) {
359  if (!tokenizr->isCPP())
360  return;
361 
362  CheckMemoryLeakInClass checkMemoryLeak(tokenizr, settings, errLog);
363  checkMemoryLeak.check();
364  }
365 
366  void check();
367 
368 private:
369  void variable(const Scope *scope, const Token *tokVarname);
370 
371  /** Public functions: possible double-allocation */
372  void checkPublicFunctions(const Scope *scope, const Token *classtok);
373  void publicAllocationError(const Token *tok, const std::string &varname);
374 
375  void unsafeClassError(const Token *tok, const std::string &classname, const std::string &varname);
376 
377  void getErrorMessages(ErrorLogger *e, const Settings *settings) const {
378  CheckMemoryLeakInClass c(0, settings, e);
379  c.publicAllocationError(0, "varname");
380  c.unsafeClassError(0, "class", "class::varname");
381  }
382 
383  static std::string myName() {
384  return "Memory leaks (class variables)";
385  }
386 
387  std::string classInfo() const {
388  return "If the constructor allocate memory then the destructor must deallocate it.\n";
389  }
390 };
391 
392 
393 
394 /** @brief detect simple memory leaks for struct members */
395 
397 public:
399  }
400 
401  CheckMemoryLeakStructMember(const Tokenizer *tokenizr, const Settings *settings, ErrorLogger *errLog)
402  : Check(myName(), tokenizr, settings, errLog), CheckMemoryLeak(tokenizr, errLog, settings) {
403  }
404 
405  void runSimplifiedChecks(const Tokenizer *tokenizr, const Settings *settings, ErrorLogger *errLog) {
406  CheckMemoryLeakStructMember checkMemoryLeak(tokenizr, settings, errLog);
407  checkMemoryLeak.check();
408  }
409 
410  void check();
411 
412 private:
413 
414  /** Is local variable allocated with malloc? */
415  static bool isMalloc(const Variable *variable);
416 
417  void checkStructVariable(const Variable * const variable);
418 
419  void getErrorMessages(ErrorLogger * /*errorLogger*/, const Settings * /*settings*/) const {
420  }
421 
422  static std::string myName() {
423  return "Memory leaks (struct members)";
424  }
425 
426  std::string classInfo() const {
427  return "Don't forget to deallocate struct members\n";
428  }
429 };
430 
431 
432 
433 /** @brief detect simple memory leaks (address not taken) */
434 
436 public:
437  CheckMemoryLeakNoVar() : Check(myName()), CheckMemoryLeak(0, 0, 0) {
438  }
439 
440  CheckMemoryLeakNoVar(const Tokenizer *tokenizr, const Settings *settings, ErrorLogger *errLog)
441  : Check(myName(), tokenizr, settings, errLog), CheckMemoryLeak(tokenizr, errLog, settings) {
442  }
443 
444  void runSimplifiedChecks(const Tokenizer *tokenizr, const Settings *settings, ErrorLogger *errLog) {
445  CheckMemoryLeakNoVar checkMemoryLeak(tokenizr, settings, errLog);
446  checkMemoryLeak.check();
447  }
448 
449  void check();
450 
451 private:
452  /**
453  * @brief %Check if a call to an allocation function like malloc() is made and its return value is not assigned.
454  * @param scope The scope of the function to check.
455  */
456  void checkForUnusedReturnValue(const Scope *scope);
457 
458  void functionCallLeak(const Token *loc, const std::string &alloc, const std::string &functionCall);
459  void returnValueNotUsedError(const Token* tok, const std::string &alloc);
460 
461  void getErrorMessages(ErrorLogger *e, const Settings *settings) const {
462  CheckMemoryLeakNoVar c(0, settings, e);
463 
464  c.functionCallLeak(0, "funcName", "funcName");
465  c.returnValueNotUsedError(0, "funcName");
466  }
467 
468  static std::string myName() {
469  return "Memory leaks (address not taken)";
470  }
471 
472  std::string classInfo() const {
473  return "Not taking the address to allocated memory\n";
474  }
475 };
476 /// @}
477 //---------------------------------------------------------------------------
478 #endif // checkmemoryleakH