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