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