Cppcheck
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules 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-2016 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 "check.h"
36 #include "config.h"
37 #include "errorlogger.h"
38 #include "tokenize.h"
39 
40 #include <list>
41 #include <string>
42 
43 class Function;
44 class Scope;
45 class Settings;
46 class SymbolDatabase;
47 class Token;
48 class Variable;
49 
50 /// @addtogroup Core
51 /// @{
52 
53 /** @brief Base class for memory leaks checking */
55 protected:
56  /** For access to the tokens */
57  const Tokenizer * const tokenizer;
58 
59 private:
60  /** ErrorLogger used to report errors */
62 
63  /** Enabled standards */
64  const Settings * const settings1;
65 
66  /** Disable the default constructors */
68 
69  /** Disable the default constructors */
71 
72  /** disable assignment operator */
73  void operator=(const CheckMemoryLeak &);
74 
75  /**
76  * Report error. Similar with the function Check::reportError
77  * @param tok the token where the error occurs
78  * @param severity the severity of the bug
79  * @param id type of message
80  * @param msg text
81  * @param cwe cwe number
82  */
83  void reportErr(const Token *tok, Severity::SeverityType severity, const std::string &id, const std::string &msg, const CWE &cwe) const;
84 
85  /**
86  * Report error. Similar with the function Check::reportError
87  * @param callstack callstack of error
88  * @param severity the severity of the bug
89  * @param id type of message
90  * @param msg text
91  * @param cwe cwe number
92  */
93  void reportErr(const std::list<const Token *> &callstack, Severity::SeverityType severity, const std::string &id, const std::string &msg, const CWE &cwe) const;
94 
95 public:
97  : tokenizer(t), errorLogger(e), settings1(s) {
98  }
99 
100  /** @brief What type of allocation are used.. the "Many" means that several types of allocation and deallocation are used */
101  enum AllocType { No, Malloc, New, NewArray, File, Fd, Pipe, OtherMem, OtherRes, Many };
102 
103  void memoryLeak(const Token *tok, const std::string &varname, AllocType alloctype) 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 = nullptr) 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 = nullptr) 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(nullptr) {
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, const Settings *settings, bool cpp);
206 
207  /** @brief Perform checking */
208  void check();
209 
210  /**
211  * Checking for a memory leak caused by improper realloc usage.
212  */
213  void checkReallocUsage();
214 
215  /**
216  * Inspect a function call. the call_func and getcode are recursive
217  * @param tok token where the function call occurs
218  * @param callstack callstack
219  * @param varid variable id to check
220  * @param alloctype if memory is allocated, this indicates the type of allocation
221  * @param dealloctype if memory is deallocated, this indicates the type of deallocation
222  * @param allocpar if function allocates varid parameter
223  * @param sz not used by call_func - see getcode
224  * @return These are the possible return values:
225  * - NULL : no significant code
226  * - "recursive" : recursive function
227  * - "alloc" : the function returns allocated memory
228  * - "dealloc" : the function deallocates the variable
229  * - "dealloc_"
230  * - "use" : the variable is used (unknown usage of the variable => the checking bails out)
231  * - "callfunc" : a function call with unknown side effects
232  * - "&use"
233  */
234  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);
235 
236  /**
237  * Extract a new tokens list that is easier to parse than the "_tokenizer->tokens()", the
238  * extracted tokens list describes how the given variable is used.
239  * The getcode and call_func are recursive
240  * @param tok start parse token
241  * @param callstack callstack
242  * @param varid variable id
243  * @param alloctype keep track of what type of allocation is used
244  * @param dealloctype keeps track of what type of deallocation is used
245  * @param classmember should be set if the inspected function is a class member
246  * @param sz size of type, used to check for mismatching size of allocation. for example "int *a;" => the sz is "sizeof(int)"
247  * @return Newly allocated token array. Caller needs to release reserved
248  * memory by calling TokenList::deleteTokens(returnValue);
249  * Returned tokens:
250  * - "alloc" : the variable is allocated
251  * - "assign" : the variable is assigned a new value
252  * - "break" : corresponds to "break"
253  * - "callfunc" : a function call with unknown side effects
254  * - "continue" : corresponds to "continue"
255  * - "dealloc" : the variable is deallocated
256  * - "goto" : corresponds to a "goto"
257  * - "if" : there is an "if"
258  * - "if(var)" : corresponds with "if ( var != 0 )"
259  * - "if(!var)" : corresponds with "if ( var == 0 )"
260  * - "ifv" : the variable is used in some way in a "if"
261  * - "loop" : corresponds to either a "for" or a "while"
262  * - "realloc" : the variable is reallocated
263  * - "return" : corresponds to a "return"
264  * - "use" : unknown usage -> bail out checking of this execution path
265  * - "&use" : the address of the variable is taken
266  * - "::use" : calling member function of class
267  * - "use_" : content of variable is accessed (used to warn access after dealloc)
268  */
269  Token *getcode(const Token *tok, std::list<const Token *> callstack, const unsigned int varid, AllocType &alloctype, AllocType &dealloctype, bool classmember, unsigned int sz);
270 
271  /**
272  * Simplify code e.g. by replacing empty "{ }" with ";"
273  * @param tok first token. The tokens list can be modified.
274  */
275  void simplifycode(Token *tok) const;
276 
277  static const Token *findleak(const Token *tokens);
278 
279  /**
280  * Checking the variable varname
281  * @param startTok start token
282  * @param varname name of variable (for error messages)
283  * @param varid variable id
284  * @param classmember is the scope inside a class member function
285  * @param sz size of type.. if the variable is a "int *" then sz should be "sizeof(int)"
286  */
287  void checkScope(const Token *startTok, const std::string &varname, unsigned int varid, bool classmember, unsigned int sz);
288 
289 private:
290  /** Report all possible errors (for the --errorlist) */
291  void getErrorMessages(ErrorLogger *e, const Settings *settings) const {
292  CheckMemoryLeakInFunction c(nullptr, settings, e);
293 
294  c.memleakError(nullptr, "varname");
295  c.resourceLeakError(nullptr, "varname");
296 
297  c.deallocDeallocError(nullptr, "varname");
298  c.deallocuseError(nullptr, "varname");
299  c.mismatchSizeError(nullptr, "sz");
300  std::list<const Token *> callstack;
301  c.mismatchAllocDealloc(callstack, "varname");
302  c.memleakUponReallocFailureError(nullptr, "varname");
303  }
304 
305  /**
306  * Get name of class (--doc)
307  * @return name of class
308  */
309  static std::string myName() {
310  return "Memory leaks (function variables)";
311  }
312 
313  /**
314  * Get class information (--doc)
315  * @return Wiki formatted information about this class
316  */
317  std::string classInfo() const {
318  return "Is there any allocated memory when a function goes out of scope\n";
319  }
320 
322 };
323 
324 
325 
326 /**
327  * @brief %Check class variables, variables that are allocated in the constructor should be deallocated in the destructor
328  */
329 
331 public:
332  CheckMemoryLeakInClass() : Check(myName()), CheckMemoryLeak(0, 0, 0) {
333  }
334 
335  CheckMemoryLeakInClass(const Tokenizer *tokenizr, const Settings *settings, ErrorLogger *errLog)
336  : Check(myName(), tokenizr, settings, errLog), CheckMemoryLeak(tokenizr, errLog, settings) {
337  }
338 
339  void runSimplifiedChecks(const Tokenizer *tokenizr, const Settings *settings, ErrorLogger *errLog) {
340  if (!tokenizr->isCPP())
341  return;
342 
343  CheckMemoryLeakInClass checkMemoryLeak(tokenizr, settings, errLog);
344  checkMemoryLeak.check();
345  }
346 
347  void check();
348 
349 private:
350  void variable(const Scope *scope, const Token *tokVarname);
351 
352  /** Public functions: possible double-allocation */
353  void checkPublicFunctions(const Scope *scope, const Token *classtok);
354  void publicAllocationError(const Token *tok, const std::string &varname);
355 
356  void unsafeClassError(const Token *tok, const std::string &classname, const std::string &varname);
357 
358  void getErrorMessages(ErrorLogger *e, const Settings *settings) const {
359  CheckMemoryLeakInClass c(0, settings, e);
360  c.publicAllocationError(0, "varname");
361  c.unsafeClassError(0, "class", "class::varname");
362  }
363 
364  static std::string myName() {
365  return "Memory leaks (class variables)";
366  }
367 
368  std::string classInfo() const {
369  return "If the constructor allocate memory then the destructor must deallocate it.\n";
370  }
371 };
372 
373 
374 
375 /** @brief detect simple memory leaks for struct members */
376 
378 public:
380  }
381 
382  CheckMemoryLeakStructMember(const Tokenizer *tokenizr, const Settings *settings, ErrorLogger *errLog)
383  : Check(myName(), tokenizr, settings, errLog), CheckMemoryLeak(tokenizr, errLog, settings) {
384  }
385 
386  void runSimplifiedChecks(const Tokenizer *tokenizr, const Settings *settings, ErrorLogger *errLog) {
387  CheckMemoryLeakStructMember checkMemoryLeak(tokenizr, settings, errLog);
388  checkMemoryLeak.check();
389  }
390 
391  void check();
392 
393 private:
394 
395  /** Is local variable allocated with malloc? */
396  static bool isMalloc(const Variable *variable);
397 
398  void checkStructVariable(const Variable * const variable);
399 
400  void getErrorMessages(ErrorLogger * /*errorLogger*/, const Settings * /*settings*/) const {
401  }
402 
403  static std::string myName() {
404  return "Memory leaks (struct members)";
405  }
406 
407  std::string classInfo() const {
408  return "Don't forget to deallocate struct members\n";
409  }
410 };
411 
412 
413 
414 /** @brief detect simple memory leaks (address not taken) */
415 
417 public:
418  CheckMemoryLeakNoVar() : Check(myName()), CheckMemoryLeak(0, 0, 0) {
419  }
420 
421  CheckMemoryLeakNoVar(const Tokenizer *tokenizr, const Settings *settings, ErrorLogger *errLog)
422  : Check(myName(), tokenizr, settings, errLog), CheckMemoryLeak(tokenizr, errLog, settings) {
423  }
424 
425  void runSimplifiedChecks(const Tokenizer *tokenizr, const Settings *settings, ErrorLogger *errLog) {
426  CheckMemoryLeakNoVar checkMemoryLeak(tokenizr, settings, errLog);
427  checkMemoryLeak.check();
428  }
429 
430  void check();
431 
432 private:
433  /**
434  * @brief %Check if a call to an allocation function like malloc() is made and its return value is not assigned.
435  * @param scope The scope of the function to check.
436  */
437  void checkForUnusedReturnValue(const Scope *scope);
438 
439  /**
440  * @brief %Check if an exception could cause a leak in an argument constructed with shared_ptr/unique_ptr.
441  * @param scope The scope of the function to check.
442  */
443  void checkForUnsafeArgAlloc(const Scope *scope);
444 
445  void functionCallLeak(const Token *loc, const std::string &alloc, const std::string &functionCall);
446  void returnValueNotUsedError(const Token* tok, const std::string &alloc);
447  void unsafeArgAllocError(const Token *tok, const std::string &funcName, const std::string &ptrType, const std::string &objType);
448 
449  void getErrorMessages(ErrorLogger *e, const Settings *settings) const {
450  CheckMemoryLeakNoVar c(nullptr, settings, e);
451 
452  c.functionCallLeak(nullptr, "funcName", "funcName");
453  c.returnValueNotUsedError(nullptr, "funcName");
454  c.unsafeArgAllocError(nullptr, "funcName", "shared_ptr", "int");
455  }
456 
457  static std::string myName() {
458  return "Memory leaks (address not taken)";
459  }
460 
461  std::string classInfo() const {
462  return "Not taking the address to allocated memory\n";
463  }
464 };
465 /// @}
466 //---------------------------------------------------------------------------
467 #endif // checkmemoryleakH
CWE id (Common Weakness Enumeration) See https://cwe.mitre.org/ for further reference.
Definition: errorlogger.h:38
bool isCPP() const
Is the code CPP.
Definition: tokenize.h:67
detect simple memory leaks for struct members
void runSimplifiedChecks(const Tokenizer *tokenizr, const Settings *settings, ErrorLogger *errLog)
run checks, the token list is simplified
CheckMemoryLeakInFunction()
This constructor is used when registering this class.
Check class variables, variables that are allocated in the constructor should be deallocated in the d...
void getErrorMessages(ErrorLogger *, const Settings *) const
get error messages
static std::string myName()
std::string classInfo() const
get information about this class, used to generate documentation
void returnValueNotUsedError(const Token *tok, const std::string &alloc)
void memleakError(const Token *tok, const std::string &varname) const
Report that there is a memory leak (new/malloc/etc)
void unsafeClassError(const Token *tok, const std::string &classname, const std::string &varname)
void checkReallocUsage()
Checking for a memory leak caused by improper realloc usage.
Information about a member variable.
The main purpose is to tokenize the source code.
Definition: tokenize.h:46
std::string classInfo() const
get information about this class, used to generate documentation
const SymbolDatabase * symbolDatabase
Interface class that cppcheck uses to communicate with the checks.
Definition: check.h:48
void resourceLeakError(const Token *tok, const std::string &varname) const
Report that there is a resource leak (fopen/popen/etc)
void functionCallLeak(const Token *loc, const std::string &alloc, const std::string &functionCall)
ErrorLogger *const errorLogger
ErrorLogger used to report errors.
#define CPPCHECKLIB
Definition: config.h:13
void deallocuseError(const Token *tok, const std::string &varname) const
std::string classInfo() const
get information about this class, used to generate documentation
Base class for memory leaks checking.
CheckMemoryLeakNoVar(const Tokenizer *tokenizr, const Settings *settings, ErrorLogger *errLog)
void runSimplifiedChecks(const Tokenizer *tokenizr, const Settings *settings, ErrorLogger *errLog)
run checks, the token list is simplified
void mismatchSizeError(const Token *tok, const std::string &sz) const
void runSimplifiedChecks(const Tokenizer *tokenizr, const Settings *settings, ErrorLogger *errLog)
run checks, the token list is simplified
void memleakUponReallocFailureError(const Token *tok, const std::string &varname) const
static std::string myName()
void runSimplifiedChecks(const Tokenizer *tokenizr, const Settings *settings, ErrorLogger *errLog)
run all simplified checks
detect simple memory leaks (address not taken)
std::string classInfo() const
Get class information (–doc)
static std::string myName()
Get name of class (–doc)
This is an interface, which the class responsible of error logging should implement.
Definition: errorlogger.h:174
void check()
Perform checking.
This is just a container for general settings so that we don't need to pass individual values to func...
Definition: settings.h:50
SeverityType
Message severities.
Definition: errorlogger.h:70
void getErrorMessages(ErrorLogger *e, const Settings *settings) const
get error messages
void getErrorMessages(ErrorLogger *e, const Settings *settings) const
Report all possible errors (for the –errorlist)
CheckMemoryLeakStructMember(const Tokenizer *tokenizr, const Settings *settings, ErrorLogger *errLog)
void unsafeArgAllocError(const Token *tok, const std::string &funcName, const std::string &ptrType, const std::string &objType)
static std::string myName()
void publicAllocationError(const Token *tok, const std::string &varname)
void deallocDeallocError(const Token *tok, const std::string &varname) const
Report error: deallocating a deallocated pointer.
void getErrorMessages(ErrorLogger *e, const Settings *settings) const
get error messages
AllocType
What type of allocation are used.
const SymbolDatabase * getSymbolDatabase() const
Definition: tokenize.h:740
void mismatchAllocDealloc(const std::list< const Token * > &callstack, const std::string &varname) const
CheckMemoryLeakInClass(const Tokenizer *tokenizr, const Settings *settings, ErrorLogger *errLog)
The token list that the TokenList generates is a linked-list of this class.
Definition: token.h:55
CheckMemoryLeakInFunction detects when a function variable is allocated but not deallocated properly...
const Settings *const settings1
Enabled standards.
const Tokenizer *const tokenizer
For access to the tokens.
CheckMemoryLeakInFunction(const Tokenizer *tokenizr, const Settings *settings, ErrorLogger *errLog)
This constructor is used when running checks.
CheckMemoryLeak(const Tokenizer *t, ErrorLogger *e, const Settings *s)