Cppcheck
ctu.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 //---------------------------------------------------------------------------
21 #include "ctu.h"
22 
23 #include "astutils.h"
24 #include "errortypes.h"
25 #include "settings.h"
26 #include "symboldatabase.h"
27 #include "token.h"
28 #include "tokenize.h"
29 #include "tokenlist.h"
30 #include "utils.h"
31 
32 #include <algorithm>
33 #include <cstdint>
34 #include <cstring>
35 #include <iterator> // back_inserter
36 #include <sstream>
37 #include <utility>
38 
39 #include "xml.h"
40 //---------------------------------------------------------------------------
41 
42 static constexpr char ATTR_CALL_ID[] = "call-id";
43 static constexpr char ATTR_CALL_FUNCNAME[] = "call-funcname";
44 static constexpr char ATTR_CALL_ARGNR[] = "call-argnr";
45 static constexpr char ATTR_CALL_ARGEXPR[] = "call-argexpr";
46 static constexpr char ATTR_CALL_ARGVALUETYPE[] = "call-argvaluetype";
47 static constexpr char ATTR_CALL_ARGVALUE[] = "call-argvalue";
48 static constexpr char ATTR_WARNING[] = "warning";
49 static constexpr char ATTR_LOC_FILENAME[] = "file";
50 static constexpr char ATTR_LOC_LINENR[] = "line";
51 static constexpr char ATTR_LOC_COLUMN[] = "col";
52 static constexpr char ATTR_INFO[] = "info";
53 static constexpr char ATTR_MY_ID[] = "my-id";
54 static constexpr char ATTR_MY_ARGNR[] = "my-argnr";
55 static constexpr char ATTR_MY_ARGNAME[] = "my-argname";
56 static constexpr char ATTR_VALUE[] = "value";
57 
59 
60 std::string CTU::getFunctionId(const Tokenizer &tokenizer, const Function *function)
61 {
62  return tokenizer.list.file(function->tokenDef) + ':' + std::to_string(function->tokenDef->linenr()) + ':' + std::to_string(function->tokenDef->column());
63 }
64 
65 CTU::FileInfo::Location::Location(const Tokenizer &tokenizer, const Token *tok)
66  : fileName(tokenizer.list.file(tok))
67  , lineNumber(tok->linenr())
68  , column(tok->column())
69 {}
70 
71 std::string CTU::FileInfo::toString() const
72 {
73  std::ostringstream out;
74 
75  // Function calls..
76  for (const CTU::FileInfo::FunctionCall &functionCall : functionCalls) {
77  out << functionCall.toXmlString();
78  }
79 
80  // Nested calls..
81  for (const CTU::FileInfo::NestedCall &nestedCall : nestedCalls) {
82  out << nestedCall.toXmlString() << "\n";
83  }
84 
85  return out.str();
86 }
87 
89 {
90  std::ostringstream out;
91  out << " " << ATTR_CALL_ID << "=\"" << callId << "\""
92  << " " << ATTR_CALL_FUNCNAME << "=\"" << ErrorLogger::toxml(callFunctionName) << "\""
93  << " " << ATTR_CALL_ARGNR << "=\"" << callArgNr << "\""
94  << " " << ATTR_LOC_FILENAME << "=\"" << ErrorLogger::toxml(location.fileName) << "\""
95  << " " << ATTR_LOC_LINENR << "=\"" << location.lineNumber << "\""
96  << " " << ATTR_LOC_COLUMN << "=\"" << location.column << "\"";
97  return out.str();
98 }
99 
101 {
102  std::ostringstream out;
103  out << "<function-call"
104  << toBaseXmlString()
105  << " " << ATTR_CALL_ARGEXPR << "=\"" << ErrorLogger::toxml(callArgumentExpression) << "\""
106  << " " << ATTR_CALL_ARGVALUETYPE << "=\"" << static_cast<int>(callValueType) << "\""
107  << " " << ATTR_CALL_ARGVALUE << "=\"" << callArgValue << "\"";
108  if (warning)
109  out << " " << ATTR_WARNING << "=\"true\"";
110  if (callValuePath.empty())
111  out << "/>";
112  else {
113  out << ">\n";
114  for (const ErrorMessage::FileLocation &loc : callValuePath)
115  out << " <path"
116  << " " << ATTR_LOC_FILENAME << "=\"" << ErrorLogger::toxml(loc.getfile()) << "\""
117  << " " << ATTR_LOC_LINENR << "=\"" << loc.line << "\""
118  << " " << ATTR_LOC_COLUMN << "=\"" << loc.column << "\""
119  << " " << ATTR_INFO << "=\"" << ErrorLogger::toxml(loc.getinfo()) << "\"/>\n";
120  out << "</function-call>";
121  }
122  return out.str();
123 }
124 
126 {
127  std::ostringstream out;
128  out << "<function-call"
129  << toBaseXmlString()
130  << " " << ATTR_MY_ID << "=\"" << myId << "\""
131  << " " << ATTR_MY_ARGNR << "=\"" << myArgNr << "\""
132  << "/>";
133  return out.str();
134 }
135 
137 {
138  std::ostringstream out;
139  out << " <unsafe-usage"
140  << " " << ATTR_MY_ID << "=\"" << myId << '\"'
141  << " " << ATTR_MY_ARGNR << "=\"" << myArgNr << '\"'
142  << " " << ATTR_MY_ARGNAME << "=\"" << myArgumentName << '\"'
143  << " " << ATTR_LOC_FILENAME << "=\"" << ErrorLogger::toxml(location.fileName) << '\"'
144  << " " << ATTR_LOC_LINENR << "=\"" << location.lineNumber << '\"'
145  << " " << ATTR_LOC_COLUMN << "=\"" << location.column << '\"'
146  << " " << ATTR_VALUE << "=\"" << value << "\""
147  << "/>\n";
148  return out.str();
149 }
150 
151 std::string CTU::toString(const std::list<CTU::FileInfo::UnsafeUsage> &unsafeUsage)
152 {
153  std::ostringstream ret;
154  for (const CTU::FileInfo::UnsafeUsage &u : unsafeUsage)
155  ret << u.toString();
156  return ret.str();
157 }
158 
159 CTU::FileInfo::CallBase::CallBase(const Tokenizer &tokenizer, const Token *callToken)
160  : callId(getFunctionId(tokenizer, callToken->function()))
161  , callFunctionName(callToken->next()->astOperand1()->expressionString())
162  , location(CTU::FileInfo::Location(tokenizer, callToken))
163 {}
164 
165 CTU::FileInfo::NestedCall::NestedCall(const Tokenizer &tokenizer, const Function *myFunction, const Token *callToken)
166  : CallBase(tokenizer, callToken)
167  , myId(getFunctionId(tokenizer, myFunction))
168 {}
169 
170 static std::string readAttrString(const tinyxml2::XMLElement *e, const char *attr, bool *error)
171 {
172  const char *value = e->Attribute(attr);
173  if (!value && error)
174  *error = true;
175  return value ? value : "";
176 }
177 
178 static long long readAttrInt(const tinyxml2::XMLElement *e, const char *attr, bool *error)
179 {
180  int64_t value = 0;
181  const bool err = (e->QueryInt64Attribute(attr, &value) != tinyxml2::XML_SUCCESS);
182  if (error)
183  *error = err;
184  return value;
185 }
186 
187 bool CTU::FileInfo::CallBase::loadBaseFromXml(const tinyxml2::XMLElement *xmlElement)
188 {
189  bool error = false;
190  callId = readAttrString(xmlElement, ATTR_CALL_ID, &error);
191  callFunctionName = readAttrString(xmlElement, ATTR_CALL_FUNCNAME, &error);
192  callArgNr = readAttrInt(xmlElement, ATTR_CALL_ARGNR, &error);
193  location.fileName = readAttrString(xmlElement, ATTR_LOC_FILENAME, &error);
194  location.lineNumber = readAttrInt(xmlElement, ATTR_LOC_LINENR, &error);
195  location.column = readAttrInt(xmlElement, ATTR_LOC_COLUMN, &error);
196  return !error;
197 }
198 
199 bool CTU::FileInfo::FunctionCall::loadFromXml(const tinyxml2::XMLElement *xmlElement)
200 {
201  if (!loadBaseFromXml(xmlElement))
202  return false;
203  bool error=false;
204  callArgumentExpression = readAttrString(xmlElement, ATTR_CALL_ARGEXPR, &error);
206  callArgValue = readAttrInt(xmlElement, ATTR_CALL_ARGVALUE, &error);
207  const char *w = xmlElement->Attribute(ATTR_WARNING);
208  warning = w && std::strcmp(w, "true") == 0;
209  for (const tinyxml2::XMLElement *e2 = xmlElement->FirstChildElement(); !error && e2; e2 = e2->NextSiblingElement()) {
210  if (std::strcmp(e2->Name(), "path") != 0)
211  continue;
212  std::string file = readAttrString(e2, ATTR_LOC_FILENAME, &error);
213  std::string info = readAttrString(e2, ATTR_INFO, &error);
214  const int line = readAttrInt(e2, ATTR_LOC_LINENR, &error);
215  const int column = readAttrInt(e2, ATTR_LOC_COLUMN, &error);
216  ErrorMessage::FileLocation loc(file, std::move(info), line, column);
217  (void)loc; // TODO: loc is unused
218  }
219  return !error;
220 }
221 
222 bool CTU::FileInfo::NestedCall::loadFromXml(const tinyxml2::XMLElement *xmlElement)
223 {
224  if (!loadBaseFromXml(xmlElement))
225  return false;
226  bool error = false;
227  myId = readAttrString(xmlElement, ATTR_MY_ID, &error);
228  myArgNr = readAttrInt(xmlElement, ATTR_MY_ARGNR, &error);
229  return !error;
230 }
231 
232 void CTU::FileInfo::loadFromXml(const tinyxml2::XMLElement *xmlElement)
233 {
234  for (const tinyxml2::XMLElement *e = xmlElement->FirstChildElement(); e; e = e->NextSiblingElement()) {
235  if (std::strcmp(e->Name(), "function-call") == 0) {
236  FunctionCall functionCall;
237  if (functionCall.loadFromXml(e))
238  functionCalls.push_back(std::move(functionCall));
239  } else if (std::strcmp(e->Name(), "nested-call") == 0) {
240  NestedCall nestedCall;
241  if (nestedCall.loadFromXml(e))
242  nestedCalls.push_back(std::move(nestedCall));
243  }
244  }
245 }
246 
247 std::map<std::string, std::list<const CTU::FileInfo::CallBase *>> CTU::FileInfo::getCallsMap() const
248 {
249  std::map<std::string, std::list<const CTU::FileInfo::CallBase *>> ret;
250  for (const CTU::FileInfo::NestedCall &nc : nestedCalls)
251  ret[nc.callId].push_back(&nc);
253  ret[fc.callId].push_back(&fc);
254  return ret;
255 }
256 
257 std::list<CTU::FileInfo::UnsafeUsage> CTU::loadUnsafeUsageListFromXml(const tinyxml2::XMLElement *xmlElement)
258 {
259  std::list<CTU::FileInfo::UnsafeUsage> ret;
260  for (const tinyxml2::XMLElement *e = xmlElement->FirstChildElement(); e; e = e->NextSiblingElement()) {
261  if (std::strcmp(e->Name(), "unsafe-usage") != 0)
262  continue;
263  bool error = false;
264  FileInfo::UnsafeUsage unsafeUsage;
265  unsafeUsage.myId = readAttrString(e, ATTR_MY_ID, &error);
266  unsafeUsage.myArgNr = readAttrInt(e, ATTR_MY_ARGNR, &error);
270  unsafeUsage.location.column = readAttrInt(e, ATTR_LOC_COLUMN, &error);
271  unsafeUsage.value = readAttrInt(e, ATTR_VALUE, &error);
272 
273  if (!error)
274  ret.push_back(std::move(unsafeUsage));
275  }
276  return ret;
277 }
278 
279 static int isCallFunction(const Scope *scope, int argnr, const Token *&tok)
280 {
281  const Variable * const argvar = scope->function->getArgumentVar(argnr);
282  if (!argvar->isPointer())
283  return -1;
284  for (const Token *tok2 = scope->bodyStart; tok2 != scope->bodyEnd; tok2 = tok2->next()) {
285  if (tok2->variable() != argvar)
286  continue;
287  if (!Token::Match(tok2->previous(), "[(,] %var% [,)]"))
288  break;
289  int argnr2 = 1;
290  const Token *prev = tok2;
291  while (prev && prev->str() != "(") {
292  if (Token::Match(prev,"]|)"))
293  prev = prev->link();
294  else if (prev->str() == ",")
295  ++argnr2;
296  prev = prev->previous();
297  }
298  if (!prev || !Token::Match(prev->previous(), "%name% ("))
299  break;
300  if (!prev->astOperand1() || !prev->astOperand1()->function())
301  break;
302  tok = prev->previous();
303  return argnr2;
304  }
305  return -1;
306 }
307 
308 
310 {
311  const SymbolDatabase * const symbolDatabase = tokenizer.getSymbolDatabase();
312 
313  auto *fileInfo = new FileInfo;
314 
315  // Parse all functions in TU
316  for (const Scope &scope : symbolDatabase->scopeList) {
317  if (!scope.isExecutable() || scope.type != Scope::eFunction || !scope.function)
318  continue;
319  const Function *const scopeFunction = scope.function;
320 
321  // source function calls
322  for (const Token *tok = scope.bodyStart; tok != scope.bodyEnd; tok = tok->next()) {
323  if (tok->str() != "(" || !tok->astOperand1() || !tok->astOperand2())
324  continue;
325  const Function* tokFunction = tok->astOperand1()->function();
326  if (!tokFunction)
327  continue;
328  const std::vector<const Token *> args(getArguments(tok->previous()));
329  for (int argnr = 0; argnr < args.size(); ++argnr) {
330  const Token *argtok = args[argnr];
331  if (!argtok)
332  continue;
333  for (const ValueFlow::Value &value : argtok->values()) {
334  if ((!value.isIntValue() || value.intvalue != 0 || value.isInconclusive()) && !value.isBufferSizeValue())
335  continue;
336  // Skip impossible values since they cannot be represented
337  if (value.isImpossible())
338  continue;
339  FileInfo::FunctionCall functionCall;
340  functionCall.callValueType = value.valueType;
341  functionCall.callId = getFunctionId(tokenizer, tokFunction);
342  functionCall.callFunctionName = tok->astOperand1()->expressionString();
343  functionCall.location = FileInfo::Location(tokenizer,tok);
344  functionCall.callArgNr = argnr + 1;
345  functionCall.callArgumentExpression = argtok->expressionString();
346  functionCall.callArgValue = value.intvalue;
347  functionCall.warning = !value.errorSeverity();
348  for (const ErrorPathItem &i : value.errorPath) {
349  const std::string& file = tokenizer.list.file(i.first);
350  const std::string& info = i.second;
351  const int line = i.first->linenr();
352  const int column = i.first->column();
353  ErrorMessage::FileLocation loc(file, info, line, column);
354  functionCall.callValuePath.push_back(std::move(loc));
355  }
356  fileInfo->functionCalls.push_back(std::move(functionCall));
357  }
358  // array
359  if (argtok->variable() && argtok->variable()->isArray() && argtok->variable()->dimensions().size() == 1 && argtok->variable()->dimensionKnown(0)) {
360  FileInfo::FunctionCall functionCall;
362  functionCall.callId = getFunctionId(tokenizer, tokFunction);
363  functionCall.callFunctionName = tok->astOperand1()->expressionString();
364  functionCall.location = FileInfo::Location(tokenizer, tok);
365  functionCall.callArgNr = argnr + 1;
366  functionCall.callArgumentExpression = argtok->expressionString();
367  const auto typeSize = argtok->valueType()->typeSize(tokenizer.getSettings().platform);
368  functionCall.callArgValue = typeSize > 0 ? argtok->variable()->dimension(0) * typeSize : -1;
369  functionCall.warning = false;
370  fileInfo->functionCalls.push_back(std::move(functionCall));
371  }
372  // &var => buffer
373  if (argtok->isUnaryOp("&") && argtok->astOperand1()->variable() && argtok->astOperand1()->valueType() && !argtok->astOperand1()->variable()->isArray()) {
374  FileInfo::FunctionCall functionCall;
376  functionCall.callId = getFunctionId(tokenizer, tokFunction);
377  functionCall.callFunctionName = tok->astOperand1()->expressionString();
378  functionCall.location = FileInfo::Location(tokenizer, tok);
379  functionCall.callArgNr = argnr + 1;
380  functionCall.callArgumentExpression = argtok->expressionString();
381  functionCall.callArgValue = argtok->astOperand1()->valueType()->typeSize(tokenizer.getSettings().platform);
382  functionCall.warning = false;
383  fileInfo->functionCalls.push_back(std::move(functionCall));
384  }
385  // pointer/reference to uninitialized data
386  auto isAddressOfArg = [](const Token* argtok) -> const Token* {
387  if (!argtok->isUnaryOp("&"))
388  return nullptr;
389  argtok = argtok->astOperand1();
390  if (!argtok || !argtok->valueType() || argtok->valueType()->pointer != 0)
391  return nullptr;
392  return argtok;
393  };
394  auto isReferenceArg = [&](const Token* argtok) -> const Token* {
395  const Variable* argvar = tokFunction->getArgumentVar(argnr);
396  if (!argvar || !argvar->valueType() || argvar->valueType()->reference == Reference::None)
397  return nullptr;
398  return argtok;
399  };
400  const Token* addr = isAddressOfArg(argtok);
401  argtok = addr ? addr : isReferenceArg(argtok);
402  if (!argtok || argtok->values().size() != 1U)
403  continue;
404  if (argtok->variable() && argtok->variable()->isClass())
405  continue;
406 
407  const ValueFlow::Value &v = argtok->values().front();
409  FileInfo::FunctionCall functionCall;
411  functionCall.callId = getFunctionId(tokenizer, tokFunction);
412  functionCall.callFunctionName = tok->astOperand1()->expressionString();
413  functionCall.location = FileInfo::Location(tokenizer, tok);
414  functionCall.callArgNr = argnr + 1;
415  functionCall.callArgValue = 0;
416  functionCall.callArgumentExpression = argtok->expressionString();
417  functionCall.warning = false;
418  fileInfo->functionCalls.push_back(std::move(functionCall));
419  continue;
420  }
421  }
422  }
423 
424  // Nested function calls
425  for (int argnr = 0; argnr < scopeFunction->argCount(); ++argnr) {
426  const Token *tok;
427  const int argnr2 = isCallFunction(&scope, argnr, tok);
428  if (argnr2 > 0) {
429  FileInfo::NestedCall nestedCall(tokenizer, scopeFunction, tok);
430  nestedCall.myArgNr = argnr + 1;
431  nestedCall.callArgNr = argnr2;
432  fileInfo->nestedCalls.push_back(std::move(nestedCall));
433  }
434  }
435  }
436 
437  return fileInfo;
438 }
439 
440 static std::list<std::pair<const Token *, MathLib::bigint>> getUnsafeFunction(const Settings &settings, const Scope *scope, int argnr, bool (*isUnsafeUsage)(const Settings &settings, const Token *argtok, MathLib::bigint *value))
441 {
442  std::list<std::pair<const Token *, MathLib::bigint>> ret;
443  const Variable * const argvar = scope->function->getArgumentVar(argnr);
444  if (!argvar->isArrayOrPointer() && !argvar->isReference())
445  return ret;
446  for (const Token *tok2 = scope->bodyStart; tok2 != scope->bodyEnd; tok2 = tok2->next()) {
447  if (Token::Match(tok2, ")|else {")) {
448  tok2 = tok2->linkAt(1);
449  if (Token::findmatch(tok2->link(), "return|throw", tok2))
450  return ret;
451  int indirect = 0;
452  if (argvar->valueType())
453  indirect = argvar->valueType()->pointer;
454  if (isVariableChanged(tok2->link(), tok2, indirect, argvar->declarationId(), false, settings))
455  return ret;
456  }
457  if (Token::Match(tok2, "%oror%|&&|?")) {
458  tok2 = tok2->findExpressionStartEndTokens().second;
459  continue;
460  }
461  if (tok2->variable() != argvar)
462  continue;
463  MathLib::bigint value = 0;
464  if (!isUnsafeUsage(settings, tok2, &value))
465  return ret; // TODO: Is this a read? then continue..
466  ret.emplace_back(tok2, value);
467  return ret;
468  }
469  return ret;
470 }
471 
472 std::list<CTU::FileInfo::UnsafeUsage> CTU::getUnsafeUsage(const Tokenizer &tokenizer, const Settings &settings, bool (*isUnsafeUsage)(const Settings &settings, const Token *argtok, MathLib::bigint *value))
473 {
474  std::list<CTU::FileInfo::UnsafeUsage> unsafeUsage;
475 
476  // Parse all functions in TU
477  const SymbolDatabase * const symbolDatabase = tokenizer.getSymbolDatabase();
478 
479  for (const Scope &scope : symbolDatabase->scopeList) {
480  if (!scope.isExecutable() || scope.type != Scope::eFunction || !scope.function)
481  continue;
482  const Function *const function = scope.function;
483 
484  // "Unsafe" functions unconditionally reads data before it is written..
485  for (int argnr = 0; argnr < function->argCount(); ++argnr) {
486  for (const std::pair<const Token *, MathLib::bigint> &v : getUnsafeFunction(settings, &scope, argnr, isUnsafeUsage)) {
487  const Token *tok = v.first;
488  const MathLib::bigint val = v.second;
489  unsafeUsage.emplace_back(CTU::getFunctionId(tokenizer, function), argnr+1, tok->str(), CTU::FileInfo::Location(tokenizer,tok), val);
490  }
491  }
492  }
493 
494  return unsafeUsage;
495 }
496 
497 static bool findPath(const std::string &callId,
498  nonneg int callArgNr,
499  MathLib::bigint unsafeValue,
500  CTU::FileInfo::InvalidValueType invalidValue,
501  const std::map<std::string, std::list<const CTU::FileInfo::CallBase *>> &callsMap,
502  const CTU::FileInfo::CallBase *path[10],
503  int index,
504  bool warning)
505 {
506  if (index >= CTU::maxCtuDepth || index >= 10)
507  return false;
508 
509  const std::map<std::string, std::list<const CTU::FileInfo::CallBase *>>::const_iterator it = callsMap.find(callId);
510  if (it == callsMap.end())
511  return false;
512 
513  for (const CTU::FileInfo::CallBase *c : it->second) {
514  if (c->callArgNr != callArgNr)
515  continue;
516 
517  const auto *functionCall = dynamic_cast<const CTU::FileInfo::FunctionCall *>(c);
518  if (functionCall) {
519  if (!warning && functionCall->warning)
520  continue;
521  switch (invalidValue) {
523  if (functionCall->callValueType != ValueFlow::Value::ValueType::INT || functionCall->callArgValue != 0)
524  continue;
525  break;
527  if (functionCall->callValueType != ValueFlow::Value::ValueType::UNINIT)
528  continue;
529  break;
531  if (functionCall->callValueType != ValueFlow::Value::ValueType::BUFFER_SIZE)
532  continue;
533  if (unsafeValue < 0 || (unsafeValue >= functionCall->callArgValue && functionCall->callArgValue >= 0))
534  break;
535  continue;
536  }
537  path[index] = functionCall;
538  return true;
539  }
540 
541  const auto *nestedCall = dynamic_cast<const CTU::FileInfo::NestedCall *>(c);
542  if (!nestedCall)
543  continue;
544 
545  if (findPath(nestedCall->myId, nestedCall->myArgNr, unsafeValue, invalidValue, callsMap, path, index + 1, warning)) {
546  path[index] = nestedCall;
547  return true;
548  }
549  }
550 
551  return false;
552 }
553 
554 std::list<ErrorMessage::FileLocation> CTU::FileInfo::getErrorPath(InvalidValueType invalidValue,
555  const CTU::FileInfo::UnsafeUsage &unsafeUsage,
556  const std::map<std::string, std::list<const CTU::FileInfo::CallBase *>> &callsMap,
557  const char info[],
558  const FunctionCall ** const functionCallPtr,
559  bool warning)
560 {
561  std::list<ErrorMessage::FileLocation> locationList;
562 
563  const CTU::FileInfo::CallBase *path[10] = {nullptr};
564 
565  if (!findPath(unsafeUsage.myId, unsafeUsage.myArgNr, unsafeUsage.value, invalidValue, callsMap, path, 0, warning))
566  return locationList;
567 
568  const std::string value1 = (invalidValue == InvalidValueType::null) ? "null" : "uninitialized";
569 
570  for (int index = 9; index >= 0; index--) {
571  if (!path[index])
572  continue;
573 
574  const auto *functionCall = dynamic_cast<const CTU::FileInfo::FunctionCall *>(path[index]);
575 
576  if (functionCall) {
577  if (functionCallPtr)
578  *functionCallPtr = functionCall;
579  std::copy(functionCall->callValuePath.cbegin(), functionCall->callValuePath.cend(), std::back_inserter(locationList));
580  }
581 
582  std::string info_s = "Calling function " + path[index]->callFunctionName + ", " + std::to_string(path[index]->callArgNr) + getOrdinalText(path[index]->callArgNr) + " argument is " + value1;
583  ErrorMessage::FileLocation fileLoc(path[index]->location.fileName, std::move(info_s), path[index]->location.lineNumber, path[index]->location.column);
584  locationList.push_back(std::move(fileLoc));
585  }
586 
587  std::string info_s = replaceStr(info, "ARG", unsafeUsage.myArgumentName);
588  ErrorMessage::FileLocation fileLoc2(unsafeUsage.location.fileName, std::move(info_s), unsafeUsage.location.lineNumber, unsafeUsage.location.column);
589  locationList.push_back(std::move(fileLoc2));
590 
591  return locationList;
592 }
std::vector< const Token * > getArguments(const Token *ftok)
Get arguments (AST)
Definition: astutils.cpp:3083
bool isVariableChanged(const Token *tok, int indirect, const Settings &settings, int depth)
Definition: astutils.cpp:2546
static bool isUnsafeUsage(const Settings &settings, const Token *vartok, MathLib::bigint *value)
Location location
Definition: ctu.h:90
std::string toBaseXmlString() const
Definition: ctu.cpp:88
bool loadBaseFromXml(const tinyxml2::XMLElement *xmlElement)
Definition: ctu.cpp:187
std::string callFunctionName
Definition: ctu.h:89
std::string callId
Definition: ctu.h:87
std::string callArgumentExpression
Definition: ctu.h:98
bool loadFromXml(const tinyxml2::XMLElement *xmlElement)
Definition: ctu.cpp:199
ValueFlow::Value::ValueType callValueType
Definition: ctu.h:100
MathLib::bigint callArgValue
Definition: ctu.h:99
std::string toXmlString() const
Definition: ctu.cpp:100
std::vector< ErrorMessage::FileLocation > callValuePath
Definition: ctu.h:101
nonneg int myArgNr
Definition: ctu.h:123
std::string toXmlString() const
Definition: ctu.cpp:125
bool loadFromXml(const tinyxml2::XMLElement *xmlElement)
Definition: ctu.cpp:222
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::list< NestedCall > nestedCalls
Definition: ctu.h:127
std::string toString() const override
Definition: ctu.cpp:71
void loadFromXml(const tinyxml2::XMLElement *xmlElement)
Definition: ctu.cpp:232
std::list< FunctionCall > functionCalls
Definition: ctu.h:126
std::map< std::string, std::list< const CallBase * > > getCallsMap() const
Definition: ctu.cpp:247
InvalidValueType
Definition: ctu.h:54
FileInfo()=default
static std::string toxml(const std::string &str)
Convert XML-sensitive characters into XML entities.
File name and line number.
Definition: errorlogger.h:55
const Variable * getArgumentVar(nonneg int num) const
nonneg int argCount() const
long long bigint
Definition: mathlib.h:68
ScopeType type
Function * function
function info for this function
const Token * bodyStart
'{' token
const Token * bodyEnd
'}' token
bool isExecutable() const
This is just a container for general settings so that we don't need to pass individual values to func...
Definition: settings.h:95
Platform platform
Definition: settings.h:255
std::list< Scope > scopeList
Information about all namespaces/classes/structures.
const std::string & file(const Token *tok) const
get filename for given token
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
static const Token * findmatch(const Token *const startTok, const char pattern[], const nonneg int varId=0)
Definition: token.cpp:1065
const ValueType * valueType() const
Definition: token.h:331
void astOperand1(Token *tok)
Definition: token.cpp:1456
std::string expressionString() const
Definition: token.cpp:1647
bool isUnaryOp(const std::string &s) const
Definition: token.h:413
void link(Token *linkToToken)
Create link to given token.
Definition: token.h:1015
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
The main purpose is to tokenize the source code.
Definition: tokenize.h:46
const Settings & getSettings() const
Definition: tokenize.h:615
TokenList list
Token list: stores all tokens.
Definition: tokenize.h:590
const SymbolDatabase * getSymbolDatabase() const
Definition: tokenize.h:563
enum ValueFlow::Value::ValueType valueType
bool isInconclusive() const
Definition: vfvalue.h:378
MathLib::bigint typeSize(const Platform &platform, bool p=false) const
Reference reference
Is the outermost indirection of this type a reference or rvalue.
nonneg int pointer
0=>not pointer, 1=>*, 2=>**, 3=>***, etc
Information about a member variable.
bool isArrayOrPointer() const
Is array or pointer variable.
bool isReference() const
Is reference variable.
nonneg int declarationId() const
Get declaration ID (varId used for variable in its declaration).
bool isPointer() const
Is pointer variable.
const ValueType * valueType() const
#define nonneg
Definition: config.h:138
static constexpr char ATTR_LOC_FILENAME[]
Definition: ctu.cpp:49
static constexpr char ATTR_INFO[]
Definition: ctu.cpp:52
static constexpr char ATTR_CALL_ARGVALUE[]
Definition: ctu.cpp:47
static long long readAttrInt(const tinyxml2::XMLElement *e, const char *attr, bool *error)
Definition: ctu.cpp:178
static bool findPath(const std::string &callId, nonneg int callArgNr, MathLib::bigint unsafeValue, CTU::FileInfo::InvalidValueType invalidValue, const std::map< std::string, std::list< const CTU::FileInfo::CallBase * >> &callsMap, const CTU::FileInfo::CallBase *path[10], int index, bool warning)
Definition: ctu.cpp:497
static constexpr char ATTR_CALL_ARGVALUETYPE[]
Definition: ctu.cpp:46
static constexpr char ATTR_CALL_FUNCNAME[]
Definition: ctu.cpp:43
static constexpr char ATTR_CALL_ARGNR[]
Definition: ctu.cpp:44
static constexpr char ATTR_MY_ID[]
Definition: ctu.cpp:53
static constexpr char ATTR_VALUE[]
Definition: ctu.cpp:56
static std::string readAttrString(const tinyxml2::XMLElement *e, const char *attr, bool *error)
Definition: ctu.cpp:170
static constexpr char ATTR_CALL_ARGEXPR[]
Definition: ctu.cpp:45
static constexpr char ATTR_MY_ARGNAME[]
Definition: ctu.cpp:55
static constexpr char ATTR_LOC_COLUMN[]
Definition: ctu.cpp:51
static constexpr char ATTR_MY_ARGNR[]
Definition: ctu.cpp:54
static int isCallFunction(const Scope *scope, int argnr, const Token *&tok)
Definition: ctu.cpp:279
static constexpr char ATTR_WARNING[]
Definition: ctu.cpp:48
static constexpr char ATTR_CALL_ID[]
Definition: ctu.cpp:42
static std::list< std::pair< const Token *, MathLib::bigint > > getUnsafeFunction(const Settings &settings, const Scope *scope, int argnr, bool(*isUnsafeUsage)(const Settings &settings, const Token *argtok, MathLib::bigint *value))
Definition: ctu.cpp:440
static constexpr char ATTR_LOC_LINENR[]
Definition: ctu.cpp:50
std::pair< const Token *, std::string > ErrorPathItem
Definition: errortypes.h:129
std::string replaceStr(std::string s, const std::string &from, const std::string &to)
Replace substring.
@ warning
Warning.
@ error
Programming error.
Whole program analysis (ctu=Cross Translation Unit)
Definition: check.h:35
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
int maxCtuDepth
Definition: ctu.cpp:58
CPPCHECKLIB std::string getFunctionId(const Tokenizer &tokenizer, const Function *function)
Definition: ctu.cpp:60
CPPCHECKLIB FileInfo * getFileInfo(const Tokenizer &tokenizer)
Parse current TU and extract file info.
Definition: ctu.cpp:309
nonneg int column
Definition: ctu.h:64
nonneg int lineNumber
Definition: ctu.h:63
std::string fileName
Definition: ctu.h:62
MathLib::bigint value
Definition: ctu.h:74
std::string myArgumentName
Definition: ctu.h:72
nonneg int myArgNr
Definition: ctu.h:71
std::string toString() const
Definition: ctu.cpp:136
std::string myId
Definition: ctu.h:70
static const char * getOrdinalText(int i)
Definition: utils.h:189