Cppcheck
checkmemoryleak.h
Go to the documentation of this file.
1 /*
2  * Cppcheck - A tool for static C/C++ code analysis
3  * Copyright (C) 2007-2024 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 "tokenize.h"
38 
39 #include <list>
40 #include <string>
41 
42 class Function;
43 class Scope;
44 class Settings;
45 class Token;
46 class Variable;
47 class ErrorLogger;
48 struct CWE;
49 enum class Severity;
50 
51 /// @addtogroup Core
52 /// @{
53 
54 /** @brief Base class for memory leaks checking */
56 private:
57  /** For access to the tokens */
58  const Tokenizer * const mTokenizer_;
59 
60  /** ErrorLogger used to report errors */
62 
63  /** Enabled standards */
64  const Settings * const mSettings_;
65 
66  /**
67  * Report error. Similar with the function Check::reportError
68  * @param tok the token where the error occurs
69  * @param severity the severity of the bug
70  * @param id type of message
71  * @param msg text
72  * @param cwe cwe number
73  */
74  void reportErr(const Token *tok, Severity severity, const std::string &id, const std::string &msg, const CWE &cwe) const;
75 
76  /**
77  * Report error. Similar with the function Check::reportError
78  * @param callstack callstack of error
79  * @param severity the severity of the bug
80  * @param id type of message
81  * @param msg text
82  * @param cwe cwe number
83  */
84  void reportErr(const std::list<const Token *> &callstack, Severity severity, const std::string &id, const std::string &msg, const CWE &cwe) const;
85 
86 public:
87  CheckMemoryLeak() = delete;
88  CheckMemoryLeak(const CheckMemoryLeak &) = delete;
90 
92  : mTokenizer_(t), mErrorLogger_(e), mSettings_(s) {}
93 
94  /** @brief What type of allocation are used.. the "Many" means that several types of allocation and deallocation are used */
95  enum AllocType { No, Malloc, New, NewArray, File, Fd, Pipe, OtherMem, OtherRes, Many };
96 
97  void memoryLeak(const Token *tok, const std::string &varname, AllocType alloctype) const;
98 
99  /**
100  * @brief Get type of deallocation at given position
101  * @param tok position
102  * @param varid variable id
103  * @return type of deallocation
104  */
105  AllocType getDeallocationType(const Token *tok, nonneg int varid) const;
106 
107  /**
108  * @brief Get type of allocation at given position
109  */
110  AllocType getAllocationType(const Token *tok2, nonneg int varid, std::list<const Function*> *callstack = nullptr) const;
111 
112  /**
113  * @brief Get type of reallocation at given position
114  */
115  AllocType getReallocationType(const Token *tok2, nonneg int varid) const;
116 
117  /**
118  * Check if token reopens a standard stream
119  * @param tok token to check
120  */
121  bool isReopenStandardStream(const Token *tok) const;
122  /**
123  * Check if token opens /dev/null
124  * @param tok token to check
125  */
126  bool isOpenDevNull(const Token *tok) const;
127  /**
128  * Report that there is a memory leak (new/malloc/etc)
129  * @param tok token where memory is leaked
130  * @param varname name of variable
131  */
132  void memleakError(const Token *tok, const std::string &varname) const;
133 
134  /**
135  * Report that there is a resource leak (fopen/popen/etc)
136  * @param tok token where resource is leaked
137  * @param varname name of variable
138  */
139  void resourceLeakError(const Token *tok, const std::string &varname) const;
140 
141  void deallocuseError(const Token *tok, const std::string &varname) const;
142  void mismatchAllocDealloc(const std::list<const Token *> &callstack, const std::string &varname) const;
143  void memleakUponReallocFailureError(const Token *tok, const std::string &reallocfunction, const std::string &varname) const;
144 
145  /** What type of allocated memory does the given function return? */
146  AllocType functionReturnType(const Function* func, std::list<const Function*> *callstack = nullptr) const;
147 };
148 
149 /// @}
150 
151 
152 
153 /// @addtogroup Checks
154 /// @{
155 
156 
157 /**
158  * @brief %CheckMemoryLeakInFunction detects when a function variable is allocated but not deallocated properly.
159  *
160  * The checking is done by looking at each function variable separately. By repeating these 4 steps over and over:
161  * -# locate a function variable
162  * -# create a simple token list that describes the usage of the function variable.
163  * -# simplify the token list.
164  * -# finally, check if the simplified token list contain any leaks.
165  */
166 
168  friend class TestMemleakInFunction;
169 
170 public:
171  /** @brief This constructor is used when registering this class */
172  CheckMemoryLeakInFunction() : Check(myName()), CheckMemoryLeak(nullptr, nullptr, nullptr) {}
173 
174 private:
175  /** @brief This constructor is used when running checks */
176  CheckMemoryLeakInFunction(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger)
177  : Check(myName(), tokenizer, settings, errorLogger), CheckMemoryLeak(tokenizer, errorLogger, settings) {}
178 
179  void runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger) override {
180  CheckMemoryLeakInFunction checkMemoryLeak(&tokenizer, &tokenizer.getSettings(), errorLogger);
181  checkMemoryLeak.checkReallocUsage();
182  }
183 
184  /**
185  * Checking for a memory leak caused by improper realloc usage.
186  */
187  void checkReallocUsage();
188 
189  /** Report all possible errors (for the --errorlist) */
190  void getErrorMessages(ErrorLogger *e, const Settings *settings) const override {
191  CheckMemoryLeakInFunction c(nullptr, settings, e);
192  c.memleakError(nullptr, "varname");
193  c.resourceLeakError(nullptr, "varname");
194  c.deallocuseError(nullptr, "varname");
195  const std::list<const Token *> callstack;
196  c.mismatchAllocDealloc(callstack, "varname");
197  c.memleakUponReallocFailureError(nullptr, "realloc", "varname");
198  }
199 
200  /**
201  * Get name of class (--doc)
202  * @return name of class
203  */
204  static std::string myName() {
205  return "Memory leaks (function variables)";
206  }
207 
208  /**
209  * Get class information (--doc)
210  * @return Wiki formatted information about this class
211  */
212  std::string classInfo() const override {
213  return "Is there any allocated memory when a function goes out of scope\n";
214  }
215 };
216 
217 
218 
219 /**
220  * @brief %Check class variables, variables that are allocated in the constructor should be deallocated in the destructor
221  */
222 
224  friend class TestMemleakInClass;
225 
226 public:
227  CheckMemoryLeakInClass() : Check(myName()), CheckMemoryLeak(nullptr, nullptr, nullptr) {}
228 
229 private:
230  CheckMemoryLeakInClass(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger)
231  : Check(myName(), tokenizer, settings, errorLogger), CheckMemoryLeak(tokenizer, errorLogger, settings) {}
232 
233  void runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger) override {
234  if (!tokenizer.isCPP())
235  return;
236 
237  CheckMemoryLeakInClass checkMemoryLeak(&tokenizer, &tokenizer.getSettings(), errorLogger);
238  checkMemoryLeak.check();
239  }
240 
241  void check();
242 
243  void variable(const Scope *scope, const Token *tokVarname);
244 
245  /** Public functions: possible double-allocation */
246  void checkPublicFunctions(const Scope *scope, const Token *classtok);
247  void publicAllocationError(const Token *tok, const std::string &varname);
248 
249  void unsafeClassError(const Token *tok, const std::string &classname, const std::string &varname);
250 
251  void getErrorMessages(ErrorLogger *e, const Settings *settings) const override {
252  CheckMemoryLeakInClass c(nullptr, settings, e);
253  c.publicAllocationError(nullptr, "varname");
254  c.unsafeClassError(nullptr, "class", "class::varname");
255  }
256 
257  static std::string myName() {
258  return "Memory leaks (class variables)";
259  }
260 
261  std::string classInfo() const override {
262  return "If the constructor allocate memory then the destructor must deallocate it.\n";
263  }
264 };
265 
266 
267 
268 /** @brief detect simple memory leaks for struct members */
269 
271  friend class TestMemleakStructMember;
272 
273 public:
274  CheckMemoryLeakStructMember() : Check(myName()), CheckMemoryLeak(nullptr, nullptr, nullptr) {}
275 
276 private:
277  CheckMemoryLeakStructMember(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger)
278  : Check(myName(), tokenizer, settings, errorLogger), CheckMemoryLeak(tokenizer, errorLogger, settings) {}
279 
280  void runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger) override {
281  CheckMemoryLeakStructMember checkMemoryLeak(&tokenizer, &tokenizer.getSettings(), errorLogger);
282  checkMemoryLeak.check();
283  }
284 
285  void check();
286 
287  /** Is local variable allocated with malloc? */
288  bool isMalloc(const Variable *variable) const;
289 
290  void checkStructVariable(const Variable* const variable) const;
291 
292  void getErrorMessages(ErrorLogger * /*errorLogger*/, const Settings * /*settings*/) const override {}
293 
294  static std::string myName() {
295  return "Memory leaks (struct members)";
296  }
297 
298  std::string classInfo() const override {
299  return "Don't forget to deallocate struct members\n";
300  }
301 };
302 
303 
304 
305 /** @brief detect simple memory leaks (address not taken) */
306 
308  friend class TestMemleakNoVar;
309 
310 public:
311  CheckMemoryLeakNoVar() : Check(myName()), CheckMemoryLeak(nullptr, nullptr, nullptr) {}
312 
313 private:
314  CheckMemoryLeakNoVar(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger)
315  : Check(myName(), tokenizer, settings, errorLogger), CheckMemoryLeak(tokenizer, errorLogger, settings) {}
316 
317  void runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger) override {
318  CheckMemoryLeakNoVar checkMemoryLeak(&tokenizer, &tokenizer.getSettings(), errorLogger);
319  checkMemoryLeak.check();
320  }
321 
322  void check();
323 
324  /**
325  * @brief %Check if an input argument to a function is the return value of an allocation function
326  * like malloc(), and the function does not release it.
327  * @param scope The scope of the function to check.
328  */
329  void checkForUnreleasedInputArgument(const Scope *scope);
330 
331  /**
332  * @brief %Check if a call to an allocation function like malloc() is made and its return value is not assigned.
333  * @param scope The scope of the function to check.
334  */
335  void checkForUnusedReturnValue(const Scope *scope);
336 
337  /**
338  * @brief %Check if an exception could cause a leak in an argument constructed with shared_ptr/unique_ptr.
339  * @param scope The scope of the function to check.
340  */
341  void checkForUnsafeArgAlloc(const Scope *scope);
342 
343  void functionCallLeak(const Token *loc, const std::string &alloc, const std::string &functionCall);
344  void returnValueNotUsedError(const Token* tok, const std::string &alloc);
345  void unsafeArgAllocError(const Token *tok, const std::string &funcName, const std::string &ptrType, const std::string &objType);
346 
347  void getErrorMessages(ErrorLogger *e, const Settings *settings) const override {
348  CheckMemoryLeakNoVar c(nullptr, settings, e);
349  c.functionCallLeak(nullptr, "funcName", "funcName");
350  c.returnValueNotUsedError(nullptr, "funcName");
351  c.unsafeArgAllocError(nullptr, "funcName", "shared_ptr", "int");
352  }
353 
354  static std::string myName() {
355  return "Memory leaks (address not taken)";
356  }
357 
358  std::string classInfo() const override {
359  return "Not taking the address to allocated memory\n";
360  }
361 };
362 /// @}
363 //---------------------------------------------------------------------------
364 #endif // checkmemoryleakH
Check class variables, variables that are allocated in the constructor should be deallocated in the d...
void getErrorMessages(ErrorLogger *e, const Settings *settings) const override
get error messages
std::string classInfo() const override
get information about this class, used to generate documentation
void runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger) override
run checks, the token list is not simplified
void unsafeClassError(const Token *tok, const std::string &classname, const std::string &varname)
static std::string myName()
CheckMemoryLeakInClass(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger)
void publicAllocationError(const Token *tok, const std::string &varname)
CheckMemoryLeakInFunction detects when a function variable is allocated but not deallocated properly.
CheckMemoryLeakInFunction()
This constructor is used when registering this class.
static std::string myName()
Get name of class (–doc)
void checkReallocUsage()
Checking for a memory leak caused by improper realloc usage.
void runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger) override
run checks, the token list is not simplified
void getErrorMessages(ErrorLogger *e, const Settings *settings) const override
Report all possible errors (for the –errorlist)
std::string classInfo() const override
Get class information (–doc)
CheckMemoryLeakInFunction(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger)
This constructor is used when running checks.
detect simple memory leaks (address not taken)
void returnValueNotUsedError(const Token *tok, const std::string &alloc)
static std::string myName()
void functionCallLeak(const Token *loc, const std::string &alloc, const std::string &functionCall)
void unsafeArgAllocError(const Token *tok, const std::string &funcName, const std::string &ptrType, const std::string &objType)
void runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger) override
run checks, the token list is not simplified
std::string classInfo() const override
get information about this class, used to generate documentation
CheckMemoryLeakNoVar(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger)
void getErrorMessages(ErrorLogger *e, const Settings *settings) const override
get error messages
detect simple memory leaks for struct members
static std::string myName()
std::string classInfo() const override
get information about this class, used to generate documentation
CheckMemoryLeakStructMember(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger)
void runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger) override
run checks, the token list is not simplified
void getErrorMessages(ErrorLogger *, const Settings *) const override
get error messages
Base class for memory leaks checking.
CheckMemoryLeak(const CheckMemoryLeak &)=delete
void deallocuseError(const Token *tok, const std::string &varname) const
const Settings *const mSettings_
Enabled standards.
const Tokenizer *const mTokenizer_
For access to the tokens.
void resourceLeakError(const Token *tok, const std::string &varname) const
Report that there is a resource leak (fopen/popen/etc)
void mismatchAllocDealloc(const std::list< const Token * > &callstack, const std::string &varname) const
CheckMemoryLeak()=delete
ErrorLogger *const mErrorLogger_
ErrorLogger used to report errors.
AllocType
What type of allocation are used.
CheckMemoryLeak & operator=(const CheckMemoryLeak &)=delete
void memleakUponReallocFailureError(const Token *tok, const std::string &reallocfunction, const std::string &varname) const
CheckMemoryLeak(const Tokenizer *t, ErrorLogger *e, const Settings *s)
void memleakError(const Token *tok, const std::string &varname) const
Report that there is a memory leak (new/malloc/etc)
Interface class that cppcheck uses to communicate with the checks.
Definition: check.h:59
This is an interface, which the class responsible of error logging should implement.
Definition: errorlogger.h:214
This is just a container for general settings so that we don't need to pass individual values to func...
Definition: settings.h:95
The token list that the TokenList generates is a linked-list of this class.
Definition: token.h:150
The main purpose is to tokenize the source code.
Definition: tokenize.h:46
const Settings & getSettings() const
Definition: tokenize.h:615
bool isCPP() const
Is the code CPP.
Definition: tokenize.h:69
Information about a member variable.
#define CPPCHECKLIB
Definition: config.h:35
#define nonneg
Definition: config.h:138
Severity
enum class for severity.
Definition: errortypes.h:63