Cppcheck
checkmemoryleak.cpp
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 #include "checkmemoryleak.h"
21 
22 #include "astutils.h"
23 #include "errorlogger.h"
24 #include "errortypes.h"
25 #include "library.h"
26 #include "mathlib.h"
27 #include "platform.h"
28 #include "settings.h"
29 #include "symboldatabase.h"
30 #include "token.h"
31 #include "tokenize.h"
32 
33 #include <algorithm>
34 #include <utility>
35 #include <vector>
36 
37 //---------------------------------------------------------------------------
38 
39 // Register this check class (by creating a static instance of it)
40 namespace {
41  CheckMemoryLeakInFunction instance1;
42  CheckMemoryLeakInClass instance2;
44  CheckMemoryLeakNoVar instance4;
45 }
46 
47 // CWE ID used:
48 static const CWE CWE398(398U); // Indicator of Poor Code Quality
49 static const CWE CWE401(401U); // Improper Release of Memory Before Removing Last Reference ('Memory Leak')
50 static const CWE CWE771(771U); // Missing Reference to Active Allocated Resource
51 static const CWE CWE772(772U); // Missing Release of Resource after Effective Lifetime
52 
53 //---------------------------------------------------------------------------
54 
55 CheckMemoryLeak::AllocType CheckMemoryLeak::getAllocationType(const Token *tok2, nonneg int varid, std::list<const Function*> *callstack) const
56 {
57  // What we may have...
58  // * var = (char *)malloc(10);
59  // * var = new char[10];
60  // * var = strdup("hello");
61  // * var = strndup("hello", 3);
62  if (tok2 && tok2->str() == "(") {
63  tok2 = tok2->link();
64  tok2 = tok2 ? tok2->next() : nullptr;
65  }
66  if (!tok2)
67  return No;
68  if (tok2->str() == "::")
69  tok2 = tok2->next();
70  if (!tok2->isName())
71  return No;
72 
73  if (!Token::Match(tok2, "%name% ::|. %type%")) {
74  // Using realloc..
75  AllocType reallocType = getReallocationType(tok2, varid);
76  if (reallocType != No)
77  return reallocType;
78 
79  if (tok2->isCpp() && tok2->str() == "new") {
80  if (tok2->strAt(1) == "(" && !Token::Match(tok2->next(),"( std| ::| nothrow )"))
81  return No;
82  if (tok2->astOperand1() && (tok2->astOperand1()->str() == "[" || (tok2->astOperand1()->astOperand1() && tok2->astOperand1()->astOperand1()->str() == "[")))
83  return NewArray;
84  const Token *typeTok = tok2->next();
85  while (Token::Match(typeTok, "%name% :: %name%"))
86  typeTok = typeTok->tokAt(2);
87  const Scope* classScope = nullptr;
88  if (typeTok->type() && typeTok->type()->isClassType()) {
89  classScope = typeTok->type()->classScope;
90  } else if (typeTok->function() && typeTok->function()->isConstructor()) {
91  classScope = typeTok->function()->nestedIn;
92  }
93  if (classScope && classScope->numConstructors > 0)
94  return No;
95  return New;
96  }
97 
98  if (mSettings_->hasLib("posix")) {
99  if (Token::Match(tok2, "open|openat|creat|mkstemp|mkostemp|socket (")) {
100  // simple sanity check of function parameters..
101  // TODO: Make such check for all these functions
102  const int num = numberOfArguments(tok2);
103  if (tok2->str() == "open" && num != 2 && num != 3)
104  return No;
105 
106  // is there a user function with this name?
107  if (tok2->function())
108  return No;
109  return Fd;
110  }
111 
112  if (Token::simpleMatch(tok2, "popen ("))
113  return Pipe;
114  }
115 
116  // Does tok2 point on a Library allocation function?
117  const int alloctype = mSettings_->library.getAllocId(tok2, -1);
118  if (alloctype > 0) {
119  if (alloctype == mSettings_->library.deallocId("free"))
120  return Malloc;
121  if (alloctype == mSettings_->library.deallocId("fclose"))
122  return File;
123  return Library::ismemory(alloctype) ? OtherMem : OtherRes;
124  }
125  }
126 
127  while (Token::Match(tok2,"%name% ::|. %type%"))
128  tok2 = tok2->tokAt(2);
129 
130  // User function
131  const Function* func = tok2->function();
132  if (func == nullptr)
133  return No;
134 
135  // Prevent recursion
136  if (callstack && std::find(callstack->cbegin(), callstack->cend(), func) != callstack->cend())
137  return No;
138 
139  std::list<const Function*> cs;
140  if (!callstack)
141  callstack = &cs;
142 
143  callstack->push_back(func);
144  return functionReturnType(func, callstack);
145 }
146 
147 
149 {
150  // What we may have...
151  // * var = (char *)realloc(..;
152  if (tok2 && tok2->str() == "(") {
153  tok2 = tok2->link();
154  tok2 = tok2 ? tok2->next() : nullptr;
155  }
156  if (!tok2)
157  return No;
158 
159  if (!Token::Match(tok2, "%name% ("))
160  return No;
161 
163  if (!(f && f->reallocArg > 0 && f->reallocArg <= numberOfArguments(tok2)))
164  return No;
165  const auto args = getArguments(tok2);
166  if (args.size() < (f->reallocArg))
167  return No;
168  const Token* arg = args.at(f->reallocArg - 1);
169  while (arg && arg->isCast())
170  arg = arg->astOperand1();
171  while (arg && arg->isUnaryOp("*"))
172  arg = arg->astOperand1();
173  if (varid > 0 && !Token::Match(arg, "%varid% [,)]", varid))
174  return No;
175 
176  const int realloctype = mSettings_->library.getReallocId(tok2, -1);
177  if (realloctype > 0) {
178  if (realloctype == mSettings_->library.deallocId("free"))
179  return Malloc;
180  if (realloctype == mSettings_->library.deallocId("fclose"))
181  return File;
182  return Library::ismemory(realloctype) ? OtherMem : OtherRes;
183  }
184  return No;
185 }
186 
187 
189 {
190  if (tok->isCpp() && tok->str() == "delete" && tok->astOperand1()) {
191  const Token* vartok = tok->astOperand1();
192  if (Token::Match(vartok, ".|::"))
193  vartok = vartok->astOperand2();
194 
195  if (vartok && vartok->varId() == varid) {
196  if (tok->strAt(1) == "[")
197  return NewArray;
198  return New;
199  }
200  }
201 
202  if (tok->str() == "::")
203  tok = tok->next();
204 
205  if (Token::Match(tok, "%name% (")) {
206  if (Token::simpleMatch(tok, "fcloseall ( )"))
207  return File;
208 
209  int argNr = 1;
210  for (const Token* tok2 = tok->tokAt(2); tok2; tok2 = tok2->nextArgument()) {
211  const Token* vartok = tok2;
212  while (Token::Match(vartok, "%name% .|::"))
213  vartok = vartok->tokAt(2);
214 
215  if (Token::Match(vartok, "%varid% )|,|-", varid)) {
216  if (tok->str() == "realloc" && Token::simpleMatch(vartok->next(), ", 0 )"))
217  return Malloc;
218 
219  if (mSettings_->hasLib("posix")) {
220  if (tok->str() == "close")
221  return Fd;
222  if (tok->str() == "pclose")
223  return Pipe;
224  }
225 
226  // Does tok point on a Library deallocation function?
227  const int dealloctype = mSettings_->library.getDeallocId(tok, argNr);
228  if (dealloctype > 0) {
229  if (dealloctype == mSettings_->library.deallocId("free"))
230  return Malloc;
231  if (dealloctype == mSettings_->library.deallocId("fclose"))
232  return File;
233  return Library::ismemory(dealloctype) ? OtherMem : OtherRes;
234  }
235  }
236  argNr++;
237  }
238  }
239 
240  return No;
241 }
242 
244 {
245  if (getReallocationType(tok, 0) == File) {
247  if (f && f->reallocArg > 0 && f->reallocArg <= numberOfArguments(tok)) {
248  const Token* arg = getArguments(tok).at(f->reallocArg - 1);
249  if (Token::Match(arg, "stdin|stdout|stderr"))
250  return true;
251  }
252  }
253  return false;
254 }
255 
256 bool CheckMemoryLeak::isOpenDevNull(const Token *tok) const
257 {
258  if (mSettings_->hasLib("posix") && tok->str() == "open" && numberOfArguments(tok) == 2) {
259  const Token* arg = getArguments(tok).at(0);
260  if (Token::simpleMatch(arg, "\"/dev/null\""))
261  return true;
262  }
263  return false;
264 }
265 
266 //--------------------------------------------------------------------------
267 
268 
269 //--------------------------------------------------------------------------
270 
271 void CheckMemoryLeak::memoryLeak(const Token *tok, const std::string &varname, AllocType alloctype) const
272 {
273  if (alloctype == CheckMemoryLeak::File ||
274  alloctype == CheckMemoryLeak::Pipe ||
275  alloctype == CheckMemoryLeak::Fd ||
276  alloctype == CheckMemoryLeak::OtherRes)
277  resourceLeakError(tok, varname);
278  else
279  memleakError(tok, varname);
280 }
281 //---------------------------------------------------------------------------
282 
283 void CheckMemoryLeak::reportErr(const Token *tok, Severity severity, const std::string &id, const std::string &msg, const CWE &cwe) const
284 {
285  std::list<const Token *> callstack;
286 
287  if (tok)
288  callstack.push_back(tok);
289 
290  reportErr(callstack, severity, id, msg, cwe);
291 }
292 
293 void CheckMemoryLeak::reportErr(const std::list<const Token *> &callstack, Severity severity, const std::string &id, const std::string &msg, const CWE &cwe) const
294 {
295  const ErrorMessage errmsg(callstack, mTokenizer_ ? &mTokenizer_->list : nullptr, severity, id, msg, cwe, Certainty::normal);
296  if (mErrorLogger_)
297  mErrorLogger_->reportErr(errmsg);
298  else
299  Check::writeToErrorList(errmsg);
300 }
301 
302 void CheckMemoryLeak::memleakError(const Token *tok, const std::string &varname) const
303 {
304  reportErr(tok, Severity::error, "memleak", "$symbol:" + varname + "\nMemory leak: $symbol", CWE(401U));
305 }
306 
307 void CheckMemoryLeak::memleakUponReallocFailureError(const Token *tok, const std::string &reallocfunction, const std::string &varname) const
308 {
309  reportErr(tok, Severity::error, "memleakOnRealloc", "$symbol:" + varname + "\nCommon " + reallocfunction + " mistake: \'$symbol\' nulled but not freed upon failure", CWE(401U));
310 }
311 
312 void CheckMemoryLeak::resourceLeakError(const Token *tok, const std::string &varname) const
313 {
314  std::string errmsg("Resource leak");
315  if (!varname.empty())
316  errmsg = "$symbol:" + varname + '\n' + errmsg + ": $symbol";
317  reportErr(tok, Severity::error, "resourceLeak", errmsg, CWE(775U));
318 }
319 
320 void CheckMemoryLeak::deallocuseError(const Token *tok, const std::string &varname) const
321 {
322  reportErr(tok, Severity::error, "deallocuse", "$symbol:" + varname + "\nDereferencing '$symbol' after it is deallocated / released", CWE(416U));
323 }
324 
325 void CheckMemoryLeak::mismatchAllocDealloc(const std::list<const Token *> &callstack, const std::string &varname) const
326 {
327  reportErr(callstack, Severity::error, "mismatchAllocDealloc", "$symbol:" + varname + "\nMismatching allocation and deallocation: $symbol", CWE(762U));
328 }
329 
330 CheckMemoryLeak::AllocType CheckMemoryLeak::functionReturnType(const Function* func, std::list<const Function*> *callstack) const
331 {
332  if (!func || !func->hasBody() || !func->functionScope)
333  return No;
334 
335  // Get return pointer..
336  const Variable* var = nullptr;
337  for (const Token *tok2 = func->functionScope->bodyStart; tok2 != func->functionScope->bodyEnd; tok2 = tok2->next()) {
338  if (const Token *endOfLambda = findLambdaEndToken(tok2))
339  tok2 = endOfLambda;
340  if (tok2->str() == "{" && !tok2->scope()->isExecutable())
341  tok2 = tok2->link();
342  if (tok2->str() == "return") {
343  const AllocType allocType = getAllocationType(tok2->next(), 0, callstack);
344  if (allocType != No)
345  return allocType;
346 
347  if (tok2->scope() != func->functionScope || !tok2->astOperand1())
348  return No;
349  const Token* tok = tok2->astOperand1();
350  if (Token::Match(tok, ".|::"))
351  tok = tok->astOperand2() ? tok->astOperand2() : tok->astOperand1();
352  if (tok)
353  var = tok->variable();
354  break;
355  }
356  }
357 
358  // Not returning pointer value..
359  if (!var)
360  return No;
361 
362  // If variable is not local then alloctype shall be "No"
363  // Todo: there can be false negatives about mismatching allocation/deallocation.
364  // => Generate "alloc ; use ;" if variable is not local?
365  if (!var->isLocal() || var->isStatic())
366  return No;
367 
368  // Check if return pointer is allocated..
369  AllocType allocType = No;
370  nonneg int const varid = var->declarationId();
371  for (const Token* tok = func->functionScope->bodyStart; tok != func->functionScope->bodyEnd; tok = tok->next()) {
372  if (Token::Match(tok, "%varid% =", varid)) {
373  allocType = getAllocationType(tok->tokAt(2), varid, callstack);
374  }
375  if (Token::Match(tok, "= %varid% ;", varid)) {
376  return No;
377  }
378  if (!tok->isC() && Token::Match(tok, "[(,] %varid% [,)]", varid)) {
379  return No;
380  }
381  if (Token::Match(tok, "[(,] & %varid% [.,)]", varid)) {
382  return No;
383  }
384  if (Token::Match(tok, "[;{}] %varid% .", varid)) {
385  return No;
386  }
387  if (allocType == No && tok->str() == "return")
388  return No;
389  }
390 
391  return allocType;
392 }
393 
394 
395 static bool notvar(const Token *tok, nonneg int varid)
396 {
397  if (!tok)
398  return false;
399  if (Token::Match(tok, "&&|;"))
400  return notvar(tok->astOperand1(),varid) || notvar(tok->astOperand2(),varid);
401  if (tok->str() == "(" && Token::Match(tok->astOperand1(), "UNLIKELY|LIKELY"))
402  return notvar(tok->astOperand2(), varid);
403  const Token *vartok = astIsVariableComparison(tok, "==", "0");
404  return vartok && (vartok->varId() == varid);
405 }
406 
407 static bool ifvar(const Token *tok, nonneg int varid, const std::string &comp, const std::string &rhs)
408 {
409  if (!Token::simpleMatch(tok, "if ("))
410  return false;
411  const Token *condition = tok->next()->astOperand2();
412  if (condition && condition->str() == "(" && Token::Match(condition->astOperand1(), "UNLIKELY|LIKELY"))
413  condition = condition->astOperand2();
414  if (!condition || condition->str() == "&&")
415  return false;
416 
417  const Token *vartok = astIsVariableComparison(condition, comp, rhs);
418  return (vartok && vartok->varId() == varid);
419 }
420 
421 //---------------------------------------------------------------------------
422 // Check for memory leaks due to improper realloc() usage.
423 // Below, "a" may be set to null without being freed if realloc() cannot
424 // allocate the requested memory:
425 // a = malloc(10); a = realloc(a, 100);
426 //---------------------------------------------------------------------------
427 
429 {
430  logChecker("CheckMemoryLeakInFunction::checkReallocUsage");
431 
432  // only check functions
433  const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
434  for (const Scope * scope : symbolDatabase->functionScopes) {
435 
436  // Search for the "var = realloc(var, 100" pattern within this function
437  for (const Token *tok = scope->bodyStart->next(); tok != scope->bodyEnd; tok = tok->next()) {
438  if (tok->varId() > 0 && Token::Match(tok, "%name% =")) {
439  // Get the parenthesis in "realloc("
440  const Token* parTok = tok->next()->astOperand2();
441  // Skip casts
442  while (parTok && parTok->isCast())
443  parTok = parTok->astOperand1();
444  if (!parTok)
445  continue;
446 
447  const Token *const reallocTok = parTok->astOperand1();
448  if (!reallocTok)
449  continue;
450  const Library::AllocFunc* f = mSettings->library.getReallocFuncInfo(reallocTok);
451  if (!(f && f->arg == -1 && mSettings->library.isnotnoreturn(reallocTok)))
452  continue;
453 
454  const AllocType allocType = getReallocationType(reallocTok, tok->varId());
455  if (!((allocType == Malloc || allocType == OtherMem)))
456  continue;
457  const Token* arg = getArguments(reallocTok).at(f->reallocArg - 1);
458  while (arg && arg->isCast())
459  arg = arg->astOperand1();
460  const Token* tok2 = tok;
461  while (arg && arg->isUnaryOp("*") && tok2 && tok2->astParent() && tok2->astParent()->isUnaryOp("*")) {
462  arg = arg->astOperand1();
463  tok2 = tok2->astParent();
464  }
465 
466  if (!arg || !tok2)
467  continue;
468 
469  if (!(tok->varId() == arg->varId() && tok->variable() && !tok->variable()->isArgument()))
470  continue;
471 
472  // Check that another copy of the pointer wasn't saved earlier in the function
473  if (Token::findmatch(scope->bodyStart, "%name% = %varid% ;", tok, tok->varId()) ||
474  Token::findmatch(scope->bodyStart, "[{};] %varid% = *| %var% .| %var%| [;=]", tok, tok->varId()))
475  continue;
476 
477  // Check if the argument is known to be null, which means it is not a memory leak
478  if (arg->hasKnownIntValue() && arg->getKnownIntValue() == 0) {
479  continue;
480  }
481 
482  const Token* tokEndRealloc = reallocTok->linkAt(1);
483  // Check that the allocation isn't followed immediately by an 'if (!var) { error(); }' that might handle failure
484  if (Token::simpleMatch(tokEndRealloc->next(), "; if (") &&
485  notvar(tokEndRealloc->tokAt(3)->astOperand2(), tok->varId())) {
486  const Token* tokEndBrace = tokEndRealloc->linkAt(3)->linkAt(1);
487  if (tokEndBrace && mTokenizer->isScopeNoReturn(tokEndBrace))
488  continue;
489  }
490 
491  memleakUponReallocFailureError(tok, reallocTok->str(), tok->str());
492  }
493  }
494  }
495 }
496 //---------------------------------------------------------------------------
497 
498 
499 //---------------------------------------------------------------------------
500 // Checks for memory leaks in classes..
501 //---------------------------------------------------------------------------
502 
503 
505 {
506  logChecker("CheckMemoryLeakInClass::check");
507 
508  const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
509 
510  // only check classes and structures
511  for (const Scope * scope : symbolDatabase->classAndStructScopes) {
512  for (const Variable &var : scope->varlist) {
513  if (!var.isStatic() && (var.isPointer() || var.isPointerArray())) {
514  // allocation but no deallocation of private variables in public function..
515  const Token *tok = var.typeStartToken();
516  // Either it is of standard type or a non-derived type
517  if (tok->isStandardType() || (var.type() && var.type()->derivedFrom.empty())) {
518  if (var.isPrivate())
519  checkPublicFunctions(scope, var.nameToken());
520 
521  variable(scope, var.nameToken());
522  }
523  }
524  }
525  }
526 }
527 
528 
529 void CheckMemoryLeakInClass::variable(const Scope *scope, const Token *tokVarname)
530 {
531  const std::string& varname = tokVarname->str();
532  const int varid = tokVarname->varId();
533  const std::string& classname = scope->className;
534 
535  // Check if member variable has been allocated and deallocated..
538 
539  bool allocInConstructor = false;
540  bool deallocInDestructor = false;
541 
542  // Inspect member functions
543  for (const Function &func : scope->functionList) {
544  const bool constructor = func.isConstructor();
545  const bool destructor = func.isDestructor();
546  if (!func.hasBody()) {
547  if (destructor && !func.isDefault()) { // implementation for destructor is not seen and not defaulted => assume it deallocates all variables properly
548  deallocInDestructor = true;
549  memberDealloc = CheckMemoryLeak::Many;
550  }
551  continue;
552  }
553  bool body = false;
554  const Token *end = func.functionScope->bodyEnd;
555  for (const Token *tok = func.arg->link(); tok != end; tok = tok->next()) {
556  if (tok == func.functionScope->bodyStart)
557  body = true;
558  else {
559  if (!body) {
560  if (!Token::Match(tok, ":|, %varid% (", varid))
561  continue;
562  }
563 
564  // Allocate..
565  if (!body || Token::Match(tok, "%varid% =|[", varid)) {
566  // var1 = var2 = ...
567  // bail out
568  if (tok->strAt(-1) == "=")
569  return;
570 
571  // Foo::var1 = ..
572  // bail out when not same class
573  if (tok->strAt(-1) == "::" &&
574  tok->strAt(-2) != scope->className)
575  return;
576 
577  const Token* allocTok = tok->tokAt(body ? 2 : 3);
578  if (tok->astParent() && tok->astParent()->str() == "[" && tok->astParent()->astParent())
579  allocTok = tok->astParent()->astParent()->astOperand2();
580 
581  AllocType alloc = getAllocationType(allocTok, 0);
582  if (alloc != CheckMemoryLeak::No) {
583  if (constructor)
584  allocInConstructor = true;
585 
586  if (memberAlloc != No && memberAlloc != alloc)
587  alloc = CheckMemoryLeak::Many;
588 
589  if (alloc != CheckMemoryLeak::Many && memberDealloc != CheckMemoryLeak::No && memberDealloc != CheckMemoryLeak::Many && memberDealloc != alloc) {
590  mismatchAllocDealloc({tok}, classname + "::" + varname);
591  }
592 
593  memberAlloc = alloc;
594  }
595  }
596 
597  if (!body)
598  continue;
599 
600  // Deallocate..
601  AllocType dealloc = getDeallocationType(tok, varid);
602  // some usage in the destructor => assume it's related
603  // to deallocation
604  if (destructor && tok->str() == varname)
605  dealloc = CheckMemoryLeak::Many;
606  if (dealloc != CheckMemoryLeak::No) {
607  if (destructor)
608  deallocInDestructor = true;
609 
610  if (dealloc != CheckMemoryLeak::Many && memberAlloc != CheckMemoryLeak::No && memberAlloc != Many && memberAlloc != dealloc) {
611  mismatchAllocDealloc({tok}, classname + "::" + varname);
612  }
613 
614  // several types of allocation/deallocation?
615  if (memberDealloc != CheckMemoryLeak::No && memberDealloc != dealloc)
616  dealloc = CheckMemoryLeak::Many;
617 
618  memberDealloc = dealloc;
619  }
620 
621  // Function call .. possible deallocation
622  else if (Token::Match(tok->previous(), "[{};] %name% (") && !tok->isKeyword() && !mSettings->library.isLeakIgnore(tok->str())) {
623  return;
624  }
625  }
626  }
627  }
628 
629  if (allocInConstructor && !deallocInDestructor) {
630  unsafeClassError(tokVarname, classname, classname + "::" + varname /*, memberAlloc*/);
631  } else if (memberAlloc != CheckMemoryLeak::No && memberDealloc == CheckMemoryLeak::No) {
632  unsafeClassError(tokVarname, classname, classname + "::" + varname /*, memberAlloc*/);
633  }
634 }
635 
636 void CheckMemoryLeakInClass::unsafeClassError(const Token *tok, const std::string &classname, const std::string &varname)
637 {
638  if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("unsafeClassCanLeak"))
639  return;
640 
641  reportError(tok, Severity::style, "unsafeClassCanLeak",
642  "$symbol:" + classname + "\n"
643  "$symbol:" + varname + "\n"
644  "Class '" + classname + "' is unsafe, '" + varname + "' can leak by wrong usage.\n"
645  "The class '" + classname + "' is unsafe, wrong usage can cause memory/resource leaks for '" + varname + "'. This can for instance be fixed by adding proper cleanup in the destructor.", CWE398, Certainty::normal);
646 }
647 
648 
649 void CheckMemoryLeakInClass::checkPublicFunctions(const Scope *scope, const Token *classtok)
650 {
651  // Check that public functions deallocate the pointers that they allocate.
652  // There is no checking how these functions are used and therefore it
653  // isn't established if there is real leaks or not.
655  return;
656 
657  const int varid = classtok->varId();
658 
659  // Parse public functions..
660  // If they allocate member variables, they should also deallocate
661  for (const Function &func : scope->functionList) {
662  if ((func.type == Function::eFunction || func.type == Function::eOperatorEqual) &&
663  func.access == AccessControl::Public && func.hasBody()) {
664  const Token *tok2 = func.functionScope->bodyStart->next();
665  if (Token::Match(tok2, "%varid% =", varid)) {
666  const CheckMemoryLeak::AllocType alloc = getAllocationType(tok2->tokAt(2), varid);
667  if (alloc != CheckMemoryLeak::No)
668  publicAllocationError(tok2, tok2->str());
669  } else if (Token::Match(tok2, "%type% :: %varid% =", varid) &&
670  tok2->str() == scope->className) {
671  const CheckMemoryLeak::AllocType alloc = getAllocationType(tok2->tokAt(4), varid);
672  if (alloc != CheckMemoryLeak::No)
673  publicAllocationError(tok2, tok2->strAt(2));
674  }
675  }
676  }
677 }
678 
679 void CheckMemoryLeakInClass::publicAllocationError(const Token *tok, const std::string &varname)
680 {
681  reportError(tok, Severity::warning, "publicAllocationError", "$symbol:" + varname + "\nPossible leak in public function. The pointer '$symbol' is not deallocated before it is allocated.", CWE398, Certainty::normal);
682 }
683 
684 
686 {
687  if (mSettings->clang)
688  return;
689 
690  logChecker("CheckMemoryLeakStructMember::check");
691 
692  const SymbolDatabase* symbolDatabase = mTokenizer->getSymbolDatabase();
693  for (const Variable* var : symbolDatabase->variableList()) {
694  if (!var || (!var->isLocal() && !(var->isArgument() && var->scope())) || var->isStatic())
695  continue;
696  if (var->isReference() || (var->valueType() && var->valueType()->pointer > 1))
697  continue;
698  if (var->typeEndToken()->isStandardType())
699  continue;
700  checkStructVariable(var);
701  }
702 }
703 
705 {
706  if (!variable)
707  return false;
708  const int declarationId(variable->declarationId());
709  bool alloc = false;
710  for (const Token *tok2 = variable->nameToken(); tok2 && tok2 != variable->scope()->bodyEnd; tok2 = tok2->next()) {
711  if (Token::Match(tok2, "= %varid% [;=]", declarationId))
712  return false;
713  if (Token::Match(tok2, "%varid% = %name% (", declarationId) && mSettings->library.getAllocFuncInfo(tok2->tokAt(2)))
714  alloc = true;
715  }
716  return alloc;
717 }
718 
720 {
721  if (!variable)
722  return;
723  // Is struct variable a pointer?
724  if (variable->isArrayOrPointer()) {
725  // Check that variable is allocated with malloc
726  if (!isMalloc(variable))
727  return;
728  } else if (!mTokenizer->isC() && (!variable->typeScope() || variable->typeScope()->getDestructor())) {
729  // For non-C code a destructor might cleanup members
730  return;
731  }
732 
733  // Check struct..
734  int indentlevel2 = 0;
735 
736  auto deallocInFunction = [this](const Token* tok, int structid) -> bool {
737  // Calling non-function / function that doesn't deallocate?
738  if (tok->isKeyword() || mSettings->library.isLeakIgnore(tok->str()))
739  return false;
740 
741  // Check if the struct is used..
742  bool deallocated = false;
743  const Token* const end = tok->linkAt(1);
744  for (const Token* tok2 = tok; tok2 != end; tok2 = tok2->next()) {
745  if (Token::Match(tok2, "[(,] &| %varid% [,)]", structid)) {
746  /** @todo check if the function deallocates the memory */
747  deallocated = true;
748  break;
749  }
750 
751  if (Token::Match(tok2, "[(,] &| %varid% . %name% [,)]", structid)) {
752  /** @todo check if the function deallocates the memory */
753  deallocated = true;
754  break;
755  }
756  }
757 
758  return deallocated;
759  };
760 
761  // return { memberTok, rhsTok }
762  auto isMemberAssignment = [](const Token* varTok, int varId) -> std::pair<const Token*, const Token*> {
763  if (varTok->varId() != varId)
764  return {};
765  const Token* top = varTok;
766  while (top->astParent()) {
767  if (Token::Match(top->astParent(), "(|["))
768  return {};
769  top = top->astParent();
770  }
771  if (!Token::simpleMatch(top, "=") || !precedes(varTok, top))
772  return {};
773  const Token* dot = top->astOperand1();
774  while (dot && dot->str() != ".")
775  dot = dot->astOperand1();
776  if (!dot)
777  return {};
778  return { dot->astOperand2(), top->next() };
779  };
780  std::pair<const Token*, const Token*> assignToks;
781 
782  const Token* tokStart = variable->nameToken();
783  if (variable->isArgument() && variable->scope())
784  tokStart = variable->scope()->bodyStart->next();
785  for (const Token *tok2 = tokStart; tok2 && tok2 != variable->scope()->bodyEnd; tok2 = tok2->next()) {
786  if (tok2->str() == "{")
787  ++indentlevel2;
788 
789  else if (tok2->str() == "}") {
790  if (indentlevel2 == 0)
791  break;
792  --indentlevel2;
793  }
794 
795  // Unknown usage of struct
796  /** @todo Check how the struct is used. Only bail out if necessary */
797  else if (Token::Match(tok2, "[(,] %varid% [,)]", variable->declarationId()))
798  break;
799 
800  // Struct member is allocated => check if it is also properly deallocated..
801  else if ((assignToks = isMemberAssignment(tok2, variable->declarationId())).first && assignToks.first->varId()) {
802  if (getAllocationType(assignToks.second, assignToks.first->varId()) == AllocType::No)
803  continue;
804 
805  if (variable->isArgument() && variable->valueType() && variable->valueType()->type == ValueType::UNKNOWN_TYPE && assignToks.first->astParent()) {
806  const Token* accessTok = assignToks.first->astParent();
807  while (Token::simpleMatch(accessTok->astOperand1(), "."))
808  accessTok = accessTok->astOperand1();
809  if (Token::simpleMatch(accessTok, ".") && accessTok->originalName() == "->")
810  continue;
811  }
812 
813  const int structid(variable->declarationId());
814  const int structmemberid(assignToks.first->varId());
815 
816  // This struct member is allocated.. check that it is deallocated
817  int indentlevel3 = indentlevel2;
818  for (const Token *tok3 = tok2; tok3; tok3 = tok3->next()) {
819  if (tok3->str() == "{")
820  ++indentlevel3;
821 
822  else if (tok3->str() == "}") {
823  if (indentlevel3 == 0) {
824  memoryLeak(tok3, variable->name() + "." + tok2->strAt(2), Malloc);
825  break;
826  }
827  --indentlevel3;
828  }
829 
830  // Deallocating the struct member..
831  else if (getDeallocationType(tok3, structmemberid) != AllocType::No) {
832  // If the deallocation happens at the base level, don't check this member anymore
833  if (indentlevel3 == 0)
834  break;
835 
836  // deallocating and then returning from function in a conditional block =>
837  // skip ahead out of the block
838  bool ret = false;
839  while (tok3) {
840  if (tok3->str() == "return")
841  ret = true;
842  else if (tok3->str() == "{" || tok3->str() == "}")
843  break;
844  tok3 = tok3->next();
845  }
846  if (!ret || !tok3 || tok3->str() != "}")
847  break;
848  --indentlevel3;
849  continue;
850  }
851 
852  // Deallocating the struct..
853  else if (Token::Match(tok3, "%name% ( %varid% )", structid) && mSettings->library.getDeallocFuncInfo(tok3)) {
854  if (indentlevel2 == 0)
855  memoryLeak(tok3, variable->name() + "." + tok2->strAt(2), Malloc);
856  break;
857  }
858 
859  // failed allocation => skip code..
860  else if (Token::simpleMatch(tok3, "if (") &&
861  notvar(tok3->next()->astOperand2(), structmemberid)) {
862  // Goto the ")"
863  tok3 = tok3->next()->link();
864 
865  // make sure we have ") {".. it should be
866  if (!Token::simpleMatch(tok3, ") {"))
867  break;
868 
869  // Goto the "}"
870  tok3 = tok3->next()->link();
871  }
872 
873  // succeeded allocation
874  else if (ifvar(tok3, structmemberid, "!=", "0")) {
875  // goto the ")"
876  tok3 = tok3->next()->link();
877 
878  // check if the variable is deallocated or returned..
879  int indentlevel4 = 0;
880  for (const Token *tok4 = tok3; tok4; tok4 = tok4->next()) {
881  if (tok4->str() == "{")
882  ++indentlevel4;
883  else if (tok4->str() == "}") {
884  --indentlevel4;
885  if (indentlevel4 == 0)
886  break;
887  } else if (Token::Match(tok4, "%name% ( %var% . %varid% )", structmemberid) && mSettings->library.getDeallocFuncInfo(tok4)) {
888  break;
889  }
890  }
891 
892  // was there a proper deallocation?
893  if (indentlevel4 > 0)
894  break;
895  }
896 
897  // Returning from function..
898  else if ((tok3->scope()->type != Scope::ScopeType::eLambda || tok3->scope() == variable->scope()) && tok3->str() == "return") {
899  // Returning from function without deallocating struct member?
900  if (!Token::Match(tok3, "return %varid% ;", structid) &&
901  !Token::Match(tok3, "return & %varid%", structid) &&
902  !(Token::Match(tok3, "return %varid% . %var%", structid) && tok3->tokAt(3)->varId() == structmemberid) &&
903  !(Token::Match(tok3, "return %name% (") && tok3->astOperand1() && deallocInFunction(tok3->astOperand1(), structid))) {
904  memoryLeak(tok3, variable->name() + "." + tok2->strAt(2), Malloc);
905  }
906  break;
907  }
908 
909  // struct assignment..
910  else if (Token::Match(tok3, "= %varid% ;", structid)) {
911  break;
912  } else if (Token::Match(tok3, "= %var% . %varid% ;", structmemberid)) {
913  break;
914  }
915 
916  // goto isn't handled well.. bail out even though there might be leaks
917  else if (tok3->str() == "goto")
918  break;
919 
920  // using struct in a function call..
921  else if (Token::Match(tok3, "%name% (")) {
922  if (deallocInFunction(tok3, structid))
923  break;
924  }
925  }
926  }
927  }
928 }
929 
930 
931 
933 {
934  logChecker("CheckMemoryLeakNoVar::check");
935 
936  const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
937 
938  // only check functions
939  for (const Scope * scope : symbolDatabase->functionScopes) {
940 
941  // Checks if a call to an allocation function like malloc() is made and its return value is not assigned.
943 
944  // Checks to see if a function is called with memory allocated for an argument that
945  // could be leaked if a function called for another argument throws.
946  checkForUnsafeArgAlloc(scope);
947 
948  // Check for leaks where a the return value of an allocation function like malloc() is an input argument,
949  // for example f(malloc(1)), where f is known to not release the input argument.
951  }
952 }
953 
954 //---------------------------------------------------------------------------
955 // Checks if an input argument to a function is the return value of an allocation function
956 // like malloc(), and the function does not release it.
957 //---------------------------------------------------------------------------
959 {
960  // parse the executable scope until tok is reached...
961  for (const Token *tok = scope->bodyStart; tok != scope->bodyEnd; tok = tok->next()) {
962  // allocating memory in parameter for function call..
963  if (tok->varId() || !Token::Match(tok, "%name% ("))
964  continue;
965 
966  // check if the output of the function is assigned
967  const Token* tok2 = tok->next()->astParent();
968  while (tok2 && (tok2->isCast() || Token::Match(tok2, "?|:")))
969  tok2 = tok2->astParent();
970  if (Token::Match(tok2, "%assign%")) // TODO: check if function returns allocated resource
971  continue;
972  if (Token::simpleMatch(tok->astTop(), "return"))
973  continue;
974 
975  const std::string& functionName = tok->str();
976  if ((tok->isCpp() && functionName == "delete") ||
977  functionName == "return")
978  continue;
979 
980  if (Token::simpleMatch(tok->next()->astParent(), "(")) // passed to another function
981  continue;
982  if (!tok->isKeyword() && !tok->function() && !mSettings->library.isLeakIgnore(functionName))
983  continue;
984 
985  const std::vector<const Token *> args = getArguments(tok);
986  int argnr = -1;
987  for (const Token* arg : args) {
988  ++argnr;
989  if (arg->isOp() && !(tok->isKeyword() && arg->str() == "*")) // e.g. switch (*new int)
990  continue;
991  while (arg->astOperand1()) {
992  if (arg->isCpp() && Token::simpleMatch(arg, "new"))
993  break;
994  arg = arg->astOperand1();
995  }
996  const AllocType alloc = getAllocationType(arg, 0);
997  if (alloc == No)
998  continue;
999  if (alloc == New || alloc == NewArray) {
1000  const Token* typeTok = arg->next();
1001  bool bail = !typeTok->isStandardType() &&
1003  !mSettings->library.podtype(typeTok->expressionString());
1004  if (bail && typeTok->type() && typeTok->type()->classScope &&
1005  typeTok->type()->classScope->numConstructors == 0 &&
1006  typeTok->type()->classScope->getDestructor() == nullptr) {
1007  bail = false;
1008  }
1009  if (bail)
1010  continue;
1011  }
1012  if (isReopenStandardStream(arg))
1013  continue;
1014  if (tok->function()) {
1015  const Variable* argvar = tok->function()->getArgumentVar(argnr);
1016  if (!argvar || !argvar->valueType())
1017  continue;
1018  const MathLib::bigint argSize = argvar->valueType()->typeSize(mSettings->platform, /*p*/ true);
1019  if (argSize <= 0 || argSize >= mSettings->platform.sizeof_pointer)
1020  continue;
1021  }
1022  functionCallLeak(arg, arg->str(), functionName);
1023  }
1024 
1025  }
1026 }
1027 
1028 //---------------------------------------------------------------------------
1029 // Checks if a call to an allocation function like malloc() is made and its return value is not assigned.
1030 //---------------------------------------------------------------------------
1032 {
1033  for (const Token *tok = scope->bodyStart; tok != scope->bodyEnd; tok = tok->next()) {
1034  const bool isNew = tok->isCpp() && tok->str() == "new";
1035  if (!isNew && !Token::Match(tok, "%name% ("))
1036  continue;
1037 
1038  if (tok->varId())
1039  continue;
1040 
1041  const AllocType allocType = getAllocationType(tok, 0);
1042  if (allocType == No)
1043  continue;
1044 
1045  if (tok != tok->next()->astOperand1() && !isNew)
1046  continue;
1047 
1048  if (isReopenStandardStream(tok))
1049  continue;
1050  if (isOpenDevNull(tok))
1051  continue;
1052 
1053  // get ast parent, skip casts
1054  const Token *parent = isNew ? tok->astParent() : tok->next()->astParent();
1055  while (parent && parent->isCast())
1056  parent = parent->astParent();
1057 
1058  bool warn = true;
1059  if (isNew) {
1060  const Token* typeTok = tok->next();
1061  warn = typeTok && (typeTok->isStandardType() || mSettings->library.detectContainer(typeTok));
1062  }
1063 
1064  if (!parent && warn) {
1065  // Check if we are in a C++11 constructor
1066  const Token * closingBrace = Token::findmatch(tok, "}|;");
1067  if (closingBrace->str() == "}" && Token::Match(closingBrace->link()->tokAt(-1), "%name%") && (!isNew && precedes(tok, closingBrace->link())))
1068  continue;
1069  returnValueNotUsedError(tok, tok->str());
1070  } else if (Token::Match(parent, "%comp%|!|,|%oror%|&&|:")) {
1071  if (parent->astParent() && parent->str() == ",")
1072  continue;
1073  if (parent->str() == ":") {
1074  if (!(Token::simpleMatch(parent->astParent(), "?") && !parent->astParent()->astParent()))
1075  continue;
1076  }
1077  returnValueNotUsedError(tok, tok->str());
1078  }
1079  }
1080 }
1081 
1082 //---------------------------------------------------------------------------
1083 // Check if an exception could cause a leak in an argument constructed with
1084 // shared_ptr/unique_ptr. For example, in the following code, it is possible
1085 // that if g() throws an exception, the memory allocated by "new int(42)"
1086 // could be leaked. See stackoverflow.com/questions/19034538/
1087 // why-is-there-memory-leak-while-using-shared-ptr-as-a-function-parameter
1088 //
1089 // void x() {
1090 // f(shared_ptr<int>(new int(42)), g());
1091 // }
1092 //---------------------------------------------------------------------------
1094 {
1095  // This test only applies to C++ source
1096  if (!mTokenizer->isCPP())
1097  return;
1098 
1100  return;
1101 
1102  logChecker("CheckMemoryLeakNoVar::checkForUnsafeArgAlloc");
1103 
1104  for (const Token *tok = scope->bodyStart; tok != scope->bodyEnd; tok = tok->next()) {
1105  if (Token::Match(tok, "%name% (")) {
1106  const Token *endParamToken = tok->next()->link();
1107  const Token* pointerType = nullptr;
1108  const Token* functionCalled = nullptr;
1109 
1110  // Scan through the arguments to the function call
1111  for (const Token *tok2 = tok->tokAt(2); tok2 && tok2 != endParamToken; tok2 = tok2->nextArgument()) {
1112  const Function *func = tok2->function();
1113  const bool isNothrow = func && (func->isAttributeNothrow() || func->isThrow());
1114 
1115  if (Token::Match(tok2, "shared_ptr|unique_ptr <") && Token::Match(tok2->next()->link(), "> ( new %name%")) {
1116  pointerType = tok2;
1117  } else if (!isNothrow) {
1118  if (Token::Match(tok2, "%name% ("))
1119  functionCalled = tok2;
1120  else if (tok2->isName() && Token::simpleMatch(tok2->next()->link(), "> ("))
1121  functionCalled = tok2;
1122  }
1123  }
1124 
1125  if (pointerType && functionCalled) {
1126  std::string functionName = functionCalled->str();
1127  if (functionCalled->strAt(1) == "<") {
1128  functionName += '<';
1129  for (const Token* tok2 = functionCalled->tokAt(2); tok2 != functionCalled->next()->link(); tok2 = tok2->next())
1130  functionName += tok2->str();
1131  functionName += '>';
1132  }
1133  std::string objectTypeName;
1134  for (const Token* tok2 = pointerType->tokAt(2); tok2 != pointerType->next()->link(); tok2 = tok2->next())
1135  objectTypeName += tok2->str();
1136 
1137  unsafeArgAllocError(tok, functionName, pointerType->str(), objectTypeName);
1138  }
1139  }
1140  }
1141 }
1142 
1143 void CheckMemoryLeakNoVar::functionCallLeak(const Token *loc, const std::string &alloc, const std::string &functionCall)
1144 {
1145  reportError(loc, Severity::error, "leakNoVarFunctionCall", "Allocation with " + alloc + ", " + functionCall + " doesn't release it.", CWE772, Certainty::normal);
1146 }
1147 
1148 void CheckMemoryLeakNoVar::returnValueNotUsedError(const Token *tok, const std::string &alloc)
1149 {
1150  reportError(tok, Severity::error, "leakReturnValNotUsed", "$symbol:" + alloc + "\nReturn value of allocation function '$symbol' is not stored.", CWE771, Certainty::normal);
1151 }
1152 
1153 void CheckMemoryLeakNoVar::unsafeArgAllocError(const Token *tok, const std::string &funcName, const std::string &ptrType, const std::string& objType)
1154 {
1155  const std::string factoryFunc = ptrType == "shared_ptr" ? "make_shared" : "make_unique";
1156  reportError(tok, Severity::warning, "leakUnsafeArgAlloc",
1157  "$symbol:" + funcName + "\n"
1158  "Unsafe allocation. If $symbol() throws, memory could be leaked. Use " + factoryFunc + "<" + objType + ">() instead.",
1159  CWE401,
1160  Certainty::inconclusive); // Inconclusive because funcName may never throw
1161 }
const Token * astIsVariableComparison(const Token *tok, const std::string &comp, const std::string &rhs, const Token **vartok)
Is given syntax tree a variable comparison against value.
Definition: astutils.cpp:351
std::vector< const Token * > getArguments(const Token *ftok)
Get arguments (AST)
Definition: astutils.cpp:3083
bool precedes(const Token *tok1, const Token *tok2)
If tok2 comes after tok1.
Definition: astutils.cpp:994
const Token * findLambdaEndToken(const Token *first)
find lambda function end token
Definition: astutils.cpp:3195
int numberOfArguments(const Token *ftok)
Determines the number of arguments - if token is a function call or macro.
Definition: astutils.cpp:3063
static const CWE CWE398(398U)
static bool notvar(const Token *tok, nonneg int varid)
static const CWE CWE772(772U)
static const CWE CWE771(771U)
static bool ifvar(const Token *tok, nonneg int varid, const std::string &comp, const std::string &rhs)
static const CWE CWE401(401U)
Check for memory leaks
Check class variables, variables that are allocated in the constructor should be deallocated in the d...
void unsafeClassError(const Token *tok, const std::string &classname, const std::string &varname)
void variable(const Scope *scope, const Token *tokVarname)
void checkPublicFunctions(const Scope *scope, const Token *classtok)
Public functions: possible double-allocation.
void publicAllocationError(const Token *tok, const std::string &varname)
CheckMemoryLeakInFunction detects when a function variable is allocated but not deallocated properly.
void checkReallocUsage()
Checking for a memory leak caused by improper realloc usage.
detect simple memory leaks (address not taken)
void returnValueNotUsedError(const Token *tok, const std::string &alloc)
void checkForUnusedReturnValue(const Scope *scope)
Check if a call to an allocation function like malloc() is made and its return value is not assigned.
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 checkForUnreleasedInputArgument(const Scope *scope)
Check if an input argument to a function is the return value of an allocation function like malloc(),...
void checkForUnsafeArgAlloc(const Scope *scope)
Check if an exception could cause a leak in an argument constructed with shared_ptr/unique_ptr.
detect simple memory leaks for struct members
void checkStructVariable(const Variable *const variable) const
bool isMalloc(const Variable *variable) const
Is local variable allocated with malloc?
AllocType functionReturnType(const Function *func, std::list< const Function * > *callstack=nullptr) const
What type of allocated memory does the given function return?
void memoryLeak(const Token *tok, const std::string &varname, AllocType alloctype) const
void deallocuseError(const Token *tok, const std::string &varname) const
AllocType getAllocationType(const Token *tok2, nonneg int varid, std::list< const Function * > *callstack=nullptr) const
Get type of allocation at given position.
AllocType getDeallocationType(const Token *tok, nonneg int varid) const
Get type of deallocation at given position.
AllocType getReallocationType(const Token *tok2, nonneg int varid) const
Get type of reallocation at given position.
bool isReopenStandardStream(const Token *tok) const
Check if token reopens a standard stream.
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
bool isOpenDevNull(const Token *tok) const
Check if token opens /dev/null.
ErrorLogger *const mErrorLogger_
ErrorLogger used to report errors.
void reportErr(const Token *tok, Severity severity, const std::string &id, const std::string &msg, const CWE &cwe) const
Report error.
AllocType
What type of allocation are used.
void memleakUponReallocFailureError(const Token *tok, const std::string &reallocfunction, const std::string &varname) const
void memleakError(const Token *tok, const std::string &varname) const
Report that there is a memory leak (new/malloc/etc)
void reportError(const Token *tok, const Severity severity, const std::string &id, const std::string &msg)
report an error
Definition: check.h:138
const Settings *const mSettings
Definition: check.h:134
static void writeToErrorList(const ErrorMessage &errmsg)
Write given error to stdout in xml format.
Definition: check.cpp:58
const Tokenizer *const mTokenizer
Definition: check.h:133
void logChecker(const char id[])
log checker
Definition: check.cpp:129
virtual void reportErr(const ErrorMessage &msg)=0
Information about found errors and warnings is directed here.
Wrapper for error messages, provided by reportErr()
Definition: errorlogger.h:48
AccessControl access
public/protected/private
const Scope * functionScope
scope of function body
bool hasBody() const
Type type
constructor, destructor, ...
bool isThrow() const
bool isDefault() const
const Token * arg
function argument start '('
bool isDestructor() const
bool isConstructor() const
bool isAttributeNothrow() const
const Container * detectContainerOrIterator(const Token *typeStart, bool *isIterator=nullptr, bool withoutStd=false) const
Definition: library.cpp:1241
int getAllocId(const Token *tok, int arg) const
get allocation id for function
Definition: library.cpp:1104
static bool ismemory(const int id)
is allocation type memory?
Definition: library.h:140
int getDeallocId(const Token *tok, int arg) const
get deallocation id for function
Definition: library.cpp:1111
bool isLeakIgnore(const std::string &functionName) const
Definition: library.cpp:1527
bool isnotnoreturn(const Token *ftok) const
Definition: library.cpp:1579
int getReallocId(const Token *tok, int arg) const
get reallocation id for function
Definition: library.cpp:1118
const AllocFunc * getAllocFuncInfo(const Token *tok) const
get allocation info for function
Definition: library.cpp:1077
const AllocFunc * getReallocFuncInfo(const Token *tok) const
get reallocation info for function
Definition: library.cpp:1095
int deallocId(const char name[]) const
get deallocation id for function by name (deprecated, use other alloc)
Definition: library.h:132
const PodType * podtype(const std::string &name) const
Definition: library.h:450
const AllocFunc * getDeallocFuncInfo(const Token *tok) const
get deallocation info for function
Definition: library.cpp:1086
const Container * detectContainer(const Token *typeStart) const
Definition: library.cpp:1231
long long bigint
Definition: mathlib.h:68
std::size_t sizeof_pointer
Definition: platform.h:102
std::list< Function > functionList
std::list< Variable > varlist
const Function * getDestructor() const
const Token * bodyStart
'{' token
const Token * bodyEnd
'}' token
nonneg int numConstructors
std::string className
bool hasLib(const std::string &lib) const
Is library specified?
Definition: settings.h:439
Library library
Library.
Definition: settings.h:237
bool clang
Use Clang.
Definition: settings.h:150
Platform platform
Definition: settings.h:255
bool isPremiumEnabled(const char id[]) const
Is checker id enabled by premiumArgs.
Definition: settings.cpp:608
SimpleEnableGroup< Certainty > certainty
Definition: settings.h:359
SimpleEnableGroup< Severity > severity
Definition: settings.h:358
bool isEnabled(T flag) const
Definition: settings.h:66
const std::vector< const Variable * > & variableList() const
std::vector< const Scope * > functionScopes
Fast access to function scopes.
std::vector< const Scope * > classAndStructScopes
Fast access to class and struct scopes.
The token list that the TokenList generates is a linked-list of this class.
Definition: token.h:150
void str(T &&s)
Definition: token.h:179
static bool Match(const Token *tok, const char pattern[], nonneg int varid=0)
Match given token (or list of tokens) to a pattern list.
Definition: token.cpp:688
bool isKeyword() const
Definition: token.h:358
const std::string & originalName() const
Definition: token.h:1193
bool isName() const
Definition: token.h:361
static const Token * findmatch(const Token *const startTok, const char pattern[], const nonneg int varId=0)
Definition: token.cpp:1065
bool hasKnownIntValue() const
Definition: token.cpp:2519
MathLib::bigint getKnownIntValue() const
Definition: token.h:1218
bool isCpp() const
Definition: token.cpp:2718
const std::string & strAt(int index) const
Definition: token.cpp:423
void astOperand1(Token *tok)
Definition: token.cpp:1456
void function(const Function *f)
Associate this token with given function.
Definition: token.cpp:1093
nonneg int varId() const
Definition: token.h:870
std::string expressionString() const
Definition: token.cpp:1647
bool isCast() const
Definition: token.h:458
bool isUnaryOp(const std::string &s) const
Definition: token.h:413
const Token * tokAt(int index) const
Definition: token.cpp:393
void astOperand2(Token *tok)
Definition: token.cpp:1468
void link(Token *linkToToken)
Create link to given token.
Definition: token.h:1015
const Token * linkAt(int index) const
Definition: token.cpp:413
void type(const ::Type *t)
Associate this token with given type.
Definition: token.cpp:2333
bool isStandardType() const
Definition: token.h:449
void variable(const Variable *v)
Associate this token with given variable.
Definition: token.h:1070
Token * next()
Definition: token.h:830
const Token * nextArgument() const
Definition: token.cpp:869
static bool simpleMatch(const Token *tok, const char(&pattern)[count])
Match given token (or list of tokens) to a pattern list.
Definition: token.h:252
void astParent(Token *tok)
Definition: token.cpp:1437
bool isScopeNoReturn(const Token *endScopeToken, bool *unknown=nullptr) const
Check if inner scope ends with a call to a noreturn function.
Definition: tokenize.cpp:8021
TokenList list
Token list: stores all tokens.
Definition: tokenize.h:590
bool isC() const
Is the code C.
Definition: tokenize.h:64
const SymbolDatabase * getSymbolDatabase() const
Definition: tokenize.h:563
bool isCPP() const
Is the code CPP.
Definition: tokenize.h:69
std::vector< BaseInfo > derivedFrom
enum ValueType::Type type
MathLib::bigint typeSize(const Platform &platform, bool p=false) const
Information about a member variable.
bool isArgument() const
Is variable a function argument.
bool isArrayOrPointer() const
Is array or pointer variable.
bool isLocal() const
Is variable local.
const Type * type() const
Get Type pointer of known type.
const Scope * scope() const
Get Scope pointer of enclosing scope.
const Scope * typeScope() const
Get Scope pointer of known type.
const std::string & name() const
Get name string.
bool isPointerArray() const
Is variable an array of pointers.
const Token * nameToken() const
Get name token.
bool isPrivate() const
Is variable private.
nonneg int declarationId() const
Get declaration ID (varId used for variable in its declaration).
const Token * typeStartToken() const
Get type start token.
bool isPointer() const
Is pointer variable.
bool isStatic() const
Is variable static.
const ValueType * valueType() const
#define nonneg
Definition: config.h:138
Severity
enum class for severity.
Definition: errortypes.h:63
@ warning
Warning.
@ style
Style warning.
@ error
Programming error.
static constexpr char CWE[]
Definition: resultstree.cpp:67