Cppcheck
checknullpointer.cpp
Go to the documentation of this file.
1 /*
2  * Cppcheck - A tool for static C/C++ code analysis
3  * Copyright (C) 2007-2023 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 //---------------------------------------------------------------------------
21 #include "checknullpointer.h"
22 
23 #include "astutils.h"
24 #include "ctu.h"
25 #include "errorlogger.h"
26 #include "errortypes.h"
27 #include "library.h"
28 #include "mathlib.h"
29 #include "settings.h"
30 #include "symboldatabase.h"
31 #include "token.h"
32 #include "tokenize.h"
33 #include "valueflow.h"
34 
35 #include <algorithm>
36 #include <cctype>
37 #include <map>
38 #include <set>
39 #include <vector>
40 
41 //---------------------------------------------------------------------------
42 
43 // CWE ids used:
44 static const CWE CWE_NULL_POINTER_DEREFERENCE(476U);
45 static const CWE CWE_INCORRECT_CALCULATION(682U);
46 
47 // Register this check class (by creating a static instance of it)
48 namespace {
49  CheckNullPointer instance;
50 }
51 
52 //---------------------------------------------------------------------------
53 
54 static bool checkNullpointerFunctionCallPlausibility(const Function* func, unsigned int arg)
55 {
56  return !func || (func->argCount() >= arg && func->getArgumentVar(arg - 1) && func->getArgumentVar(arg - 1)->isPointer());
57 }
58 
59 /**
60  * @brief parse a function call and extract information about variable usage
61  * @param tok first token
62  * @param var variables that the function read / write.
63  * @param library --library files data
64  */
65 void CheckNullPointer::parseFunctionCall(const Token &tok, std::list<const Token *> &var, const Library &library)
66 {
67  if (Token::Match(&tok, "%name% ( )") || !tok.tokAt(2))
68  return;
69 
70  const std::vector<const Token *> args = getArguments(&tok);
71 
72  for (int argnr = 1; argnr <= args.size(); ++argnr) {
73  const Token *param = args[argnr - 1];
74  if (library.isnullargbad(&tok, argnr) && checkNullpointerFunctionCallPlausibility(tok.function(), argnr))
75  var.push_back(param);
76  else if (tok.function()) {
77  const Variable* argVar = tok.function()->getArgumentVar(argnr-1);
78  if (argVar && argVar->isStlStringType() && !argVar->isArrayOrPointer())
79  var.push_back(param);
80  }
81  }
82 
83  if (library.formatstr_function(&tok)) {
84  const int formatStringArgNr = library.formatstr_argno(&tok);
85  if (formatStringArgNr < 0 || formatStringArgNr >= args.size())
86  return;
87 
88  // 1st parameter..
89  if (Token::Match(&tok, "snprintf|vsnprintf|fnprintf|vfnprintf") && args.size() > 1 && !(args[1] && args[1]->hasKnownIntValue() && args[1]->getKnownIntValue() == 0)) // Only if length (second parameter) is not zero
90  var.push_back(args[0]);
91 
92  if (args[formatStringArgNr]->tokType() != Token::eString)
93  return;
94  const std::string &formatString = args[formatStringArgNr]->strValue();
95  int argnr = formatStringArgNr + 1;
96  const bool scan = library.formatstr_scan(&tok);
97 
98  bool percent = false;
99  for (std::string::const_iterator i = formatString.cbegin(); i != formatString.cend(); ++i) {
100  if (*i == '%') {
101  percent = !percent;
102  } else if (percent) {
103  percent = false;
104 
105  bool _continue = false;
106  while (!std::isalpha((unsigned char)*i)) {
107  if (*i == '*') {
108  if (scan)
109  _continue = true;
110  else
111  argnr++;
112  }
113  ++i;
114  if (i == formatString.end())
115  return;
116  }
117  if (_continue)
118  continue;
119 
120  if (argnr < args.size() && (*i == 'n' || *i == 's' || scan))
121  var.push_back(args[argnr]);
122 
123  if (*i != 'm') // %m is a non-standard glibc extension that requires no parameter
124  argnr++;
125  }
126  }
127  }
128 }
129 
130 namespace {
131  const std::set<std::string> stl_stream = {
132  "fstream", "ifstream", "iostream", "istream",
133  "istringstream", "ofstream", "ostream", "ostringstream",
134  "stringstream", "wistringstream", "wostringstream", "wstringstream"
135  };
136 }
137 
138 /**
139  * Is there a pointer dereference? Everything that should result in
140  * a nullpointer dereference error message will result in a true
141  * return value. If it's unknown if the pointer is dereferenced false
142  * is returned.
143  * @param tok token for the pointer
144  * @param unknown it is not known if there is a pointer dereference (could be reported as a debug message)
145  * @return true => there is a dereference
146  */
147 bool CheckNullPointer::isPointerDeRef(const Token *tok, bool &unknown) const
148 {
149  return isPointerDeRef(tok, unknown, *mSettings);
150 }
151 
152 bool CheckNullPointer::isPointerDeRef(const Token *tok, bool &unknown, const Settings &settings)
153 {
154  unknown = false;
155 
156  // Is pointer used as function parameter?
157  if (Token::Match(tok->previous(), "[(,] %name% [,)]")) {
158  const Token *ftok = tok->previous();
159  while (ftok && ftok->str() != "(") {
160  if (ftok->str() == ")")
161  ftok = ftok->link();
162  ftok = ftok->previous();
163  }
164  if (ftok && ftok->previous()) {
165  std::list<const Token *> varlist;
166  parseFunctionCall(*ftok->previous(), varlist, settings.library);
167  if (std::find(varlist.cbegin(), varlist.cend(), tok) != varlist.cend()) {
168  return true;
169  }
170  }
171  }
172 
173  if (tok->str() == "(" && !tok->scope()->isExecutable())
174  return false;
175 
176  const Token* parent = tok->astParent();
177  if (!parent)
178  return false;
179  const bool addressOf = parent->astParent() && parent->astParent()->str() == "&";
180  if (parent->str() == "." && astIsRHS(tok))
181  return isPointerDeRef(parent, unknown, settings);
182  const bool firstOperand = parent->astOperand1() == tok;
183  parent = astParentSkipParens(tok);
184  if (!parent)
185  return false;
186 
187  // Dereferencing pointer..
188  const Token* grandParent = parent->astParent();
189  if (parent->isUnaryOp("*") && !(grandParent && isUnevaluated(grandParent->previous()))) {
190  // declaration of function pointer
191  if (tok->variable() && tok->variable()->nameToken() == tok)
192  return false;
193  if (!addressOf)
194  return true;
195  }
196 
197  // array access
198  if (firstOperand && parent->str() == "[" && !addressOf)
199  return true;
200 
201  // address of member variable / array element
202  const Token *parent2 = parent;
203  while (Token::Match(parent2, "[|."))
204  parent2 = parent2->astParent();
205  if (parent2 != parent && parent2 && parent2->isUnaryOp("&"))
206  return false;
207 
208  // read/write member variable
209  if (firstOperand && parent->originalName() == "->" && !addressOf)
210  return true;
211 
212  // If its a function pointer then check if its called
213  if (tok->variable() && tok->variable()->isPointer() && Token::Match(tok->variable()->nameToken(), "%name% ) (") &&
214  Token::Match(tok, "%name% ("))
215  return true;
216 
217  if (Token::Match(tok, "%var% = %var% .") &&
218  tok->varId() == tok->tokAt(2)->varId())
219  return true;
220 
221  // std::string dereferences nullpointers
222  if (Token::Match(parent->tokAt(-3), "std :: string|wstring (|{ %name% )|}"))
223  return true;
224  if (Token::Match(parent->previous(), "%name% (|{ %name% )|}")) {
225  const Variable* var = tok->tokAt(-2)->variable();
226  if (var && !var->isPointer() && !var->isArray() && var->isStlStringType())
227  return true;
228  }
229 
230  // streams dereference nullpointers
231  if (Token::Match(parent, "<<|>>") && !firstOperand) {
232  const Variable* var = tok->variable();
233  if (var && var->isPointer() && Token::Match(var->typeStartToken(), "char|wchar_t")) { // Only outputting or reading to char* can cause problems
234  const Token* tok2 = parent; // Find start of statement
235  for (; tok2; tok2 = tok2->previous()) {
236  if (Token::Match(tok2->previous(), ";|{|}|:"))
237  break;
238  }
239  if (Token::Match(tok2, "std :: cout|cin|cerr"))
240  return true;
241  if (tok2 && tok2->varId() != 0) {
242  const Variable* var2 = tok2->variable();
243  if (var2 && var2->isStlType(stl_stream))
244  return true;
245  }
246  }
247  }
248 
249  const Variable *ovar = nullptr;
250  if (Token::Match(parent, "+|==|!=") || (parent->str() == "=" && !firstOperand)) {
251  if (parent->astOperand1() == tok && parent->astOperand2())
252  ovar = parent->astOperand2()->variable();
253  else if (parent->astOperand1() && parent->astOperand2() == tok)
254  ovar = parent->astOperand1()->variable();
255  }
256  if (ovar && !ovar->isPointer() && !ovar->isArray() && ovar->isStlStringType())
257  return true;
258 
259  // assume that it's not a dereference (no false positives)
260  return false;
261 }
262 
263 
264 static bool isNullablePointer(const Token* tok)
265 {
266  if (!tok)
267  return false;
268  if (Token::simpleMatch(tok, "new") && tok->varId() == 0)
269  return false;
270  if (astIsPointer(tok))
271  return true;
272  if (astIsSmartPointer(tok))
273  return true;
274  if (Token::simpleMatch(tok, "."))
275  return isNullablePointer(tok->astOperand2());
276  if (const Variable* var = tok->variable()) {
277  return (var->isPointer() || var->isSmartPointer());
278  }
279  return false;
280 }
281 
283 {
284  const bool printInconclusive = (mSettings->certainty.isEnabled(Certainty::inconclusive));
285 
286  for (const Token *tok = mTokenizer->tokens(); tok; tok = tok->next()) {
287  if (isUnevaluated(tok)) {
288  tok = tok->next()->link();
289  continue;
290  }
291 
292  if (Token::Match(tok, "%num%|%char%|%str%"))
293  continue;
294 
295  if (!isNullablePointer(tok) ||
296  (tok->str() == "." && isNullablePointer(tok->astOperand2()) && tok->astOperand2()->getValue(0))) // avoid duplicate warning
297  continue;
298 
299  // Can pointer be NULL?
300  const ValueFlow::Value *value = tok->getValue(0);
301  if (!value)
302  continue;
303 
304  if (!printInconclusive && value->isInconclusive())
305  continue;
306 
307  // Pointer dereference.
308  bool unknown = false;
309  if (!isPointerDeRef(tok,unknown)) {
310  if (unknown)
311  nullPointerError(tok, tok->expressionString(), value, true);
312  continue;
313  }
314 
315  nullPointerError(tok, tok->expressionString(), value, value->isInconclusive());
316  }
317 }
318 
320 {
321  logChecker("CheckNullPointer::nullPointer");
323 }
324 
325 namespace {
326  const std::set<std::string> stl_istream = {
327  "fstream", "ifstream", "iostream", "istream",
328  "istringstream", "stringstream", "wistringstream", "wstringstream"
329  };
330 }
331 
332 /** Dereferencing null constant (simplified token list) */
334 {
335  logChecker("CheckNullPointer::nullConstantDereference");
336 
337  const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
338 
339  for (const Scope * scope : symbolDatabase->functionScopes) {
340  if (scope->function == nullptr || !scope->function->hasBody()) // We only look for functions with a body
341  continue;
342 
343  const Token *tok = scope->bodyStart;
344 
345  if (scope->function->isConstructor())
346  tok = scope->function->token; // Check initialization list
347 
348  for (; tok != scope->bodyEnd; tok = tok->next()) {
349  if (isUnevaluated(tok))
350  tok = tok->next()->link();
351 
352  else if (Token::simpleMatch(tok, "* 0")) {
353  if (Token::Match(tok->previous(), "return|throw|;|{|}|:|[|(|,") || tok->previous()->isOp()) {
354  nullPointerError(tok);
355  }
356  }
357 
358  else if (Token::Match(tok, "0 [") && (tok->previous()->str() != "&" || !Token::Match(tok->next()->link()->next(), "[.(]")))
359  nullPointerError(tok);
360 
361  else if (Token::Match(tok->previous(), "!!. %name% (|{") && (tok->previous()->str() != "::" || tok->strAt(-2) == "std")) {
362  if (Token::Match(tok->tokAt(2), "0|NULL|nullptr )|}") && tok->varId()) { // constructor call
363  const Variable *var = tok->variable();
364  if (var && !var->isPointer() && !var->isArray() && var->isStlStringType())
365  nullPointerError(tok);
366  } else { // function call
367  std::list<const Token *> var;
368  parseFunctionCall(*tok, var, mSettings->library);
369 
370  // is one of the var items a NULL pointer?
371  for (const Token *vartok : var) {
372  if (vartok->hasKnownIntValue() && vartok->getKnownIntValue() == 0)
373  nullPointerError(vartok);
374  }
375  }
376  } else if (Token::Match(tok, "std :: string|wstring ( 0|NULL|nullptr )"))
377  nullPointerError(tok);
378 
379  else if (Token::Match(tok->previous(), "::|. %name% (")) {
380  const std::vector<const Token *> &args = getArguments(tok);
381  for (int argnr = 0; argnr < args.size(); ++argnr) {
382  const Token *argtok = args[argnr];
383  if (!argtok->hasKnownIntValue())
384  continue;
385  if (argtok->values().front().intvalue != 0)
386  continue;
387  if (mSettings->library.isnullargbad(tok, argnr+1))
388  nullPointerError(argtok);
389  }
390  }
391 
392  else if (Token::Match(tok->previous(), ">> 0|NULL|nullptr")) { // Only checking input stream operations is safe here, because otherwise 0 can be an integer as well
393  const Token* tok2 = tok->previous(); // Find start of statement
394  for (; tok2; tok2 = tok2->previous()) {
395  if (Token::Match(tok2->previous(), ";|{|}|:|("))
396  break;
397  }
398  if (tok2 && tok2->previous() && tok2->previous()->str()=="(")
399  continue;
400  if (Token::simpleMatch(tok2, "std :: cin"))
401  nullPointerError(tok);
402  if (tok2 && tok2->varId() != 0) {
403  const Variable *var = tok2->variable();
404  if (var && var->isStlType(stl_istream))
405  nullPointerError(tok);
406  }
407  }
408 
409  const Variable *ovar = nullptr;
410  const Token *tokNull = nullptr;
411  if (Token::Match(tok, "0|NULL|nullptr ==|!=|>|>=|<|<= %var%")) {
412  if (!Token::Match(tok->tokAt(3),".|[")) {
413  ovar = tok->tokAt(2)->variable();
414  tokNull = tok;
415  }
416  } else if (Token::Match(tok, "%var% ==|!=|>|>=|<|<= 0|NULL|nullptr") ||
417  Token::Match(tok, "%var% =|+ 0|NULL|nullptr )|]|,|;|+")) {
418  ovar = tok->variable();
419  tokNull = tok->tokAt(2);
420  }
421  if (ovar && !ovar->isPointer() && !ovar->isArray() && ovar->isStlStringType() && tokNull && tokNull->originalName() != "'\\0'")
422  nullPointerError(tokNull);
423  }
424  }
425 }
426 
427 void CheckNullPointer::nullPointerError(const Token *tok, const std::string &varname, const ValueFlow::Value *value, bool inconclusive)
428 {
429  const std::string errmsgcond("$symbol:" + varname + '\n' + ValueFlow::eitherTheConditionIsRedundant(value ? value->condition : nullptr) + " or there is possible null pointer dereference: $symbol.");
430  const std::string errmsgdefarg("$symbol:" + varname + "\nPossible null pointer dereference if the default parameter value is used: $symbol");
431 
432  if (!tok) {
433  reportError(tok, Severity::error, "nullPointer", "Null pointer dereference", CWE_NULL_POINTER_DEREFERENCE, Certainty::normal);
434  reportError(tok, Severity::warning, "nullPointerDefaultArg", errmsgdefarg, CWE_NULL_POINTER_DEREFERENCE, Certainty::normal);
435  reportError(tok, Severity::warning, "nullPointerRedundantCheck", errmsgcond, CWE_NULL_POINTER_DEREFERENCE, Certainty::normal);
436  return;
437  }
438 
439  if (!value) {
441  return;
442  }
443 
444  if (!mSettings->isEnabled(value, inconclusive))
445  return;
446 
447  const ErrorPath errorPath = getErrorPath(tok, value, "Null pointer dereference");
448 
449  if (value->condition) {
450  reportError(errorPath, Severity::warning, "nullPointerRedundantCheck", errmsgcond, CWE_NULL_POINTER_DEREFERENCE, inconclusive || value->isInconclusive() ? Certainty::inconclusive : Certainty::normal);
451  } else if (value->defaultArg) {
452  reportError(errorPath, Severity::warning, "nullPointerDefaultArg", errmsgdefarg, CWE_NULL_POINTER_DEREFERENCE, inconclusive || value->isInconclusive() ? Certainty::inconclusive : Certainty::normal);
453  } else {
454  std::string errmsg = std::string(value->isKnown() ? "Null" : "Possible null") + " pointer dereference";
455  if (!varname.empty())
456  errmsg = "$symbol:" + varname + '\n' + errmsg + ": $symbol";
457 
458  reportError(errorPath,
460  "nullPointer",
461  errmsg,
463  }
464 }
465 
467 {
468  logChecker("CheckNullPointer::arithmetic");
469  const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
470  for (const Scope * scope : symbolDatabase->functionScopes) {
471  for (const Token* tok = scope->bodyStart->next(); tok != scope->bodyEnd; tok = tok->next()) {
472  if (!Token::Match(tok, "-|+|+=|-=|++|--"))
473  continue;
474  const Token *pointerOperand;
475  const Token *numericOperand;
476  if (tok->astOperand1() && tok->astOperand1()->valueType() && tok->astOperand1()->valueType()->pointer != 0) {
477  pointerOperand = tok->astOperand1();
478  numericOperand = tok->astOperand2();
479  } else if (tok->astOperand2() && tok->astOperand2()->valueType() && tok->astOperand2()->valueType()->pointer != 0) {
480  pointerOperand = tok->astOperand2();
481  numericOperand = tok->astOperand1();
482  } else
483  continue;
484  if (numericOperand && numericOperand->valueType() && !numericOperand->valueType()->isIntegral())
485  continue;
486  const ValueFlow::Value* numValue = numericOperand ? numericOperand->getValue(0) : nullptr;
487  if (numValue && numValue->intvalue == 0) // don't warn for arithmetic with 0
488  continue;
489  const ValueFlow::Value* value = pointerOperand->getValue(0);
490  if (!value)
491  continue;
493  continue;
495  continue;
496  if (value->condition)
497  redundantConditionWarning(tok, value, value->condition, value->isInconclusive());
498  else
499  pointerArithmeticError(tok, value, value->isInconclusive());
500  }
501  }
502 }
503 
504 static std::string arithmeticTypeString(const Token *tok)
505 {
506  if (tok && tok->str()[0] == '-')
507  return "subtraction";
508  if (tok && tok->str()[0] == '+')
509  return "addition";
510  return "arithmetic";
511 }
512 
513 void CheckNullPointer::pointerArithmeticError(const Token* tok, const ValueFlow::Value *value, bool inconclusive)
514 {
515  // cppcheck-suppress shadowFunction - TODO: fix this
516  std::string arithmetic = arithmeticTypeString(tok);
517  std::string errmsg;
518  if (tok && tok->str()[0] == '-') {
519  errmsg = "Overflow in pointer arithmetic, NULL pointer is subtracted.";
520  } else {
521  errmsg = "Pointer " + arithmetic + " with NULL pointer.";
522  }
523  const ErrorPath errorPath = getErrorPath(tok, value, "Null pointer " + arithmetic);
524  reportError(errorPath,
526  "nullPointerArithmetic",
527  errmsg,
530 }
531 
532 void CheckNullPointer::redundantConditionWarning(const Token* tok, const ValueFlow::Value *value, const Token *condition, bool inconclusive)
533 {
534  // cppcheck-suppress shadowFunction - TODO: fix this
535  std::string arithmetic = arithmeticTypeString(tok);
536  std::string errmsg;
537  if (tok && tok->str()[0] == '-') {
538  errmsg = ValueFlow::eitherTheConditionIsRedundant(condition) + " or there is overflow in pointer " + arithmetic + ".";
539  } else {
540  errmsg = ValueFlow::eitherTheConditionIsRedundant(condition) + " or there is pointer arithmetic with NULL pointer.";
541  }
542  const ErrorPath errorPath = getErrorPath(tok, value, "Null pointer " + arithmetic);
543  reportError(errorPath,
545  "nullPointerArithmeticRedundantCheck",
546  errmsg,
549 }
550 
551 // NOLINTNEXTLINE(readability-non-const-parameter) - used as callback so we need to preserve the signature
552 static bool isUnsafeUsage(const Settings &settings, const Token *vartok, MathLib::bigint *value)
553 {
554  (void)value;
555  bool unknown = false;
556  return CheckNullPointer::isPointerDeRef(vartok, unknown, settings);
557 }
558 
559 // a Clang-built executable will crash when using the anonymous MyFileInfo later on - so put it in a unique namespace for now
560 // see https://trac.cppcheck.net/ticket/12108 for more details
561 #ifdef __clang__
562 inline namespace CheckNullPointer_internal
563 #else
564 namespace
565 #endif
566 {
567  /* data for multifile checking */
568  class MyFileInfo : public Check::FileInfo {
569  public:
570  /** function arguments that are dereferenced without checking if they are null */
571  std::list<CTU::FileInfo::UnsafeUsage> unsafeUsage;
572 
573  /** Convert data into xml string */
574  std::string toString() const override
575  {
576  return CTU::toString(unsafeUsage);
577  }
578  };
579 }
580 
581 Check::FileInfo *CheckNullPointer::getFileInfo(const Tokenizer &tokenizer, const Settings &settings) const
582 {
583  const std::list<CTU::FileInfo::UnsafeUsage> &unsafeUsage = CTU::getUnsafeUsage(tokenizer, settings, isUnsafeUsage);
584  if (unsafeUsage.empty())
585  return nullptr;
586 
587  auto *fileInfo = new MyFileInfo;
588  fileInfo->unsafeUsage = unsafeUsage;
589  return fileInfo;
590 }
591 
592 Check::FileInfo * CheckNullPointer::loadFileInfoFromXml(const tinyxml2::XMLElement *xmlElement) const
593 {
594  const std::list<CTU::FileInfo::UnsafeUsage> &unsafeUsage = CTU::loadUnsafeUsageListFromXml(xmlElement);
595  if (unsafeUsage.empty())
596  return nullptr;
597 
598  auto *fileInfo = new MyFileInfo;
599  fileInfo->unsafeUsage = unsafeUsage;
600  return fileInfo;
601 }
602 
603 bool CheckNullPointer::analyseWholeProgram(const CTU::FileInfo *ctu, const std::list<Check::FileInfo*> &fileInfo, const Settings& settings, ErrorLogger &errorLogger)
604 {
605  if (!ctu)
606  return false;
607  bool foundErrors = false;
608  (void)settings; // This argument is unused
609 
610  CheckNullPointer dummy(nullptr, &settings, &errorLogger);
611  dummy.
612  logChecker("CheckNullPointer::analyseWholeProgram"); // unusedfunctions
613 
614  const std::map<std::string, std::list<const CTU::FileInfo::CallBase *>> callsMap = ctu->getCallsMap();
615 
616  for (const Check::FileInfo* fi1 : fileInfo) {
617  const MyFileInfo *fi = dynamic_cast<const MyFileInfo*>(fi1);
618  if (!fi)
619  continue;
620  for (const CTU::FileInfo::UnsafeUsage &unsafeUsage : fi->unsafeUsage) {
621  for (int warning = 0; warning <= 1; warning++) {
622  if (warning == 1 && !settings.severity.isEnabled(Severity::warning))
623  break;
624 
625  const std::list<ErrorMessage::FileLocation> &locationList =
627  unsafeUsage,
628  callsMap,
629  "Dereferencing argument ARG that is null",
630  nullptr,
631  warning);
632  if (locationList.empty())
633  continue;
634 
635  const ErrorMessage errmsg(locationList,
636  emptyString,
638  "Null pointer dereference: " + unsafeUsage.myArgumentName,
639  "ctunullpointer",
641  errorLogger.reportErr(errmsg);
642 
643  foundErrors = true;
644  break;
645  }
646  }
647  }
648 
649  return foundErrors;
650 }
std::vector< const Token * > getArguments(const Token *ftok)
Get arguments (AST)
Definition: astutils.cpp:3074
bool astIsPointer(const Token *tok)
Definition: astutils.cpp:220
bool astIsSmartPointer(const Token *tok)
Definition: astutils.cpp:225
const Token * astParentSkipParens(const Token *tok)
Definition: astutils.cpp:557
bool astIsRHS(const Token *tok)
Definition: astutils.cpp:792
bool isUnevaluated(const Token *tok)
Definition: astutils.cpp:3587
static bool isNullablePointer(const Token *tok)
static const CWE CWE_NULL_POINTER_DEREFERENCE(476U)
static bool checkNullpointerFunctionCallPlausibility(const Function *func, unsigned int arg)
static const CWE CWE_INCORRECT_CALCULATION(682U)
static std::string arithmeticTypeString(const Token *tok)
static bool isUnsafeUsage(const Settings &settings, const Token *vartok, MathLib::bigint *value)
static std::list< ErrorMessage::FileLocation > getErrorPath(InvalidValueType invalidValue, const UnsafeUsage &unsafeUsage, const std::map< std::string, std::list< const CallBase * >> &callsMap, const char info[], const FunctionCall **const functionCallPtr, bool warning)
Definition: ctu.cpp:554
std::map< std::string, std::list< const CallBase * > > getCallsMap() const
Definition: ctu.cpp:247
check for null pointer dereferencing
static void parseFunctionCall(const Token &tok, std::list< const Token * > &var, const Library &library)
parse a function call and extract information about variable usage
void nullPointerByDeRefAndChec()
Does one part of the check for nullPointer().
Check::FileInfo * loadFileInfoFromXml(const tinyxml2::XMLElement *xmlElement) const override
void nullPointer()
possible null pointer dereference
void pointerArithmeticError(const Token *tok, const ValueFlow::Value *value, bool inconclusive)
Check::FileInfo * getFileInfo(const Tokenizer &tokenizer, const Settings &settings) const override
Parse current TU and extract file info.
void redundantConditionWarning(const Token *tok, const ValueFlow::Value *value, const Token *condition, bool inconclusive)
void arithmetic()
undefined null pointer arithmetic
void nullConstantDereference()
dereferencing null constant (after Tokenizer::simplifyKnownVariables)
void nullPointerError(const Token *tok)
bool analyseWholeProgram(const CTU::FileInfo *ctu, const std::list< Check::FileInfo * > &fileInfo, const Settings &settings, ErrorLogger &errorLogger) override
Analyse all file infos for all TU.
bool isPointerDeRef(const Token *tok, bool &unknown) const
Is there a pointer dereference? Everything that should result in a nullpointer dereference error mess...
Base class used for whole-program analysis.
Definition: check.h:103
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
ErrorPath getErrorPath(const Token *errtok, const ValueFlow::Value *value, std::string bug) const
Definition: check.cpp:111
const Tokenizer *const mTokenizer
Definition: check.h:133
void logChecker(const char id[])
log checker
Definition: check.cpp:129
This is an interface, which the class responsible of error logging should implement.
Definition: errorlogger.h:214
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
bool hasBody() const
const Variable * getArgumentVar(nonneg int num) const
nonneg int argCount() const
const Token * token
function name token in implementation
bool isConstructor() const
Library definitions handling.
Definition: library.h:52
bool isnullargbad(const Token *ftok, int argnr) const
Definition: library.cpp:1046
bool formatstr_function(const Token *ftok) const
Definition: library.cpp:1361
int formatstr_argno(const Token *ftok) const
Definition: library.cpp:1372
bool formatstr_scan(const Token *ftok) const
Definition: library.cpp:1381
long long bigint
Definition: mathlib.h:68
Function * function
function info for this function
const Token * bodyStart
'{' token
const Token * bodyEnd
'}' token
This is just a container for general settings so that we don't need to pass individual values to func...
Definition: settings.h:95
bool isEnabled(const ValueFlow::Value *value, bool inconclusiveCheck=false) const
Returns true if given value can be shown.
Definition: settings.cpp:257
Library library
Library.
Definition: settings.h:237
SimpleEnableGroup< Certainty > certainty
Definition: settings.h:356
SimpleEnableGroup< Severity > severity
Definition: settings.h:355
bool isEnabled(T flag) const
Definition: settings.h:66
std::vector< const Scope * > functionScopes
Fast access to function 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
const ValueFlow::Value * getValue(const MathLib::bigint val) const
Definition: token.cpp:2596
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:722
const std::string & originalName() const
Definition: token.h:1193
bool hasKnownIntValue() const
Definition: token.cpp:2553
const ValueType * valueType() const
Definition: token.h:331
const std::string & strAt(int index) const
Definition: token.cpp:457
void astOperand1(Token *tok)
Definition: token.cpp:1490
void function(const Function *f)
Associate this token with given function.
Definition: token.cpp:1127
nonneg int varId() const
Definition: token.h:870
bool isUnaryOp(const std::string &s) const
Definition: token.h:413
bool isOp() const
Definition: token.h:380
const Token * tokAt(int index) const
Definition: token.cpp:427
void astOperand2(Token *tok)
Definition: token.cpp:1502
void scope(const Scope *s)
Associate this token with given scope.
Definition: token.h:1042
void link(Token *linkToToken)
Create link to given token.
Definition: token.h:1015
@ eString
Definition: token.h:162
Token * previous()
Definition: token.h:862
void variable(const Variable *v)
Associate this token with given variable.
Definition: token.h:1070
Token * next()
Definition: token.h:830
const std::list< ValueFlow::Value > & values() const
Definition: token.h:1197
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:1471
The main purpose is to tokenize the source code.
Definition: tokenize.h:46
const Token * tokens() const
Definition: tokenize.h:592
const SymbolDatabase * getSymbolDatabase() const
Definition: tokenize.h:563
bool defaultArg
Is this value passed as default parameter to the function?
Definition: vfvalue.h:299
bool isKnown() const
Definition: vfvalue.h:353
const Token * condition
Condition that this value depends on.
Definition: vfvalue.h:280
long long intvalue
int value (or sometimes bool value?)
Definition: vfvalue.h:268
bool isInconclusive() const
Definition: vfvalue.h:378
bool isIntegral() const
Information about a member variable.
bool isArrayOrPointer() const
Is array or pointer variable.
bool isStlType() const
Checks if the variable is an STL type ('std::') E.g.
bool isArray() const
Is variable an array.
const Token * typeStartToken() const
Get type start token.
bool isPointer() const
Is pointer variable.
bool isStlStringType() const
Checks if the variable is an STL type ('std::') E.g.
std::string toString(Color c)
Definition: color.cpp:54
static const std::string emptyString
Definition: config.h:127
std::list< ErrorPathItem > ErrorPath
Definition: errortypes.h:130
@ warning
Warning.
@ error
Programming error.
CPPCHECKLIB std::list< FileInfo::UnsafeUsage > getUnsafeUsage(const Tokenizer &tokenizer, const Settings &settings, bool(*isUnsafeUsage)(const Settings &settings, const Token *argtok, MathLib::bigint *value))
Definition: ctu.cpp:472
CPPCHECKLIB std::string toString(const std::list< FileInfo::UnsafeUsage > &unsafeUsage)
Definition: ctu.cpp:151
CPPCHECKLIB std::list< FileInfo::UnsafeUsage > loadUnsafeUsageListFromXml(const tinyxml2::XMLElement *xmlElement)
Definition: ctu.cpp:257
std::string eitherTheConditionIsRedundant(const Token *condition)
Definition: valueflow.cpp:9657
std::string myArgumentName
Definition: ctu.h:72