Cppcheck
valueflow.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  * @brief This is the ValueFlow component in Cppcheck.
21  *
22  * Each @sa Token in the token list has a list of values. These are
23  * the "possible" values for the Token at runtime.
24  *
25  * In the --debug and --debug-normal output you can see the ValueFlow data. For example:
26  *
27  * int f()
28  * {
29  * int x = 10;
30  * return 4 * x + 2;
31  * }
32  *
33  * The --debug-normal output says:
34  *
35  * ##Value flow
36  * Line 3
37  * 10 always 10
38  * Line 4
39  * 4 always 4
40  * * always 40
41  * x always 10
42  * + always 42
43  * 2 always 2
44  *
45  * All value flow analysis is executed in the ValueFlow::setValues() function. The ValueFlow analysis is executed after
46  * the tokenizer/ast/symboldatabase/etc.. The ValueFlow analysis is done in a series of valueFlow* function calls, where
47  * each such function call can only use results from previous function calls. The function calls should be arranged so
48  * that valueFlow* that do not require previous ValueFlow information should be first.
49  *
50  * Type of analysis
51  * ================
52  *
53  * This is "flow sensitive" value flow analysis. We _usually_ track the value for 1 variable at a time.
54  *
55  * How are calculations handled
56  * ============================
57  *
58  * Here is an example code:
59  *
60  * x = 3 + 4;
61  *
62  * The valueFlowNumber set the values for the "3" and "4" tokens by calling setTokenValue().
63  * The setTokenValue() handle the calculations automatically. When both "3" and "4" have values, the "+" can be
64  * calculated. setTokenValue() recursively calls itself when parents in calculations can be calculated.
65  *
66  * Forward / Reverse flow analysis
67  * ===============================
68  *
69  * In forward value flow analysis we know a value and see what happens when we are stepping the program forward. Like
70  * normal execution. The valueFlowForward is used in this analysis.
71  *
72  * In reverse value flow analysis we know the value of a variable at line X. And try to "execute backwards" to determine
73  * possible values before line X. The valueFlowReverse is used in this analysis.
74  *
75  *
76  */
77 
78 #include "valueflow.h"
79 
80 #include "analyzer.h"
81 #include "astutils.h"
82 #include "calculate.h"
83 #include "checkuninitvar.h"
84 #include "config.h"
85 #include "errorlogger.h"
86 #include "errortypes.h"
87 #include "findtoken.h"
88 #include "forwardanalyzer.h"
89 #include "infer.h"
90 #include "library.h"
91 #include "mathlib.h"
92 #include "path.h"
93 #include "platform.h"
94 #include "programmemory.h"
95 #include "reverseanalyzer.h"
96 #include "settings.h"
97 #include "smallvector.h"
98 #include "sourcelocation.h"
99 #include "standards.h"
100 #include "symboldatabase.h"
101 #include "timer.h"
102 #include "token.h"
103 #include "tokenlist.h"
104 #include "utils.h"
105 #include "valueptr.h"
106 #include "vfvalue.h"
107 
108 #include <algorithm>
109 #include <array>
110 #include <cassert>
111 #include <chrono>
112 #include <climits>
113 #include <cstdlib>
114 #include <cstring>
115 #include <exception>
116 #include <functional>
117 #include <initializer_list>
118 #include <iterator>
119 #include <limits>
120 #include <map>
121 #include <memory>
122 #include <numeric>
123 #include <set>
124 #include <sstream>
125 #include <string>
126 #include <type_traits>
127 #include <unordered_map>
128 #include <unordered_set>
129 #include <vector>
130 
131 static void bailoutInternal(const std::string& type, const TokenList &tokenlist, ErrorLogger &errorLogger, const Token *tok, const std::string &what, const std::string &file, int line, std::string function)
132 {
133  if (function.find("operator") != std::string::npos)
134  function = "(valueFlow)";
135  ErrorMessage::FileLocation loc(tok, &tokenlist);
136  const std::string location = Path::stripDirectoryPart(file) + ":" + std::to_string(line) + ":";
137  ErrorMessage errmsg({std::move(loc)}, tokenlist.getSourceFilePath(), Severity::debug,
138  (file.empty() ? "" : location) + function + " bailout: " + what, type, Certainty::normal);
139  errorLogger.reportErr(errmsg);
140 }
141 
142 #define bailout2(type, tokenlist, errorLogger, tok, what) bailoutInternal((type), (tokenlist), (errorLogger), (tok), (what), __FILE__, __LINE__, __func__)
143 
144 #define bailout(tokenlist, errorLogger, tok, what) bailout2("valueFlowBailout", (tokenlist), (errorLogger), (tok), (what))
145 
146 #define bailoutIncompleteVar(tokenlist, errorLogger, tok, what) bailoutInternal("valueFlowBailoutIncompleteVar", (tokenlist), (errorLogger), (tok), (what), "", 0, __func__)
147 
148 static std::string debugString(const ValueFlow::Value& v)
149 {
150  std::string kind;
151  switch (v.valueKind) {
152 
155  kind = "always";
156  break;
158  kind = "inconclusive";
159  break;
161  kind = "possible";
162  break;
163  }
164  return kind + " " + v.toString();
165 }
166 
168  SourceLocation ctx,
169  const Token* tok,
171 {
172  std::string file = ctx.file_name();
173  if (file.empty())
174  return;
175  std::string s = Path::stripDirectoryPart(file) + ":" + std::to_string(ctx.line()) + ": " + ctx.function_name() +
176  " => " + local.function_name() + ": " + debugString(v);
177  v.debugPath.emplace_back(tok, std::move(s));
178 }
179 
180 static void changeKnownToPossible(std::list<ValueFlow::Value> &values, int indirect=-1)
181 {
182  for (ValueFlow::Value& v: values) {
183  if (indirect >= 0 && v.indirect != indirect)
184  continue;
186  }
187 }
188 
189 static void removeImpossible(std::list<ValueFlow::Value>& values, int indirect = -1)
190 {
191  values.remove_if([&](const ValueFlow::Value& v) {
192  if (indirect >= 0 && v.indirect != indirect)
193  return false;
194  return v.isImpossible();
195  });
196 }
197 
198 static void lowerToPossible(std::list<ValueFlow::Value>& values, int indirect = -1)
199 {
200  changeKnownToPossible(values, indirect);
201  removeImpossible(values, indirect);
202 }
203 
204 static void changePossibleToKnown(std::list<ValueFlow::Value>& values, int indirect = -1)
205 {
206  for (ValueFlow::Value& v : values) {
207  if (indirect >= 0 && v.indirect != indirect)
208  continue;
209  if (!v.isPossible())
210  continue;
212  continue;
213  v.setKnown();
214  }
215 }
216 
218 {
219  if (v.conditional)
220  return false;
221  if (v.condition)
222  return false;
223  if (!v.isPossible())
224  return false;
225  if (!v.isIntValue())
226  return false;
227  return true;
228 }
229 
230 static void setValueUpperBound(ValueFlow::Value& value, bool upper)
231 {
232  if (upper)
234  else
236 }
237 
238 static void setValueBound(ValueFlow::Value& value, const Token* tok, bool invert)
239 {
240  if (Token::Match(tok, "<|<=")) {
241  setValueUpperBound(value, !invert);
242  } else if (Token::Match(tok, ">|>=")) {
243  setValueUpperBound(value, invert);
244  }
245 }
246 
247 static void setConditionalValue(ValueFlow::Value& value, const Token* tok, MathLib::bigint i)
248 {
249  assert(value.isIntValue());
250  value.intvalue = i;
251  value.assumeCondition(tok);
252  value.setPossible();
253 }
254 
255 static void setConditionalValues(const Token* tok,
256  bool lhs,
257  MathLib::bigint value,
258  ValueFlow::Value& true_value,
259  ValueFlow::Value& false_value)
260 {
261  if (Token::Match(tok, "==|!=|>=|<=")) {
262  setConditionalValue(true_value, tok, value);
263  const char* greaterThan = ">=";
264  const char* lessThan = "<=";
265  if (lhs)
266  std::swap(greaterThan, lessThan);
267  if (Token::simpleMatch(tok, greaterThan, strlen(greaterThan))) {
268  setConditionalValue(false_value, tok, value - 1);
269  } else if (Token::simpleMatch(tok, lessThan, strlen(lessThan))) {
270  setConditionalValue(false_value, tok, value + 1);
271  } else {
272  setConditionalValue(false_value, tok, value);
273  }
274  } else {
275  const char* greaterThan = ">";
276  const char* lessThan = "<";
277  if (lhs)
278  std::swap(greaterThan, lessThan);
279  if (Token::simpleMatch(tok, greaterThan, strlen(greaterThan))) {
280  setConditionalValue(true_value, tok, value + 1);
281  setConditionalValue(false_value, tok, value);
282  } else if (Token::simpleMatch(tok, lessThan, strlen(lessThan))) {
283  setConditionalValue(true_value, tok, value - 1);
284  setConditionalValue(false_value, tok, value);
285  }
286  }
287  setValueBound(true_value, tok, lhs);
288  setValueBound(false_value, tok, !lhs);
289 }
290 
291 static bool isSaturated(MathLib::bigint value)
292 {
293  return value == std::numeric_limits<MathLib::bigint>::max() || value == std::numeric_limits<MathLib::bigint>::min();
294 }
295 
297  const Token* tok,
298  const std::function<void(const Token* varTok, ValueFlow::Value true_value, ValueFlow::Value false_value)>& each,
299  const std::function<std::vector<ValueFlow::Value>(const Token*)>& evaluate)
300 {
301  if (!tok->astOperand1() || !tok->astOperand2())
302  return;
303  if (tok->isComparisonOp()) {
304  std::vector<ValueFlow::Value> value1 = evaluate(tok->astOperand1());
305  std::vector<ValueFlow::Value> value2 = evaluate(tok->astOperand2());
306  if (!value1.empty() && !value2.empty()) {
307  if (tok->astOperand1()->hasKnownIntValue())
308  value2.clear();
309  if (tok->astOperand2()->hasKnownIntValue())
310  value1.clear();
311  }
312  for (const ValueFlow::Value& v1 : value1) {
313  ValueFlow::Value true_value = v1;
314  ValueFlow::Value false_value = v1;
315  if (isSaturated(v1.intvalue) || astIsFloat(tok->astOperand2(), /*unknown*/ false))
316  continue;
317  setConditionalValues(tok, true, v1.intvalue, true_value, false_value);
318  each(tok->astOperand2(), std::move(true_value), std::move(false_value));
319  }
320  for (const ValueFlow::Value& v2 : value2) {
321  ValueFlow::Value true_value = v2;
322  ValueFlow::Value false_value = v2;
323  if (isSaturated(v2.intvalue) || astIsFloat(tok->astOperand1(), /*unknown*/ false))
324  continue;
325  setConditionalValues(tok, false, v2.intvalue, true_value, false_value);
326  each(tok->astOperand1(), std::move(true_value), std::move(false_value));
327  }
328  }
329 }
330 
332  const Token* tok,
333  const std::function<void(const Token* varTok, ValueFlow::Value true_value, ValueFlow::Value false_value)>& each)
334 {
335  parseCompareEachInt(tok, each, [](const Token* t) -> std::vector<ValueFlow::Value> {
336  if (t->hasKnownIntValue())
337  return {t->values().front()};
338  std::vector<ValueFlow::Value> result;
339  std::copy_if(t->values().cbegin(), t->values().cend(), std::back_inserter(result), [&](const ValueFlow::Value& v) {
340  if (v.path < 1)
341  return false;
342  if (!isNonConditionalPossibleIntValue(v))
343  return false;
344  return true;
345  });
346  return result;
347  });
348 }
349 
351  ValueFlow::Value& true_value,
352  ValueFlow::Value& false_value,
353  const std::function<std::vector<MathLib::bigint>(const Token*)>& evaluate)
354 {
355  const Token* result = nullptr;
357  tok,
358  [&](const Token* vartok, ValueFlow::Value true_value2, ValueFlow::Value false_value2) {
359  if (result)
360  return;
361  result = vartok;
362  true_value = std::move(true_value2);
363  false_value = std::move(false_value2);
364  },
365  [&](const Token* t) -> std::vector<ValueFlow::Value> {
366  std::vector<ValueFlow::Value> r;
367  std::vector<MathLib::bigint> v = evaluate(t);
368 
369  std::transform(v.cbegin(), v.cend(), std::back_inserter(r), [&](MathLib::bigint i) {
370  return ValueFlow::Value{i};
371  });
372  return r;
373  });
374  return result;
375 }
376 
377 const Token *ValueFlow::parseCompareInt(const Token *tok, ValueFlow::Value &true_value, ValueFlow::Value &false_value)
378 {
379  return parseCompareInt(tok, true_value, false_value, [](const Token* t) -> std::vector<MathLib::bigint> {
380  if (t->hasKnownIntValue())
381  return {t->values().front().intvalue};
382  return std::vector<MathLib::bigint>{};
383  });
384 }
385 
386 static bool isEscapeScope(const Token* tok, const Settings& settings, bool unknown = false)
387 {
388  if (!Token::simpleMatch(tok, "{"))
389  return false;
390  // TODO this search for termTok in all subscopes. It should check the end of the scope.
391  const Token * termTok = Token::findmatch(tok, "return|continue|break|throw|goto", tok->link());
392  if (termTok && termTok->scope() == tok->scope())
393  return true;
394  std::string unknownFunction;
395  if (settings.library.isScopeNoReturn(tok->link(), &unknownFunction))
396  return unknownFunction.empty() || unknown;
397  return false;
398 }
399 
401 {
402  if (value.isFloatValue()) {
404  if (value.floatValue >= std::numeric_limits<int>::min() && value.floatValue <= std::numeric_limits<int>::max()) {
405  value.intvalue = value.floatValue;
406  } else { // don't perform UB
407  value.intvalue = 0;
408  }
409  }
410  if (bit < MathLib::bigint_bits) {
411  constexpr MathLib::biguint one = 1;
412  value.intvalue &= (one << bit) - 1;
413  if (sign == ValueType::Sign::SIGNED && value.intvalue & (one << (bit - 1))) {
414  value.intvalue |= ~((one << bit) - 1ULL);
415  }
416  }
417  return value;
418 }
419 
420 static bool isNumeric(const ValueFlow::Value& value) {
421  return value.isIntValue() || value.isFloatValue();
422 }
423 
425 {
426  if (value1.isKnown() && value2.isKnown())
427  result.setKnown();
428  else if (value1.isImpossible() || value2.isImpossible())
429  result.setImpossible();
430  else if (value1.isInconclusive() || value2.isInconclusive())
431  result.setInconclusive();
432  else
433  result.setPossible();
434  if (value1.tokvalue)
435  result.tokvalue = value1.tokvalue;
436  else if (value2.tokvalue)
437  result.tokvalue = value2.tokvalue;
438  if (value1.isSymbolicValue()) {
439  result.valueType = value1.valueType;
440  result.tokvalue = value1.tokvalue;
441  }
442  if (value2.isSymbolicValue()) {
443  result.valueType = value2.valueType;
444  result.tokvalue = value2.tokvalue;
445  }
446  if (value1.isIteratorValue())
447  result.valueType = value1.valueType;
448  if (value2.isIteratorValue())
449  result.valueType = value2.valueType;
450  result.condition = value1.condition ? value1.condition : value2.condition;
451  result.varId = (value1.varId != 0) ? value1.varId : value2.varId;
452  result.varvalue = (result.varId == value1.varId) ? value1.varvalue : value2.varvalue;
453  result.errorPath = (value1.errorPath.empty() ? value2 : value1).errorPath;
454  result.safe = value1.safe || value2.safe;
460  }
461  if (value1.path != value2.path)
462  result.path = -1;
463  else
464  result.path = value1.path;
465 }
466 
467 static const Token *getCastTypeStartToken(const Token *parent, const Settings& settings)
468 {
469  // TODO: This might be a generic utility function?
470  if (!Token::Match(parent, "{|("))
471  return nullptr;
472  // Functional cast
473  if (parent->isBinaryOp() && Token::Match(parent->astOperand1(), "%type% (|{") &&
474  parent->astOperand1()->tokType() == Token::eType && astIsPrimitive(parent))
475  return parent->astOperand1();
476  if (parent->str() != "(")
477  return nullptr;
478  if (!parent->astOperand2() && Token::Match(parent, "( %name%|::")) {
479  const Token* ftok = parent->next();
480  if (ftok->isStandardType())
481  return ftok;
482  if (Token::simpleMatch(ftok, "::"))
483  ftok = ftok->next();
484  while (Token::Match(ftok, "%name% ::"))
485  ftok = ftok->tokAt(2);
486  if (settings.library.isNotLibraryFunction(ftok))
487  return parent->next();
488  }
489  if (parent->astOperand2() && Token::Match(parent->astOperand1(), "const_cast|dynamic_cast|reinterpret_cast|static_cast <"))
490  return parent->astOperand1()->tokAt(2);
491  return nullptr;
492 }
493 
494 // does the operation cause a loss of information?
495 static bool isNonInvertibleOperation(const Token* tok)
496 {
497  return !Token::Match(tok, "+|-");
498 }
499 
500 static bool isComputableValue(const Token* parent, const ValueFlow::Value& value)
501 {
502  const bool noninvertible = isNonInvertibleOperation(parent);
503  if (noninvertible && value.isImpossible())
504  return false;
505  if (!value.isIntValue() && !value.isFloatValue() && !value.isTokValue() && !value.isIteratorValue())
506  return false;
507  if (value.isIteratorValue() && !Token::Match(parent, "+|-"))
508  return false;
509  if (value.isTokValue() && (!parent->isComparisonOp() || !Token::Match(value.tokvalue, "{|%str%")))
510  return false;
511  return true;
512 }
513 
514 static Library::Container::Yield getContainerYield(Token* tok, const Settings& settings, Token** parent = nullptr)
515 {
516  if (Token::Match(tok, ". %name% (") && tok->astParent() == tok->tokAt(2) && tok->astOperand1() &&
517  tok->astOperand1()->valueType()) {
519  if (parent)
520  *parent = tok->astParent();
521  return c ? c->getYield(tok->strAt(1)) : Library::Container::Yield::NO_YIELD;
522  }
523  if (Token::Match(tok->previous(), "%name% (")) {
524  if (parent)
525  *parent = tok;
526  if (const Library::Function* f = settings.library.getFunction(tok->previous())) {
527  return f->containerYield;
528  }
529  }
531 }
532 
533 /** Set token value for cast */
534 static void setTokenValueCast(Token *parent, const ValueType &valueType, const ValueFlow::Value &value, const Settings &settings);
535 
537 {
538  static const std::unordered_map<ValueFlow::Value::ValueType,
539  std::unordered_set<ValueFlow::Value::ValueType, EnumClassHash>,
541  compatibleTypes = {
550  };
551  if (x == y)
552  return true;
553  auto it = compatibleTypes.find(x);
554  if (it == compatibleTypes.end())
555  return false;
556  return it->second.count(y) > 0;
557 }
558 
559 static bool isCompatibleValues(const ValueFlow::Value& value1, const ValueFlow::Value& value2)
560 {
561  if (value1.isSymbolicValue() && value2.isSymbolicValue() && value1.tokvalue->exprId() != value2.tokvalue->exprId())
562  return false;
563  if (!isCompatibleValueTypes(value1.valueType, value2.valueType))
564  return false;
565  if (value1.isKnown() || value2.isKnown())
566  return true;
567  if (value1.isImpossible() || value2.isImpossible())
568  return false;
569  if (value1.varId == 0 || value2.varId == 0)
570  return true;
571  if (value1.varId == value2.varId && value1.varvalue == value2.varvalue && value1.isIntValue() && value2.isIntValue())
572  return true;
573  return false;
574 }
575 
576 static ValueFlow::Value truncateImplicitConversion(Token* parent, const ValueFlow::Value& value, const Settings& settings)
577 {
578  if (!value.isIntValue() && !value.isFloatValue())
579  return value;
580  if (!parent)
581  return value;
582  if (!parent->isBinaryOp())
583  return value;
584  if (!parent->isConstOp())
585  return value;
586  if (!astIsIntegral(parent->astOperand1(), false))
587  return value;
588  if (!astIsIntegral(parent->astOperand2(), false))
589  return value;
590  const ValueType* vt1 = parent->astOperand1()->valueType();
591  const ValueType* vt2 = parent->astOperand2()->valueType();
592  // If the sign is the same there is no truncation
593  if (vt1->sign == vt2->sign)
594  return value;
595  const size_t n1 = ValueFlow::getSizeOf(*vt1, settings);
596  const size_t n2 = ValueFlow::getSizeOf(*vt2, settings);
597  ValueType::Sign sign = ValueType::Sign::UNSIGNED;
598  if (n1 < n2)
599  sign = vt2->sign;
600  else if (n1 > n2)
601  sign = vt1->sign;
602  ValueFlow::Value v = castValue(value, sign, std::max(n1, n2) * 8);
603  v.wideintvalue = value.intvalue;
604  return v;
605 }
606 
607 static long long truncateIntValue(long long value, size_t value_size, const ValueType::Sign dst_sign)
608 {
609  const MathLib::biguint unsignedMaxValue = (1ULL << (value_size * 8)) - 1ULL;
610  const MathLib::biguint signBit = 1ULL << (value_size * 8 - 1);
611  value &= unsignedMaxValue;
612  if (dst_sign == ValueType::Sign::SIGNED && (value & signBit))
613  value |= ~unsignedMaxValue;
614 
615  return value;
616 }
617 
618 /** set ValueFlow value and perform calculations if possible */
619 static void setTokenValue(Token* tok,
620  ValueFlow::Value value,
621  const Settings& settings,
623 {
624  // Skip setting values that are too big since its ambiguous
625  if (!value.isImpossible() && value.isIntValue() && value.intvalue < 0 && astIsUnsigned(tok) &&
626  ValueFlow::getSizeOf(*tok->valueType(), settings) >= sizeof(MathLib::bigint))
627  return;
628 
629  if (!value.isImpossible() && value.isIntValue())
630  value = truncateImplicitConversion(tok->astParent(), value, settings);
631 
632  if (settings.debugnormal)
633  setSourceLocation(value, loc, tok);
634 
635  if (!tok->addValue(value))
636  return;
637 
638  if (value.path < 0)
639  return;
640 
641  Token *parent = tok->astParent();
642  if (!parent)
643  return;
644 
645  if (Token::simpleMatch(parent, ",") && !parent->isInitComma() && astIsRHS(tok)) {
646  const Token* callParent = findParent(parent, [](const Token* p) {
647  return !Token::simpleMatch(p, ",");
648  });
649  // Ensure that the comma isn't a function call
650  if (!callParent || (!Token::Match(callParent->previous(), "%name%|> (") && !Token::simpleMatch(callParent, "{") &&
651  (!Token::Match(callParent, "( %name%") || settings.library.isNotLibraryFunction(callParent->next())) &&
652  !(callParent->str() == "(" && (Token::simpleMatch(callParent->astOperand1(), "*") || Token::Match(callParent->astOperand1(), "%name%|("))))) {
653  setTokenValue(parent, std::move(value), settings);
654  return;
655  }
656  }
657 
658  if (Token::simpleMatch(parent, "=") && astIsRHS(tok)) {
659  setTokenValue(parent, value, settings);
660  if (!value.isUninitValue())
661  return;
662  }
663 
664  if (value.isContainerSizeValue() && astIsContainer(tok)) {
665  // .empty, .size, +"abc", +'a'
666  if (Token::Match(parent, "+|==|!=") && parent->astOperand1() && parent->astOperand2()) {
667  for (const ValueFlow::Value &value1 : parent->astOperand1()->values()) {
668  if (value1.isImpossible())
669  continue;
670  for (const ValueFlow::Value &value2 : parent->astOperand2()->values()) {
671  if (value2.isImpossible())
672  continue;
673  if (value1.path != value2.path)
674  continue;
675  ValueFlow::Value result;
676  if (Token::Match(parent, "%comp%"))
678  else
680 
681  if (value1.isContainerSizeValue() && value2.isContainerSizeValue())
682  result.intvalue = calculate(parent->str(), value1.intvalue, value2.intvalue);
683  else if (value1.isContainerSizeValue() && value2.isTokValue() && value2.tokvalue->tokType() == Token::eString)
684  result.intvalue = calculate(parent->str(), value1.intvalue, MathLib::bigint(Token::getStrLength(value2.tokvalue)));
685  else if (value2.isContainerSizeValue() && value1.isTokValue() && value1.tokvalue->tokType() == Token::eString)
686  result.intvalue = calculate(parent->str(), MathLib::bigint(Token::getStrLength(value1.tokvalue)), value2.intvalue);
687  else
688  continue;
689 
690  combineValueProperties(value1, value2, result);
691 
692  if (Token::simpleMatch(parent, "==") && result.intvalue)
693  continue;
694  if (Token::simpleMatch(parent, "!=") && !result.intvalue)
695  continue;
696 
697  setTokenValue(parent, std::move(result), settings);
698  }
699  }
700  }
701  Token* next = nullptr;
702  const Library::Container::Yield yields = getContainerYield(parent, settings, &next);
703  if (yields == Library::Container::Yield::SIZE) {
704  ValueFlow::Value v(value);
706  setTokenValue(next, std::move(v), settings);
707  } else if (yields == Library::Container::Yield::EMPTY) {
708  ValueFlow::Value v(value);
711  if (value.isImpossible()) {
712  if (value.intvalue == 0)
713  v.setKnown();
714  else if ((value.bound == ValueFlow::Value::Bound::Upper && value.intvalue > 0) ||
715  (value.bound == ValueFlow::Value::Bound::Lower && value.intvalue < 0)) {
716  v.intvalue = 0;
717  v.setKnown();
718  } else
719  v.setPossible();
720  } else {
721  v.intvalue = !v.intvalue;
722  }
723  setTokenValue(next, std::move(v), settings);
724  }
725  return;
726  }
727 
728  if (value.isLifetimeValue()) {
729  if (!ValueFlow::isLifetimeBorrowed(parent, settings))
730  return;
732  setTokenValue(parent,std::move(value),settings);
733  } else if (astIsPointer(tok) && astIsPointer(parent) && !parent->isUnaryOp("*") &&
734  (parent->isArithmeticalOp() || parent->isCast())) {
735  setTokenValue(parent,std::move(value),settings);
736  }
737  return;
738  }
739 
740  if (value.isUninitValue()) {
741  if (Token::Match(tok, ". %var%"))
742  setTokenValue(tok->next(), value, settings);
743  if (parent->isCast()) {
744  setTokenValue(parent, std::move(value), settings);
745  return;
746  }
747  ValueFlow::Value pvalue = value;
748  if (!value.subexpressions.empty() && Token::Match(parent, ". %var%")) {
749  if (contains(value.subexpressions, parent->next()->str()))
750  pvalue.subexpressions.clear();
751  else
752  return;
753  }
754  if (parent->isUnaryOp("&")) {
755  pvalue.indirect++;
756  setTokenValue(parent, std::move(pvalue), settings);
757  } else if (Token::Match(parent, ". %var%") && parent->astOperand1() == tok && parent->astOperand2()) {
758  if (parent->originalName() == "->" && pvalue.indirect > 0)
759  pvalue.indirect--;
760  setTokenValue(parent->astOperand2(), std::move(pvalue), settings);
761  } else if (Token::Match(parent->astParent(), ". %var%") && parent->astParent()->astOperand1() == parent) {
762  if (parent->astParent()->originalName() == "->" && pvalue.indirect > 0)
763  pvalue.indirect--;
764  setTokenValue(parent->astParent()->astOperand2(), std::move(pvalue), settings);
765  } else if (parent->isUnaryOp("*") && pvalue.indirect > 0) {
766  pvalue.indirect--;
767  setTokenValue(parent, std::move(pvalue), settings);
768  }
769  return;
770  }
771 
772  // cast..
773  if (const Token *castType = getCastTypeStartToken(parent, settings)) {
775  Token::simpleMatch(parent->astOperand1(), "dynamic_cast"))
776  return;
777  const ValueType &valueType = ValueType::parseDecl(castType, settings);
778  if (value.isImpossible() && value.isIntValue() && value.intvalue < 0 && astIsUnsigned(tok) &&
779  valueType.sign == ValueType::SIGNED && tok->valueType() &&
780  ValueFlow::getSizeOf(*tok->valueType(), settings) >= ValueFlow::getSizeOf(valueType, settings))
781  return;
782  setTokenValueCast(parent, valueType, value, settings);
783  }
784 
785  else if (parent->str() == ":") {
786  setTokenValue(parent,std::move(value),settings);
787  }
788 
789  else if (parent->str() == "?" && tok->str() == ":" && tok == parent->astOperand2() && parent->astOperand1()) {
790  // is condition always true/false?
791  if (parent->astOperand1()->hasKnownValue()) {
792  const ValueFlow::Value &condvalue = parent->astOperand1()->values().front();
793  const bool cond(condvalue.isTokValue() || (condvalue.isIntValue() && condvalue.intvalue != 0));
794  if (cond && !tok->astOperand1()) { // true condition, no second operator
795  setTokenValue(parent, condvalue, settings);
796  } else {
797  const Token *op = cond ? tok->astOperand1() : tok->astOperand2();
798  if (!op) // #7769 segmentation fault at setTokenValue()
799  return;
800  const std::list<ValueFlow::Value> &values = op->values();
801  if (std::find(values.cbegin(), values.cend(), value) != values.cend())
802  setTokenValue(parent, std::move(value), settings);
803  }
804  } else if (!value.isImpossible()) {
805  // is condition only depending on 1 variable?
806  // cppcheck-suppress[variableScope] #8541
807  nonneg int varId = 0;
808  bool ret = false;
809  visitAstNodes(parent->astOperand1(),
810  [&](const Token *t) {
811  if (t->varId()) {
812  if (varId > 0 || value.varId != 0)
813  ret = true;
814  varId = t->varId();
815  } else if (t->str() == "(" && Token::Match(t->previous(), "%name%"))
816  ret = true; // function call
818  });
819  if (ret)
820  return;
821 
822  ValueFlow::Value v(std::move(value));
823  v.conditional = true;
825 
826  setTokenValue(parent, std::move(v), settings);
827  }
828  }
829 
830  else if (parent->str() == "?" && value.isIntValue() && tok == parent->astOperand1() && value.isKnown() &&
831  parent->astOperand2() && parent->astOperand2()->astOperand1() && parent->astOperand2()->astOperand2()) {
832  const std::list<ValueFlow::Value> &values = (value.intvalue == 0
833  ? parent->astOperand2()->astOperand2()->values()
834  : parent->astOperand2()->astOperand1()->values());
835 
836  for (const ValueFlow::Value &v : values)
837  setTokenValue(parent, v, settings);
838  }
839 
840  // Calculations..
841  else if ((parent->isArithmeticalOp() || parent->isComparisonOp() || (parent->tokType() == Token::eBitOp) || (parent->tokType() == Token::eLogicalOp)) &&
842  parent->astOperand1() &&
843  parent->astOperand2()) {
844 
845  const bool noninvertible = isNonInvertibleOperation(parent);
846 
847  // Skip operators with impossible values that are not invertible
848  if (noninvertible && value.isImpossible())
849  return;
850 
851  // known result when a operand is 0.
852  if (Token::Match(parent, "[&*]") && astIsIntegral(parent, true) && value.isKnown() && value.isIntValue() &&
853  value.intvalue == 0) {
854  setTokenValue(parent, std::move(value), settings);
855  return;
856  }
857 
858  // known result when a operand is true.
859  if (Token::simpleMatch(parent, "&&") && value.isKnown() && value.isIntValue() && value.intvalue==0) {
860  setTokenValue(parent, std::move(value), settings);
861  return;
862  }
863 
864  // known result when a operand is false.
865  if (Token::simpleMatch(parent, "||") && value.isKnown() && value.isIntValue() && value.intvalue!=0) {
866  setTokenValue(parent, std::move(value), settings);
867  return;
868  }
869 
870  for (const ValueFlow::Value &value1 : parent->astOperand1()->values()) {
871  if (!isComputableValue(parent, value1))
872  continue;
873  for (const ValueFlow::Value &value2 : parent->astOperand2()->values()) {
874  if (value1.path != value2.path)
875  continue;
876  if (!isComputableValue(parent, value2))
877  continue;
878  if (value1.isIteratorValue() && value2.isIteratorValue())
879  continue;
880  if (!isCompatibleValues(value1, value2))
881  continue;
882  ValueFlow::Value result(0);
883  combineValueProperties(value1, value2, result);
884  if (astIsFloat(parent, false)) {
885  if (!result.isIntValue() && !result.isFloatValue())
886  continue;
887  result.valueType = ValueFlow::Value::ValueType::FLOAT;
888  }
889  const double floatValue1 = value1.isFloatValue() ? value1.floatValue : value1.intvalue;
890  const double floatValue2 = value2.isFloatValue() ? value2.floatValue : value2.intvalue;
891  const auto intValue1 = [&]() -> MathLib::bigint {
892  return value1.isFloatValue() ? static_cast<MathLib::bigint>(value1.floatValue) : value1.intvalue;
893  };
894  const auto intValue2 = [&]() -> MathLib::bigint {
895  return value2.isFloatValue() ? static_cast<MathLib::bigint>(value2.floatValue) : value2.intvalue;
896  };
897  if ((value1.isFloatValue() || value2.isFloatValue()) && Token::Match(parent, "&|^|%|<<|>>|==|!=|%or%"))
898  continue;
899  if (Token::Match(parent, "==|!=")) {
900  if ((value1.isIntValue() && value2.isTokValue()) || (value1.isTokValue() && value2.isIntValue())) {
901  if (parent->str() == "==")
902  result.intvalue = 0;
903  else if (parent->str() == "!=")
904  result.intvalue = 1;
905  } else if (value1.isIntValue() && value2.isIntValue()) {
906  bool error = false;
907  result.intvalue = calculate(parent->str(), intValue1(), intValue2(), &error);
908  if (error)
909  continue;
910  } else if (value1.isTokValue() && value2.isTokValue() &&
911  (astIsContainer(parent->astOperand1()) || astIsContainer(parent->astOperand2()))) {
912  const Token* tok1 = value1.tokvalue;
913  const Token* tok2 = value2.tokvalue;
914  bool equal = false;
915  if (Token::Match(tok1, "%str%") && Token::Match(tok2, "%str%")) {
916  equal = tok1->str() == tok2->str();
917  } else if (Token::simpleMatch(tok1, "{") && Token::simpleMatch(tok2, "{")) {
918  std::vector<const Token*> args1 = getArguments(tok1);
919  std::vector<const Token*> args2 = getArguments(tok2);
920  if (args1.size() == args2.size()) {
921  if (!std::all_of(args1.begin(), args1.end(), std::mem_fn(&Token::hasKnownIntValue)))
922  continue;
923  if (!std::all_of(args2.begin(), args2.end(), std::mem_fn(&Token::hasKnownIntValue)))
924  continue;
925  equal = std::equal(args1.begin(),
926  args1.end(),
927  args2.begin(),
928  [&](const Token* atok, const Token* btok) {
929  return atok->values().front().intvalue ==
930  btok->values().front().intvalue;
931  });
932  } else {
933  equal = false;
934  }
935  } else {
936  continue;
937  }
938  result.intvalue = parent->str() == "==" ? equal : !equal;
939  } else {
940  continue;
941  }
942  setTokenValue(parent, std::move(result), settings);
943  } else if (Token::Match(parent, "%op%")) {
944  if (Token::Match(parent, "%comp%")) {
945  if (!result.isFloatValue() && !value1.isIntValue() && !value2.isIntValue())
946  continue;
947  } else {
948  if (value1.isTokValue() || value2.isTokValue())
949  break;
950  }
951  bool error = false;
952  if (result.isFloatValue()) {
953  result.floatValue = calculate(parent->str(), floatValue1, floatValue2, &error);
954  } else {
955  result.intvalue = calculate(parent->str(), intValue1(), intValue2(), &error);
956  }
957  if (error)
958  continue;
959  // If the bound comes from the second value then invert the bound when subtracting
960  if (Token::simpleMatch(parent, "-") && value2.bound == result.bound &&
961  value2.bound != ValueFlow::Value::Bound::Point)
962  result.invertBound();
963  setTokenValue(parent, std::move(result), settings);
964  }
965  }
966  }
967  }
968 
969  // !
970  else if (parent->str() == "!") {
971  for (const ValueFlow::Value &val : tok->values()) {
972  if (!val.isIntValue())
973  continue;
974  if (val.isImpossible() && val.intvalue != 0)
975  continue;
976  ValueFlow::Value v(val);
977  if (val.isImpossible())
978  v.setKnown();
979  else
980  v.intvalue = !v.intvalue;
981  setTokenValue(parent, std::move(v), settings);
982  }
983  }
984 
985  // ~
986  else if (parent->str() == "~") {
987  for (const ValueFlow::Value &val : tok->values()) {
988  if (!val.isIntValue())
989  continue;
990  ValueFlow::Value v(val);
991  v.intvalue = ~v.intvalue;
992  int bits = 0;
993  if (tok->valueType() &&
994  tok->valueType()->sign == ValueType::Sign::UNSIGNED &&
995  tok->valueType()->pointer == 0) {
996  if (tok->valueType()->type == ValueType::Type::INT)
997  bits = settings.platform.int_bit;
998  else if (tok->valueType()->type == ValueType::Type::LONG)
999  bits = settings.platform.long_bit;
1000  }
1001  if (bits > 0 && bits < MathLib::bigint_bits)
1002  v.intvalue &= (((MathLib::biguint)1)<<bits) - 1;
1003  setTokenValue(parent, std::move(v), settings);
1004  }
1005  }
1006 
1007  // unary minus
1008  else if (parent->isUnaryOp("-")) {
1009  for (const ValueFlow::Value &val : tok->values()) {
1010  if (!val.isIntValue() && !val.isFloatValue())
1011  continue;
1012  ValueFlow::Value v(val);
1013  if (v.isIntValue()) {
1014  if (v.intvalue == LLONG_MIN)
1015  // Value can't be inverted
1016  continue;
1017  v.intvalue = -v.intvalue;
1018  } else
1019  v.floatValue = -v.floatValue;
1020  v.invertBound();
1021  setTokenValue(parent, std::move(v), settings);
1022  }
1023  }
1024 
1025  // increment
1026  else if (parent->str() == "++") {
1027  for (const ValueFlow::Value &val : tok->values()) {
1028  if (!val.isIntValue() && !val.isFloatValue() && !val.isSymbolicValue())
1029  continue;
1030  ValueFlow::Value v(val);
1031  if (parent == tok->previous()) {
1032  if (v.isIntValue() || v.isSymbolicValue())
1033  v.intvalue = v.intvalue + 1;
1034  else
1035  v.floatValue = v.floatValue + 1.0;
1036  }
1037  setTokenValue(parent, std::move(v), settings);
1038  }
1039  }
1040 
1041  // decrement
1042  else if (parent->str() == "--") {
1043  for (const ValueFlow::Value &val : tok->values()) {
1044  if (!val.isIntValue() && !val.isFloatValue() && !val.isSymbolicValue())
1045  continue;
1046  ValueFlow::Value v(val);
1047  if (parent == tok->previous()) {
1048  if (v.isIntValue() || v.isSymbolicValue())
1049  v.intvalue = v.intvalue - 1;
1050  else
1051  v.floatValue = v.floatValue - 1.0;
1052  }
1053  setTokenValue(parent, std::move(v), settings);
1054  }
1055  }
1056 
1057  // C++ init
1058  else if (parent->str() == "{" && Token::simpleMatch(parent->previous(), "= {") && Token::simpleMatch(parent->link(), "} ;")) {
1059  const Token* lhs = parent->previous()->astOperand1();
1060  if (lhs && lhs->valueType()) {
1061  if (lhs->valueType()->isIntegral() || lhs->valueType()->isFloat() || (lhs->valueType()->pointer > 0 && value.isIntValue())) {
1062  setTokenValue(parent, std::move(value), settings);
1063  }
1064  }
1065  }
1066 
1067  else if (Token::Match(parent, ":: %name%") && parent->astOperand2() == tok) {
1068  setTokenValue(parent, std::move(value), settings);
1069  }
1070  // Calling std::size or std::empty on an array
1071  else if (value.isTokValue() && Token::simpleMatch(value.tokvalue, "{") && tok->variable() &&
1072  tok->variable()->isArray() && Token::Match(parent->previous(), "%name% (") && astIsRHS(tok)) {
1073  std::vector<const Token*> args = getArguments(value.tokvalue);
1074  if (const Library::Function* f = settings.library.getFunction(parent->previous())) {
1075  if (f->containerYield == Library::Container::Yield::SIZE) {
1076  ValueFlow::Value v(std::move(value));
1078  v.intvalue = args.size();
1079  setTokenValue(parent, std::move(v), settings);
1080  } else if (f->containerYield == Library::Container::Yield::EMPTY) {
1081  ValueFlow::Value v(std::move(value));
1082  v.intvalue = args.empty();
1084  setTokenValue(parent, std::move(v), settings);
1085  }
1086  }
1087  }
1088 }
1089 
1090 static void setTokenValueCast(Token *parent, const ValueType &valueType, const ValueFlow::Value &value, const Settings &settings)
1091 {
1092  if (valueType.pointer || value.isImpossible())
1093  setTokenValue(parent,value,settings);
1094  else if (valueType.type == ValueType::Type::CHAR)
1095  setTokenValue(parent, castValue(value, valueType.sign, settings.platform.char_bit), settings);
1096  else if (valueType.type == ValueType::Type::SHORT)
1097  setTokenValue(parent, castValue(value, valueType.sign, settings.platform.short_bit), settings);
1098  else if (valueType.type == ValueType::Type::INT)
1099  setTokenValue(parent, castValue(value, valueType.sign, settings.platform.int_bit), settings);
1100  else if (valueType.type == ValueType::Type::LONG)
1101  setTokenValue(parent, castValue(value, valueType.sign, settings.platform.long_bit), settings);
1102  else if (valueType.type == ValueType::Type::LONGLONG)
1103  setTokenValue(parent, castValue(value, valueType.sign, settings.platform.long_long_bit), settings);
1104  else if (valueType.isFloat() && isNumeric(value)) {
1105  ValueFlow::Value floatValue = value;
1107  if (value.isIntValue())
1108  floatValue.floatValue = value.intvalue;
1109  setTokenValue(parent, std::move(floatValue), settings);
1110  } else if (value.isIntValue()) {
1111  const long long charMax = settings.platform.signedCharMax();
1112  const long long charMin = settings.platform.signedCharMin();
1113  if (charMin <= value.intvalue && value.intvalue <= charMax) {
1114  // unknown type, but value is small so there should be no truncation etc
1115  setTokenValue(parent,value,settings);
1116  }
1117  }
1118 }
1119 
1120 template<class F>
1121 static size_t accumulateStructMembers(const Scope* scope, F f)
1122 {
1123  size_t total = 0;
1124  std::set<const Scope*> anonScopes;
1125  for (const Variable& var : scope->varlist) {
1126  if (var.isStatic())
1127  continue;
1128  if (const ValueType* vt = var.valueType()) {
1129  if (vt->type == ValueType::Type::RECORD && vt->typeScope == scope)
1130  return 0;
1131  const MathLib::bigint dim = std::accumulate(var.dimensions().cbegin(), var.dimensions().cend(), 1LL, [](MathLib::bigint i1, const Dimension& dim) {
1132  return i1 * dim.num;
1133  });
1134  if (var.nameToken()->scope() != scope && var.nameToken()->scope()->definedType) { // anonymous union
1135  const auto ret = anonScopes.insert(var.nameToken()->scope());
1136  if (ret.second)
1137  total = f(total, *vt, dim);
1138  }
1139  else
1140  total = f(total, *vt, dim);
1141  }
1142  if (total == 0)
1143  return 0;
1144  }
1145  return total;
1146 }
1147 
1148 static size_t bitCeil(size_t x)
1149 {
1150  if (x <= 1)
1151  return 1;
1152  --x;
1153  x |= x >> 1;
1154  x |= x >> 2;
1155  x |= x >> 4;
1156  x |= x >> 8;
1157  x |= x >> 16;
1158  x |= x >> 32;
1159  return x + 1;
1160 }
1161 
1162 static size_t getAlignOf(const ValueType& vt, const Settings& settings, int maxRecursion = 0)
1163 {
1164  if (maxRecursion == 100)
1165  return 0;
1166  if (vt.pointer || vt.reference != Reference::None || vt.isPrimitive()) {
1167  auto align = ValueFlow::getSizeOf(vt, settings);
1168  return align == 0 ? 0 : bitCeil(align);
1169  }
1170  if (vt.type == ValueType::Type::RECORD && vt.typeScope) {
1171  auto accHelper = [&](size_t max, const ValueType& vt2, size_t /*dim*/) {
1172  size_t a = getAlignOf(vt2, settings, ++maxRecursion);
1173  return std::max(max, a);
1174  };
1175  size_t total = 0;
1176  if (const Type* dt = vt.typeScope->definedType) {
1177  total = std::accumulate(dt->derivedFrom.begin(), dt->derivedFrom.end(), total, [&](size_t v, const Type::BaseInfo& bi) {
1178  if (bi.type && bi.type->classScope)
1179  v += accumulateStructMembers(bi.type->classScope, accHelper);
1180  return v;
1181  });
1182  }
1183  return total + accumulateStructMembers(vt.typeScope, accHelper);
1184  }
1185  if (vt.type == ValueType::Type::CONTAINER)
1186  return settings.platform.sizeof_pointer; // Just guess
1187  return 0;
1188 }
1189 
1190 static nonneg int getSizeOfType(const Token *typeTok, const Settings &settings)
1191 {
1192  const ValueType &valueType = ValueType::parseDecl(typeTok, settings);
1193 
1194  return ValueFlow::getSizeOf(valueType, settings);
1195 }
1196 
1197 size_t ValueFlow::getSizeOf(const ValueType &vt, const Settings &settings, int maxRecursion)
1198 {
1199  if (maxRecursion == 100)
1200  return 0;
1201  if (vt.pointer || vt.reference != Reference::None)
1202  return settings.platform.sizeof_pointer;
1203  if (vt.type == ValueType::Type::BOOL || vt.type == ValueType::Type::CHAR)
1204  return 1;
1205  if (vt.type == ValueType::Type::SHORT)
1206  return settings.platform.sizeof_short;
1207  if (vt.type == ValueType::Type::WCHAR_T)
1208  return settings.platform.sizeof_wchar_t;
1209  if (vt.type == ValueType::Type::INT)
1210  return settings.platform.sizeof_int;
1211  if (vt.type == ValueType::Type::LONG)
1212  return settings.platform.sizeof_long;
1213  if (vt.type == ValueType::Type::LONGLONG)
1214  return settings.platform.sizeof_long_long;
1215  if (vt.type == ValueType::Type::FLOAT)
1216  return settings.platform.sizeof_float;
1217  if (vt.type == ValueType::Type::DOUBLE)
1218  return settings.platform.sizeof_double;
1219  if (vt.type == ValueType::Type::LONGDOUBLE)
1220  return settings.platform.sizeof_long_double;
1221  if (vt.type == ValueType::Type::CONTAINER)
1222  return 3 * settings.platform.sizeof_pointer; // Just guess
1223  if (vt.type == ValueType::Type::RECORD && vt.typeScope) {
1224  auto accHelper = [&](size_t total, const ValueType& vt2, size_t dim) -> size_t {
1225  size_t n = ValueFlow::getSizeOf(vt2, settings, ++maxRecursion);
1226  size_t a = getAlignOf(vt2, settings);
1227  if (n == 0 || a == 0)
1228  return 0;
1229  n *= dim;
1230  size_t padding = (a - (total % a)) % a;
1231  return vt.typeScope->type == Scope::eUnion ? std::max(total, n) : total + padding + n;
1232  };
1233  size_t total = accumulateStructMembers(vt.typeScope, accHelper);
1234  if (const Type* dt = vt.typeScope->definedType) {
1235  total = std::accumulate(dt->derivedFrom.begin(), dt->derivedFrom.end(), total, [&](size_t v, const Type::BaseInfo& bi) {
1236  if (bi.type && bi.type->classScope)
1237  v += accumulateStructMembers(bi.type->classScope, accHelper);
1238  return v;
1239  });
1240  }
1241  if (total == 0)
1242  return 0;
1243  size_t align = getAlignOf(vt, settings);
1244  if (align == 0)
1245  return 0;
1246  total += (align - (total % align)) % align;
1247  return total;
1248  }
1249  return 0;
1250 }
1251 
1252 
1253 static bool getMinMaxValues(const ValueType* vt, const Platform& platform, MathLib::bigint& minValue, MathLib::bigint& maxValue);
1254 
1255 // Handle various constants..
1256 static Token * valueFlowSetConstantValue(Token *tok, const Settings &settings)
1257 {
1258  if ((tok->isNumber() && MathLib::isInt(tok->str())) || (tok->tokType() == Token::eChar)) {
1259  try {
1260  MathLib::bigint signedValue = MathLib::toBigNumber(tok->str());
1261  const ValueType* vt = tok->valueType();
1262  if (vt && vt->sign == ValueType::UNSIGNED && signedValue < 0 && ValueFlow::getSizeOf(*vt, settings) < sizeof(MathLib::bigint)) {
1263  MathLib::bigint minValue{}, maxValue{};
1264  if (getMinMaxValues(tok->valueType(), settings.platform, minValue, maxValue))
1265  signedValue += maxValue + 1;
1266  }
1267  ValueFlow::Value value(signedValue);
1268  if (!tok->isTemplateArg())
1269  value.setKnown();
1270  setTokenValue(tok, std::move(value), settings);
1271  } catch (const std::exception & /*e*/) {
1272  // Bad character literal
1273  }
1274  } else if (tok->isNumber() && MathLib::isFloat(tok->str())) {
1275  ValueFlow::Value value;
1277  value.floatValue = MathLib::toDoubleNumber(tok->str());
1278  if (!tok->isTemplateArg())
1279  value.setKnown();
1280  setTokenValue(tok, std::move(value), settings);
1281  } else if (tok->enumerator() && tok->enumerator()->value_known) {
1282  ValueFlow::Value value(tok->enumerator()->value);
1283  if (!tok->isTemplateArg())
1284  value.setKnown();
1285  setTokenValue(tok, std::move(value), settings);
1286  } else if (tok->str() == "NULL" || (tok->isCpp() && tok->str() == "nullptr")) {
1287  ValueFlow::Value value(0);
1288  if (!tok->isTemplateArg())
1289  value.setKnown();
1290  setTokenValue(tok, std::move(value), settings);
1291  } else if (Token::simpleMatch(tok, "sizeof (")) {
1292  if (tok->next()->astOperand2() && !tok->next()->astOperand2()->isLiteral() && tok->next()->astOperand2()->valueType() &&
1293  (tok->next()->astOperand2()->valueType()->pointer == 0 || // <- TODO this is a bailout, abort when there are array->pointer conversions
1294  (tok->next()->astOperand2()->variable() && !tok->next()->astOperand2()->variable()->isArray())) &&
1295  !tok->next()->astOperand2()->valueType()->isEnum()) { // <- TODO this is a bailout, handle enum with non-int types
1296  const size_t sz = ValueFlow::getSizeOf(*tok->next()->astOperand2()->valueType(), settings);
1297  if (sz) {
1298  ValueFlow::Value value(sz);
1299  value.setKnown();
1300  setTokenValue(tok->next(), std::move(value), settings);
1301  return tok->linkAt(1);
1302  }
1303  }
1304 
1305  const Token *tok2 = tok->tokAt(2);
1306  // skip over tokens to find variable or type
1307  while (tok2 && !tok2->isStandardType() && Token::Match(tok2, "%name% ::|.|[")) {
1308  if (tok2->next()->str() == "[")
1309  tok2 = tok2->linkAt(1)->next();
1310  else
1311  tok2 = tok2->tokAt(2);
1312  }
1313  if (Token::simpleMatch(tok, "sizeof ( *")) {
1314  const ValueType *vt = tok->tokAt(2)->valueType();
1315  const size_t sz = vt ? ValueFlow::getSizeOf(*vt, settings) : 0;
1316  if (sz > 0) {
1317  ValueFlow::Value value(sz);
1318  if (!tok2->isTemplateArg() && settings.platform.type != Platform::Type::Unspecified)
1319  value.setKnown();
1320  setTokenValue(tok->next(), std::move(value), settings);
1321  }
1322  } else if (tok2->enumerator() && tok2->enumerator()->scope) {
1323  long long size = settings.platform.sizeof_int;
1324  const Token * type = tok2->enumerator()->scope->enumType;
1325  if (type) {
1326  size = getSizeOfType(type, settings);
1327  if (size == 0)
1328  tok->linkAt(1);
1329  }
1330  ValueFlow::Value value(size);
1331  if (!tok2->isTemplateArg() && settings.platform.type != Platform::Type::Unspecified)
1332  value.setKnown();
1333  setTokenValue(tok, value, settings);
1334  setTokenValue(tok->next(), std::move(value), settings);
1335  } else if (tok2->type() && tok2->type()->isEnumType()) {
1336  long long size = settings.platform.sizeof_int;
1337  if (tok2->type()->classScope) {
1338  const Token * type = tok2->type()->classScope->enumType;
1339  if (type) {
1340  size = getSizeOfType(type, settings);
1341  }
1342  }
1343  ValueFlow::Value value(size);
1344  if (!tok2->isTemplateArg() && settings.platform.type != Platform::Type::Unspecified)
1345  value.setKnown();
1346  setTokenValue(tok, value, settings);
1347  setTokenValue(tok->next(), std::move(value), settings);
1348  } else if (Token::Match(tok, "sizeof ( %var% ) /") && tok->next()->astParent() == tok->tokAt(4) &&
1349  tok->tokAt(4)->astOperand2() && Token::simpleMatch(tok->tokAt(4)->astOperand2()->previous(), "sizeof (")) {
1350  // Get number of elements in array
1351  const Token *sz1 = tok->tokAt(2);
1352  const Token *sz2 = tok->tokAt(4)->astOperand2(); // left parenthesis of sizeof on rhs
1353  const nonneg int varid1 = sz1->varId();
1354  if (varid1 &&
1355  sz1->variable() &&
1356  sz1->variable()->isArray() &&
1357  !sz1->variable()->dimensions().empty() &&
1358  sz1->variable()->dimensionKnown(0) &&
1359  Token::Match(sz2->astOperand2(), "*|[") && Token::Match(sz2->astOperand2()->astOperand1(), "%varid%", varid1)) {
1360  ValueFlow::Value value(sz1->variable()->dimension(0));
1361  if (!tok2->isTemplateArg() && settings.platform.type != Platform::Type::Unspecified)
1362  value.setKnown();
1363  setTokenValue(tok->tokAt(4), std::move(value), settings);
1364  }
1365  } else if (Token::Match(tok2, "%var% )")) {
1366  const Variable *var = tok2->variable();
1367  // only look for single token types (no pointers or references yet)
1368  if (var && var->typeStartToken() == var->typeEndToken()) {
1369  // find the size of the type
1370  size_t size = 0;
1371  if (var->isEnumType()) {
1372  size = settings.platform.sizeof_int;
1373  if (var->type()->classScope && var->type()->classScope->enumType)
1374  size = getSizeOfType(var->type()->classScope->enumType, settings);
1375  } else if (var->valueType()) {
1376  size = ValueFlow::getSizeOf(*var->valueType(), settings);
1377  } else if (!var->type()) {
1378  size = getSizeOfType(var->typeStartToken(), settings);
1379  }
1380  // find the number of elements
1381  size_t count = 1;
1382  for (size_t i = 0; i < var->dimensions().size(); ++i) {
1383  if (var->dimensionKnown(i))
1384  count *= var->dimension(i);
1385  else
1386  count = 0;
1387  }
1388  if (size && count > 0) {
1389  ValueFlow::Value value(count * size);
1390  if (settings.platform.type != Platform::Type::Unspecified)
1391  value.setKnown();
1392  setTokenValue(tok, value, settings);
1393  setTokenValue(tok->next(), std::move(value), settings);
1394  }
1395  }
1396  } else if (tok2->tokType() == Token::eString) {
1397  const size_t sz = Token::getStrSize(tok2, settings);
1398  if (sz > 0) {
1399  ValueFlow::Value value(sz);
1400  value.setKnown();
1401  setTokenValue(tok->next(), std::move(value), settings);
1402  }
1403  } else if (tok2->tokType() == Token::eChar) {
1404  nonneg int sz = 0;
1405  if (tok2->isCpp() && settings.standards.cpp >= Standards::CPP20 && tok2->isUtf8())
1406  sz = 1;
1407  else if (tok2->isUtf16())
1408  sz = 2;
1409  else if (tok2->isUtf32())
1410  sz = 4;
1411  else if (tok2->isLong())
1412  sz = settings.platform.sizeof_wchar_t;
1413  else if ((!tok2->isCpp() && tok2->isCChar()) || (tok2->isCMultiChar()))
1414  sz = settings.platform.sizeof_int;
1415  else
1416  sz = 1;
1417 
1418  if (sz > 0) {
1419  ValueFlow::Value value(sz);
1420  value.setKnown();
1421  setTokenValue(tok->next(), std::move(value), settings);
1422  }
1423  } else if (!tok2->type()) {
1424  const ValueType& vt = ValueType::parseDecl(tok2, settings);
1425  size_t sz = ValueFlow::getSizeOf(vt, settings);
1426  const Token* brac = tok2->astParent();
1427  while (Token::simpleMatch(brac, "[")) {
1428  const Token* num = brac->astOperand2();
1429  if (num && ((num->isNumber() && MathLib::isInt(num->str())) || num->tokType() == Token::eChar)) {
1430  try {
1431  const MathLib::biguint dim = MathLib::toBigUNumber(num->str());
1432  sz *= dim;
1433  brac = brac->astParent();
1434  continue;
1435  }
1436  catch (const std::exception& /*e*/) {
1437  // Bad integer literal
1438  }
1439  }
1440  sz = 0;
1441  break;
1442  }
1443  if (sz > 0) {
1444  ValueFlow::Value value(sz);
1445  if (!tok2->isTemplateArg() && settings.platform.type != Platform::Type::Unspecified)
1446  value.setKnown();
1447  setTokenValue(tok->next(), std::move(value), settings);
1448  }
1449  }
1450  // skip over enum
1451  tok = tok->linkAt(1);
1452  } else if (Token::Match(tok, "%name% [{(] [)}]") && (tok->isStandardType() ||
1453  (tok->variable() && tok->variable()->nameToken() == tok &&
1454  (tok->variable()->isPointer() || (tok->variable()->valueType() && tok->variable()->valueType()->isIntegral()))))) {
1455  ValueFlow::Value value(0);
1456  if (!tok->isTemplateArg())
1457  value.setKnown();
1458  setTokenValue(tok->next(), std::move(value), settings);
1459  } else if (Token::simpleMatch(tok, "= { } ;")) {
1460  const Token* lhs = tok->astOperand1();
1461  if (lhs && lhs->valueType() && (lhs->valueType()->isIntegral() || lhs->valueType()->pointer > 0)) {
1462  ValueFlow::Value value(0);
1463  value.setKnown();
1464  setTokenValue(tok->next(), std::move(value), settings);
1465  }
1466  }
1467  return tok->next();
1468 }
1469 
1470 static void valueFlowNumber(TokenList &tokenlist, const Settings& settings)
1471 {
1472  for (Token *tok = tokenlist.front(); tok;) {
1473  tok = valueFlowSetConstantValue(tok, settings);
1474  }
1475 
1476  if (tokenlist.isCPP()) {
1477  for (Token *tok = tokenlist.front(); tok; tok = tok->next()) {
1478  if (tok->isName() && !tok->varId() && Token::Match(tok, "false|true")) {
1479  ValueFlow::Value value(tok->str() == "true");
1480  if (!tok->isTemplateArg())
1481  value.setKnown();
1482  setTokenValue(tok, std::move(value), settings);
1483  } else if (Token::Match(tok, "[(,] NULL [,)]")) {
1484  // NULL function parameters are not simplified in the
1485  // normal tokenlist
1486  ValueFlow::Value value(0);
1487  if (!tok->isTemplateArg())
1488  value.setKnown();
1489  setTokenValue(tok->next(), std::move(value), settings);
1490  }
1491  }
1492  }
1493 }
1494 
1495 static void valueFlowString(TokenList &tokenlist, const Settings& settings)
1496 {
1497  for (Token *tok = tokenlist.front(); tok; tok = tok->next()) {
1498  if (tok->tokType() == Token::eString) {
1499  ValueFlow::Value strvalue;
1501  strvalue.tokvalue = tok;
1502  strvalue.setKnown();
1503  setTokenValue(tok, std::move(strvalue), settings);
1504  }
1505  }
1506 }
1507 
1508 static void valueFlowArray(TokenList &tokenlist, const Settings &settings)
1509 {
1510  std::map<nonneg int, const Token *> constantArrays;
1511 
1512  for (Token *tok = tokenlist.front(); tok; tok = tok->next()) {
1513  if (tok->varId() > 0) {
1514  // array
1515  const std::map<nonneg int, const Token *>::const_iterator it = constantArrays.find(tok->varId());
1516  if (it != constantArrays.end()) {
1517  ValueFlow::Value value;
1519  value.tokvalue = it->second;
1520  value.setKnown();
1521  setTokenValue(tok, std::move(value), settings);
1522  }
1523 
1524  // const array decl
1525  else if (tok->variable() && tok->variable()->isArray() && tok->variable()->isConst() &&
1526  tok->variable()->nameToken() == tok && Token::Match(tok, "%var% [ %num%| ] = {")) {
1527  Token* rhstok = tok->next()->link()->tokAt(2);
1528  constantArrays[tok->varId()] = rhstok;
1529  tok = rhstok->link();
1530  }
1531 
1532  // pointer = array
1533  else if (tok->variable() && tok->variable()->isArray() && Token::simpleMatch(tok->astParent(), "=") &&
1534  astIsRHS(tok) && tok->astParent()->astOperand1() &&
1535  tok->astParent()->astOperand1()->variable() &&
1536  tok->astParent()->astOperand1()->variable()->isPointer()) {
1537  ValueFlow::Value value;
1539  value.tokvalue = tok;
1540  value.setKnown();
1541  setTokenValue(tok, std::move(value), settings);
1542  }
1543  continue;
1544  }
1545 
1546  if (Token::Match(tok, "const %type% %var% [ %num%| ] = {")) {
1547  Token *vartok = tok->tokAt(2);
1548  Token *rhstok = vartok->next()->link()->tokAt(2);
1549  constantArrays[vartok->varId()] = rhstok;
1550  tok = rhstok->link();
1551  continue;
1552  }
1553 
1554  if (Token::Match(tok, "const char %var% [ %num%| ] = %str% ;")) {
1555  Token *vartok = tok->tokAt(2);
1556  Token *strtok = vartok->next()->link()->tokAt(2);
1557  constantArrays[vartok->varId()] = strtok;
1558  tok = strtok->next();
1559  continue;
1560  }
1561  }
1562 }
1563 
1564 static bool isNonZero(const Token *tok)
1565 {
1566  return tok && (!tok->hasKnownIntValue() || tok->values().front().intvalue != 0);
1567 }
1568 
1569 static const Token *getOtherOperand(const Token *tok)
1570 {
1571  if (!tok)
1572  return nullptr;
1573  if (!tok->astParent())
1574  return nullptr;
1575  if (tok->astParent()->astOperand1() != tok)
1576  return tok->astParent()->astOperand1();
1577  if (tok->astParent()->astOperand2() != tok)
1578  return tok->astParent()->astOperand2();
1579  return nullptr;
1580 }
1581 
1582 static void valueFlowArrayBool(TokenList &tokenlist, const Settings &settings)
1583 {
1584  for (Token *tok = tokenlist.front(); tok; tok = tok->next()) {
1585  if (tok->hasKnownIntValue())
1586  continue;
1587  const Variable *var = nullptr;
1588  bool known = false;
1589  const std::list<ValueFlow::Value>::const_iterator val =
1590  std::find_if(tok->values().cbegin(), tok->values().cend(), std::mem_fn(&ValueFlow::Value::isTokValue));
1591  if (val == tok->values().end()) {
1592  var = tok->variable();
1593  known = true;
1594  } else {
1595  var = val->tokvalue->variable();
1596  known = val->isKnown();
1597  }
1598  if (!var)
1599  continue;
1600  if (!var->isArray() || var->isArgument() || var->isStlType())
1601  continue;
1602  if (isNonZero(getOtherOperand(tok)) && Token::Match(tok->astParent(), "%comp%"))
1603  continue;
1604  // TODO: Check for function argument
1605  if ((astIsBool(tok->astParent()) && !Token::Match(tok->astParent(), "(|%name%")) ||
1606  (tok->astParent() && Token::Match(tok->astParent()->previous(), "if|while|for ("))) {
1607  ValueFlow::Value value{1};
1608  if (known)
1609  value.setKnown();
1610  setTokenValue(tok, std::move(value), settings);
1611  }
1612  }
1613 }
1614 
1615 static void valueFlowArrayElement(TokenList& tokenlist, const Settings& settings)
1616 {
1617  for (Token* tok = tokenlist.front(); tok; tok = tok->next()) {
1618  if (tok->hasKnownIntValue())
1619  continue;
1620  const Token* indexTok = nullptr;
1621  const Token* arrayTok = nullptr;
1622  if (Token::simpleMatch(tok, "[") && tok->isBinaryOp()) {
1623  indexTok = tok->astOperand2();
1624  arrayTok = tok->astOperand1();
1625  } else if (Token::Match(tok->tokAt(-2), ". %name% (") && astIsContainer(tok->tokAt(-2)->astOperand1())) {
1626  arrayTok = tok->tokAt(-2)->astOperand1();
1627  const Library::Container* container = getLibraryContainer(arrayTok);
1628  if (!container || container->stdAssociativeLike)
1629  continue;
1630  const Library::Container::Yield yield = container->getYield(tok->strAt(-1));
1632  continue;
1633  indexTok = tok->astOperand2();
1634  }
1635 
1636  if (!indexTok || !arrayTok)
1637  continue;
1638 
1639  for (const ValueFlow::Value& arrayValue : arrayTok->values()) {
1640  if (!arrayValue.isTokValue())
1641  continue;
1642  if (arrayValue.isImpossible())
1643  continue;
1644  for (const ValueFlow::Value& indexValue : indexTok->values()) {
1645  if (!indexValue.isIntValue())
1646  continue;
1647  if (indexValue.isImpossible())
1648  continue;
1649  if (!arrayValue.isKnown() && !indexValue.isKnown() && arrayValue.varId != 0 && indexValue.varId != 0 &&
1650  !(arrayValue.varId == indexValue.varId && arrayValue.varvalue == indexValue.varvalue))
1651  continue;
1652 
1653  ValueFlow::Value result(0);
1654  result.condition = arrayValue.condition ? arrayValue.condition : indexValue.condition;
1655  result.setInconclusive(arrayValue.isInconclusive() || indexValue.isInconclusive());
1656  result.varId = (arrayValue.varId != 0) ? arrayValue.varId : indexValue.varId;
1657  result.varvalue = (result.varId == arrayValue.varId) ? arrayValue.intvalue : indexValue.intvalue;
1658  if (arrayValue.valueKind == indexValue.valueKind)
1659  result.valueKind = arrayValue.valueKind;
1660 
1661  result.errorPath.insert(result.errorPath.end(), arrayValue.errorPath.cbegin(), arrayValue.errorPath.cend());
1662  result.errorPath.insert(result.errorPath.end(), indexValue.errorPath.cbegin(), indexValue.errorPath.cend());
1663 
1664  const MathLib::bigint index = indexValue.intvalue;
1665 
1666  if (arrayValue.tokvalue->tokType() == Token::eString) {
1667  const std::string s = arrayValue.tokvalue->strValue();
1668  if (index == s.size()) {
1669  result.intvalue = 0;
1670  setTokenValue(tok, std::move(result), settings);
1671  } else if (index >= 0 && index < s.size()) {
1672  result.intvalue = s[index];
1673  setTokenValue(tok, std::move(result), settings);
1674  }
1675  } else if (Token::simpleMatch(arrayValue.tokvalue, "{")) {
1676  std::vector<const Token*> args = getArguments(arrayValue.tokvalue);
1677  if (index < 0 || index >= args.size())
1678  continue;
1679  const Token* arg = args[index];
1680  if (!arg->hasKnownIntValue())
1681  continue;
1682  const ValueFlow::Value& v = arg->values().front();
1683  result.intvalue = v.intvalue;
1684  result.errorPath.insert(result.errorPath.end(), v.errorPath.cbegin(), v.errorPath.cend());
1685  setTokenValue(tok, std::move(result), settings);
1686  }
1687  }
1688  }
1689  }
1690 }
1691 
1692 static void valueFlowPointerAlias(TokenList &tokenlist, const Settings& settings)
1693 {
1694  for (Token *tok = tokenlist.front(); tok; tok = tok->next()) {
1695  // not address of
1696  if (!tok->isUnaryOp("&"))
1697  continue;
1698 
1699  // parent should be a '='
1700  if (!Token::simpleMatch(tok->astParent(), "="))
1701  continue;
1702 
1703  // child should be some buffer or variable
1704  const Token *vartok = tok->astOperand1();
1705  while (vartok) {
1706  if (vartok->str() == "[")
1707  vartok = vartok->astOperand1();
1708  else if (vartok->str() == "." || vartok->str() == "::")
1709  vartok = vartok->astOperand2();
1710  else
1711  break;
1712  }
1713  if (!(vartok && vartok->variable() && !vartok->variable()->isPointer()))
1714  continue;
1715 
1716  ValueFlow::Value value;
1718  value.tokvalue = tok;
1719  setTokenValue(tok, std::move(value), settings);
1720  }
1721 }
1722 
1723 static void valueFlowBitAnd(TokenList &tokenlist, const Settings& settings)
1724 {
1725  for (Token *tok = tokenlist.front(); tok; tok = tok->next()) {
1726  if (tok->str() != "&")
1727  continue;
1728 
1729  if (tok->hasKnownValue())
1730  continue;
1731 
1732  if (!tok->astOperand1() || !tok->astOperand2())
1733  continue;
1734 
1735  MathLib::bigint number;
1736  if (MathLib::isInt(tok->astOperand1()->str()))
1737  number = MathLib::toBigNumber(tok->astOperand1()->str());
1738  else if (MathLib::isInt(tok->astOperand2()->str()))
1739  number = MathLib::toBigNumber(tok->astOperand2()->str());
1740  else
1741  continue;
1742 
1743  int bit = 0;
1744  while (bit <= (MathLib::bigint_bits - 2) && ((((MathLib::bigint)1) << bit) < number))
1745  ++bit;
1746 
1747  if ((((MathLib::bigint)1) << bit) == number) {
1748  setTokenValue(tok, ValueFlow::Value(0), settings);
1749  setTokenValue(tok, ValueFlow::Value(number), settings);
1750  }
1751  }
1752 }
1753 
1754 static void valueFlowSameExpressions(TokenList &tokenlist, const Settings& settings)
1755 {
1756  for (Token *tok = tokenlist.front(); tok; tok = tok->next()) {
1757  if (tok->hasKnownIntValue())
1758  continue;
1759 
1760  if (!tok->astOperand1() || !tok->astOperand2())
1761  continue;
1762 
1763  if (tok->astOperand1()->isLiteral() || tok->astOperand2()->isLiteral())
1764  continue;
1765 
1766  if (!astIsIntegral(tok->astOperand1(), false) && !astIsIntegral(tok->astOperand2(), false))
1767  continue;
1768 
1769  ValueFlow::Value val;
1770 
1771  if (Token::Match(tok, "==|>=|<=|/")) {
1772  val = ValueFlow::Value(1);
1773  val.setKnown();
1774  }
1775 
1776  if (Token::Match(tok, "!=|>|<|%|-")) {
1777  val = ValueFlow::Value(0);
1778  val.setKnown();
1779  }
1780 
1781  if (!val.isKnown())
1782  continue;
1783 
1784  if (isSameExpression(false, tok->astOperand1(), tok->astOperand2(), settings, true, true, &val.errorPath)) {
1785  setTokenValue(tok, std::move(val), settings);
1786  }
1787  }
1788 }
1789 
1790 static bool getExpressionRange(const Token *expr, MathLib::bigint *minvalue, MathLib::bigint *maxvalue)
1791 {
1792  if (expr->hasKnownIntValue()) {
1793  if (minvalue)
1794  *minvalue = expr->values().front().intvalue;
1795  if (maxvalue)
1796  *maxvalue = expr->values().front().intvalue;
1797  return true;
1798  }
1799 
1800  if (expr->str() == "&" && expr->astOperand1() && expr->astOperand2()) {
1801  MathLib::bigint vals[4];
1802  const bool lhsHasKnownRange = getExpressionRange(expr->astOperand1(), &vals[0], &vals[1]);
1803  const bool rhsHasKnownRange = getExpressionRange(expr->astOperand2(), &vals[2], &vals[3]);
1804  if (!lhsHasKnownRange && !rhsHasKnownRange)
1805  return false;
1806  if (!lhsHasKnownRange || !rhsHasKnownRange) {
1807  if (minvalue)
1808  *minvalue = lhsHasKnownRange ? vals[0] : vals[2];
1809  if (maxvalue)
1810  *maxvalue = lhsHasKnownRange ? vals[1] : vals[3];
1811  } else {
1812  if (minvalue)
1813  *minvalue = vals[0] & vals[2];
1814  if (maxvalue)
1815  *maxvalue = vals[1] & vals[3];
1816  }
1817  return true;
1818  }
1819 
1820  if (expr->str() == "%" && expr->astOperand1() && expr->astOperand2()) {
1821  MathLib::bigint vals[4];
1822  if (!getExpressionRange(expr->astOperand2(), &vals[2], &vals[3]))
1823  return false;
1824  if (vals[2] <= 0)
1825  return false;
1826  const bool lhsHasKnownRange = getExpressionRange(expr->astOperand1(), &vals[0], &vals[1]);
1827  if (lhsHasKnownRange && vals[0] < 0)
1828  return false;
1829  // If lhs has unknown value, it must be unsigned
1830  if (!lhsHasKnownRange && (!expr->astOperand1()->valueType() || expr->astOperand1()->valueType()->sign != ValueType::Sign::UNSIGNED))
1831  return false;
1832  if (minvalue)
1833  *minvalue = 0;
1834  if (maxvalue)
1835  *maxvalue = vals[3] - 1;
1836  return true;
1837  }
1838 
1839  return false;
1840 }
1841 
1842 static void valueFlowRightShift(TokenList &tokenList, const Settings& settings)
1843 {
1844  for (Token *tok = tokenList.front(); tok; tok = tok->next()) {
1845  if (tok->str() != ">>")
1846  continue;
1847 
1848  if (tok->hasKnownValue())
1849  continue;
1850 
1851  if (!tok->astOperand1() || !tok->astOperand2())
1852  continue;
1853 
1854  if (!tok->astOperand2()->hasKnownValue())
1855  continue;
1856 
1857  const MathLib::bigint rhsvalue = tok->astOperand2()->values().front().intvalue;
1858  if (rhsvalue < 0)
1859  continue;
1860 
1861  if (!tok->astOperand1()->valueType() || !tok->astOperand1()->valueType()->isIntegral())
1862  continue;
1863 
1864  if (!tok->astOperand2()->valueType() || !tok->astOperand2()->valueType()->isIntegral())
1865  continue;
1866 
1867  MathLib::bigint lhsmax=0;
1868  if (!getExpressionRange(tok->astOperand1(), nullptr, &lhsmax))
1869  continue;
1870  if (lhsmax < 0)
1871  continue;
1872  int lhsbits;
1873  if ((tok->astOperand1()->valueType()->type == ValueType::Type::CHAR) ||
1874  (tok->astOperand1()->valueType()->type == ValueType::Type::SHORT) ||
1875  (tok->astOperand1()->valueType()->type == ValueType::Type::WCHAR_T) ||
1876  (tok->astOperand1()->valueType()->type == ValueType::Type::BOOL) ||
1877  (tok->astOperand1()->valueType()->type == ValueType::Type::INT))
1878  lhsbits = settings.platform.int_bit;
1879  else if (tok->astOperand1()->valueType()->type == ValueType::Type::LONG)
1880  lhsbits = settings.platform.long_bit;
1881  else if (tok->astOperand1()->valueType()->type == ValueType::Type::LONGLONG)
1882  lhsbits = settings.platform.long_long_bit;
1883  else
1884  continue;
1885  if (rhsvalue >= lhsbits || rhsvalue >= MathLib::bigint_bits || (1ULL << rhsvalue) <= lhsmax)
1886  continue;
1887 
1888  ValueFlow::Value val(0);
1889  val.setKnown();
1890  setTokenValue(tok, std::move(val), settings);
1891  }
1892 }
1893 
1894 static std::vector<MathLib::bigint> minUnsignedValue(const Token* tok, int depth = 8)
1895 {
1896  std::vector<MathLib::bigint> result;
1897  if (!tok)
1898  return result;
1899  if (depth < 0)
1900  return result;
1901  if (tok->hasKnownIntValue()) {
1902  result = {tok->values().front().intvalue};
1903  } else if (!Token::Match(tok, "-|%|&|^") && tok->isConstOp() && tok->astOperand1() && tok->astOperand2()) {
1904  std::vector<MathLib::bigint> op1 = minUnsignedValue(tok->astOperand1(), depth - 1);
1905  std::vector<MathLib::bigint> op2 = minUnsignedValue(tok->astOperand2(), depth - 1);
1906  if (!op1.empty() && !op2.empty()) {
1907  result = calculate<std::vector<MathLib::bigint>>(tok->str(), op1.front(), op2.front());
1908  }
1909  }
1910  if (result.empty() && astIsUnsigned(tok))
1911  result = {0};
1912  return result;
1913 }
1914 
1915 static bool isConvertedToIntegral(const Token* tok, const Settings& settings)
1916 {
1917  if (!tok)
1918  return false;
1919  std::vector<ValueType> parentTypes = getParentValueTypes(tok, settings);
1920  if (parentTypes.empty())
1921  return false;
1922  const ValueType& vt = parentTypes.front();
1923  return vt.type != ValueType::UNKNOWN_INT && vt.isIntegral();
1924 }
1925 
1926 static bool isSameToken(const Token* tok1, const Token* tok2)
1927 {
1928  if (!tok1 || !tok2)
1929  return false;
1930  if (tok1->exprId() != 0 && tok1->exprId() == tok2->exprId())
1931  return true;
1932  if (tok1->hasKnownIntValue() && tok2->hasKnownIntValue())
1933  return tok1->values().front().intvalue == tok2->values().front().intvalue;
1934  return false;
1935 }
1936 
1937 static void valueFlowImpossibleValues(TokenList& tokenList, const Settings& settings)
1938 {
1939  for (Token* tok = tokenList.front(); tok; tok = tok->next()) {
1940  if (tok->hasKnownIntValue())
1941  continue;
1942  if (Token::Match(tok, "true|false"))
1943  continue;
1944  if (astIsBool(tok) || Token::Match(tok, "%comp%")) {
1945  ValueFlow::Value lower{-1};
1947  lower.setImpossible();
1948  setTokenValue(tok, std::move(lower), settings);
1949 
1950  ValueFlow::Value upper{2};
1952  upper.setImpossible();
1953  setTokenValue(tok, std::move(upper), settings);
1954  } else if (astIsUnsigned(tok) && !astIsPointer(tok)) {
1955  std::vector<MathLib::bigint> minvalue = minUnsignedValue(tok);
1956  if (minvalue.empty())
1957  continue;
1958  ValueFlow::Value value{std::max<MathLib::bigint>(0, minvalue.front()) - 1};
1960  value.setImpossible();
1961  setTokenValue(tok, std::move(value), settings);
1962  }
1963  if (Token::simpleMatch(tok, "?") && Token::Match(tok->astOperand1(), "<|<=|>|>=")) {
1964  const Token* condTok = tok->astOperand1();
1965  const Token* branchesTok = tok->astOperand2();
1966 
1967  auto tokens = makeArray(condTok->astOperand1(), condTok->astOperand2());
1968  auto branches = makeArray(branchesTok->astOperand1(), branchesTok->astOperand2());
1969  bool flipped = false;
1970  if (std::equal(tokens.cbegin(), tokens.cend(), branches.crbegin(), &isSameToken))
1971  flipped = true;
1972  else if (!std::equal(tokens.cbegin(), tokens.cend(), branches.cbegin(), &isSameToken))
1973  continue;
1974  const bool isMin = Token::Match(condTok, "<|<=") ^ flipped;
1975  std::vector<ValueFlow::Value> values;
1976  for (const Token* tok2 : tokens) {
1977  if (tok2->hasKnownIntValue()) {
1978  values.emplace_back(tok2->values().front());
1979  } else {
1980  ValueFlow::Value symValue{};
1982  symValue.tokvalue = tok2;
1983  values.push_back(symValue);
1984  std::copy_if(tok2->values().cbegin(),
1985  tok2->values().cend(),
1986  std::back_inserter(values),
1987  [](const ValueFlow::Value& v) {
1988  if (!v.isKnown())
1989  return false;
1990  return v.isSymbolicValue();
1991  });
1992  }
1993  }
1994  for (ValueFlow::Value& value : values) {
1995  value.setImpossible();
1996  if (isMin) {
1997  value.intvalue++;
1999  } else {
2000  value.intvalue--;
2002  }
2003  setTokenValue(tok, std::move(value), settings);
2004  }
2005 
2006  } else if (Token::simpleMatch(tok, "%") && tok->astOperand2() && tok->astOperand2()->hasKnownIntValue()) {
2007  ValueFlow::Value value{tok->astOperand2()->values().front()};
2009  value.setImpossible();
2010  setTokenValue(tok, std::move(value), settings);
2011  } else if (Token::Match(tok, "abs|labs|llabs|fabs|fabsf|fabsl (")) {
2012  ValueFlow::Value value{-1};
2014  value.setImpossible();
2015  setTokenValue(tok->next(), std::move(value), settings);
2016  } else if (Token::Match(tok, ". data|c_str (") && astIsContainerOwned(tok->astOperand1())) {
2017  const Library::Container* container = getLibraryContainer(tok->astOperand1());
2018  if (!container)
2019  continue;
2020  if (!container->stdStringLike)
2021  continue;
2022  if (container->view)
2023  continue;
2024  ValueFlow::Value value{0};
2025  value.setImpossible();
2026  setTokenValue(tok->tokAt(2), std::move(value), settings);
2027  } else if (Token::Match(tok, "make_shared|make_unique <") && Token::simpleMatch(tok->linkAt(1), "> (")) {
2028  ValueFlow::Value value{0};
2029  value.setImpossible();
2030  setTokenValue(tok->linkAt(1)->next(), std::move(value), settings);
2031  } else if ((tokenList.isCPP() && Token::simpleMatch(tok, "this")) || tok->isUnaryOp("&")) {
2032  ValueFlow::Value value{0};
2033  value.setImpossible();
2034  setTokenValue(tok, std::move(value), settings);
2035  } else if (tok->isIncompleteVar() && tok->astParent() && tok->astParent()->isUnaryOp("-") &&
2036  isConvertedToIntegral(tok->astParent(), settings)) {
2037  ValueFlow::Value value{0};
2038  value.setImpossible();
2039  setTokenValue(tok, std::move(value), settings);
2040  }
2041  }
2042 }
2043 
2044 static void valueFlowEnumValue(SymbolDatabase & symboldatabase, const Settings & settings)
2045 {
2046  for (Scope & scope : symboldatabase.scopeList) {
2047  if (scope.type != Scope::eEnum)
2048  continue;
2049  MathLib::bigint value = 0;
2050  bool prev_enum_is_known = true;
2051 
2052  for (Enumerator & enumerator : scope.enumeratorList) {
2053  if (enumerator.start) {
2054  Token* rhs = const_cast<Token*>(enumerator.start->previous()->astOperand2());
2055  ValueFlow::valueFlowConstantFoldAST(rhs, settings);
2056  if (rhs && rhs->hasKnownIntValue()) {
2057  enumerator.value = rhs->values().front().intvalue;
2058  enumerator.value_known = true;
2059  value = enumerator.value + 1;
2060  prev_enum_is_known = true;
2061  } else
2062  prev_enum_is_known = false;
2063  } else if (prev_enum_is_known) {
2064  enumerator.value = value++;
2065  enumerator.value_known = true;
2066  }
2067  }
2068  }
2069 }
2070 
2071 static void valueFlowGlobalConstVar(TokenList& tokenList, const Settings &settings)
2072 {
2073  // Get variable values...
2074  std::map<const Variable*, ValueFlow::Value> vars;
2075  for (const Token* tok = tokenList.front(); tok; tok = tok->next()) {
2076  if (!tok->variable())
2077  continue;
2078  // Initialization...
2079  if (tok == tok->variable()->nameToken() &&
2080  !tok->variable()->isVolatile() &&
2081  !tok->variable()->isArgument() &&
2082  tok->variable()->isConst() &&
2083  tok->valueType() &&
2084  tok->valueType()->isIntegral() &&
2085  tok->valueType()->pointer == 0 &&
2086  tok->valueType()->constness == 1 &&
2087  Token::Match(tok, "%name% =") &&
2088  tok->next()->astOperand2() &&
2089  tok->next()->astOperand2()->hasKnownIntValue()) {
2090  vars[tok->variable()] = tok->next()->astOperand2()->values().front();
2091  }
2092  }
2093 
2094  // Set values..
2095  for (Token* tok = tokenList.front(); tok; tok = tok->next()) {
2096  if (!tok->variable())
2097  continue;
2098  const std::map<const Variable*, ValueFlow::Value>::const_iterator var = vars.find(tok->variable());
2099  if (var == vars.end())
2100  continue;
2101  setTokenValue(tok, var->second, settings);
2102  }
2103 }
2104 
2105 static void valueFlowGlobalStaticVar(TokenList &tokenList, const Settings &settings)
2106 {
2107  // Get variable values...
2108  std::map<const Variable *, ValueFlow::Value> vars;
2109  for (const Token *tok = tokenList.front(); tok; tok = tok->next()) {
2110  if (!tok->variable())
2111  continue;
2112  // Initialization...
2113  if (tok == tok->variable()->nameToken() &&
2114  tok->variable()->isStatic() &&
2115  !tok->variable()->isConst() &&
2116  tok->valueType() &&
2117  tok->valueType()->isIntegral() &&
2118  tok->valueType()->pointer == 0 &&
2119  tok->valueType()->constness == 0 &&
2120  Token::Match(tok, "%name% =") &&
2121  tok->next()->astOperand2() &&
2122  tok->next()->astOperand2()->hasKnownIntValue()) {
2123  vars[tok->variable()] = tok->next()->astOperand2()->values().front();
2124  } else {
2125  // If variable is written anywhere in TU then remove it from vars
2126  if (!tok->astParent())
2127  continue;
2128  if (Token::Match(tok->astParent(), "++|--|&") && !tok->astParent()->astOperand2())
2129  vars.erase(tok->variable());
2130  else if (tok->astParent()->isAssignmentOp()) {
2131  if (tok == tok->astParent()->astOperand1())
2132  vars.erase(tok->variable());
2133  else if (tok->isCpp() && Token::Match(tok->astParent()->tokAt(-2), "& %name% ="))
2134  vars.erase(tok->variable());
2135  } else if (isLikelyStreamRead(tok->astParent())) {
2136  vars.erase(tok->variable());
2137  } else if (Token::Match(tok->astParent(), "[(,]"))
2138  vars.erase(tok->variable());
2139  }
2140  }
2141 
2142  // Set values..
2143  for (Token *tok = tokenList.front(); tok; tok = tok->next()) {
2144  if (!tok->variable())
2145  continue;
2146  const std::map<const Variable *, ValueFlow::Value>::const_iterator var = vars.find(tok->variable());
2147  if (var == vars.end())
2148  continue;
2149  setTokenValue(tok, var->second, settings);
2150  }
2151 }
2152 
2153 static ValuePtr<Analyzer> makeAnalyzer(const Token* exprTok, ValueFlow::Value value, const TokenList& tokenlist, const Settings& settings);
2154 static ValuePtr<Analyzer> makeReverseAnalyzer(const Token* exprTok, ValueFlow::Value value, const TokenList& tokenlist, const Settings& settings);
2155 
2157  const Token* endToken,
2158  const Token* exprTok,
2159  ValueFlow::Value value,
2160  const TokenList& tokenlist,
2161  ErrorLogger& errorLogger,
2162  const Settings& settings,
2164 {
2165  if (settings.debugnormal)
2166  setSourceLocation(value, loc, startToken);
2167  return valueFlowGenericForward(startToken,
2168  endToken,
2169  makeAnalyzer(exprTok, std::move(value), tokenlist, settings),
2170  tokenlist,
2171  errorLogger,
2172  settings);
2173 }
2174 
2176  const Token* endToken,
2177  const Token* exprTok,
2178  std::list<ValueFlow::Value> values,
2179  const TokenList& tokenlist,
2180  ErrorLogger& errorLogger,
2181  const Settings& settings,
2183 {
2184  Analyzer::Result result{};
2185  for (ValueFlow::Value& v : values) {
2186  result.update(valueFlowForward(startToken, endToken, exprTok, std::move(v), tokenlist, errorLogger, settings, loc));
2187  }
2188  return result;
2189 }
2190 
2191 template<class ValueOrValues>
2193  const Token* exprTok,
2194  ValueOrValues v,
2195  const TokenList& tokenlist,
2196  ErrorLogger& errorLogger,
2197  const Settings& settings,
2199 {
2200  const Token* endToken = nullptr;
2201  const Function* f = Scope::nestedInFunction(startToken->scope());
2202  if (f && f->functionScope)
2203  endToken = f->functionScope->bodyEnd;
2204  return valueFlowForward(startToken, endToken, exprTok, std::move(v), tokenlist, errorLogger, settings, loc);
2205 }
2206 
2208  const Token* exprTok,
2209  std::list<ValueFlow::Value> values,
2210  const TokenList& tokenlist,
2211  ErrorLogger& errorLogger,
2212  const Settings& settings,
2214 {
2215  Analyzer::Result result{};
2216  for (ValueFlow::Value& v : values) {
2217  if (settings.debugnormal)
2218  setSourceLocation(v, loc, top);
2219  result.update(
2220  valueFlowGenericForward(top, makeAnalyzer(exprTok, std::move(v), tokenlist, settings), tokenlist, errorLogger, settings));
2221  }
2222  return result;
2223 }
2224 
2225 static void valueFlowReverse(Token* tok,
2226  const Token* const endToken,
2227  const Token* const varToken,
2228  std::list<ValueFlow::Value> values,
2229  const TokenList& tokenlist,
2230  ErrorLogger& errorLogger,
2231  const Settings& settings,
2233 {
2234  for (ValueFlow::Value& v : values) {
2235  if (settings.debugnormal)
2236  setSourceLocation(v, loc, tok);
2237  valueFlowGenericReverse(tok, endToken, makeReverseAnalyzer(varToken, std::move(v), tokenlist, settings), tokenlist, errorLogger, settings);
2238  }
2239 }
2240 
2241 // Deprecated
2242 static void valueFlowReverse(const TokenList& tokenlist,
2243  Token* tok,
2244  const Token* const varToken,
2245  ValueFlow::Value val,
2246  ErrorLogger& errorLogger,
2247  const Settings& settings,
2249 {
2250  valueFlowReverse(tok, nullptr, varToken, {std::move(val)}, tokenlist, errorLogger, settings, loc);
2251 }
2252 
2253 static bool isConditionKnown(const Token* tok, bool then)
2254 {
2255  const char* op = "||";
2256  if (then)
2257  op = "&&";
2258  const Token* parent = tok->astParent();
2259  while (parent && (parent->str() == op || parent->str() == "!" || parent->isCast()))
2260  parent = parent->astParent();
2261  const Token* top = tok->astTop();
2262  if (top && Token::Match(top->previous(), "if|while|for ("))
2263  return parent == top || Token::simpleMatch(parent, ";");
2264  return parent && parent->str() != op;
2265 }
2266 
2267 static const std::string& invertAssign(const std::string& assign)
2268 {
2269  static std::unordered_map<std::string, std::string> lookup = {{"=", "="},
2270  {"+=", "-="},
2271  {"-=", "+="},
2272  {"*=", "/="},
2273  {"/=", "*="},
2274  {"<<=", ">>="},
2275  {">>=", "<<="},
2276  {"^=", "^="}};
2277  auto it = lookup.find(assign);
2278  if (it == lookup.end()) {
2279  return emptyString;
2280  }
2281  return it->second;
2282 }
2283 
2284 static std::string removeAssign(const std::string& assign) {
2285  return std::string{assign.cbegin(), assign.cend() - 1};
2286 }
2287 
2288 template<class T, class U>
2289 static T calculateAssign(const std::string& assign, const T& x, const U& y, bool* error = nullptr)
2290 {
2291  if (assign.empty() || assign.back() != '=') {
2292  if (error)
2293  *error = true;
2294  return T{};
2295  }
2296  if (assign == "=")
2297  return y;
2298  return calculate<T, T>(removeAssign(assign), x, y, error);
2299 }
2300 
2301 template<class T, class U>
2302 static void assignValueIfMutable(T& x, const U& y)
2303 {
2304  x = y;
2305 }
2306 
2307 template<class T, class U>
2308 static void assignValueIfMutable(const T& /*unused*/, const U& /*unused*/)
2309 {}
2310 
2311 template<class Value, REQUIRES("Value must ValueFlow::Value", std::is_convertible<Value&, const ValueFlow::Value&> )>
2312 static bool evalAssignment(Value& lhsValue, const std::string& assign, const ValueFlow::Value& rhsValue)
2313 {
2314  bool error = false;
2315  if (lhsValue.isSymbolicValue() && rhsValue.isIntValue()) {
2316  if (assign != "+=" && assign != "-=")
2317  return false;
2318  assignValueIfMutable(lhsValue.intvalue, calculateAssign(assign, lhsValue.intvalue, rhsValue.intvalue, &error));
2319  } else if (lhsValue.isIntValue() && rhsValue.isIntValue()) {
2320  assignValueIfMutable(lhsValue.intvalue, calculateAssign(assign, lhsValue.intvalue, rhsValue.intvalue, &error));
2321  } else if (lhsValue.isFloatValue() && rhsValue.isIntValue()) {
2322  assignValueIfMutable(lhsValue.floatValue,
2323  calculateAssign(assign, lhsValue.floatValue, rhsValue.intvalue, &error));
2324  } else {
2325  return false;
2326  }
2327  return !error;
2328 }
2329 
2331 {
2332  if (!tok)
2334  const Token* parent = tok->astParent();
2335  if (!Token::simpleMatch(parent, "("))
2337  const Token* ftok = parent->astOperand1();
2338  if (!ftok)
2340  if (Token::simpleMatch(ftok->astOperand1(), "std :: move"))
2342  if (Token::simpleMatch(ftok->astOperand1(), "std :: forward"))
2344  // TODO: Check for cast
2346 }
2347 
2348 template<class T>
2349 struct SingleRange {
2350  T* x;
2351  T* begin() const {
2352  return x;
2353  }
2354  T* end() const {
2355  return x+1;
2356  }
2357 };
2358 
2359 template<class T>
2361 {
2362  return {&x};
2363 }
2364 
2366  using M = std::unordered_map<nonneg int, ValueFlow::Value>;
2367 
2368  struct Iterator {
2369  using iterator_category = std::forward_iterator_tag;
2371  using pointer = value_type *;
2373  using difference_type = std::ptrdiff_t;
2374 
2375  explicit Iterator(const M::const_iterator & it)
2376  : mIt(it) {}
2377 
2379  return mIt->second;
2380  }
2381 
2383  return &mIt->second;
2384  }
2385 
2387  // cppcheck-suppress postfixOperator - forward iterator needs to perform post-increment
2388  mIt++;
2389  return *this;
2390  }
2391 
2392  friend bool operator==(const Iterator &a, const Iterator &b) {
2393  return a.mIt == b.mIt;
2394  }
2395 
2396  friend bool operator!=(const Iterator &a, const Iterator &b) {
2397  return a.mIt != b.mIt;
2398  }
2399 
2400  private:
2401  M::const_iterator mIt;
2402  };
2403 
2404 public:
2405  explicit SelectValueFromVarIdMapRange(const M *m)
2406  : mMap(m) {}
2407 
2408  Iterator begin() const {
2409  return Iterator(mMap->begin());
2410  }
2411  Iterator end() const {
2412  return Iterator(mMap->end());
2413  }
2414 
2415 private:
2416  const M *mMap;
2417 };
2418 
2419 // Check if its an alias of the variable or is being aliased to this variable
2420 template<typename V>
2421 static bool isAliasOf(const Variable * var, const Token *tok, nonneg int varid, const V& values, bool* inconclusive = nullptr)
2422 {
2423  if (tok->varId() == varid)
2424  return false;
2425  if (tok->varId() == 0)
2426  return false;
2427  if (isAliasOf(tok, varid, inconclusive))
2428  return true;
2429  if (var && !var->isPointer())
2430  return false;
2431  // Search through non value aliases
2432  return std::any_of(values.begin(), values.end(), [&](const ValueFlow::Value& val) {
2433  if (!val.isNonValue())
2434  return false;
2435  if (val.isInconclusive())
2436  return false;
2437  if (val.isLifetimeValue() && !val.isLocalLifetimeValue())
2438  return false;
2439  if (val.isLifetimeValue() && val.lifetimeKind != ValueFlow::Value::LifetimeKind::Address)
2440  return false;
2441  if (!Token::Match(val.tokvalue, ".|&|*|%var%"))
2442  return false;
2443  return astHasVar(val.tokvalue, tok->varId());
2444  });
2445 }
2446 
2447 static bool bifurcate(const Token* tok, const std::set<nonneg int>& varids, const Settings& settings, int depth = 20);
2448 
2449 static bool bifurcateVariableChanged(const Variable* var,
2450  const std::set<nonneg int>& varids,
2451  const Token* start,
2452  const Token* end,
2453  const Settings& settings,
2454  int depth = 20)
2455 {
2456  bool result = false;
2457  const Token* tok = start;
2458  while ((tok = findVariableChanged(
2459  tok->next(), end, var->isPointer(), var->declarationId(), var->isGlobal(), settings))) {
2460  if (Token::Match(tok->astParent(), "%assign%")) {
2461  if (!bifurcate(tok->astParent()->astOperand2(), varids, settings, depth - 1))
2462  return true;
2463  } else {
2464  result = true;
2465  }
2466  }
2467  return result;
2468 }
2469 
2470 static bool bifurcate(const Token* tok, const std::set<nonneg int>& varids, const Settings& settings, int depth)
2471 {
2472  if (depth < 0)
2473  return false;
2474  if (!tok)
2475  return true;
2476  if (tok->hasKnownIntValue())
2477  return true;
2478  if (tok->isConstOp())
2479  return bifurcate(tok->astOperand1(), varids, settings, depth) && bifurcate(tok->astOperand2(), varids, settings, depth);
2480  if (tok->varId() != 0) {
2481  if (varids.count(tok->varId()) > 0)
2482  return true;
2483  const Variable* var = tok->variable();
2484  if (!var)
2485  return false;
2486  const Token* start = var->declEndToken();
2487  if (!start)
2488  return false;
2489  if (start->strAt(-1) == ")" || start->strAt(-1) == "}")
2490  return false;
2491  if (Token::Match(start, "; %varid% =", var->declarationId()))
2492  start = start->tokAt(2);
2493  if (var->isConst() || !bifurcateVariableChanged(var, varids, start, tok, settings, depth))
2494  return var->isArgument() || bifurcate(start->astOperand2(), varids, settings, depth - 1);
2495  return false;
2496  }
2497  return false;
2498 }
2499 
2504 
2505  explicit ValueFlowAnalyzer(const TokenList& t, const Settings& s) : tokenlist(t), settings(s), pms(&settings) {}
2506 
2507  virtual const ValueFlow::Value* getValue(const Token* tok) const = 0;
2508  virtual ValueFlow::Value* getValue(const Token* tok) = 0;
2509 
2510  virtual void makeConditional() = 0;
2511 
2512  virtual void addErrorPath(const Token* tok, const std::string& s) = 0;
2513 
2514  virtual bool match(const Token* tok) const = 0;
2515 
2516  virtual bool internalMatch(const Token* /*tok*/) const {
2517  return false;
2518  }
2519 
2520  virtual bool isAlias(const Token* tok, bool& inconclusive) const = 0;
2521 
2523 
2524  virtual ProgramState getProgramState() const = 0;
2525 
2526  virtual int getIndirect(const Token* tok) const {
2527  const ValueFlow::Value* value = getValue(tok);
2528  if (value)
2529  return value->indirect;
2530  return 0;
2531  }
2532 
2533  virtual bool isGlobal() const {
2534  return false;
2535  }
2536  virtual bool dependsOnThis() const {
2537  return false;
2538  }
2539  virtual bool isVariable() const {
2540  return false;
2541  }
2542 
2543  bool isCPP() const {
2544  return tokenlist.isCPP();
2545  }
2546 
2547  const Settings& getSettings() const {
2548  return settings;
2549  }
2550 
2551  // Returns Action::Match if its an exact match, return Action::Read if it partially matches the lifetime
2552  Action analyzeLifetime(const Token* tok) const
2553  {
2554  if (!tok)
2555  return Action::None;
2556  if (match(tok))
2557  return Action::Match;
2558  if (Token::simpleMatch(tok, ".") && analyzeLifetime(tok->astOperand1()) != Action::None)
2559  return Action::Read;
2560  if (astIsRHS(tok) && Token::simpleMatch(tok->astParent(), "."))
2561  return analyzeLifetime(tok->astParent());
2562  return Action::None;
2563  }
2564 
2566  bool dependent = true;
2567  bool unknown = true;
2568 
2569  bool isUnknownDependent() const {
2570  return unknown && dependent;
2571  }
2572  };
2573 
2574  std::unordered_map<nonneg int, const Token*> getSymbols(const Token* tok) const
2575  {
2576  std::unordered_map<nonneg int, const Token*> result;
2577  if (!tok)
2578  return result;
2579  for (const ValueFlow::Value& v : tok->values()) {
2580  if (!v.isSymbolicValue())
2581  continue;
2582  if (v.isImpossible())
2583  continue;
2584  if (!v.tokvalue)
2585  continue;
2586  if (v.tokvalue->exprId() == 0)
2587  continue;
2588  if (match(v.tokvalue))
2589  continue;
2590  result[v.tokvalue->exprId()] = v.tokvalue;
2591  }
2592  return result;
2593  }
2594 
2595  ConditionState analyzeCondition(const Token* tok, int depth = 20) const
2596  {
2597  ConditionState result;
2598  if (!tok)
2599  return result;
2600  if (depth < 0)
2601  return result;
2602  depth--;
2603  if (analyze(tok, Direction::Forward).isRead()) {
2604  result.dependent = true;
2605  result.unknown = false;
2606  return result;
2607  }
2608  if (tok->hasKnownIntValue() || tok->isLiteral()) {
2609  result.dependent = false;
2610  result.unknown = false;
2611  return result;
2612  }
2613  if (Token::Match(tok, "%cop%")) {
2614  if (isLikelyStream(tok->astOperand1())) {
2615  result.dependent = false;
2616  return result;
2617  }
2618  ConditionState lhs = analyzeCondition(tok->astOperand1(), depth - 1);
2619  if (lhs.isUnknownDependent())
2620  return lhs;
2621  ConditionState rhs = analyzeCondition(tok->astOperand2(), depth - 1);
2622  if (rhs.isUnknownDependent())
2623  return rhs;
2624  if (Token::Match(tok, "%comp%"))
2625  result.dependent = lhs.dependent && rhs.dependent;
2626  else
2627  result.dependent = lhs.dependent || rhs.dependent;
2628  result.unknown = lhs.unknown || rhs.unknown;
2629  return result;
2630  }
2631  if (Token::Match(tok->previous(), "%name% (")) {
2632  std::vector<const Token*> args = getArguments(tok->previous());
2633  if (Token::Match(tok->tokAt(-2), ". %name% (")) {
2634  args.push_back(tok->tokAt(-2)->astOperand1());
2635  }
2636  result.dependent = std::any_of(args.cbegin(), args.cend(), [&](const Token* arg) {
2637  ConditionState cs = analyzeCondition(arg, depth - 1);
2638  return cs.dependent;
2639  });
2640  if (result.dependent) {
2641  // Check if we can evaluate the function
2642  if (!evaluate(Evaluate::Integral, tok).empty())
2643  result.unknown = false;
2644  }
2645  return result;
2646  }
2647 
2648  std::unordered_map<nonneg int, const Token*> symbols = getSymbols(tok);
2649  result.dependent = false;
2650  for (auto&& p : symbols) {
2651  const Token* arg = p.second;
2652  ConditionState cs = analyzeCondition(arg, depth - 1);
2653  result.dependent = cs.dependent;
2654  if (result.dependent)
2655  break;
2656  }
2657  if (result.dependent) {
2658  // Check if we can evaluate the token
2659  if (!evaluate(Evaluate::Integral, tok).empty())
2660  result.unknown = false;
2661  }
2662  return result;
2663  }
2664 
2665  virtual Action isModified(const Token* tok) const {
2666  const Action read = Action::Read;
2667  const ValueFlow::Value* value = getValue(tok);
2668  if (value) {
2669  // Moving a moved value won't change the moved value
2671  return read;
2672  // Inserting elements to container won't change the lifetime
2673  if (astIsContainer(tok) && value->isLifetimeValue() &&
2677  astContainerAction(tok)))
2678  return read;
2679  }
2680  bool inconclusive = false;
2682  return read | Action::Invalid;
2683  if (inconclusive)
2684  return read | Action::Inconclusive;
2685  if (isVariableChanged(tok, getIndirect(tok), getSettings())) {
2686  if (Token::Match(tok->astParent(), "*|[|.|++|--"))
2687  return read | Action::Invalid;
2688  // Check if its assigned to the same value
2689  if (value && !value->isImpossible() && Token::simpleMatch(tok->astParent(), "=") && astIsLHS(tok) &&
2690  astIsIntegral(tok->astParent()->astOperand2(), false)) {
2691  std::vector<MathLib::bigint> result = evaluateInt(tok->astParent()->astOperand2());
2692  if (!result.empty() && value->equalTo(result.front()))
2693  return Action::Idempotent;
2694  }
2695  return Action::Invalid;
2696  }
2697  return read;
2698  }
2699 
2700  virtual Action isAliasModified(const Token* tok, int indirect = -1) const {
2701  // Lambda function call
2702  if (Token::Match(tok, "%var% ("))
2703  // TODO: Check if modified in the lambda function
2704  return Action::Invalid;
2705  if (indirect == -1) {
2706  indirect = 0;
2707  if (const ValueType* vt = tok->valueType()) {
2708  indirect = vt->pointer;
2709  if (vt->type == ValueType::ITERATOR)
2710  ++indirect;
2711  }
2712  }
2713  for (int i = 0; i <= indirect; ++i)
2714  if (isVariableChanged(tok, i, getSettings()))
2715  return Action::Invalid;
2716  return Action::None;
2717  }
2718 
2719  virtual Action isThisModified(const Token* tok) const {
2720  if (isThisChanged(tok, 0, getSettings()))
2721  return Action::Invalid;
2722  return Action::None;
2723  }
2724 
2725  Action isGlobalModified(const Token* tok) const
2726  {
2727  if (tok->function()) {
2728  if (!tok->function()->isConstexpr() && !isConstFunctionCall(tok, getSettings().library))
2729  return Action::Invalid;
2730  } else if (getSettings().library.getFunction(tok)) {
2731  // Assume library function doesn't modify user-global variables
2732  return Action::None;
2733  } else if (Token::simpleMatch(tok->astParent(), ".") && astIsContainer(tok->astParent()->astOperand1())) {
2734  // Assume container member function doesn't modify user-global variables
2735  return Action::None;
2736  } else if (tok->tokType() == Token::eType && astIsPrimitive(tok->next())) {
2737  // Function cast does not modify global variables
2738  return Action::None;
2739  } else if (!tok->isKeyword() && Token::Match(tok, "%name% (")) {
2740  return Action::Invalid;
2741  }
2742  return Action::None;
2743  }
2744 
2745  static const std::string& getAssign(const Token* tok, Direction d)
2746  {
2747  if (d == Direction::Forward)
2748  return tok->str();
2749  return invertAssign(tok->str());
2750  }
2751 
2752  virtual Action isWritable(const Token* tok, Direction d) const {
2753  const ValueFlow::Value* value = getValue(tok);
2754  if (!value)
2755  return Action::None;
2756  if (!(value->isIntValue() || value->isFloatValue() || value->isSymbolicValue() || value->isLifetimeValue()))
2757  return Action::None;
2758  const Token* parent = tok->astParent();
2759  // Only if its invertible
2760  if (value->isImpossible() && !Token::Match(parent, "+=|-=|*=|++|--"))
2761  return Action::None;
2762  if (value->isLifetimeValue()) {
2764  return Action::None;
2765  if (!Token::Match(parent, "++|--|+="))
2766  return Action::None;
2767  return Action::Read | Action::Write;
2768  }
2769  if (parent && parent->isAssignmentOp() && astIsLHS(tok)) {
2770  const Token* rhs = parent->astOperand2();
2771  std::vector<MathLib::bigint> result = evaluateInt(rhs);
2772  if (!result.empty()) {
2773  ValueFlow::Value rhsValue{result.front()};
2774  Action a;
2775  if (!evalAssignment(*value, getAssign(parent, d), rhsValue))
2776  a = Action::Invalid;
2777  else
2778  a = Action::Write;
2779  if (parent->str() != "=") {
2781  } else {
2782  if (!value->isImpossible() && value->equalValue(rhsValue))
2783  a = Action::Idempotent;
2784  if (tok->exprId() != 0 &&
2785  findAstNode(rhs, [&](const Token* child) {
2786  return tok->exprId() == child->exprId();
2787  }))
2788  a |= Action::Incremental;
2789  }
2790  return a;
2791  }
2792  }
2793 
2794  // increment/decrement
2795  if (Token::Match(tok->astParent(), "++|--")) {
2797  }
2798  return Action::None;
2799  }
2800 
2801  virtual void writeValue(ValueFlow::Value* value, const Token* tok, Direction d) const {
2802  if (!value)
2803  return;
2804  if (!tok->astParent())
2805  return;
2806  // Lifetime value doesn't change
2807  if (value->isLifetimeValue())
2808  return;
2809  if (tok->astParent()->isAssignmentOp()) {
2810  const Token* rhs = tok->astParent()->astOperand2();
2811  std::vector<MathLib::bigint> result = evaluateInt(rhs);
2812  assert(!result.empty());
2813  ValueFlow::Value rhsValue{result.front()};
2814  if (evalAssignment(*value, getAssign(tok->astParent(), d), rhsValue)) {
2815  std::string info("Compound assignment '" + tok->astParent()->str() + "', assigned value is " +
2816  value->infoString());
2817  if (tok->astParent()->str() == "=")
2818  value->errorPath.clear();
2819  value->errorPath.emplace_back(tok, std::move(info));
2820  } else {
2821  assert(false && "Writable value cannot be evaluated");
2822  // TODO: Don't set to zero
2823  value->intvalue = 0;
2824  }
2825  } else if (tok->astParent()->tokType() == Token::eIncDecOp) {
2826  bool inc = tok->astParent()->str() == "++";
2827  const std::string opName(inc ? "incremented" : "decremented");
2828  if (d == Direction::Reverse)
2829  inc = !inc;
2830  value->intvalue += (inc ? 1 : -1);
2831 
2832  /* Truncate value */
2833  const ValueType *dst = tok->valueType();
2834  if (dst) {
2835  const size_t sz = ValueFlow::getSizeOf(*dst, settings);
2836  if (sz > 0 && sz < 8)
2837  value->intvalue = truncateIntValue(value->intvalue, sz, dst->sign);
2838 
2839  value->errorPath.emplace_back(tok, tok->str() + " is " + opName + "', new value is " + value->infoString());
2840  }
2841  }
2842  }
2843 
2844  virtual bool useSymbolicValues() const {
2845  return true;
2846  }
2847 
2848  const Token* findMatch(const Token* tok) const
2849  {
2850  return findAstNode(tok, [&](const Token* child) {
2851  return match(child);
2852  });
2853  }
2854 
2855  bool isSameSymbolicValue(const Token* tok, ValueFlow::Value* value = nullptr) const
2856  {
2857  if (!useSymbolicValues())
2858  return false;
2859  if (Token::Match(tok, "%assign%"))
2860  return false;
2861  const ValueFlow::Value* currValue = getValue(tok);
2862  if (!currValue)
2863  return false;
2864  // If the same symbolic value is already there then skip
2865  if (currValue->isSymbolicValue() &&
2866  std::any_of(tok->values().cbegin(), tok->values().cend(), [&](const ValueFlow::Value& v) {
2867  return v.isSymbolicValue() && currValue->equalValue(v);
2868  }))
2869  return false;
2870  const bool isPoint = currValue->bound == ValueFlow::Value::Bound::Point && currValue->isIntValue();
2871  const bool exact = !currValue->isIntValue() || currValue->isImpossible();
2872  for (const ValueFlow::Value& v : tok->values()) {
2873  if (!v.isSymbolicValue())
2874  continue;
2875  if (currValue->equalValue(v))
2876  continue;
2877  const bool toImpossible = v.isImpossible() && currValue->isKnown();
2878  if (!v.isKnown() && !toImpossible)
2879  continue;
2880  if (exact && v.intvalue != 0 && !isPoint)
2881  continue;
2882  std::vector<MathLib::bigint> r;
2883  ValueFlow::Value::Bound bound = currValue->bound;
2884  if (match(v.tokvalue)) {
2885  r = {currValue->intvalue};
2886  } else if (!exact && findMatch(v.tokvalue)) {
2887  r = evaluate(Evaluate::Integral, v.tokvalue, tok);
2888  if (bound == ValueFlow::Value::Bound::Point)
2889  bound = v.bound;
2890  }
2891  if (!r.empty()) {
2892  if (value) {
2893  value->errorPath.insert(value->errorPath.end(), v.errorPath.cbegin(), v.errorPath.cend());
2894  value->intvalue = r.front() + v.intvalue;
2895  if (toImpossible)
2896  value->setImpossible();
2897  value->bound = bound;
2898  }
2899  return true;
2900  }
2901  }
2902  return false;
2903  }
2904 
2905  Action analyzeMatch(const Token* tok, Direction d) const {
2906  const Token* parent = tok->astParent();
2907  if (d == Direction::Reverse && isGlobal() && !dependsOnThis() && Token::Match(parent, ". %name% (")) {
2908  Action a = isGlobalModified(parent->next());
2909  if (a != Action::None)
2910  return a;
2911  }
2912  if ((astIsPointer(tok) || astIsSmartPointer(tok)) &&
2913  (Token::Match(parent, "*|[") || (parent && parent->originalName() == "->")) && getIndirect(tok) <= 0)
2914  return Action::Read;
2915 
2916  Action w = isWritable(tok, d);
2917  if (w != Action::None)
2918  return w;
2919 
2920  // Check for modifications by function calls
2921  return isModified(tok);
2922  }
2923 
2924  Action analyzeToken(const Token* ref, const Token* tok, Direction d, bool inconclusiveRef) const {
2925  if (!ref)
2926  return Action::None;
2927  // If its an inconclusiveRef then ref != tok
2928  assert(!inconclusiveRef || ref != tok);
2929  bool inconclusive = false;
2930  if (match(ref)) {
2931  if (inconclusiveRef) {
2932  Action a = isModified(tok);
2933  if (a.isModified() || a.isInconclusive())
2934  return Action::Inconclusive;
2935  } else {
2936  return analyzeMatch(tok, d) | Action::Match;
2937  }
2938  } else if (ref->isUnaryOp("*") && !match(ref->astOperand1())) {
2939  const Token* lifeTok = nullptr;
2940  for (const ValueFlow::Value& v:ref->astOperand1()->values()) {
2941  if (!v.isLocalLifetimeValue())
2942  continue;
2943  if (lifeTok)
2944  return Action::None;
2945  lifeTok = v.tokvalue;
2946  }
2947  if (!lifeTok)
2948  return Action::None;
2949  Action la = analyzeLifetime(lifeTok);
2950  if (la.matches()) {
2951  Action a = Action::Read;
2952  if (isModified(tok).isModified())
2953  a = Action::Invalid;
2954  if (Token::Match(tok->astParent(), "%assign%") && astIsLHS(tok))
2955  a |= Action::Invalid;
2956  if (inconclusiveRef && a.isModified())
2957  return Action::Inconclusive;
2958  return a;
2959  }
2960  if (la.isRead()) {
2961  return isAliasModified(tok);
2962  }
2963  return Action::None;
2964 
2965  } else if (isAlias(ref, inconclusive)) {
2966  inconclusive |= inconclusiveRef;
2967  Action a = isAliasModified(tok);
2968  if (inconclusive && a.isModified())
2969  return Action::Inconclusive;
2970  return a;
2971  }
2972  if (isSameSymbolicValue(ref))
2974 
2975  return Action::None;
2976  }
2977 
2978  Action analyze(const Token* tok, Direction d) const override {
2979  if (invalid())
2980  return Action::Invalid;
2981  // Follow references
2982  auto refs = followAllReferences(tok);
2983  const bool inconclusiveRefs = refs.size() != 1;
2984  if (std::none_of(refs.cbegin(), refs.cend(), [&](const ReferenceToken& ref) {
2985  return tok == ref.token;
2986  }))
2987  refs.emplace_back(ReferenceToken{tok, {}});
2988  for (const ReferenceToken& ref:refs) {
2989  Action a = analyzeToken(ref.token, tok, d, inconclusiveRefs && ref.token != tok);
2990  if (internalMatch(ref.token))
2991  a |= Action::Internal;
2992  if (a != Action::None)
2993  return a;
2994  }
2995  if (dependsOnThis() && exprDependsOnThis(tok, !isVariable()))
2996  return isThisModified(tok);
2997 
2998  // bailout: global non-const variables
2999  if (isGlobal() && !dependsOnThis() && Token::Match(tok, "%name% (") &&
3000  !Token::simpleMatch(tok->linkAt(1), ") {")) {
3001  return isGlobalModified(tok);
3002  }
3003  return Action::None;
3004  }
3005 
3006  template<class F>
3007  std::vector<MathLib::bigint> evaluateInt(const Token* tok, F getProgramMemory) const
3008  {
3009  if (tok->hasKnownIntValue())
3010  return {static_cast<int>(tok->values().front().intvalue)};
3011  std::vector<MathLib::bigint> result;
3013  if (Token::Match(tok, "&&|%oror%")) {
3014  if (conditionIsTrue(tok, pm, getSettings()))
3015  result.push_back(1);
3016  if (conditionIsFalse(tok, std::move(pm), getSettings()))
3017  result.push_back(0);
3018  } else {
3019  MathLib::bigint out = 0;
3020  bool error = false;
3021  execute(tok, pm, &out, &error, getSettings());
3022  if (!error)
3023  result.push_back(out);
3024  }
3025  return result;
3026  }
3027  std::vector<MathLib::bigint> evaluateInt(const Token* tok) const
3028  {
3029  return evaluateInt(tok, [&] {
3030  return ProgramMemory{getProgramState()};
3031  });
3032  }
3033 
3034  std::vector<MathLib::bigint> evaluate(Evaluate e, const Token* tok, const Token* ctx = nullptr) const override
3035  {
3036  if (e == Evaluate::Integral) {
3037  return evaluateInt(tok, [&] {
3038  return pms.get(tok, ctx, getProgramState());
3039  });
3040  }
3041  if (e == Evaluate::ContainerEmpty) {
3042  const ValueFlow::Value* value = ValueFlow::findValue(tok->values(), settings, [](const ValueFlow::Value& v) {
3043  return v.isKnown() && v.isContainerSizeValue();
3044  });
3045  if (value)
3046  return {value->intvalue == 0};
3047  ProgramMemory pm = pms.get(tok, ctx, getProgramState());
3048  MathLib::bigint out = 0;
3049  if (pm.getContainerEmptyValue(tok->exprId(), out))
3050  return {static_cast<int>(out)};
3051  return {};
3052  }
3053  return {};
3054  }
3055 
3056  void assume(const Token* tok, bool state, unsigned int flags) override {
3057  // Update program state
3058  pms.removeModifiedVars(tok);
3059  pms.addState(tok, getProgramState());
3060  pms.assume(tok, state, flags & Assume::ContainerEmpty);
3061 
3062  bool isCondBlock = false;
3063  const Token* parent = tok->astParent();
3064  if (parent) {
3065  isCondBlock = Token::Match(parent->previous(), "if|while (");
3066  }
3067 
3068  if (isCondBlock) {
3069  const Token* startBlock = parent->link()->next();
3070  if (Token::simpleMatch(startBlock, ";") && Token::simpleMatch(parent->tokAt(-2), "} while ("))
3071  startBlock = parent->linkAt(-2);
3072  const Token* endBlock = startBlock->link();
3073  if (state) {
3074  pms.removeModifiedVars(endBlock);
3075  pms.addState(endBlock->previous(), getProgramState());
3076  } else {
3077  if (Token::simpleMatch(endBlock, "} else {"))
3078  pms.addState(endBlock->linkAt(2)->previous(), getProgramState());
3079  }
3080  }
3081 
3082  if (!(flags & Assume::Quiet)) {
3083  if (flags & Assume::ContainerEmpty) {
3084  std::string s = state ? "empty" : "not empty";
3085  addErrorPath(tok, "Assuming container is " + s);
3086  } else {
3087  std::string s = bool_to_string(state);
3088  addErrorPath(tok, "Assuming condition is " + s);
3089  }
3090  }
3091  if (!(flags & Assume::Absolute))
3092  makeConditional();
3093  }
3094 
3095  void updateState(const Token* tok) override
3096  {
3097  // Update program state
3098  pms.removeModifiedVars(tok);
3099  pms.addState(tok, getProgramState());
3100  }
3101 
3102  virtual void internalUpdate(Token* /*tok*/, const ValueFlow::Value& /*v*/, Direction /*d*/)
3103  {
3104  assert(false && "Internal update unimplemented.");
3105  }
3106 
3107  void update(Token* tok, Action a, Direction d) override {
3108  ValueFlow::Value* value = getValue(tok);
3109  if (!value)
3110  return;
3111  ValueFlow::Value localValue;
3112  if (a.isSymbolicMatch()) {
3113  // Make a copy of the value to modify it
3114  localValue = *value;
3115  value = &localValue;
3116  isSameSymbolicValue(tok, &localValue);
3117  }
3118  if (a.isInternal())
3119  internalUpdate(tok, *value, d);
3120  // Read first when moving forward
3121  if (d == Direction::Forward && a.isRead())
3122  setTokenValue(tok, *value, getSettings());
3123  if (a.isInconclusive())
3124  (void)lowerToInconclusive();
3125  if (a.isWrite() && tok->astParent()) {
3126  writeValue(value, tok, d);
3127  }
3128  // Read last when moving in reverse
3129  if (d == Direction::Reverse && a.isRead())
3130  setTokenValue(tok, *value, getSettings());
3131  }
3132 
3133  ValuePtr<Analyzer> reanalyze(Token* /*tok*/, const std::string& /*msg*/) const override {
3134  return {};
3135  }
3136 };
3137 
3139  std::unordered_map<nonneg int, const Variable*> varids;
3140  std::unordered_map<nonneg int, const Variable*> aliases;
3142 
3143  SingleValueFlowAnalyzer(ValueFlow::Value v, const TokenList& t, const Settings& s) : ValueFlowAnalyzer(t, s), value(std::move(v)) {}
3144 
3145  const std::unordered_map<nonneg int, const Variable*>& getVars() const {
3146  return varids;
3147  }
3148 
3149  const std::unordered_map<nonneg int, const Variable*>& getAliasedVars() const {
3150  return aliases;
3151  }
3152 
3153  const ValueFlow::Value* getValue(const Token* /*tok*/) const override {
3154  return &value;
3155  }
3156  ValueFlow::Value* getValue(const Token* /*tok*/) override {
3157  return &value;
3158  }
3159 
3160  void makeConditional() override {
3161  value.conditional = true;
3162  }
3163 
3164  bool useSymbolicValues() const override
3165  {
3166  if (value.isUninitValue())
3167  return false;
3168  if (value.isLifetimeValue())
3169  return false;
3170  return true;
3171  }
3172 
3173  void addErrorPath(const Token* tok, const std::string& s) override {
3174  value.errorPath.emplace_back(tok, s);
3175  }
3176 
3177  bool isAlias(const Token* tok, bool& inconclusive) const override {
3178  if (value.isLifetimeValue())
3179  return false;
3180  for (const auto& m: {
3181  std::ref(getVars()), std::ref(getAliasedVars())
3182  }) {
3183  for (const auto& p:m.get()) {
3184  nonneg int const varid = p.first;
3185  const Variable* var = p.second;
3186  if (tok->varId() == varid)
3187  return true;
3188  if (isAliasOf(var, tok, varid, MakeSingleRange(value), &inconclusive))
3189  return true;
3190  }
3191  }
3192  return false;
3193  }
3194 
3195  bool isGlobal() const override {
3196  const auto& vars = getVars();
3197  return std::any_of(vars.cbegin(), vars.cend(), [] (const std::pair<nonneg int, const Variable*>& p) {
3198  const Variable* var = p.second;
3199  return !var->isLocal() && !var->isArgument() && !var->isConst();
3200  });
3201  }
3202 
3203  bool lowerToPossible() override {
3204  if (value.isImpossible())
3205  return false;
3207  return true;
3208  }
3209  bool lowerToInconclusive() override {
3210  if (value.isImpossible())
3211  return false;
3213  return true;
3214  }
3215 
3216  bool isConditional() const override {
3217  if (value.conditional)
3218  return true;
3219  if (value.condition)
3220  return !value.isKnown() && !value.isImpossible();
3221  return false;
3222  }
3223 
3224  bool stopOnCondition(const Token* condTok) const override
3225  {
3226  if (value.isNonValue())
3227  return false;
3228  if (value.isImpossible())
3229  return false;
3230  if (isConditional() && !value.isKnown() && !value.isImpossible())
3231  return true;
3232  if (value.isSymbolicValue())
3233  return false;
3234  ConditionState cs = analyzeCondition(condTok);
3235  return cs.isUnknownDependent();
3236  }
3237 
3238  bool updateScope(const Token* endBlock, bool /*modified*/) const override {
3239  const Scope* scope = endBlock->scope();
3240  if (!scope)
3241  return false;
3242  if (scope->type == Scope::eLambda)
3243  return value.isLifetimeValue();
3244  if (scope->type == Scope::eIf || scope->type == Scope::eElse || scope->type == Scope::eWhile ||
3245  scope->type == Scope::eFor) {
3246  if (value.isKnown() || value.isImpossible())
3247  return true;
3248  if (value.isLifetimeValue())
3249  return true;
3250  if (isConditional())
3251  return false;
3252  const Token* condTok = getCondTokFromEnd(endBlock);
3253  std::set<nonneg int> varids2;
3254  std::transform(getVars().cbegin(), getVars().cend(), std::inserter(varids2, varids2.begin()), SelectMapKeys{});
3255  return bifurcate(condTok, varids2, getSettings());
3256  }
3257 
3258  return false;
3259  }
3260 
3261  ValuePtr<Analyzer> reanalyze(Token* tok, const std::string& msg) const override {
3262  ValueFlow::Value newValue = value;
3263  newValue.errorPath.emplace_back(tok, msg);
3264  return makeAnalyzer(tok, std::move(newValue), tokenlist, settings);
3265  }
3266 };
3267 
3269  const Token* expr;
3270  bool local = true;
3271  bool unknown{};
3274 
3275  ExpressionAnalyzer(const Token* e, ValueFlow::Value val, const TokenList& t, const Settings& s)
3276  : SingleValueFlowAnalyzer(std::move(val), t, s),
3277  expr(e)
3278  {
3279 
3280  assert(e && e->exprId() != 0 && "Not a valid expression");
3283  if (value.isSymbolicValue()) {
3286  }
3287  uniqueExprId =
3288  expr->isUniqueExprId() && (Token::Match(expr, "%cop%") || !isVariableChanged(expr, 0, s));
3289  }
3290 
3291  static bool nonLocal(const Variable* var, bool deref) {
3292  return !var || (!var->isLocal() && !var->isArgument()) || (deref && var->isArgument() && var->isPointer()) ||
3293  var->isStatic() || var->isReference() || var->isExtern();
3294  }
3295 
3296  void setupExprVarIds(const Token* start, int depth = 0) {
3297  constexpr int maxDepth = 4;
3298  if (depth > maxDepth)
3299  return;
3300  visitAstNodes(start, [&](const Token* tok) {
3301  const bool top = depth == 0 && tok == start;
3302  const bool ispointer = astIsPointer(tok) || astIsSmartPointer(tok) || astIsIterator(tok);
3303  if (!top || !ispointer || value.indirect != 0) {
3304  for (const ValueFlow::Value& v : tok->values()) {
3305  if (!(v.isLocalLifetimeValue() || (ispointer && v.isSymbolicValue() && v.isKnown())))
3306  continue;
3307  if (!v.tokvalue)
3308  continue;
3309  if (v.tokvalue == tok)
3310  continue;
3311  setupExprVarIds(v.tokvalue, depth + 1);
3312  }
3313  }
3314  if (depth == 0 && tok->isIncompleteVar()) {
3315  // TODO: Treat incomplete var as global, but we need to update
3316  // the alias variables to just expr ids instead of requiring
3317  // Variable
3318  unknown = true;
3319  return ChildrenToVisit::none;
3320  }
3321  if (tok->varId() > 0) {
3322  varids[tok->varId()] = tok->variable();
3323  if (!Token::simpleMatch(tok->previous(), ".")) {
3324  const Variable* var = tok->variable();
3325  if (var && var->isReference() && var->isLocal() && Token::Match(var->nameToken(), "%var% [=(]") &&
3326  !isGlobalData(var->nameToken()->next()->astOperand2()))
3327  return ChildrenToVisit::none;
3328  const bool deref = tok->astParent() &&
3329  (tok->astParent()->isUnaryOp("*") ||
3330  (tok->astParent()->str() == "[" && tok == tok->astParent()->astOperand1()));
3331  local &= !nonLocal(tok->variable(), deref);
3332  }
3333  }
3335  });
3336  }
3337 
3338  virtual bool skipUniqueExprIds() const {
3339  return true;
3340  }
3341 
3342  bool invalid() const override {
3344  return true;
3345  return unknown;
3346  }
3347 
3348  ProgramState getProgramState() const override {
3349  ProgramState ps;
3350  ps[expr] = value;
3351  return ps;
3352  }
3353 
3354  bool match(const Token* tok) const override {
3355  return tok->exprId() == expr->exprId();
3356  }
3357 
3358  bool dependsOnThis() const override {
3359  return dependOnThis;
3360  }
3361 
3362  bool isGlobal() const override {
3363  return !local;
3364  }
3365 
3366  bool isVariable() const override {
3367  return expr->varId() > 0;
3368  }
3369 
3370  Action isAliasModified(const Token* tok, int indirect) const override {
3371  if (value.isSymbolicValue() && tok->exprId() == value.tokvalue->exprId())
3372  indirect = 0;
3373  return SingleValueFlowAnalyzer::isAliasModified(tok, indirect);
3374  }
3375 };
3376 
3379  : ExpressionAnalyzer(e, std::move(val), t, s)
3380  {}
3381 
3382  bool skipUniqueExprIds() const override {
3383  return false;
3384  }
3385 
3386  bool match(const Token* tok) const override
3387  {
3388  return isSameExpression(true, expr, tok, getSettings(), true, true);
3389  }
3390 };
3391 
3393  bool isNot{};
3394 
3395  OppositeExpressionAnalyzer(bool pIsNot, const Token* e, ValueFlow::Value val, const TokenList& t, const Settings& s)
3396  : ExpressionAnalyzer(e, std::move(val), t, s), isNot(pIsNot)
3397  {}
3398 
3399  bool skipUniqueExprIds() const override {
3400  return false;
3401  }
3402 
3403  bool match(const Token* tok) const override {
3404  return isOppositeCond(isNot, expr, tok, getSettings(), true, true);
3405  }
3406 };
3407 
3409  using PartialReadContainer = std::vector<std::pair<Token *, ValueFlow::Value>>;
3410  // A shared_ptr is used so partial reads can be captured even after forking
3411  std::shared_ptr<PartialReadContainer> partialReads;
3412 
3414  : ExpressionAnalyzer(e, std::move(val), t, s), partialReads(std::make_shared<PartialReadContainer>())
3415  {}
3416 
3417  virtual bool submatch(const Token* tok, bool exact = true) const = 0;
3418 
3419  bool isAlias(const Token* tok, bool& inconclusive) const override
3420  {
3421  if (tok->exprId() == expr->exprId() && tok->astParent() && submatch(tok->astParent(), false))
3422  return false;
3424  }
3425 
3426  bool match(const Token* tok) const override
3427  {
3428  return tok->astOperand1() && tok->astOperand1()->exprId() == expr->exprId() && submatch(tok);
3429  }
3430  bool internalMatch(const Token* tok) const override
3431  {
3432  return tok->exprId() == expr->exprId() && !(astIsLHS(tok) && submatch(tok->astParent(), false));
3433  }
3434  void internalUpdate(Token* tok, const ValueFlow::Value& v, Direction /*d*/) override
3435  {
3436  partialReads->emplace_back(tok, v);
3437  }
3438 
3439  // No reanalysis for subexpression
3440  ValuePtr<Analyzer> reanalyze(Token* /*tok*/, const std::string& /*msg*/) const override {
3441  return {};
3442  }
3443 };
3444 
3446  std::string varname;
3447 
3448  MemberExpressionAnalyzer(std::string varname, const Token* e, ValueFlow::Value val, const TokenList& t, const Settings& s)
3449  : SubExpressionAnalyzer(e, std::move(val), t, s), varname(std::move(varname))
3450  {}
3451 
3452  bool submatch(const Token* tok, bool exact) const override
3453  {
3454  if (!Token::Match(tok, ". %var%"))
3455  return false;
3456  if (!exact)
3457  return true;
3458  return tok->next()->str() == varname;
3459  }
3460 };
3461 
3463 
3464 static std::string lifetimeType(const Token *tok, const ValueFlow::Value *val)
3465 {
3466  std::string result;
3467  if (!val)
3468  return "object";
3469  switch (val->lifetimeKind) {
3471  result = "lambda";
3472  break;
3474  result = "iterator";
3475  break;
3479  if (astIsPointer(tok))
3480  result = "pointer";
3481  else if (Token::simpleMatch(tok, "=") && astIsPointer(tok->astOperand2()))
3482  result = "pointer";
3483  else
3484  result = "object";
3485  break;
3486  }
3487  return result;
3488 }
3489 
3490 std::string ValueFlow::lifetimeMessage(const Token *tok, const ValueFlow::Value *val, ErrorPath &errorPath)
3491 {
3492  const Token *tokvalue = val ? val->tokvalue : nullptr;
3493  const Variable *tokvar = tokvalue ? tokvalue->variable() : nullptr;
3494  const Token *vartok = tokvar ? tokvar->nameToken() : nullptr;
3495  const bool classVar = tokvar ? (!tokvar->isLocal() && !tokvar->isArgument() && !tokvar->isGlobal()) : false;
3496  std::string type = lifetimeType(tok, val);
3497  std::string msg = type;
3498  if (vartok) {
3499  if (!classVar)
3500  errorPath.emplace_back(vartok, "Variable created here.");
3501  const Variable * var = vartok->variable();
3502  if (var) {
3503  std::string submessage;
3504  switch (val->lifetimeKind) {
3508  if (type == "pointer")
3509  submessage = " to local variable";
3510  else
3511  submessage = " that points to local variable";
3512  break;
3514  submessage = " that captures local variable";
3515  break;
3517  submessage = " to local container";
3518  break;
3519  }
3520  if (classVar)
3521  submessage.replace(submessage.find("local"), 5, "member");
3522  msg += submessage + " '" + var->name() + "'";
3523  }
3524  }
3525  return msg;
3526 }
3527 
3528 std::vector<ValueFlow::Value> ValueFlow::getLifetimeObjValues(const Token* tok, bool inconclusive, MathLib::bigint path)
3529 {
3530  std::vector<ValueFlow::Value> result;
3531  auto pred = [&](const ValueFlow::Value& v) {
3532  if (!v.isLocalLifetimeValue() && !(path != 0 && v.isSubFunctionLifetimeValue()))
3533  return false;
3534  if (!inconclusive && v.isInconclusive())
3535  return false;
3536  if (!v.tokvalue)
3537  return false;
3538  if (path >= 0 && v.path != 0 && v.path != path)
3539  return false;
3540  return true;
3541  };
3542  std::copy_if(tok->values().cbegin(), tok->values().cend(), std::back_inserter(result), pred);
3543  return result;
3544 }
3545 
3546 static bool hasUniqueOwnership(const Token* tok)
3547 {
3548  if (!tok)
3549  return false;
3550  const Variable* var = tok->variable();
3551  if (var && var->isArray() && !var->isArgument())
3552  return true;
3553  if (astIsPointer(tok))
3554  return false;
3555  if (astIsUniqueSmartPointer(tok))
3556  return true;
3557  if (astIsContainerOwned(tok))
3558  return true;
3559  return false;
3560 }
3561 
3562 // Check if dereferencing an object that doesn't have unique ownership
3563 static bool derefShared(const Token* tok)
3564 {
3565  if (!tok)
3566  return false;
3567  if (!tok->isUnaryOp("*") && tok->str() != "[" && tok->str() != ".")
3568  return false;
3569  if (tok->str() == "." && tok->originalName() != "->")
3570  return false;
3571  const Token* ptrTok = tok->astOperand1();
3572  return !hasUniqueOwnership(ptrTok);
3573 }
3574 
3576 {
3577  std::vector<ValueFlow::Value> values = ValueFlow::getLifetimeObjValues(tok, inconclusive);
3578  // There should only be one lifetime
3579  if (values.size() != 1)
3580  return ValueFlow::Value{};
3581  return values.front();
3582 }
3583 
3584 template<class Predicate>
3585 static std::vector<ValueFlow::LifetimeToken> getLifetimeTokens(const Token* tok,
3586  bool escape,
3587  ValueFlow::Value::ErrorPath errorPath,
3588  Predicate pred,
3589  const Settings& settings,
3590  int depth = 20)
3591 {
3592  if (!tok)
3593  return std::vector<ValueFlow::LifetimeToken> {};
3594  if (Token::simpleMatch(tok, "..."))
3595  return std::vector<ValueFlow::LifetimeToken>{};
3596  const Variable *var = tok->variable();
3597  if (pred(tok))
3598  return {{tok, std::move(errorPath)}};
3599  if (depth < 0)
3600  return {{tok, std::move(errorPath)}};
3601  if (var && var->declarationId() == tok->varId()) {
3602  if (var->isReference() || var->isRValueReference()) {
3603  const Token * const varDeclEndToken = var->declEndToken();
3604  if (!varDeclEndToken)
3605  return {{tok, true, std::move(errorPath)}};
3606  if (var->isArgument()) {
3607  errorPath.emplace_back(varDeclEndToken, "Passed to reference.");
3608  return {{tok, true, std::move(errorPath)}};
3609  }
3610  if (Token::Match(varDeclEndToken, "=|{")) {
3611  errorPath.emplace_back(varDeclEndToken, "Assigned to reference.");
3612  const Token *vartok = varDeclEndToken->astOperand2();
3613  const bool temporary = isTemporary(vartok, nullptr, true);
3614  const bool nonlocal = var->isStatic() || var->isGlobal();
3615  if (vartok == tok || (nonlocal && temporary) ||
3616  (!escape && (var->isConst() || var->isRValueReference()) && temporary))
3617  return {{tok, true, std::move(errorPath)}};
3618  if (vartok)
3619  return getLifetimeTokens(vartok, escape, std::move(errorPath), pred, settings, depth - 1);
3620  } else if (Token::simpleMatch(var->nameToken()->astParent(), ":") &&
3621  var->nameToken()->astParent()->astParent() &&
3622  Token::simpleMatch(var->nameToken()->astParent()->astParent()->previous(), "for (")) {
3623  errorPath.emplace_back(var->nameToken(), "Assigned to reference.");
3624  const Token* vartok = var->nameToken();
3625  if (vartok == tok)
3626  return {{tok, true, std::move(errorPath)}};
3627  const Token* contok = var->nameToken()->astParent()->astOperand2();
3628  if (astIsContainer(contok))
3629  return getLifetimeTokens(contok, escape, std::move(errorPath), pred, settings, depth - 1);
3630  return std::vector<ValueFlow::LifetimeToken>{};
3631  } else {
3632  return std::vector<ValueFlow::LifetimeToken> {};
3633  }
3634  }
3635  } else if (Token::Match(tok->previous(), "%name% (")) {
3636  const Function *f = tok->previous()->function();
3637  if (f) {
3639  return {{tok, std::move(errorPath)}};
3640  std::vector<ValueFlow::LifetimeToken> result;
3641  std::vector<const Token*> returns = Function::findReturns(f);
3642  for (const Token* returnTok : returns) {
3643  if (returnTok == tok)
3644  continue;
3645  for (ValueFlow::LifetimeToken& lt : getLifetimeTokens(returnTok, escape, errorPath, pred, settings, depth - returns.size())) {
3646  const Token* argvarTok = lt.token;
3647  const Variable* argvar = argvarTok->variable();
3648  if (!argvar)
3649  continue;
3650  const Token* argTok = nullptr;
3651  if (argvar->isArgument() && (argvar->isReference() || argvar->isRValueReference())) {
3652  const int n = getArgumentPos(argvar, f);
3653  if (n < 0)
3654  return std::vector<ValueFlow::LifetimeToken> {};
3655  std::vector<const Token*> args = getArguments(tok->previous());
3656  // TODO: Track lifetimes of default parameters
3657  if (n >= args.size())
3658  return std::vector<ValueFlow::LifetimeToken> {};
3659  argTok = args[n];
3660  lt.errorPath.emplace_back(returnTok, "Return reference.");
3661  lt.errorPath.emplace_back(tok->previous(), "Called function passing '" + argTok->expressionString() + "'.");
3662  } else if (Token::Match(tok->tokAt(-2), ". %name% (") && !derefShared(tok->tokAt(-2)) &&
3663  exprDependsOnThis(argvarTok)) {
3664  argTok = tok->tokAt(-2)->astOperand1();
3665  lt.errorPath.emplace_back(returnTok, "Return reference that depends on 'this'.");
3666  lt.errorPath.emplace_back(tok->previous(),
3667  "Calling member function on '" + argTok->expressionString() + "'.");
3668  }
3669  if (argTok) {
3670  std::vector<ValueFlow::LifetimeToken> arglts = ValueFlow::LifetimeToken::setInconclusive(
3671  getLifetimeTokens(argTok, escape, std::move(lt.errorPath), pred, settings, depth - returns.size()),
3672  returns.size() > 1);
3673  result.insert(result.end(), arglts.cbegin(), arglts.cend());
3674  }
3675  }
3676  }
3677  return result;
3678  }
3679  if (Token::Match(tok->tokAt(-2), ". %name% (") && tok->tokAt(-2)->originalName() != "->" && astIsContainer(tok->tokAt(-2)->astOperand1())) {
3680  const Library::Container* library = getLibraryContainer(tok->tokAt(-2)->astOperand1());
3681  const Library::Container::Yield y = library->getYield(tok->previous()->str());
3683  errorPath.emplace_back(tok->previous(), "Accessing container.");
3685  getLifetimeTokens(tok->tokAt(-2)->astOperand1(), escape, std::move(errorPath), pred, settings, depth - 1),
3686  false);
3687  }
3688  }
3689  } else if (Token::Match(tok, ".|::|[") || tok->isUnaryOp("*")) {
3690 
3691  const Token *vartok = tok;
3692  while (vartok) {
3693  if (vartok->str() == "[" || vartok->isUnaryOp("*"))
3694  vartok = vartok->astOperand1();
3695  else if (vartok->str() == ".") {
3696  if (vartok->originalName().empty() || !Token::simpleMatch(vartok->astOperand1(), "."))
3697  vartok = vartok->astOperand1();
3698  else
3699  break;
3700  }
3701  else if (vartok->str() == "::")
3702  vartok = vartok->astOperand2();
3703  else
3704  break;
3705  }
3706 
3707  if (!vartok)
3708  return {{tok, std::move(errorPath)}};
3709  if (derefShared(vartok->astParent())) {
3710  for (const ValueFlow::Value &v : vartok->values()) {
3711  if (!v.isLocalLifetimeValue())
3712  continue;
3713  if (v.tokvalue == tok)
3714  continue;
3715  errorPath.insert(errorPath.end(), v.errorPath.cbegin(), v.errorPath.cend());
3716  return getLifetimeTokens(v.tokvalue, escape, std::move(errorPath), pred, settings, depth - 1);
3717  }
3718  } else {
3719  return ValueFlow::LifetimeToken::setAddressOf(getLifetimeTokens(vartok, escape, std::move(errorPath), pred, settings, depth - 1),
3720  !(astIsContainer(vartok) && Token::simpleMatch(vartok->astParent(), "[")));
3721  }
3722  } else if (Token::simpleMatch(tok, "{") && getArgumentStart(tok) &&
3723  !Token::simpleMatch(getArgumentStart(tok), ",") && getArgumentStart(tok)->valueType()) {
3724  const Token* vartok = getArgumentStart(tok);
3725  auto vts = getParentValueTypes(tok, settings);
3726  auto it = std::find_if(vts.cbegin(), vts.cend(), [&](const ValueType& vt) {
3727  return vt.isTypeEqual(vartok->valueType());
3728  });
3729  if (it != vts.end())
3730  return getLifetimeTokens(vartok, escape, std::move(errorPath), pred, settings, depth - 1);
3731  }
3732  return {{tok, std::move(errorPath)}};
3733 }
3734 
3735 std::vector<ValueFlow::LifetimeToken> ValueFlow::getLifetimeTokens(const Token* tok, const Settings& settings, bool escape, ValueFlow::Value::ErrorPath errorPath)
3736 {
3737  return getLifetimeTokens(tok, escape, std::move(errorPath), [](const Token*) {
3738  return false;
3739  }, settings);
3740 }
3741 
3742 bool ValueFlow::hasLifetimeToken(const Token* tok, const Token* lifetime, const Settings& settings)
3743 {
3744  bool result = false;
3745  getLifetimeTokens(tok, false, ValueFlow::Value::ErrorPath{}, [&](const Token* tok2) {
3746  result = tok2->exprId() == lifetime->exprId();
3747  return result;
3748  }, settings);
3749  return result;
3750 }
3751 
3752 static const Token* getLifetimeToken(const Token* tok, ValueFlow::Value::ErrorPath& errorPath, const Settings& settings, bool* addressOf = nullptr)
3753 {
3754  std::vector<ValueFlow::LifetimeToken> lts = ValueFlow::getLifetimeTokens(tok, settings);
3755  if (lts.size() != 1)
3756  return nullptr;
3757  if (lts.front().inconclusive)
3758  return nullptr;
3759  if (addressOf)
3760  *addressOf = lts.front().addressOf;
3761  errorPath.insert(errorPath.end(), lts.front().errorPath.cbegin(), lts.front().errorPath.cend());
3762  return lts.front().token;
3763 }
3764 
3765 const Variable* ValueFlow::getLifetimeVariable(const Token* tok, ValueFlow::Value::ErrorPath& errorPath, const Settings& settings, bool* addressOf)
3766 {
3767  const Token* tok2 = getLifetimeToken(tok, errorPath, settings, addressOf);
3768  if (tok2 && tok2->variable())
3769  return tok2->variable();
3770  return nullptr;
3771 }
3772 
3773 const Variable* ValueFlow::getLifetimeVariable(const Token* tok, const Settings& settings)
3774 {
3775  ValueFlow::Value::ErrorPath errorPath;
3776  return getLifetimeVariable(tok, errorPath, settings, nullptr);
3777 }
3778 
3779 static bool isNotLifetimeValue(const ValueFlow::Value& val)
3780 {
3781  return !val.isLifetimeValue();
3782 }
3783 
3784 static bool isLifetimeOwned(const ValueType* vtParent)
3785 {
3786  if (vtParent->container)
3787  return !vtParent->container->view;
3788  return vtParent->type == ValueType::CONTAINER;
3789 }
3790 
3791 static bool isLifetimeOwned(const ValueType *vt, const ValueType *vtParent)
3792 {
3793  if (!vtParent)
3794  return false;
3795  if (isLifetimeOwned(vtParent))
3796  return true;
3797  if (!vt)
3798  return false;
3799  // If converted from iterator to pointer then the iterator is most likely a pointer
3800  if (vtParent->pointer == 1 && vt->pointer == 0 && vt->type == ValueType::ITERATOR)
3801  return false;
3802  if (vt->type != ValueType::UNKNOWN_TYPE && vtParent->type != ValueType::UNKNOWN_TYPE) {
3803  if (vt->pointer != vtParent->pointer)
3804  return true;
3805  if (vt->type != vtParent->type) {
3806  if (vtParent->type == ValueType::RECORD)
3807  return true;
3808  if (isLifetimeOwned(vtParent))
3809  return true;
3810  }
3811  }
3812 
3813  return false;
3814 }
3815 
3816 static bool isLifetimeBorrowed(const ValueType *vt, const ValueType *vtParent)
3817 {
3818  if (!vtParent)
3819  return false;
3820  if (!vt)
3821  return false;
3822  if (vt->pointer > 0 && vt->pointer == vtParent->pointer)
3823  return true;
3824  if (vtParent->container && vtParent->container->view)
3825  return true;
3826  if (vt->type != ValueType::UNKNOWN_TYPE && vtParent->type != ValueType::UNKNOWN_TYPE && vtParent->container == vt->container) {
3827  if (vtParent->pointer > vt->pointer)
3828  return true;
3829  if (vtParent->pointer < vt->pointer && vtParent->isIntegral())
3830  return true;
3831  if (vtParent->str() == vt->str())
3832  return true;
3833  }
3834 
3835  return false;
3836 }
3837 
3838 static const Token* skipCVRefs(const Token* tok, const Token* endTok)
3839 {
3840  while (tok != endTok && Token::Match(tok, "const|volatile|auto|&|&&"))
3841  tok = tok->next();
3842  return tok;
3843 }
3844 
3845 static bool isNotEqual(std::pair<const Token*, const Token*> x, std::pair<const Token*, const Token*> y)
3846 {
3847  const Token* start1 = x.first;
3848  const Token* start2 = y.first;
3849  if (start1 == nullptr || start2 == nullptr)
3850  return false;
3851  while (start1 != x.second && start2 != y.second) {
3852  const Token* tok1 = skipCVRefs(start1, x.second);
3853  if (tok1 != start1) {
3854  start1 = tok1;
3855  continue;
3856  }
3857  const Token* tok2 = skipCVRefs(start2, y.second);
3858  if (tok2 != start2) {
3859  start2 = tok2;
3860  continue;
3861  }
3862  if (start1->str() != start2->str())
3863  return true;
3864  start1 = start1->next();
3865  start2 = start2->next();
3866  }
3867  start1 = skipCVRefs(start1, x.second);
3868  start2 = skipCVRefs(start2, y.second);
3869  return !(start1 == x.second && start2 == y.second);
3870 }
3871 static bool isNotEqual(std::pair<const Token*, const Token*> x, const std::string& y, bool cpp)
3872 {
3873  TokenList tokenList(nullptr);
3874  std::istringstream istr(y);
3875  tokenList.createTokens(istr, cpp ? Standards::Language::CPP : Standards::Language::C); // TODO: check result?
3876  return isNotEqual(x, std::make_pair(tokenList.front(), tokenList.back()));
3877 }
3878 static bool isNotEqual(std::pair<const Token*, const Token*> x, const ValueType* y, bool cpp)
3879 {
3880  if (y == nullptr)
3881  return false;
3882  if (y->originalTypeName.empty())
3883  return false;
3884  return isNotEqual(x, y->originalTypeName, cpp);
3885 }
3886 
3887 static bool isDifferentType(const Token* src, const Token* dst)
3888 {
3889  const Type* t = Token::typeOf(src);
3890  const Type* parentT = Token::typeOf(dst);
3891  if (t && parentT) {
3892  if (t->classDef && parentT->classDef && t->classDef != parentT->classDef)
3893  return true;
3894  } else {
3895  std::pair<const Token*, const Token*> decl = Token::typeDecl(src);
3896  std::pair<const Token*, const Token*> parentdecl = Token::typeDecl(dst);
3897  if (isNotEqual(decl, parentdecl))
3898  return true;
3899  if (isNotEqual(decl, dst->valueType(), dst->isCpp()))
3900  return true;
3901  if (isNotEqual(parentdecl, src->valueType(), src->isCpp()))
3902  return true;
3903  }
3904  return false;
3905 }
3906 
3907 bool ValueFlow::isLifetimeBorrowed(const Token *tok, const Settings &settings)
3908 {
3909  if (!tok)
3910  return true;
3911  if (tok->str() == ",")
3912  return true;
3913  if (!tok->astParent())
3914  return true;
3915  const Token* parent = nullptr;
3916  const ValueType* vt = tok->valueType();
3917  std::vector<ValueType> vtParents = getParentValueTypes(tok, settings, &parent);
3918  for (const ValueType& vtParent : vtParents) {
3919  if (isLifetimeBorrowed(vt, &vtParent))
3920  return true;
3921  if (isLifetimeOwned(vt, &vtParent))
3922  return false;
3923  }
3924  if (parent) {
3925  if (isDifferentType(tok, parent))
3926  return false;
3927  }
3928  return true;
3929 }
3930 
3931 static void valueFlowLifetimeFunction(Token *tok, const TokenList &tokenlist, ErrorLogger &errorLogger, const Settings &settings);
3932 
3933 static void valueFlowLifetimeConstructor(Token *tok,
3934  const TokenList &tokenlist,
3935  ErrorLogger &errorLogger,
3936  const Settings &settings);
3937 
3938 static bool isRangeForScope(const Scope* scope)
3939 {
3940  if (!scope)
3941  return false;
3942  if (scope->type != Scope::eFor)
3943  return false;
3944  if (!scope->bodyStart)
3945  return false;
3946  if (!Token::simpleMatch(scope->bodyStart->previous(), ") {"))
3947  return false;
3948  return Token::simpleMatch(scope->bodyStart->linkAt(-1)->astOperand2(), ":");
3949 }
3950 
3951 static const Token* getEndOfVarScope(const Variable* var)
3952 {
3953  if (!var)
3954  return nullptr;
3955  const Scope* innerScope = var->scope();
3956  const Scope* outerScope = innerScope;
3957  if (var->typeStartToken() && var->typeStartToken()->scope())
3958  outerScope = var->typeStartToken()->scope();
3959  if (!innerScope && outerScope)
3960  innerScope = outerScope;
3961  if (!innerScope || !outerScope)
3962  return nullptr;
3963  if (!innerScope->isExecutable())
3964  return nullptr;
3965  // If the variable is defined in a for/while initializer then we want to
3966  // pick one token after the end so forward analysis can analyze the exit
3967  // conditions
3968  if (innerScope != outerScope && outerScope->isExecutable() && innerScope->isLoopScope() &&
3969  !isRangeForScope(innerScope))
3970  return innerScope->bodyEnd->next();
3971  return innerScope->bodyEnd;
3972 }
3973 
3974 const Token* ValueFlow::getEndOfExprScope(const Token* tok, const Scope* defaultScope, bool smallest)
3975 {
3976  const Token* end = nullptr;
3977  bool local = false;
3978  visitAstNodes(tok, [&](const Token* child) {
3979  if (const Variable* var = child->variable()) {
3980  local |= var->isLocal();
3981  if (var->isLocal() || var->isArgument()) {
3982  const Token* varEnd = getEndOfVarScope(var);
3983  if (!end || (smallest ? precedes(varEnd, end) : succeeds(varEnd, end)))
3984  end = varEnd;
3985 
3986  const Token* top = var->nameToken()->astTop();
3987  if (top && Token::simpleMatch(top->tokAt(-1), "if (")) { // variable declared in if (...)
3988  const Token* elseTok = top->link()->linkAt(1);
3989  if (Token::simpleMatch(elseTok, "} else {") && tok->scope()->isNestedIn(elseTok->tokAt(2)->scope()))
3990  end = tok->scope()->bodyEnd;
3991  }
3992  }
3993  }
3995  });
3996  if (!end && defaultScope)
3997  end = defaultScope->bodyEnd;
3998  if (!end) {
3999  const Scope* scope = tok->scope();
4000  if (scope)
4001  end = scope->bodyEnd;
4002  // If there is no local variables then pick the function scope
4003  if (!local) {
4004  while (scope && scope->isLocal())
4005  scope = scope->nestedIn;
4006  if (scope && scope->isExecutable())
4007  end = scope->bodyEnd;
4008  }
4009  }
4010  return end;
4011 }
4012 
4013 static void valueFlowForwardLifetime(Token * tok, const TokenList &tokenlist, ErrorLogger &errorLogger, const Settings &settings)
4014 {
4015  // Forward lifetimes to constructed variable
4016  if (Token::Match(tok->previous(), "%var% {|(") && isVariableDecl(tok->previous())) {
4017  std::list<ValueFlow::Value> values = tok->values();
4018  values.remove_if(&isNotLifetimeValue);
4019  valueFlowForward(nextAfterAstRightmostLeaf(tok), ValueFlow::getEndOfExprScope(tok), tok->previous(), std::move(values), tokenlist, errorLogger, settings);
4020  return;
4021  }
4022  Token *parent = tok->astParent();
4023  while (parent && parent->str() == ",")
4024  parent = parent->astParent();
4025  if (!parent)
4026  return;
4027  // Assignment
4028  if (parent->str() == "=" && (!parent->astParent() || Token::simpleMatch(parent->astParent(), ";"))) {
4029  // Rhs values..
4030  if (!parent->astOperand2() || parent->astOperand2()->values().empty())
4031  return;
4032 
4033  if (!ValueFlow::isLifetimeBorrowed(parent->astOperand2(), settings))
4034  return;
4035 
4036  const Token* expr = getLHSVariableToken(parent);
4037  if (!expr)
4038  return;
4039 
4040  if (expr->exprId() == 0)
4041  return;
4042 
4043  const Token* endOfVarScope = ValueFlow::getEndOfExprScope(expr);
4044 
4045  // Only forward lifetime values
4046  std::list<ValueFlow::Value> values = parent->astOperand2()->values();
4047  values.remove_if(&isNotLifetimeValue);
4048  // Dont forward lifetimes that overlap
4049  values.remove_if([&](const ValueFlow::Value& value) {
4050  return findAstNode(value.tokvalue, [&](const Token* child) {
4051  return child->exprId() == expr->exprId();
4052  });
4053  });
4054 
4055  // Skip RHS
4056  Token* nextExpression = nextAfterAstRightmostLeaf(parent);
4057 
4058  if (expr->exprId() > 0) {
4059  valueFlowForward(nextExpression, endOfVarScope->next(), expr, values, tokenlist, errorLogger, settings);
4060 
4061  for (ValueFlow::Value& val : values) {
4064  }
4065  // TODO: handle `[`
4066  if (Token::simpleMatch(parent->astOperand1(), ".")) {
4067  const Token* parentLifetime =
4068  getParentLifetime(parent->astOperand1()->astOperand2(), settings.library);
4069  if (parentLifetime && parentLifetime->exprId() > 0) {
4070  valueFlowForward(nextExpression, endOfVarScope, parentLifetime, std::move(values), tokenlist, errorLogger, settings);
4071  }
4072  }
4073  }
4074  // Constructor
4075  } else if (Token::simpleMatch(parent, "{") && !isScopeBracket(parent)) {
4076  valueFlowLifetimeConstructor(parent, tokenlist, errorLogger, settings);
4077  valueFlowForwardLifetime(parent, tokenlist, errorLogger, settings);
4078  // Function call
4079  } else if (Token::Match(parent->previous(), "%name% (")) {
4080  valueFlowLifetimeFunction(parent->previous(), tokenlist, errorLogger, settings);
4081  valueFlowForwardLifetime(parent, tokenlist, errorLogger, settings);
4082  // Variable
4083  } else if (tok->variable() && tok->variable()->scope()) {
4084  const Variable *var = tok->variable();
4085  const Token *endOfVarScope = var->scope()->bodyEnd;
4086 
4087  std::list<ValueFlow::Value> values = tok->values();
4088  Token *nextExpression = nextAfterAstRightmostLeaf(parent);
4089  // Only forward lifetime values
4090  values.remove_if(&isNotLifetimeValue);
4091  valueFlowForward(nextExpression, endOfVarScope, tok, std::move(values), tokenlist, errorLogger, settings);
4092  // Cast
4093  } else if (parent->isCast()) {
4094  std::list<ValueFlow::Value> values = tok->values();
4095  // Only forward lifetime values
4096  values.remove_if(&isNotLifetimeValue);
4097  for (ValueFlow::Value& value:values)
4098  setTokenValue(parent, std::move(value), settings);
4099  valueFlowForwardLifetime(parent, tokenlist, errorLogger, settings);
4100  }
4101 }
4102 
4104  const Token* argtok{};
4105  std::string message;
4109  bool forward = true;
4110 
4111  LifetimeStore() = default;
4112 
4114  std::string message,
4116  bool inconclusive = false)
4117  : argtok(argtok),
4118  message(std::move(message)),
4119  type(type),
4121  {}
4122 
4123  template<class F>
4124  static void forEach(const TokenList& tokenlist,
4125  ErrorLogger& errorLogger,
4126  const Settings& settings,
4127  const std::vector<const Token*>& argtoks,
4128  const std::string& message,
4130  F f) {
4131  std::set<Token*> forwardToks;
4132  for (const Token* arg : argtoks) {
4133  LifetimeStore ls{arg, message, type};
4134  ls.forward = false;
4135  f(ls);
4136  if (ls.forwardTok)
4137  forwardToks.emplace(ls.forwardTok);
4138  }
4139  for (auto* tok : forwardToks) {
4140  valueFlowForwardLifetime(tok, tokenlist, errorLogger, settings);
4141  }
4142  }
4143 
4144  static LifetimeStore fromFunctionArg(const Function * f, const Token *tok, const Variable *var, const TokenList &tokenlist, const Settings& settings, ErrorLogger &errorLogger) {
4145  if (!var)
4146  return LifetimeStore{};
4147  if (!var->isArgument())
4148  return LifetimeStore{};
4149  const int n = getArgumentPos(var, f);
4150  if (n < 0)
4151  return LifetimeStore{};
4152  std::vector<const Token *> args = getArguments(tok);
4153  if (n >= args.size()) {
4154  if (settings.debugwarnings)
4155  bailout(tokenlist,
4156  errorLogger,
4157  tok,
4158  "Argument mismatch: Function '" + tok->str() + "' returning lifetime from argument index " +
4159  std::to_string(n) + " but only " + std::to_string(args.size()) +
4160  " arguments are available.");
4161  return LifetimeStore{};
4162  }
4163  const Token *argtok2 = args[n];
4164  return LifetimeStore{argtok2, "Passed to '" + tok->expressionString() + "'.", ValueFlow::Value::LifetimeKind::Object};
4165  }
4166 
4167  template<class Predicate>
4168  bool byRef(Token* tok,
4169  const TokenList& tokenlist,
4170  ErrorLogger& errorLogger,
4171  const Settings& settings,
4172  Predicate pred,
4174  {
4175  if (!argtok)
4176  return false;
4177  bool update = false;
4178  for (const ValueFlow::LifetimeToken& lt : ValueFlow::getLifetimeTokens(argtok, settings)) {
4179  if (!settings.certainty.isEnabled(Certainty::inconclusive) && lt.inconclusive)
4180  continue;
4181  ErrorPath er = errorPath;
4182  er.insert(er.end(), lt.errorPath.cbegin(), lt.errorPath.cend());
4183  if (!lt.token)
4184  return false;
4185  if (!pred(lt.token))
4186  return false;
4187  er.emplace_back(argtok, message);
4188 
4189  ValueFlow::Value value;
4192  value.tokvalue = lt.token;
4193  value.errorPath = std::move(er);
4194  value.lifetimeKind = type;
4195  value.setInconclusive(lt.inconclusive || inconclusive);
4196  // Don't add the value a second time
4197  if (std::find(tok->values().cbegin(), tok->values().cend(), value) != tok->values().cend())
4198  return false;
4199  if (settings.debugnormal)
4200  setSourceLocation(value, loc, tok);
4201  setTokenValue(tok, std::move(value), settings);
4202  update = true;
4203  }
4204  if (update && forward)
4205  forwardLifetime(tok, tokenlist, errorLogger, settings);
4206  return update;
4207  }
4208 
4209  bool byRef(Token* tok,
4210  const TokenList& tokenlist,
4211  ErrorLogger& errorLogger,
4212  const Settings& settings,
4214  {
4215  return byRef(
4216  tok,
4217  tokenlist,
4218  errorLogger,
4219  settings,
4220  [](const Token*) {
4221  return true;
4222  },
4223  loc);
4224  }
4225 
4226  template<class Predicate>
4227  bool byVal(Token* tok,
4228  const TokenList& tokenlist,
4229  ErrorLogger& errorLogger,
4230  const Settings& settings,
4231  Predicate pred,
4233  {
4234  if (!argtok)
4235  return false;
4236  bool update = false;
4237  if (argtok->values().empty()) {
4238  ErrorPath er;
4239  er.emplace_back(argtok, message);
4240  for (const ValueFlow::LifetimeToken& lt : ValueFlow::getLifetimeTokens(argtok, settings)) {
4241  if (!settings.certainty.isEnabled(Certainty::inconclusive) && lt.inconclusive)
4242  continue;
4243  ValueFlow::Value value;
4245  value.tokvalue = lt.token;
4246  value.capturetok = argtok;
4247  value.errorPath = er;
4248  value.lifetimeKind = type;
4249  value.setInconclusive(inconclusive || lt.inconclusive);
4250  const Variable* var = lt.token->variable();
4251  if (var && var->isArgument()) {
4253  } else {
4254  continue;
4255  }
4256  // Don't add the value a second time
4257  if (std::find(tok->values().cbegin(), tok->values().cend(), value) != tok->values().cend())
4258  continue;
4259  if (settings.debugnormal)
4260  setSourceLocation(value, loc, tok);
4261  setTokenValue(tok, std::move(value), settings);
4262  update = true;
4263  }
4264  }
4265  for (const ValueFlow::Value &v : argtok->values()) {
4266  if (!v.isLifetimeValue())
4267  continue;
4268  const Token *tok3 = v.tokvalue;
4269  for (const ValueFlow::LifetimeToken& lt : ValueFlow::getLifetimeTokens(tok3, settings)) {
4270  if (!settings.certainty.isEnabled(Certainty::inconclusive) && lt.inconclusive)
4271  continue;
4272  ErrorPath er = v.errorPath;
4273  er.insert(er.end(), lt.errorPath.cbegin(), lt.errorPath.cend());
4274  if (!lt.token)
4275  return false;
4276  if (!pred(lt.token))
4277  return false;
4278  er.emplace_back(argtok, message);
4279  er.insert(er.end(), errorPath.cbegin(), errorPath.cend());
4280 
4281  ValueFlow::Value value;
4283  value.lifetimeScope = v.lifetimeScope;
4284  value.path = v.path;
4285  value.tokvalue = lt.token;
4286  value.capturetok = argtok;
4287  value.errorPath = std::move(er);
4288  value.lifetimeKind = type;
4289  value.setInconclusive(lt.inconclusive || v.isInconclusive() || inconclusive);
4290  // Don't add the value a second time
4291  if (std::find(tok->values().cbegin(), tok->values().cend(), value) != tok->values().cend())
4292  continue;
4293  if (settings.debugnormal)
4294  setSourceLocation(value, loc, tok);
4295  setTokenValue(tok, std::move(value), settings);
4296  update = true;
4297  }
4298  }
4299  if (update && forward)
4300  forwardLifetime(tok, tokenlist, errorLogger, settings);
4301  return update;
4302  }
4303 
4304  bool byVal(Token* tok,
4305  const TokenList& tokenlist,
4306  ErrorLogger& errorLogger,
4307  const Settings& settings,
4309  {
4310  return byVal(
4311  tok,
4312  tokenlist,
4313  errorLogger,
4314  settings,
4315  [](const Token*) {
4316  return true;
4317  },
4318  loc);
4319  }
4320 
4321  template<class Predicate>
4322  bool byDerefCopy(Token* tok,
4323  const TokenList& tokenlist,
4324  ErrorLogger& errorLogger,
4325  const Settings& settings,
4326  Predicate pred,
4328  {
4329  bool update = false;
4331  return update;
4332  if (!argtok)
4333  return update;
4334  if (!tok)
4335  return update;
4336  for (const ValueFlow::Value &v : argtok->values()) {
4337  if (!v.isLifetimeValue())
4338  continue;
4339  const Token *tok2 = v.tokvalue;
4340  ErrorPath er = v.errorPath;
4341  const Variable *var = ValueFlow::getLifetimeVariable(tok2, er, settings);
4342  // TODO: the inserted data is never used
4343  er.insert(er.end(), errorPath.cbegin(), errorPath.cend());
4344  if (!var)
4345  continue;
4346  const Token * const varDeclEndToken = var->declEndToken();
4347  for (const Token *tok3 = tok; tok3 && tok3 != varDeclEndToken; tok3 = tok3->previous()) {
4348  if (tok3->varId() == var->declarationId()) {
4349  update |= LifetimeStore{tok3, message, type, inconclusive}
4350  .byVal(tok, tokenlist, errorLogger, settings, pred, loc);
4351  break;
4352  }
4353  }
4354  }
4355  return update;
4356  }
4357 
4358  bool byDerefCopy(Token* tok,
4359  const TokenList& tokenlist,
4360  ErrorLogger& errorLogger,
4361  const Settings& settings,
4363  {
4364  return byDerefCopy(
4365  tok,
4366  tokenlist,
4367  errorLogger,
4368  settings,
4369  [](const Token*) {
4370  return true;
4371  },
4372  loc);
4373  }
4374 
4375 private:
4376  // cppcheck-suppress naming-privateMemberVariable
4378  void forwardLifetime(Token* tok, const TokenList& tokenlist, ErrorLogger& errorLogger, const Settings& settings) {
4379  forwardTok = tok;
4380  valueFlowForwardLifetime(tok, tokenlist, errorLogger, settings);
4381  }
4382 };
4383 
4384 static bool hasBorrowingVariables(const std::list<Variable>& vars, const std::vector<const Token*>& args, int depth = 10)
4385 {
4386  if (depth < 0)
4387  return true;
4388  return std::any_of(vars.cbegin(), vars.cend(), [&](const Variable& var) {
4389  if (const ValueType* vt = var.valueType()) {
4390  if (vt->pointer > 0 &&
4391  std::none_of(args.begin(), args.end(), [vt](const Token* arg) {
4392  return arg->valueType() && arg->valueType()->type == vt->type;
4393  }))
4394  return false;
4395  if (vt->pointer > 0)
4396  return true;
4397  if (vt->reference != Reference::None)
4398  return true;
4399  if (vt->isPrimitive())
4400  return false;
4401  if (vt->isEnum())
4402  return false;
4403  // TODO: Check container inner type
4404  if (vt->type == ValueType::CONTAINER && vt->container)
4405  return vt->container->view;
4406  if (vt->typeScope)
4407  return hasBorrowingVariables(vt->typeScope->varlist, args, depth - 1);
4408  }
4409  return true;
4410  });
4411 }
4412 
4414  const Function* constructor,
4415  const std::string& name,
4416  const std::vector<const Token*>& args,
4417  const TokenList& tokenlist,
4418  ErrorLogger& errorLogger,
4419  const Settings& settings)
4420 {
4421  if (!constructor)
4422  return;
4423  std::unordered_map<const Token*, const Variable*> argToParam;
4424  for (std::size_t i = 0; i < args.size(); i++)
4425  argToParam[args[i]] = constructor->getArgumentVar(i);
4426  if (const Token* initList = constructor->constructorMemberInitialization()) {
4427  std::unordered_map<const Variable*, LifetimeCapture> paramCapture;
4428  for (const Token* tok2 : astFlatten(initList->astOperand2(), ",")) {
4429  if (!Token::simpleMatch(tok2, "("))
4430  continue;
4431  if (!tok2->astOperand1())
4432  continue;
4433  if (!tok2->astOperand2())
4434  continue;
4435  const Variable* var = tok2->astOperand1()->variable();
4436  const Token* expr = tok2->astOperand2();
4437  if (!var)
4438  continue;
4439  if (!ValueFlow::isLifetimeBorrowed(expr, settings))
4440  continue;
4441  const Variable* argvar = ValueFlow::getLifetimeVariable(expr, settings);
4442  if (var->isReference() || var->isRValueReference()) {
4443  if (argvar && argvar->isArgument() && (argvar->isReference() || argvar->isRValueReference())) {
4444  paramCapture[argvar] = LifetimeCapture::ByReference;
4445  }
4446  } else {
4447  bool found = false;
4448  for (const ValueFlow::Value& v : expr->values()) {
4449  if (!v.isLifetimeValue())
4450  continue;
4451  if (v.path > 0)
4452  continue;
4453  if (!v.tokvalue)
4454  continue;
4455  const Variable* lifeVar = v.tokvalue->variable();
4456  if (!lifeVar)
4457  continue;
4459  if (!v.isArgumentLifetimeValue() && (lifeVar->isReference() || lifeVar->isRValueReference()))
4461  else if (v.isArgumentLifetimeValue())
4463  if (c != LifetimeCapture::Undefined) {
4464  paramCapture[lifeVar] = c;
4465  found = true;
4466  }
4467  }
4468  if (!found && argvar && argvar->isArgument())
4469  paramCapture[argvar] = LifetimeCapture::ByValue;
4470  }
4471  }
4472  // TODO: Use SubExpressionAnalyzer for members
4473  LifetimeStore::forEach(tokenlist,
4474  errorLogger,
4475  settings,
4476  args,
4477  "Passed to constructor of '" + name + "'.",
4479  [&](LifetimeStore& ls) {
4480  const Variable* paramVar = argToParam.at(ls.argtok);
4481  if (paramCapture.count(paramVar) == 0)
4482  return;
4483  const LifetimeCapture c = paramCapture.at(paramVar);
4485  ls.byRef(tok, tokenlist, errorLogger, settings);
4486  else
4487  ls.byVal(tok, tokenlist, errorLogger, settings);
4488  });
4489  } else if (hasBorrowingVariables(constructor->nestedIn->varlist, args)) {
4490  LifetimeStore::forEach(tokenlist,
4491  errorLogger,
4492  settings,
4493  args,
4494  "Passed to constructor of '" + name + "'.",
4496  [&](LifetimeStore& ls) {
4497  ls.inconclusive = true;
4498  const Variable* var = argToParam.at(ls.argtok);
4499  if (var && !var->isConst() && var->isReference())
4500  ls.byRef(tok, tokenlist, errorLogger, settings);
4501  else
4502  ls.byVal(tok, tokenlist, errorLogger, settings);
4503  });
4504  }
4505 }
4506 
4507 static void valueFlowLifetimeFunction(Token *tok, const TokenList &tokenlist, ErrorLogger &errorLogger, const Settings &settings)
4508 {
4509  if (!Token::Match(tok, "%name% ("))
4510  return;
4511  Token* memtok = nullptr;
4512  if (Token::Match(tok->astParent(), ". %name% (") && astIsRHS(tok))
4513  memtok = tok->astParent()->astOperand1();
4514  const int returnContainer = settings.library.returnValueContainer(tok);
4515  if (returnContainer >= 0) {
4516  std::vector<const Token *> args = getArguments(tok);
4517  for (int argnr = 1; argnr <= args.size(); ++argnr) {
4518  const Library::ArgumentChecks::IteratorInfo *i = settings.library.getArgIteratorInfo(tok, argnr);
4519  if (!i)
4520  continue;
4521  if (i->container != returnContainer)
4522  continue;
4523  const Token * const argTok = args[argnr - 1];
4524  bool forward = false;
4525  for (ValueFlow::Value val : argTok->values()) {
4526  if (!val.isLifetimeValue())
4527  continue;
4528  val.errorPath.emplace_back(argTok, "Passed to '" + tok->str() + "'.");
4529  setTokenValue(tok->next(), std::move(val), settings);
4530  forward = true;
4531  }
4532  // Check if lifetime is available to avoid adding the lifetime twice
4533  if (forward) {
4534  valueFlowForwardLifetime(tok, tokenlist, errorLogger, settings);
4535  break;
4536  }
4537  }
4538  } else if (Token::Match(tok->tokAt(-2), "std :: ref|cref|tie|front_inserter|back_inserter")) {
4539  for (const Token *argtok : getArguments(tok)) {
4540  LifetimeStore{argtok, "Passed to '" + tok->str() + "'.", ValueFlow::Value::LifetimeKind::Object}.byRef(
4541  tok->next(), tokenlist, errorLogger, settings);
4542  }
4543  } else if (Token::Match(tok->tokAt(-2), "std :: make_tuple|tuple_cat|make_pair|make_reverse_iterator|next|prev|move|bind")) {
4544  for (const Token *argtok : getArguments(tok)) {
4545  LifetimeStore{argtok, "Passed to '" + tok->str() + "'.", ValueFlow::Value::LifetimeKind::Object}.byVal(
4546  tok->next(), tokenlist, errorLogger, settings);
4547  }
4548  } else if (memtok && Token::Match(tok->astParent(), ". push_back|push_front|insert|push|assign") &&
4549  astIsNonStringContainer(memtok)) {
4550  std::vector<const Token *> args = getArguments(tok);
4551  const std::size_t n = args.size();
4552  if (n > 1 && Token::typeStr(args[n - 2]) == Token::typeStr(args[n - 1]) &&
4553  (((astIsIterator(args[n - 2]) && astIsIterator(args[n - 1])) ||
4554  (astIsPointer(args[n - 2]) && astIsPointer(args[n - 1]))))) {
4555  LifetimeStore{
4556  args.back(), "Added to container '" + memtok->str() + "'.", ValueFlow::Value::LifetimeKind::Object}
4557  .byDerefCopy(memtok, tokenlist, errorLogger, settings);
4558  } else if (!args.empty() && ValueFlow::isLifetimeBorrowed(args.back(), settings)) {
4559  LifetimeStore{
4560  args.back(), "Added to container '" + memtok->str() + "'.", ValueFlow::Value::LifetimeKind::Object}
4561  .byVal(memtok, tokenlist, errorLogger, settings);
4562  }
4563  } else if (tok->function()) {
4564  const Function *f = tok->function();
4565  if (f->isConstructor()) {
4566  valueFlowLifetimeUserConstructor(tok->next(), f, tok->str(), getArguments(tok), tokenlist, errorLogger, settings);
4567  return;
4568  }
4570  return;
4571  std::vector<const Token*> returns = Function::findReturns(f);
4572  const bool inconclusive = returns.size() > 1;
4573  bool update = false;
4574  for (const Token* returnTok : returns) {
4575  if (returnTok == tok)
4576  continue;
4577  const Variable *returnVar = ValueFlow::getLifetimeVariable(returnTok, settings);
4578  if (returnVar && returnVar->isArgument() && (returnVar->isConst() || !isVariableChanged(returnVar, settings))) {
4579  LifetimeStore ls = LifetimeStore::fromFunctionArg(f, tok, returnVar, tokenlist, settings, errorLogger);
4581  ls.forward = false;
4582  update |= ls.byVal(tok->next(), tokenlist, errorLogger, settings);
4583  }
4584  for (const ValueFlow::Value &v : returnTok->values()) {
4585  if (!v.isLifetimeValue())
4586  continue;
4587  if (!v.tokvalue)
4588  continue;
4589  if (memtok &&
4591  v.lifetimeScope) ||
4592  exprDependsOnThis(v.tokvalue))) {
4593  LifetimeStore ls = LifetimeStore{memtok,
4594  "Passed to member function '" + tok->expressionString() + "'.",
4597  ls.forward = false;
4598  ls.errorPath = v.errorPath;
4599  ls.errorPath.emplace_front(returnTok, "Return " + lifetimeType(returnTok, &v) + ".");
4600  int thisIndirect = v.lifetimeScope == ValueFlow::Value::LifetimeScope::ThisValue ? 0 : 1;
4601  if (derefShared(memtok->astParent()))
4602  thisIndirect--;
4603  if (thisIndirect == -1)
4604  update |= ls.byDerefCopy(tok->next(), tokenlist, errorLogger, settings);
4605  else if (thisIndirect == 0)
4606  update |= ls.byVal(tok->next(), tokenlist, errorLogger, settings);
4607  else if (thisIndirect == 1)
4608  update |= ls.byRef(tok->next(), tokenlist, errorLogger, settings);
4609  continue;
4610  }
4611  const Variable *var = v.tokvalue->variable();
4612  LifetimeStore ls = LifetimeStore::fromFunctionArg(f, tok, var, tokenlist, settings, errorLogger);
4613  if (!ls.argtok)
4614  continue;
4615  ls.forward = false;
4617  ls.errorPath = v.errorPath;
4618  ls.errorPath.emplace_front(returnTok, "Return " + lifetimeType(returnTok, &v) + ".");
4619  if (!v.isArgumentLifetimeValue() && (var->isReference() || var->isRValueReference())) {
4620  update |= ls.byRef(tok->next(), tokenlist, errorLogger, settings);
4621  } else if (v.isArgumentLifetimeValue()) {
4622  update |= ls.byVal(tok->next(), tokenlist, errorLogger, settings);
4623  }
4624  }
4625  }
4626  if (update)
4627  valueFlowForwardLifetime(tok->next(), tokenlist, errorLogger, settings);
4628  } else if (tok->valueType()) {
4629  // TODO: Propagate lifetimes with library functions
4630  if (settings.library.getFunction(tok->previous()))
4631  return;
4632  // Assume constructing the valueType
4633  valueFlowLifetimeConstructor(tok->next(), tokenlist, errorLogger, settings);
4634  valueFlowForwardLifetime(tok->next(), tokenlist, errorLogger, settings);
4635  } else {
4636  const std::string& retVal = settings.library.returnValue(tok);
4637  if (startsWith(retVal, "arg")) {
4638  std::size_t iArg{};
4639  try {
4640  iArg = strToInt<std::size_t>(retVal.substr(3));
4641  } catch (...) {
4642  return;
4643  }
4644  std::vector<const Token*> args = getArguments(tok);
4645  if (iArg > 0 && iArg <= args.size()) {
4646  const Token* varTok = args[iArg - 1];
4647  if (varTok->variable() && varTok->variable()->isLocal())
4648  LifetimeStore{ varTok, "Passed to '" + tok->str() + "'.", ValueFlow::Value::LifetimeKind::Address }.byRef(
4649  tok->next(), tokenlist, errorLogger, settings);
4650  }
4651  }
4652  }
4653 }
4654 
4655 static bool isScope(const Token* tok)
4656 {
4657  if (!tok)
4658  return false;
4659  if (!Token::simpleMatch(tok, "{"))
4660  return false;
4661  const Scope* scope = tok->scope();
4662  if (!scope)
4663  return false;
4664  if (!scope->bodyStart)
4665  return false;
4666  return scope->bodyStart == tok;
4667 }
4668 
4669 static const Function* findConstructor(const Scope* scope, const Token* tok, const std::vector<const Token*>& args)
4670 {
4671  if (!tok)
4672  return nullptr;
4673  const Function* f = tok->function();
4674  if (!f && tok->astOperand1())
4675  f = tok->astOperand1()->function();
4676  // Search for a constructor
4677  if (!f || !f->isConstructor()) {
4678  f = nullptr;
4679  std::vector<const Function*> candidates;
4680  for (const Function& function : scope->functionList) {
4681  if (function.minArgCount() > args.size())
4682  continue;
4683  if (!function.isConstructor())
4684  continue;
4685  candidates.push_back(&function);
4686  }
4687  // TODO: Narrow the candidates
4688  if (candidates.size() == 1)
4689  f = candidates.front();
4690  }
4691  if (!f)
4692  return nullptr;
4693  return f;
4694 }
4695 
4697  const Type* t,
4698  const TokenList& tokenlist,
4699  ErrorLogger& errorLogger,
4700  const Settings& settings)
4701 {
4702  if (!Token::Match(tok, "(|{"))
4703  return;
4704  if (isScope(tok))
4705  return;
4706  if (!t) {
4707  if (tok->valueType() && tok->valueType()->type != ValueType::RECORD)
4708  return;
4709  if (tok->str() != "{" && !Token::Match(tok->previous(), "%var% (") && !isVariableDecl(tok->previous()))
4710  return;
4711  // If the type is unknown then assume it captures by value in the
4712  // constructor, but make each lifetime inconclusive
4713  std::vector<const Token*> args = getArguments(tok);
4714  LifetimeStore::forEach(tokenlist,
4715  errorLogger,
4716  settings,
4717  args,
4718  "Passed to initializer list.",
4720  [&](LifetimeStore& ls) {
4721  ls.inconclusive = true;
4722  ls.byVal(tok, tokenlist, errorLogger, settings);
4723  });
4724  return;
4725  }
4726  const Scope* scope = t->classScope;
4727  if (!scope)
4728  return;
4729  // Aggregate constructor
4730  if (t->derivedFrom.empty() && (t->isClassType() || t->isStructType())) {
4731  std::vector<const Token*> args = getArguments(tok);
4732  if (scope->numConstructors == 0) {
4733  auto it = scope->varlist.cbegin();
4735  tokenlist,
4736  errorLogger,
4737  settings,
4738  args,
4739  "Passed to constructor of '" + t->name() + "'.",
4741  [&](LifetimeStore& ls) {
4742  // Skip static variable
4743  it = std::find_if(it, scope->varlist.cend(), [](const Variable& var) {
4744  return !var.isStatic();
4745  });
4746  if (it == scope->varlist.cend())
4747  return;
4748  const Variable& var = *it;
4749  if (var.isReference() || var.isRValueReference()) {
4750  ls.byRef(tok, tokenlist, errorLogger, settings);
4751  } else if (ValueFlow::isLifetimeBorrowed(ls.argtok, settings)) {
4752  ls.byVal(tok, tokenlist, errorLogger, settings);
4753  }
4754  it++;
4755  });
4756  } else {
4757  const Function* constructor = findConstructor(scope, tok, args);
4758  valueFlowLifetimeUserConstructor(tok, constructor, t->name(), args, tokenlist, errorLogger, settings);
4759  }
4760  }
4761 }
4762 
4763 static void valueFlowLifetimeConstructor(Token* tok, const TokenList& tokenlist, ErrorLogger& errorLogger, const Settings& settings)
4764 {
4765  if (!Token::Match(tok, "(|{"))
4766  return;
4767  if (isScope(tok))
4768  return;
4769  std::vector<ValueType> vts;
4770  if (tok->valueType()) {
4771  vts = {*tok->valueType()};
4772  } else if (Token::Match(tok->previous(), "%var% {|(") && isVariableDecl(tok->previous()) &&
4773  tok->previous()->valueType()) {
4774  vts = {*tok->previous()->valueType()};
4775  } else if (Token::simpleMatch(tok, "{") && !Token::Match(tok->previous(), "%name%")) {
4776  vts = getParentValueTypes(tok, settings);
4777  }
4778 
4779  for (const ValueType& vt : vts) {
4780  if (vt.pointer > 0) {
4781  std::vector<const Token*> args = getArguments(tok);
4782  LifetimeStore::forEach(tokenlist,
4783  errorLogger,
4784  settings,
4785  args,
4786  "Passed to initializer list.",
4788  [&](LifetimeStore& ls) {
4789  ls.byVal(tok, tokenlist, errorLogger, settings);
4790  });
4791  } else if (vt.container && vt.type == ValueType::CONTAINER) {
4792  std::vector<const Token*> args = getArguments(tok);
4793  if (args.size() == 1 && vt.container->view && astIsContainerOwned(args.front())) {
4794  LifetimeStore{args.front(), "Passed to container view.", ValueFlow::Value::LifetimeKind::SubObject}
4795  .byRef(tok, tokenlist, errorLogger, settings);
4796  } else if (args.size() == 2 && astIsIterator(args[0]) && astIsIterator(args[1])) {
4798  tokenlist,
4799  errorLogger,
4800  settings,
4801  args,
4802  "Passed to initializer list.",
4804  [&](const LifetimeStore& ls) {
4805  ls.byDerefCopy(tok, tokenlist, errorLogger, settings);
4806  });
4807  } else if (vt.container->hasInitializerListConstructor) {
4808  LifetimeStore::forEach(tokenlist,
4809  errorLogger,
4810  settings,
4811  args,
4812  "Passed to initializer list.",
4814  [&](LifetimeStore& ls) {
4815  ls.byVal(tok, tokenlist, errorLogger, settings);
4816  });
4817  }
4818  } else {
4819  const Type* t = nullptr;
4820  if (vt.typeScope && vt.typeScope->definedType)
4821  t = vt.typeScope->definedType;
4822  else
4823  t = Token::typeOf(tok->previous());
4824  valueFlowLifetimeClassConstructor(tok, t, tokenlist, errorLogger, settings);
4825  }
4826  }
4827 }
4828 
4829 struct Lambda {
4830  explicit Lambda(const Token* tok)
4831  {
4832  if (!Token::simpleMatch(tok, "[") || !tok->link())
4833  return;
4834  capture = tok;
4835 
4836  if (Token::simpleMatch(capture->link(), "] (")) {
4837  arguments = capture->link()->next();
4838  }
4839  const Token * afterArguments = arguments ? arguments->link()->next() : capture->link()->next();
4840  if (afterArguments && afterArguments->originalName() == "->") {
4841  returnTok = afterArguments->next();
4843  } else if (Token::simpleMatch(afterArguments, "{")) {
4844  bodyTok = afterArguments;
4845  }
4846  for (const Token* c:getCaptures()) {
4847  if (Token::Match(c, "this !!.")) {
4848  explicitCaptures[c->variable()] = std::make_pair(c, LifetimeCapture::ByReference);
4849  } else if (Token::simpleMatch(c, "* this")) {
4850  explicitCaptures[c->next()->variable()] = std::make_pair(c->next(), LifetimeCapture::ByValue);
4851  } else if (c->variable()) {
4852  explicitCaptures[c->variable()] = std::make_pair(c, LifetimeCapture::ByValue);
4853  } else if (c->isUnaryOp("&") && Token::Match(c->astOperand1(), "%var%")) {
4854  explicitCaptures[c->astOperand1()->variable()] =
4855  std::make_pair(c->astOperand1(), LifetimeCapture::ByReference);
4856  } else {
4857  const std::string& s = c->expressionString();
4858  if (s == "=")
4860  else if (s == "&")
4862  }
4863  }
4864  }
4865 
4866  const Token* capture{};
4867  const Token* arguments{};
4868  const Token* returnTok{};
4869  const Token* bodyTok{};
4870  std::unordered_map<const Variable*, std::pair<const Token*, LifetimeCapture>> explicitCaptures;
4872 
4873  std::vector<const Token*> getCaptures() const {
4874  return getArguments(capture);
4875  }
4876 
4877  bool isLambda() const {
4878  return capture && bodyTok;
4879  }
4880 };
4881 
4882 static bool isDecayedPointer(const Token *tok)
4883 {
4884  if (!tok)
4885  return false;
4886  if (!tok->astParent())
4887  return false;
4888  if (astIsPointer(tok->astParent()) && !Token::simpleMatch(tok->astParent(), "return"))
4889  return true;
4890  if (tok->astParent()->isConstOp())
4891  return true;
4892  if (!Token::simpleMatch(tok->astParent(), "return"))
4893  return false;
4894  return astIsPointer(tok->astParent());
4895 }
4896 
4897 static bool isConvertedToView(const Token* tok, const Settings& settings)
4898 {
4899  std::vector<ValueType> vtParents = getParentValueTypes(tok, settings);
4900  return std::any_of(vtParents.cbegin(), vtParents.cend(), [&](const ValueType& vt) {
4901  if (!vt.container)
4902  return false;
4903  return vt.container->view;
4904  });
4905 }
4906 
4907 static bool isContainerOfPointers(const Token* tok, const Settings& settings)
4908 {
4909  if (!tok)
4910  {
4911  return true;
4912  }
4913 
4914  ValueType vt = ValueType::parseDecl(tok, settings);
4915  return vt.pointer > 0;
4916 }
4917 
4918 static void valueFlowLifetime(TokenList &tokenlist, ErrorLogger &errorLogger, const Settings &settings)
4919 {
4920  for (Token *tok = tokenlist.front(); tok; tok = tok->next()) {
4921  if (!tok->scope())
4922  continue;
4923  if (tok->scope()->type == Scope::eGlobal)
4924  continue;
4925  Lambda lam(tok);
4926  // Lambdas
4927  if (lam.isLambda()) {
4928  const Scope * bodyScope = lam.bodyTok->scope();
4929 
4930  std::set<const Scope *> scopes;
4931  // Avoid capturing a variable twice
4932  std::set<nonneg int> varids;
4933  bool capturedThis = false;
4934 
4935  auto isImplicitCapturingVariable = [&](const Token *varTok) {
4936  const Variable *var = varTok->variable();
4937  if (!var)
4938  return false;
4939  if (varids.count(var->declarationId()) > 0)
4940  return false;
4941  if (!var->isLocal() && !var->isArgument())
4942  return false;
4943  const Scope *scope = var->scope();
4944  if (!scope)
4945  return false;
4946  if (scopes.count(scope) > 0)
4947  return false;
4948  if (scope->isNestedIn(bodyScope))
4949  return false;
4950  scopes.insert(scope);
4951  varids.insert(var->declarationId());
4952  return true;
4953  };
4954 
4955  bool update = false;
4956  auto captureVariable = [&](const Token* tok2, LifetimeCapture c, const std::function<bool(const Token*)> &pred) {
4957  if (varids.count(tok->varId()) > 0)
4958  return;
4959  if (c == LifetimeCapture::ByReference) {
4960  LifetimeStore ls{
4961  tok2, "Lambda captures variable by reference here.", ValueFlow::Value::LifetimeKind::Lambda};
4962  ls.forward = false;
4963  update |= ls.byRef(tok, tokenlist, errorLogger, settings, pred);
4964  } else if (c == LifetimeCapture::ByValue) {
4965  LifetimeStore ls{
4966  tok2, "Lambda captures variable by value here.", ValueFlow::Value::LifetimeKind::Lambda};
4967  ls.forward = false;
4968  update |= ls.byVal(tok, tokenlist, errorLogger, settings, pred);
4969  pred(tok2);
4970  }
4971  };
4972 
4973  auto captureThisVariable = [&](const Token* tok2, LifetimeCapture c) {
4974  ValueFlow::Value value;
4978  else if (c == LifetimeCapture::ByValue)
4980  value.tokvalue = tok2;
4981  value.errorPath.emplace_back(tok2, "Lambda captures the 'this' variable here.");
4983  capturedThis = true;
4984  // Don't add the value a second time
4985  if (std::find(tok->values().cbegin(), tok->values().cend(), value) != tok->values().cend())
4986  return;
4987  setTokenValue(tok, std::move(value), settings);
4988  update |= true;
4989  };
4990 
4991  // Handle explicit capture
4992  for (const auto& p:lam.explicitCaptures) {
4993  const Variable* var = p.first;
4994  const Token* tok2 = p.second.first;
4995  const LifetimeCapture c = p.second.second;
4996  if (Token::Match(tok2, "this !!.")) {
4997  captureThisVariable(tok2, c);
4998  } else if (var) {
4999  captureVariable(tok2, c, [](const Token*) {
5000  return true;
5001  });
5002  varids.insert(var->declarationId());
5003  }
5004  }
5005 
5006  auto isImplicitCapturingThis = [&](const Token* tok2) {
5007  if (capturedThis)
5008  return false;
5009  if (Token::simpleMatch(tok2, "this"))
5010  return true;
5011  if (tok2->variable()) {
5012  if (Token::simpleMatch(tok2->previous(), "."))
5013  return false;
5014  const Variable* var = tok2->variable();
5015  if (var->isLocal())
5016  return false;
5017  if (var->isArgument())
5018  return false;
5019  return exprDependsOnThis(tok2);
5020  }
5021  if (Token::simpleMatch(tok2, "("))
5022  return exprDependsOnThis(tok2);
5023  return false;
5024  };
5025 
5026  for (const Token * tok2 = lam.bodyTok; tok2 != lam.bodyTok->link(); tok2 = tok2->next()) {
5027  if (isImplicitCapturingThis(tok2)) {
5028  captureThisVariable(tok2, LifetimeCapture::ByReference);
5029  } else if (tok2->variable()) {
5030  captureVariable(tok2, lam.implicitCapture, isImplicitCapturingVariable);
5031  }
5032  }
5033  if (update)
5034  valueFlowForwardLifetime(tok, tokenlist, errorLogger, settings);
5035  }
5036  // address of
5037  else if (tok->isUnaryOp("&")) {
5038  if (Token::simpleMatch(tok->astParent(), "*"))
5039  continue;
5040  for (const ValueFlow::LifetimeToken& lt : ValueFlow::getLifetimeTokens(tok->astOperand1(), settings)) {
5041  if (!settings.certainty.isEnabled(Certainty::inconclusive) && lt.inconclusive)
5042  continue;
5043  ErrorPath errorPath = lt.errorPath;
5044  errorPath.emplace_back(tok, "Address of variable taken here.");
5045 
5046  ValueFlow::Value value;
5049  value.tokvalue = lt.token;
5050  value.errorPath = std::move(errorPath);
5051  if (lt.addressOf || astIsPointer(lt.token) || !Token::Match(lt.token->astParent(), ".|["))
5053  value.setInconclusive(lt.inconclusive);
5054  setTokenValue(tok, std::move(value), settings);
5055 
5056  valueFlowForwardLifetime(tok, tokenlist, errorLogger, settings);
5057  }
5058  }
5059  // Converting to container view
5060  else if (astIsContainerOwned(tok) && isConvertedToView(tok, settings)) {
5061  LifetimeStore ls =
5062  LifetimeStore{tok, "Converted to container view", ValueFlow::Value::LifetimeKind::SubObject};
5063  ls.byRef(tok, tokenlist, errorLogger, settings);
5064  valueFlowForwardLifetime(tok, tokenlist, errorLogger, settings);
5065  }
5066  // container lifetimes
5067  else if (astIsContainer(tok)) {
5068  Token * parent = astParentSkipParens(tok);
5069  if (!parent)
5070  continue;
5071  if (!Token::Match(parent, ". %name% (") && !Token::Match(parent->previous(), "%name% ("))
5072  continue;
5073 
5074  // Skip if its a free function that doesnt yield an iterator to the container
5075  if (Token::Match(parent->previous(), "%name% (") &&
5077  astFunctionYield(parent->previous(), settings)))
5078  continue;
5079 
5080  ValueFlow::Value master;
5083 
5084  if (astIsIterator(parent->tokAt(2))) {
5085  master.errorPath.emplace_back(parent->tokAt(2), "Iterator to container is created here.");
5087  } else if (astIsIterator(parent) && Token::Match(parent->previous(), "%name% (") &&
5089  astFunctionYield(parent->previous(), settings))) {
5090  master.errorPath.emplace_back(parent, "Iterator to container is created here.");
5092  } else if ((astIsPointer(parent->tokAt(2)) &&
5093  !isContainerOfPointers(tok->valueType()->containerTypeToken, settings)) ||
5094  Token::Match(parent->next(), "data|c_str")) {
5095  master.errorPath.emplace_back(parent->tokAt(2), "Pointer to container is created here.");
5097  } else {
5098  continue;
5099  }
5100 
5101  std::vector<const Token*> toks;
5102  if (tok->isUnaryOp("*") || parent->originalName() == "->") {
5103  for (const ValueFlow::Value& v : tok->values()) {
5104  if (!v.isLocalLifetimeValue())
5105  continue;
5106  if (v.lifetimeKind != ValueFlow::Value::LifetimeKind::Address)
5107  continue;
5108  if (!v.tokvalue)
5109  continue;
5110  toks.push_back(v.tokvalue);
5111  }
5112  } else if (astIsContainerView(tok)) {
5113  for (const ValueFlow::Value& v : tok->values()) {
5114  if (!v.isLocalLifetimeValue())
5115  continue;
5116  if (!v.tokvalue)
5117  continue;
5118  if (!astIsContainerOwned(v.tokvalue))
5119  continue;
5120  toks.push_back(v.tokvalue);
5121  }
5122  } else {
5123  toks = {tok};
5124  }
5125 
5126  for (const Token* tok2 : toks) {
5127  for (const ReferenceToken& rt : followAllReferences(tok2, false)) {
5128  ValueFlow::Value value = master;
5129  value.tokvalue = rt.token;
5130  value.errorPath.insert(value.errorPath.begin(), rt.errors.cbegin(), rt.errors.cend());
5131  if (Token::simpleMatch(parent, "("))
5132  setTokenValue(parent, std::move(value), settings);
5133  else
5134  setTokenValue(parent->tokAt(2), std::move(value), settings);
5135 
5136  if (!rt.token->variable()) {
5138  rt.token, master.errorPath.back().second, ValueFlow::Value::LifetimeKind::Object};
5139  ls.byRef(parent->tokAt(2), tokenlist, errorLogger, settings);
5140  }
5141  }
5142  }
5143  valueFlowForwardLifetime(parent->tokAt(2), tokenlist, errorLogger, settings);
5144  }
5145  // Check constructors
5146  else if (Token::Match(tok, "=|return|%name%|{|,|> {") && !isScope(tok->next())) {
5147  valueFlowLifetimeConstructor(tok->next(), tokenlist, errorLogger, settings);
5148  }
5149  // Check function calls
5150  else if (Token::Match(tok, "%name% (") && !Token::simpleMatch(tok->next()->link(), ") {")) {
5151  valueFlowLifetimeFunction(tok, tokenlist, errorLogger, settings);
5152  }
5153  // Unique pointer lifetimes
5154  else if (astIsUniqueSmartPointer(tok) && astIsLHS(tok) && Token::simpleMatch(tok->astParent(), ". get ( )")) {
5155  Token* ptok = tok->astParent()->tokAt(2);
5156  ErrorPath errorPath = {{ptok, "Raw pointer to smart pointer created here."}};
5157  ValueFlow::Value value;
5161  value.tokvalue = tok;
5162  value.errorPath = std::move(errorPath);
5163  setTokenValue(ptok, std::move(value), settings);
5164  valueFlowForwardLifetime(ptok, tokenlist, errorLogger, settings);
5165  }
5166  // Check variables
5167  else if (tok->variable()) {
5168  ErrorPath errorPath;
5169  const Variable * var = ValueFlow::getLifetimeVariable(tok, errorPath, settings);
5170  if (!var)
5171  continue;
5172  if (var->nameToken() == tok)
5173  continue;
5174  if (var->isArray() && !var->isStlType() && !var->isArgument() && isDecayedPointer(tok)) {
5175  errorPath.emplace_back(tok, "Array decayed to pointer here.");
5176 
5177  ValueFlow::Value value;
5180  value.tokvalue = var->nameToken();
5181  value.errorPath = std::move(errorPath);
5182  setTokenValue(tok, std::move(value), settings);
5183 
5184  valueFlowForwardLifetime(tok, tokenlist, errorLogger, settings);
5185  }
5186  }
5187  // Forward any lifetimes
5188  else if (std::any_of(tok->values().cbegin(), tok->values().cend(), std::mem_fn(&ValueFlow::Value::isLifetimeValue))) {
5189  valueFlowForwardLifetime(tok, tokenlist, errorLogger, settings);
5190  }
5191  }
5192 }
5193 
5194 static bool isStdMoveOrStdForwarded(Token * tok, ValueFlow::Value::MoveKind * moveKind, Token ** varTok = nullptr)
5195 {
5196  if (tok->str() != "std")
5197  return false;
5199  Token * variableToken = nullptr;
5200  if (Token::Match(tok, "std :: move ( %var% )")) {
5201  variableToken = tok->tokAt(4);
5203  } else if (Token::simpleMatch(tok, "std :: forward <")) {
5204  Token * const leftAngle = tok->tokAt(3);
5205  Token * rightAngle = leftAngle->link();
5206  if (Token::Match(rightAngle, "> ( %var% )")) {
5207  variableToken = rightAngle->tokAt(2);
5209  }
5210  }
5211  if (!variableToken)
5212  return false;
5213  if (variableToken->strAt(2) == ".") // Only partially moved
5214  return false;
5215  if (variableToken->valueType() && variableToken->valueType()->type >= ValueType::Type::VOID)
5216  return false;
5217  if (moveKind != nullptr)
5218  *moveKind = kind;
5219  if (varTok != nullptr)
5220  *varTok = variableToken;
5221  return true;
5222 }
5223 
5224 static bool isOpenParenthesisMemberFunctionCallOfVarId(const Token * openParenthesisToken, nonneg int varId)
5225 {
5226  const Token * varTok = openParenthesisToken->tokAt(-3);
5227  return Token::Match(varTok, "%varid% . %name% (", varId) &&
5228  varTok->next()->originalName().empty();
5229 }
5230 
5232 {
5233  Token* tok = moveVarTok;
5234  while (tok && tok->str() != "(")
5235  tok = tok->previous();
5236  return tok;
5237 }
5238 
5240 {
5241  if (!parameterToken)
5242  return nullptr;
5243  Token* parent = parameterToken->astParent();
5244  while (parent && !parent->isOp() && !Token::Match(parent, "[({]"))
5245  parent = parent->astParent();
5246  if (!parent)
5247  return nullptr;
5248  return nextAfterAstRightmostLeaf(parent);
5249 }
5250 
5251 static void valueFlowAfterMove(const TokenList& tokenlist, const SymbolDatabase& symboldatabase, ErrorLogger& errorLogger, const Settings& settings)
5252 {
5253  if (!tokenlist.isCPP() || settings.standards.cpp < Standards::CPP11)
5254  return;
5255  for (const Scope * scope : symboldatabase.functionScopes) {
5256  if (!scope)
5257  continue;
5258  const Token * start = scope->bodyStart;
5259  if (scope->function) {
5260  const Token * memberInitializationTok = scope->function->constructorMemberInitialization();
5261  if (memberInitializationTok)
5262  start = memberInitializationTok;
5263  }
5264 
5265  for (auto* tok = const_cast<Token*>(start); tok != scope->bodyEnd; tok = tok->next()) {
5266  Token * varTok;
5267  if (Token::Match(tok, "%var% . reset|clear (") && tok->next()->originalName().empty()) {
5268  varTok = tok;
5269 
5270  const Variable *var = tok->variable();
5271  if (!var || (!var->isLocal() && !var->isArgument()))
5272  continue;
5273 
5274  ValueFlow::Value value;
5277  value.errorPath.emplace_back(tok, "Calling " + tok->next()->expressionString() + " makes " + tok->str() + " 'non-moved'");
5278  value.setKnown();
5279 
5280  setTokenValue(tok, value, settings);
5281  if (var->scope()) {
5282  const Token* const endOfVarScope = var->scope()->bodyEnd;
5283  valueFlowForward(tok->next(), endOfVarScope, tok, std::move(value), tokenlist, errorLogger, settings);
5284  }
5285  continue;
5286  }
5287  ValueFlow::Value::MoveKind moveKind;
5288  if (!isStdMoveOrStdForwarded(tok, &moveKind, &varTok))
5289  continue;
5290  const nonneg int varId = varTok->varId();
5291  // x is not MOVED after assignment if code is: x = ... std::move(x) .. ;
5292  const Token *parent = tok->astParent();
5293  while (parent && parent->str() != "=" && parent->str() != "return" &&
5294  !(parent->str() == "(" && isOpenParenthesisMemberFunctionCallOfVarId(parent, varId)))
5295  parent = parent->astParent();
5296  if (parent &&
5297  (parent->str() == "return" || // MOVED in return statement
5298  parent->str() == "(")) // MOVED in self assignment, isOpenParenthesisMemberFunctionCallOfVarId == true
5299  continue;
5300  if (parent && parent->astOperand1() && parent->astOperand1()->varId() == varId)
5301  continue;
5302  const Token* const endOfVarScope = ValueFlow::getEndOfExprScope(varTok);
5303 
5304  Token* openParentesisOfMove = findOpenParentesisOfMove(varTok);
5305  Token* endOfFunctionCall = findEndOfFunctionCallForParameter(openParentesisOfMove);
5306  if (endOfFunctionCall) {
5307  if (endOfFunctionCall->str() == ")") {
5308  Token* ternaryColon = endOfFunctionCall->link()->astParent();
5309  while (Token::simpleMatch(ternaryColon, "("))
5310  ternaryColon = ternaryColon->astParent();
5311  if (Token::simpleMatch(ternaryColon, ":")) {
5312  endOfFunctionCall = ternaryColon->astOperand2();
5313  if (Token::simpleMatch(endOfFunctionCall, "("))
5314  endOfFunctionCall = endOfFunctionCall->link();
5315  }
5316  }
5317  ValueFlow::Value value;
5319  value.moveKind = moveKind;
5321  value.errorPath.emplace_back(tok, "Calling std::move(" + varTok->str() + ")");
5322  else // if (moveKind == ValueFlow::Value::ForwardedVariable)
5323  value.errorPath.emplace_back(tok, "Calling std::forward(" + varTok->str() + ")");
5324  value.setKnown();
5325 
5326  valueFlowForward(endOfFunctionCall, endOfVarScope, varTok, std::move(value), tokenlist, errorLogger, settings);
5327  }
5328  }
5329  }
5330 }
5331 
5332 static const Token* findIncompleteVar(const Token* start, const Token* end)
5333 {
5334  for (const Token* tok = start; tok != end; tok = tok->next()) {
5335  if (tok->isIncompleteVar())
5336  return tok;
5337  }
5338  return nullptr;
5339 }
5340 
5342  const Token* condTok,
5343  bool assume,
5344  bool impossible,
5345  const Settings& settings,
5347 {
5348  ValueFlow::Value v(val);
5349  v.setKnown();
5350  if (impossible) {
5351  v.intvalue = !v.intvalue;
5352  v.setImpossible();
5353  }
5354  v.condition = condTok;
5355  if (assume)
5356  v.errorPath.emplace_back(condTok, "Assuming condition '" + condTok->expressionString() + "' is true");
5357  else
5358  v.errorPath.emplace_back(condTok, "Assuming condition '" + condTok->expressionString() + "' is false");
5359  if (settings.debugnormal)
5360  setSourceLocation(v, loc, condTok);
5361  return v;
5362 }
5363 
5364 static std::vector<const Token*> getConditions(const Token* tok, const char* op)
5365 {
5366  std::vector<const Token*> conds = {tok};
5367  if (tok->str() == op) {
5368  std::vector<const Token*> args = astFlatten(tok, op);
5369  std::copy_if(args.cbegin(), args.cend(), std::back_inserter(conds), [&](const Token* tok2) {
5370  if (tok2->exprId() == 0)
5371  return false;
5372  if (tok2->hasKnownIntValue())
5373  return false;
5374  if (Token::Match(tok2, "%var%|.") && !astIsBool(tok2))
5375  return false;
5376  return true;
5377  });
5378  }
5379  return conds;
5380 }
5381 
5382 static bool isBreakOrContinueScope(const Token* endToken)
5383 {
5384  if (!Token::simpleMatch(endToken, "}"))
5385  return false;
5386  return Token::Match(endToken->tokAt(-2), "break|continue ;");
5387 }
5388 
5389 static const Scope* getLoopScope(const Token* tok)
5390 {
5391  if (!tok)
5392  return nullptr;
5393  const Scope* scope = tok->scope();
5394  while (scope && scope->type != Scope::eWhile && scope->type != Scope::eFor && scope->type != Scope::eDo)
5395  scope = scope->nestedIn;
5396  return scope;
5397 }
5398 
5399 //
5400 static void valueFlowConditionExpressions(const TokenList &tokenlist, const SymbolDatabase& symboldatabase, ErrorLogger &errorLogger, const Settings &settings)
5401 {
5402  if (!settings.daca && (settings.checkLevel == Settings::CheckLevel::normal))
5403  {
5404  if (settings.debugwarnings) {
5405  ErrorMessage::FileLocation loc(tokenlist.getSourceFilePath(), 0, 0);
5406  const ErrorMessage errmsg({std::move(loc)}, tokenlist.getSourceFilePath(), Severity::debug, "Analysis of condition expressions is disabled. Use --check-level=exhaustive to enable it.", "normalCheckLevelConditionExpressions", Certainty::normal);
5407  errorLogger.reportErr(errmsg);
5408  }
5409  return;
5410  }
5411 
5412  for (const Scope * scope : symboldatabase.functionScopes) {
5413  if (const Token* incompleteTok = findIncompleteVar(scope->bodyStart, scope->bodyEnd)) {
5414  if (settings.debugwarnings)
5415  bailoutIncompleteVar(tokenlist, errorLogger, incompleteTok, "Skipping function due to incomplete variable " + incompleteTok->str());
5416  continue;
5417  }
5418 
5419  if (settings.daca && (settings.checkLevel == Settings::CheckLevel::normal))
5420  continue;
5421 
5422  for (Token* tok = const_cast<Token*>(scope->bodyStart); tok != scope->bodyEnd; tok = tok->next()) {
5423  if (!Token::simpleMatch(tok, "if ("))
5424  continue;
5425  Token* parenTok = tok->next();
5426  if (!Token::simpleMatch(parenTok->link(), ") {"))
5427  continue;
5428  Token * blockTok = parenTok->link()->tokAt(1);
5429  const Token* condTok = parenTok->astOperand2();
5430  if (condTok->exprId() == 0)
5431  continue;
5432  if (condTok->hasKnownIntValue())
5433  continue;
5434  if (!isConstExpression(condTok, settings.library))
5435  continue;
5436  const bool is1 = (condTok->isComparisonOp() || condTok->tokType() == Token::eLogicalOp || astIsBool(condTok));
5437 
5438  Token* startTok = blockTok;
5439  // Inner condition
5440  {
5441  for (const Token* condTok2 : getConditions(condTok, "&&")) {
5442  if (is1) {
5443  const bool isBool = astIsBool(condTok2) || Token::Match(condTok2, "%comp%|%oror%|&&");
5444  SameExpressionAnalyzer a1(condTok2, makeConditionValue(1, condTok2, /*assume*/ true, !isBool, settings), tokenlist, settings); // don't set '1' for non-boolean expressions
5445  valueFlowGenericForward(startTok, startTok->link(), a1, tokenlist, errorLogger, settings);
5446  }
5447 
5448  OppositeExpressionAnalyzer a2(true, condTok2, makeConditionValue(0, condTok2, true, false, settings), tokenlist, settings);
5449  valueFlowGenericForward(startTok, startTok->link(), a2, tokenlist, errorLogger, settings);
5450  }
5451  }
5452 
5453  std::vector<const Token*> conds = getConditions(condTok, "||");
5454 
5455  // Check else block
5456  if (Token::simpleMatch(startTok->link(), "} else {")) {
5457  startTok = startTok->link()->tokAt(2);
5458  for (const Token* condTok2:conds) {
5459  SameExpressionAnalyzer a1(condTok2, makeConditionValue(0, condTok2, false, false, settings), tokenlist, settings);
5460  valueFlowGenericForward(startTok, startTok->link(), a1, tokenlist, errorLogger, settings);
5461 
5462  if (is1) {
5463  OppositeExpressionAnalyzer a2(true, condTok2, makeConditionValue(1, condTok2, false, false, settings), tokenlist, settings);
5464  valueFlowGenericForward(startTok, startTok->link(), a2, tokenlist, errorLogger, settings);
5465  }
5466  }
5467  }
5468 
5469  // Check if the block terminates early
5470  if (isEscapeScope(blockTok, settings)) {
5471  const Scope* scope2 = scope;
5472  // If escaping a loop then only use the loop scope
5473  if (isBreakOrContinueScope(blockTok->link())) {
5474  scope2 = getLoopScope(blockTok->link());
5475  if (!scope2)
5476  continue;
5477  }
5478  for (const Token* condTok2:conds) {
5479  SameExpressionAnalyzer a1(condTok2, makeConditionValue(0, condTok2, false, false, settings), tokenlist, settings);
5480  valueFlowGenericForward(startTok->link()->next(), scope2->bodyEnd, a1, tokenlist, errorLogger, settings);
5481 
5482  if (is1) {
5483  OppositeExpressionAnalyzer a2(true, condTok2, makeConditionValue(1, condTok2, false, false, settings), tokenlist, settings);
5484  valueFlowGenericForward(startTok->link()->next(), scope2->bodyEnd, a2, tokenlist, errorLogger, settings);
5485  }
5486  }
5487  }
5488  }
5489  }
5490 }
5491 
5492 static bool isTruncated(const ValueType* src, const ValueType* dst, const Settings& settings)
5493 {
5494  if (src->pointer > 0 || dst->pointer > 0)
5495  return src->pointer != dst->pointer;
5496  if (src->smartPointer && dst->smartPointer)
5497  return false;
5498  if ((src->isIntegral() && dst->isIntegral()) || (src->isFloat() && dst->isFloat())) {
5499  const size_t srcSize = ValueFlow::getSizeOf(*src, settings);
5500  const size_t dstSize = ValueFlow::getSizeOf(*dst, settings);
5501  if (srcSize > dstSize)
5502  return true;
5503  if (srcSize == dstSize && src->sign != dst->sign)
5504  return true;
5505  } else if (src->type == dst->type) {
5506  if (src->type == ValueType::Type::RECORD)
5507  return src->typeScope != dst->typeScope;
5508  } else {
5509  return true;
5510  }
5511  return false;
5512 }
5513 
5514 static void setSymbolic(ValueFlow::Value& value, const Token* tok)
5515 {
5516  assert(tok && tok->exprId() > 0 && "Missing expr id for symbolic value");
5518  value.tokvalue = tok;
5519 }
5520 
5522 {
5523  ValueFlow::Value value;
5524  value.setKnown();
5525  setSymbolic(value, tok);
5526  value.intvalue = delta;
5527  return value;
5528 }
5529 
5530 static std::set<nonneg int> getVarIds(const Token* tok)
5531 {
5532  std::set<nonneg int> result;
5533  visitAstNodes(tok, [&](const Token* child) {
5534  if (child->varId() > 0)
5535  result.insert(child->varId());
5537  });
5538  return result;
5539 }
5540 
5541 static void valueFlowSymbolic(const TokenList& tokenlist, const SymbolDatabase& symboldatabase, ErrorLogger& errorLogger, const Settings& settings)
5542 {
5543  for (const Scope* scope : symboldatabase.functionScopes) {
5544  for (auto* tok = const_cast<Token*>(scope->bodyStart); tok != scope->bodyEnd; tok = tok->next()) {
5545  if (!Token::simpleMatch(tok, "="))
5546  continue;
5547  if (tok->astParent())
5548  continue;
5549  if (!tok->astOperand1())
5550  continue;
5551  if (!tok->astOperand2())
5552  continue;
5553  if (tok->astOperand1()->hasKnownIntValue())
5554  continue;
5555  if (tok->astOperand2()->hasKnownIntValue())
5556  continue;
5557  if (tok->astOperand1()->exprId() == 0)
5558  continue;
5559  if (tok->astOperand2()->exprId() == 0)
5560  continue;
5561  if (!isConstExpression(tok->astOperand2(), settings.library))
5562  continue;
5563  if (tok->astOperand1()->valueType() && tok->astOperand2()->valueType()) {
5564  if (isTruncated(
5565  tok->astOperand2()->valueType(), tok->astOperand1()->valueType(), settings))
5566  continue;
5567  } else if (isDifferentType(tok->astOperand2(), tok->astOperand1())) {
5568  continue;
5569  }
5570  const std::set<nonneg int> rhsVarIds = getVarIds(tok->astOperand2());
5571  const std::vector<const Variable*> vars = getLHSVariables(tok);
5572  if (std::any_of(vars.cbegin(), vars.cend(), [&](const Variable* var) {
5573  if (rhsVarIds.count(var->declarationId()) > 0)
5574  return true;
5575  if (var->isLocal())
5576  return var->isStatic();
5577  return !var->isArgument();
5578  }))
5579  continue;
5580 
5581  if (findAstNode(tok, [](const Token* child) {
5582  return child->isIncompleteVar();
5583  }))
5584  continue;
5585 
5586  Token* start = nextAfterAstRightmostLeaf(tok);
5587  const Token* end = ValueFlow::getEndOfExprScope(tok->astOperand1(), scope);
5588 
5590  rhs.errorPath.emplace_back(tok,
5591  tok->astOperand1()->expressionString() + " is assigned '" +
5592  tok->astOperand2()->expressionString() + "' here.");
5593  valueFlowForward(start, end, tok->astOperand1(), std::move(rhs), tokenlist, errorLogger, settings);
5594 
5596  lhs.errorPath.emplace_back(tok,
5597  tok->astOperand1()->expressionString() + " is assigned '" +
5598  tok->astOperand2()->expressionString() + "' here.");
5599  valueFlowForward(start, end, tok->astOperand2(), std::move(lhs), tokenlist, errorLogger, settings);
5600  }
5601  }
5602 }
5603 
5604 static const Token* isStrlenOf(const Token* tok, const Token* expr, int depth = 10)
5605 {
5606  if (depth < 0)
5607  return nullptr;
5608  if (!tok)
5609  return nullptr;
5610  if (!expr)
5611  return nullptr;
5612  if (expr->exprId() == 0)
5613  return nullptr;
5614  if (Token::simpleMatch(tok->previous(), "strlen (")) {
5615  if (tok->astOperand2()->exprId() == expr->exprId())
5616  return tok;
5617  } else {
5618  for (const ValueFlow::Value& v : tok->values()) {
5619  if (!v.isSymbolicValue())
5620  continue;
5621  if (!v.isKnown())
5622  continue;
5623  if (v.intvalue != 0)
5624  continue;
5625  if (const Token* next = isStrlenOf(v.tokvalue, expr, depth - 1))
5626  return next;
5627  }
5628  }
5629  return nullptr;
5630 }
5631 
5632 static ValueFlow::Value inferCondition(const std::string& op, const Token* varTok, MathLib::bigint val);
5633 
5634 static void valueFlowSymbolicOperators(const SymbolDatabase& symboldatabase, const Settings& settings)
5635 {
5636  for (const Scope* scope : symboldatabase.functionScopes) {
5637  for (auto* tok = const_cast<Token*>(scope->bodyStart); tok != scope->bodyEnd; tok = tok->next()) {
5638  if (tok->hasKnownIntValue())
5639  continue;
5640 
5641  if (Token::Match(tok, "abs|labs|llabs|fabs|fabsf|fabsl (")) {
5642  const Token* arg = tok->next()->astOperand2();
5643  if (!arg)
5644  continue;
5645  if (arg->exprId() == 0)
5646  continue;
5647  ValueFlow::Value c = inferCondition(">=", arg, 0);
5648  if (!c.isKnown())
5649  continue;
5650 
5651  ValueFlow::Value v = makeSymbolic(arg);
5652  v.errorPath = c.errorPath;
5653  v.errorPath.emplace_back(tok, "Passed to " + tok->str());
5654  if (c.intvalue == 0)
5655  v.setImpossible();
5656  else
5657  v.setKnown();
5658  setTokenValue(tok->next(), std::move(v), settings);
5659  } else if (Token::Match(tok, "*|/|<<|>>|^|+|-|%or%")) {
5660  if (!tok->astOperand1())
5661  continue;
5662  if (!tok->astOperand2())
5663  continue;
5664  if (!astIsIntegral(tok->astOperand1(), false) && !astIsIntegral(tok->astOperand2(), false))
5665  continue;
5666  const ValueFlow::Value* constant = nullptr;
5667  const Token* vartok = nullptr;
5668  if (tok->astOperand1()->hasKnownIntValue()) {
5669  constant = &tok->astOperand1()->values().front();
5670  vartok = tok->astOperand2();
5671  }
5672  if (tok->astOperand2()->hasKnownIntValue()) {
5673  constant = &tok->astOperand2()->values().front();
5674  vartok = tok->astOperand1();
5675  }
5676  if (!constant)
5677  continue;
5678  if (!vartok)
5679  continue;
5680  if (vartok->exprId() == 0)
5681  continue;
5682  if (Token::Match(tok, "<<|>>|/") && !astIsLHS(vartok))
5683  continue;
5684  if (Token::Match(tok, "<<|>>|^|+|-|%or%") && constant->intvalue != 0)
5685  continue;
5686  if (Token::Match(tok, "*|/") && constant->intvalue != 1)
5687  continue;
5688  std::vector<ValueFlow::Value> values = {makeSymbolic(vartok)};
5689  std::unordered_set<nonneg int> ids = {vartok->exprId()};
5690  std::copy_if(vartok->values().cbegin(),
5691  vartok->values().cend(),
5692  std::back_inserter(values),
5693  [&](const ValueFlow::Value& v) {
5694  if (!v.isSymbolicValue())
5695  return false;
5696  if (!v.tokvalue)
5697  return false;
5698  return ids.insert(v.tokvalue->exprId()).second;
5699  });
5700  for (ValueFlow::Value& v : values)
5701  setTokenValue(tok, std::move(v), settings);
5702  } else if (Token::simpleMatch(tok, "[")) {
5703  const Token* arrayTok = tok->astOperand1();
5704  const Token* indexTok = tok->astOperand2();
5705  if (!arrayTok)
5706  continue;
5707  if (!indexTok)
5708  continue;
5709  for (const ValueFlow::Value& value : indexTok->values()) {
5710  if (!value.isSymbolicValue())
5711  continue;
5712  if (value.intvalue != 0)
5713  continue;
5714  const Token* strlenTok = isStrlenOf(value.tokvalue, arrayTok);
5715  if (!strlenTok)
5716  continue;
5717  ValueFlow::Value v = value;
5720  v.errorPath.emplace_back(strlenTok, "Return index of first '\\0' character in string");
5721  setTokenValue(tok, std::move(v), settings);
5722  }
5723  }
5724  }
5725  }
5726 }
5727 
5729  const Token* expr;
5730  explicit SymbolicInferModel(const Token* tok) : expr(tok) {
5731  assert(expr->exprId() != 0);
5732  }
5733  bool match(const ValueFlow::Value& value) const override
5734  {
5735  return value.isSymbolicValue() && value.tokvalue && value.tokvalue->exprId() == expr->exprId();
5736  }
5738  {
5739  ValueFlow::Value result(value);
5741  result.tokvalue = expr;
5742  result.setKnown();
5743  return result;
5744  }
5745 };
5746 
5747 static void valueFlowSymbolicInfer(const SymbolDatabase& symboldatabase, const Settings& settings)
5748 {
5749  for (const Scope* scope : symboldatabase.functionScopes) {
5750  for (auto* tok = const_cast<Token*>(scope->bodyStart); tok != scope->bodyEnd; tok = tok->next()) {
5751  if (!Token::Match(tok, "-|%comp%"))
5752  continue;
5753  if (tok->hasKnownIntValue())
5754  continue;
5755  if (!tok->astOperand1())
5756  continue;
5757  if (!tok->astOperand2())
5758  continue;
5759  if (tok->astOperand1()->exprId() == 0)
5760  continue;
5761  if (tok->astOperand2()->exprId() == 0)
5762  continue;
5763  if (tok->astOperand1()->hasKnownIntValue())
5764  continue;
5765  if (tok->astOperand2()->hasKnownIntValue())
5766  continue;
5767  if (astIsFloat(tok->astOperand1(), false))
5768  continue;
5769  if (astIsFloat(tok->astOperand2(), false))
5770  continue;
5771 
5772  SymbolicInferModel leftModel{tok->astOperand1()};
5773  std::vector<ValueFlow::Value> values = infer(leftModel, tok->str(), 0, tok->astOperand2()->values());
5774  if (values.empty()) {
5775  SymbolicInferModel rightModel{tok->astOperand2()};
5776  values = infer(rightModel, tok->str(), tok->astOperand1()->values(), 0);
5777  }
5778  for (ValueFlow::Value& value : values) {
5779  setTokenValue(tok, std::move(value), settings);
5780  }
5781  }
5782  }
5783 }
5784 
5785 template<class ContainerOfValue>
5786 static void valueFlowForwardConst(Token* start,
5787  const Token* end,
5788  const Variable* var,
5789  const ContainerOfValue& values,
5790  const Settings& settings,
5791  int /*unused*/ = 0)
5792 {
5793  if (!precedes(start, end))
5794  throw InternalError(var->nameToken(), "valueFlowForwardConst: start token does not precede the end token.");
5795  for (Token* tok = start; tok != end; tok = tok->next()) {
5796  if (tok->varId() == var->declarationId()) {
5797  for (const ValueFlow::Value& value : values)
5798  setTokenValue(tok, value, settings);
5799  } else {
5800  [&] {
5801  // Follow references
5802  auto refs = followAllReferences(tok);
5803  auto it = std::find_if(refs.cbegin(), refs.cend(), [&](const ReferenceToken& ref) {
5804  return ref.token->varId() == var->declarationId();
5805  });
5806  if (it != refs.end()) {
5807  for (ValueFlow::Value value : values) {
5808  if (refs.size() > 1)
5809  value.setInconclusive();
5810  value.errorPath.insert(value.errorPath.end(), it->errors.cbegin(), it->errors.cend());
5811  setTokenValue(tok, std::move(value), settings);
5812  }
5813  return;
5814  }
5815  // Follow symbolic values
5816  for (const ValueFlow::Value& v : tok->values()) {
5817  if (!v.isSymbolicValue())
5818  continue;
5819  if (!v.tokvalue)
5820  continue;
5821  if (v.tokvalue->varId() != var->declarationId())
5822  continue;
5823  for (ValueFlow::Value value : values) {
5824  if (!v.isKnown() && value.isImpossible())
5825  continue;
5826  if (v.intvalue != 0) {
5827  if (!value.isIntValue())
5828  continue;
5829  value.intvalue += v.intvalue;
5830  }
5831  if (!value.isImpossible())
5832  value.valueKind = v.valueKind;
5833  value.bound = v.bound;
5834  value.errorPath.insert(value.errorPath.end(), v.errorPath.cbegin(), v.errorPath.cend());
5835  setTokenValue(tok, std::move(value), settings);
5836  }
5837  }
5838  }();
5839  }
5840  }
5841 }
5842 
5843 static void valueFlowForwardConst(Token* start,
5844  const Token* end,
5845  const Variable* var,
5846  const std::initializer_list<ValueFlow::Value>& values,
5847  const Settings& settings)
5848 {
5849  valueFlowForwardConst(start, end, var, values, settings, 0);
5850 }
5851 
5853  const Token* start,
5854  const Token* end,
5855  const Settings& settings)
5856 {
5858  const Token* next = start;
5859  while ((next = findExpressionChangedSkipDeadCode(
5860  var->nameToken(), next->next(), end, settings, &evaluateKnownValues))) {
5862  if (next->varId() != var->declarationId())
5864  if (Token::simpleMatch(next->astParent(), "++"))
5866  else if (Token::simpleMatch(next->astParent(), "--"))
5868  else
5870  if (result == ValueFlow::Value::Bound::Point)
5871  result = b;
5872  else if (result != b)
5874  }
5875  return result;
5876 }
5877 
5878 static bool isInitialVarAssign(const Token* tok)
5879 {
5880  if (!tok)
5881  return false;
5882  if (!tok->variable())
5883  return false;
5884  if (tok->variable()->nameToken() == tok)
5885  return true;
5886  const Token* prev = tok->tokAt(2);
5887  if (!Token::Match(prev, "%var% ; %var%"))
5888  return false;
5889  return tok->varId() == prev->varId() && tok->variable()->nameToken() == prev;
5890 }
5891 
5892 static void valueFlowForwardAssign(Token* const tok,
5893  const Token* expr,
5894  std::vector<const Variable*> vars,
5895  std::list<ValueFlow::Value> values,
5896  const bool init,
5897  const TokenList& tokenlist,
5898  ErrorLogger& errorLogger,
5899  const Settings& settings)
5900 {
5901  if (Token::simpleMatch(tok->astParent(), "return"))
5902  return;
5903  const Token* endOfVarScope = ValueFlow::getEndOfExprScope(expr);
5904  if (std::any_of(values.cbegin(), values.cend(), std::mem_fn(&ValueFlow::Value::isLifetimeValue))) {
5905  valueFlowForwardLifetime(tok, tokenlist, errorLogger, settings);
5906  values.remove_if(std::mem_fn(&ValueFlow::Value::isLifetimeValue));
5907  }
5908  if (std::all_of(
5909  vars.cbegin(), vars.cend(), [&](const Variable* var) {
5910  return !var->isPointer() && !var->isSmartPointer();
5911  }))
5912  values.remove_if(std::mem_fn(&ValueFlow::Value::isTokValue));
5913  if (tok->astParent()) {
5914  for (ValueFlow::Value& value : values) {
5915  std::string valueKind;
5918  valueKind = "never ";
5919  else if (value.bound == ValueFlow::Value::Bound::Lower)
5920  valueKind = "less than ";
5921  else if (value.bound == ValueFlow::Value::Bound::Upper)
5922  valueKind = "greater than ";
5923  }
5924  std::string info = "Assignment '" + tok->astParent()->expressionString() + "', assigned value is " + valueKind + value.infoString();
5925  value.errorPath.emplace_back(tok, std::move(info));
5926  }
5927  }
5928 
5929  if (tokenlist.isCPP() && vars.size() == 1 && Token::Match(vars.front()->typeStartToken(), "bool|_Bool")) {
5930  for (ValueFlow::Value& value : values) {
5931  if (value.isImpossible())
5932  continue;
5933  if (value.isIntValue())
5934  value.intvalue = (value.intvalue != 0);
5935  if (value.isTokValue())
5936  value.intvalue = (value.tokvalue != nullptr);
5937  }
5938  }
5939 
5940  // Static variable initialisation?
5941  if (vars.size() == 1 && vars.front()->isStatic() && init)
5942  lowerToPossible(values);
5943 
5944  // is volatile
5945  if (std::any_of(vars.cbegin(), vars.cend(), [&](const Variable* var) {
5946  return var->isVolatile();
5947  }))
5948  lowerToPossible(values);
5949 
5950  // Skip RHS
5951  Token* nextExpression = tok->astParent() ? nextAfterAstRightmostLeaf(tok->astParent()) : tok->next();
5952  if (!nextExpression)
5953  return;
5954 
5955  for (ValueFlow::Value& value : values) {
5956  if (value.isSymbolicValue())
5957  continue;
5958  if (value.isTokValue())
5959  continue;
5960  value.tokvalue = tok;
5961  }
5962  // Const variable
5963  if (expr->variable() && expr->variable()->isConst() && !expr->variable()->isReference()) {
5964  auto it = std::remove_if(values.begin(), values.end(), [](const ValueFlow::Value& value) {
5965  if (!value.isKnown())
5966  return false;
5967  if (value.isIntValue())
5968  return true;
5969  if (value.isFloatValue())
5970  return true;
5971  if (value.isContainerSizeValue())
5972  return true;
5973  if (value.isIteratorValue())
5974  return true;
5975  return false;
5976  });
5977  std::list<ValueFlow::Value> constValues;
5978  constValues.splice(constValues.end(), values, it, values.end());
5979  valueFlowForwardConst(nextExpression, endOfVarScope, expr->variable(), constValues, settings);
5980  }
5981  if (isInitialVarAssign(expr)) {
5982  // Check if variable is only incremented or decremented
5983  ValueFlow::Value::Bound b = findVarBound(expr->variable(), nextExpression, endOfVarScope, settings);
5984  if (b != ValueFlow::Value::Bound::Point) {
5985  auto knownValueIt = std::find_if(values.begin(), values.end(), [](const ValueFlow::Value& value) {
5986  if (!value.isKnown())
5987  return false;
5988  return value.isIntValue();
5989  });
5990  if (knownValueIt != values.end()) {
5991  ValueFlow::Value value = *knownValueIt;
5992  value.bound = b;
5993  value.invertRange();
5994  value.setImpossible();
5995  valueFlowForwardConst(nextExpression, endOfVarScope, expr->variable(), {std::move(value)}, settings);
5996  }
5997  }
5998  }
5999  valueFlowForward(nextExpression, endOfVarScope, expr, std::move(values), tokenlist, errorLogger, settings);
6000 }
6001 
6002 static void valueFlowForwardAssign(Token* const tok,
6003  const Variable* const var,
6004  const std::list<ValueFlow::Value>& values,
6005  const bool /*unused*/,
6006  const bool init,
6007  const TokenList& tokenlist,
6008  ErrorLogger& errorLogger,
6009  const Settings& settings)
6010 {
6011  valueFlowForwardAssign(tok, var->nameToken(), {var}, values, init, tokenlist, errorLogger, settings);
6012 }
6013 
6014 static std::list<ValueFlow::Value> truncateValues(std::list<ValueFlow::Value> values,
6015  const ValueType* dst,
6016  const ValueType* src,
6017  const Settings& settings)
6018 {
6019  if (!dst || !dst->isIntegral())
6020  return values;
6021 
6022  const size_t sz = ValueFlow::getSizeOf(*dst, settings);
6023 
6024  if (src) {
6025  const size_t osz = ValueFlow::getSizeOf(*src, settings);
6026  if (osz >= sz && dst->sign == ValueType::Sign::SIGNED && src->sign == ValueType::Sign::UNSIGNED) {
6027  values.remove_if([&](const ValueFlow::Value& value) {
6028  if (!value.isIntValue())
6029  return false;
6030  if (!value.isImpossible())
6031  return false;
6033  return false;
6034  if (osz == sz && value.intvalue < 0)
6035  return true;
6036  if (osz > sz)
6037  return true;
6038  return false;
6039  });
6040  }
6041  }
6042 
6043  for (ValueFlow::Value &value : values) {
6044  // Don't truncate impossible values since those can be outside of the valid range
6045  if (value.isImpossible())
6046  continue;
6047  if (value.isFloatValue()) {
6048  value.intvalue = value.floatValue;
6050  }
6051 
6052  if (value.isIntValue() && sz > 0 && sz < 8)
6053  value.intvalue = truncateIntValue(value.intvalue, sz, dst->sign);
6054  }
6055  return values;
6056 }
6057 
6058 static bool isVariableInit(const Token *tok)
6059 {
6060  return (tok->str() == "(" || tok->str() == "{") &&
6061  (tok->isBinaryOp() || (tok->astOperand1() && tok->link() == tok->next())) &&
6062  tok->astOperand1()->variable() &&
6063  tok->astOperand1()->variable()->nameToken() == tok->astOperand1() &&
6064  tok->astOperand1()->variable()->valueType() &&
6065  tok->astOperand1()->variable()->valueType()->type >= ValueType::Type::VOID &&
6066  !Token::simpleMatch(tok->astOperand2(), ",");
6067 }
6068 
6069 // Return true if two associative containers intersect
6070 template<class C1, class C2>
6071 static bool intersects(const C1& c1, const C2& c2)
6072 {
6073  if (c1.size() > c2.size())
6074  return intersects(c2, c1);
6075  // NOLINTNEXTLINE(readability-use-anyofallof) - TODO: fix if possible / also Cppcheck false negative
6076  for (auto&& x : c1) {
6077  if (c2.find(x) != c2.end())
6078  return true;
6079  }
6080  return false;
6081 }
6082 
6083 static void valueFlowAfterAssign(TokenList &tokenlist,
6084  const SymbolDatabase& symboldatabase,
6085  ErrorLogger &errorLogger,
6086  const Settings &settings,
6087  const std::set<const Scope*>& skippedFunctions)
6088 {
6089  for (const Scope * scope : symboldatabase.functionScopes) {
6090  if (skippedFunctions.count(scope))
6091  continue;
6092  std::unordered_map<nonneg int, std::unordered_set<nonneg int>> backAssigns;
6093  for (auto* tok = const_cast<Token*>(scope->bodyStart); tok != scope->bodyEnd; tok = tok->next()) {
6094  // Assignment
6095  bool isInit = false;
6096  if (tok->str() != "=" && !(isInit = isVariableInit(tok)))
6097  continue;
6098 
6099  if (tok->astParent() && !((tok->astParent()->str() == ";" && astIsLHS(tok)) || tok->astParent()->str() == "*"))
6100  continue;
6101 
6102  // Lhs should be a variable
6103  if (!tok->astOperand1() || !tok->astOperand1()->exprId())
6104  continue;
6105  std::vector<const Variable*> vars = getLHSVariables(tok);
6106 
6107  // Rhs values..
6108  Token* rhs = tok->astOperand2();
6109  if (!rhs && isInit)
6110  rhs = tok;
6111  if (!rhs || rhs->values().empty())
6112  continue;
6113 
6114  std::list<ValueFlow::Value> values = truncateValues(
6115  rhs->values(), tok->astOperand1()->valueType(), rhs->valueType(), settings);
6116  // Remove known values
6117  std::set<ValueFlow::Value::ValueType> types;
6118  if (tok->astOperand1()->hasKnownValue()) {
6119  for (const ValueFlow::Value& value:tok->astOperand1()->values()) {
6120  if (value.isKnown() && !value.isSymbolicValue())
6121  types.insert(value.valueType);
6122  }
6123  }
6124  values.remove_if([&](const ValueFlow::Value& value) {
6125  return types.count(value.valueType) > 0;
6126  });
6127  // Remove container size if its not a container
6128  if (!astIsContainer(tok->astOperand2()))
6129  values.remove_if([&](const ValueFlow::Value& value) {
6131  });
6132  // Remove symbolic values that are the same as the LHS
6133  values.remove_if([&](const ValueFlow::Value& value) {
6134  if (value.isSymbolicValue() && value.tokvalue)
6135  return value.tokvalue->exprId() == tok->astOperand1()->exprId();
6136  return false;
6137  });
6138  // Find references to LHS in RHS
6139  auto isIncremental = [&](const Token* tok2) -> bool {
6140  return findAstNode(tok2,
6141  [&](const Token* child) {
6142  return child->exprId() == tok->astOperand1()->exprId();
6143  });
6144  };
6145  // Check symbolic values as well
6146  const bool incremental = isIncremental(tok->astOperand2()) ||
6147  std::any_of(values.cbegin(), values.cend(), [&](const ValueFlow::Value& value) {
6148  if (!value.isSymbolicValue())
6149  return false;
6150  return isIncremental(value.tokvalue);
6151  });
6152  // Remove values from the same assignment if it is incremental
6153  if (incremental) {
6154  values.remove_if([&](const ValueFlow::Value& value) {
6155  if (value.tokvalue)
6156  return value.tokvalue == tok->astOperand2();
6157  return false;
6158  });
6159  }
6160  // If assignment copy by value, remove Uninit values..
6161  if ((tok->astOperand1()->valueType() && tok->astOperand1()->valueType()->pointer == 0) ||
6162  (tok->astOperand1()->variable() && tok->astOperand1()->variable()->isReference() && tok->astOperand1()->variable()->nameToken() == tok->astOperand1()))
6163  values.remove_if([&](const ValueFlow::Value& value) {
6164  return value.isUninitValue();
6165  });
6166  if (values.empty())
6167  continue;
6168  const bool init = vars.size() == 1 && (vars.front()->nameToken() == tok->astOperand1() || tok->isSplittedVarDeclEq());
6170  rhs, tok->astOperand1(), std::move(vars), values, init, tokenlist, errorLogger, settings);
6171  // Back propagate symbolic values
6172  if (tok->astOperand1()->exprId() > 0) {
6173  Token* start = nextAfterAstRightmostLeaf(tok);
6174  const Token* end = scope->bodyEnd;
6175  // Collect symbolic ids
6176  std::unordered_set<nonneg int> ids;
6177  for (const ValueFlow::Value& value : values) {
6178  if (!value.isSymbolicValue())
6179  continue;
6180  if (!value.tokvalue)
6181  continue;
6182  if (value.tokvalue->exprId() == 0)
6183  continue;
6184  ids.insert(value.tokvalue->exprId());
6185  }
6186  for (ValueFlow::Value value : values) {
6187  if (!value.isSymbolicValue())
6188  continue;
6189  const Token* expr = value.tokvalue;
6190  value.intvalue = -value.intvalue;
6191  value.tokvalue = tok->astOperand1();
6192 
6193  // Skip if it intersects with an already assigned symbol
6194  auto& s = backAssigns[value.tokvalue->exprId()];
6195  if (intersects(s, ids))
6196  continue;
6197  s.insert(expr->exprId());
6198 
6199  value.errorPath.emplace_back(tok,
6200  tok->astOperand1()->expressionString() + " is assigned '" +
6201  tok->astOperand2()->expressionString() + "' here.");
6202  valueFlowForward(start, end, expr, std::move(value), tokenlist, errorLogger, settings);
6203  }
6204  }
6205  }
6206  }
6207 }
6208 
6209 static std::vector<const Variable*> getVariables(const Token* tok)
6210 {
6211  std::vector<const Variable*> result;
6212  visitAstNodes(tok, [&](const Token* child) {
6213  if (child->variable())
6214  result.push_back(child->variable());
6216  });
6217  return result;
6218 }
6219 
6220 static void valueFlowAfterSwap(const TokenList& tokenlist,
6221  const SymbolDatabase& symboldatabase,
6222  ErrorLogger& errorLogger,
6223  const Settings& settings)
6224 {
6225  for (const Scope* scope : symboldatabase.functionScopes) {
6226  for (auto* tok = const_cast<Token*>(scope->bodyStart); tok != scope->bodyEnd; tok = tok->next()) {
6227  if (!Token::simpleMatch(tok, "swap ("))
6228  continue;
6229  if (!Token::simpleMatch(tok->next()->astOperand2(), ","))
6230  continue;
6231  std::vector<Token*> args = astFlatten(tok->next()->astOperand2(), ",");
6232  if (args.size() != 2)
6233  continue;
6234  if (args[0]->exprId() == 0)
6235  continue;
6236  if (args[1]->exprId() == 0)
6237  continue;
6238  for (int i = 0; i < 2; i++) {
6239  std::vector<const Variable*> vars = getVariables(args[0]);
6240  const std::list<ValueFlow::Value>& values = args[0]->values();
6241  valueFlowForwardAssign(args[0], args[1], std::move(vars), values, false, tokenlist, errorLogger, settings);
6242  std::swap(args[0], args[1]);
6243  }
6244  }
6245  }
6246 }
6247 
6248 static void valueFlowSetConditionToKnown(const Token* tok, std::list<ValueFlow::Value>& values, bool then)
6249 {
6250  if (values.empty())
6251  return;
6252  if (then && !Token::Match(tok, "==|!|("))
6253  return;
6254  if (!then && !Token::Match(tok, "!=|%var%|("))
6255  return;
6256  if (isConditionKnown(tok, then))
6257  changePossibleToKnown(values);
6258 }
6259 
6260 static bool isBreakScope(const Token* const endToken)
6261 {
6262  if (!Token::simpleMatch(endToken, "}"))
6263  return false;
6264  if (!Token::simpleMatch(endToken->link(), "{"))
6265  return false;
6266  return Token::findmatch(endToken->link(), "break|goto", endToken);
6267 }
6268 
6270 {
6271  v.invertRange();
6272  v.setImpossible();
6273  return v;
6274 }
6275 
6276 static void insertImpossible(std::list<ValueFlow::Value>& values, const std::list<ValueFlow::Value>& input)
6277 {
6278  std::transform(input.cbegin(), input.cend(), std::back_inserter(values), &ValueFlow::asImpossible);
6279 }
6280 
6281 static void insertNegateKnown(std::list<ValueFlow::Value>& values, const std::list<ValueFlow::Value>& input)
6282 {
6283  for (ValueFlow::Value value:input) {
6284  if (!value.isIntValue() && !value.isContainerSizeValue())
6285  continue;
6286  value.intvalue = !value.intvalue;
6287  value.setKnown();
6288  values.push_back(std::move(value));
6289  }
6290 }
6291 
6293  struct Condition {
6294  const Token* vartok{};
6295  std::list<ValueFlow::Value> true_values;
6296  std::list<ValueFlow::Value> false_values;
6297  bool inverted = false;
6298  // Whether to insert impossible values for the condition or only use possible values
6299  bool impossible = true;
6300 
6301  bool isBool() const {
6302  return astIsBool(vartok);
6303  }
6304 
6305  static MathLib::bigint findPath(const std::list<ValueFlow::Value>& values)
6306  {
6307  auto it = std::find_if(values.cbegin(), values.cend(), [](const ValueFlow::Value& v) {
6308  return v.path > 0;
6309  });
6310  if (it == values.end())
6311  return 0;
6312  assert(std::all_of(it, values.end(), [&](const ValueFlow::Value& v) {
6313  return v.path == 0 || v.path == it->path;
6314  }));
6315  return it->path;
6316  }
6317 
6319  {
6320  assert(std::abs(findPath(true_values) - findPath(false_values)) == 0);
6322  }
6323 
6325  std::list<ValueFlow::Value>& thenValues,
6326  std::list<ValueFlow::Value>& elseValues,
6327  bool known = false) const
6328  {
6329  const MathLib::bigint path = getPath();
6330  const bool allowKnown = path == 0;
6331  const bool allowImpossible = impossible && allowKnown;
6332 
6333  bool inverted2 = inverted;
6334  Token* ctx = skipNotAndCasts(condTok, &inverted2);
6335  bool then = !inverted || !inverted2;
6336 
6337  if (!Token::Match(condTok, "!=|=|(|.") && condTok != vartok) {
6338  thenValues.insert(thenValues.end(), true_values.cbegin(), true_values.cend());
6339  if (allowImpossible && (known || isConditionKnown(ctx, !then)))
6340  insertImpossible(elseValues, false_values);
6341  }
6342  if (!Token::Match(condTok, "==|!")) {
6343  elseValues.insert(elseValues.end(), false_values.cbegin(), false_values.cend());
6344  if (allowImpossible && (known || isConditionKnown(ctx, then))) {
6345  insertImpossible(thenValues, true_values);
6346  if (isBool())
6347  insertNegateKnown(thenValues, true_values);
6348  }
6349  }
6350 
6351  if (inverted2)
6352  std::swap(thenValues, elseValues);
6353 
6354  return ctx;
6355  }
6356  };
6357 
6358  virtual std::vector<Condition> parse(const Token* tok, const Settings& settings) const = 0;
6359 
6361  const Token* stop,
6362  const Token* exprTok,
6363  const std::list<ValueFlow::Value>& values,
6364  TokenList& tokenlist,
6365  ErrorLogger& errorLogger,
6366  const Settings& settings,
6368  {
6369  return valueFlowForward(start->next(), stop, exprTok, values, tokenlist, errorLogger, settings, loc);
6370  }
6371 
6373  const Token* exprTok,
6374  const std::list<ValueFlow::Value>& values,
6375  TokenList& tokenlist,
6376  ErrorLogger& errorLogger,
6377  const Settings& settings,
6379  {
6380  return valueFlowForwardRecursive(top, exprTok, values, tokenlist, errorLogger, settings, loc);
6381  }
6382 
6383  virtual void reverse(Token* start,
6384  const Token* endToken,
6385  const Token* exprTok,
6386  const std::list<ValueFlow::Value>& values,
6387  TokenList& tokenlist,
6388  ErrorLogger& errorLogger,
6389  const Settings& settings,
6391  {
6392  valueFlowReverse(start, endToken, exprTok, values, tokenlist, errorLogger, settings, loc);
6393  }
6394 
6395  void traverseCondition(const SymbolDatabase& symboldatabase,
6396  const Settings& settings,
6397  const std::set<const Scope*>& skippedFunctions,
6398  const std::function<void(const Condition& cond, Token* tok, const Scope* scope)>& f) const
6399  {
6400  for (const Scope *scope : symboldatabase.functionScopes) {
6401  if (skippedFunctions.count(scope))
6402  continue;
6403  for (auto *tok = const_cast<Token *>(scope->bodyStart); tok != scope->bodyEnd; tok = tok->next()) {
6404  if (Token::Match(tok, "if|while|for ("))
6405  continue;
6406  if (Token::Match(tok, ":|;|,"))
6407  continue;
6408 
6409  const Token* top = tok->astTop();
6410  if (!top)
6411  continue;
6412 
6413  if (!Token::Match(top->previous(), "if|while|for (") && !Token::Match(tok->astParent(), "&&|%oror%|?|!"))
6414  continue;
6415  for (const Condition& cond : parse(tok, settings)) {
6416  if (!cond.vartok)
6417  continue;
6418  if (cond.vartok->exprId() == 0)
6419  continue;
6420  if (cond.vartok->hasKnownIntValue())
6421  continue;
6422  if (cond.true_values.empty() || cond.false_values.empty())
6423  continue;
6424  if (!isConstExpression(cond.vartok, settings.library))
6425  continue;
6426  f(cond, tok, scope);
6427  }
6428  }
6429  }
6430  }
6431 
6432  void beforeCondition(TokenList& tokenlist,
6433  const SymbolDatabase& symboldatabase,
6434  ErrorLogger& errorLogger,
6435  const Settings& settings,
6436  const std::set<const Scope*>& skippedFunctions) const {
6437  traverseCondition(symboldatabase, settings, skippedFunctions, [&](const Condition& cond, Token* tok, const Scope*) {
6438  if (cond.vartok->exprId() == 0)
6439  return;
6440 
6441  // If condition is known then don't propagate value
6442  if (tok->hasKnownIntValue())
6443  return;
6444 
6445  Token* top = tok->astTop();
6446 
6447  if (Token::Match(top, "%assign%"))
6448  return;
6449  if (Token::Match(cond.vartok->astParent(), "%assign%|++|--"))
6450  return;
6451 
6452  if (Token::simpleMatch(tok->astParent(), "?") && tok->astParent()->isExpandedMacro()) {
6453  if (settings.debugwarnings)
6454  bailout(tokenlist,
6455  errorLogger,
6456  tok,
6457  "variable '" + cond.vartok->expressionString() + "', condition is defined in macro");
6458  return;
6459  }
6460 
6461  // if,macro => bailout
6462  if (Token::simpleMatch(top->previous(), "if (") && top->previous()->isExpandedMacro()) {
6463  if (settings.debugwarnings)
6464  bailout(tokenlist,
6465  errorLogger,
6466  tok,
6467  "variable '" + cond.vartok->expressionString() + "', condition is defined in macro");
6468  return;
6469  }
6470 
6471  std::list<ValueFlow::Value> values = cond.true_values;
6472  if (cond.true_values != cond.false_values)
6473  values.insert(values.end(), cond.false_values.cbegin(), cond.false_values.cend());
6474 
6475  // extra logic for unsigned variables 'i>=1' => possible value can also be 0
6476  if (Token::Match(tok, "<|>|<=|>=")) {
6477  values.remove_if([](const ValueFlow::Value& v) {
6478  if (v.isIntValue())
6479  return v.intvalue != 0;
6480  return false;
6481  });
6482  if (cond.vartok->valueType() && cond.vartok->valueType()->sign != ValueType::Sign::UNSIGNED)
6483  return;
6484  }
6485  if (values.empty())
6486  return;
6487 
6488  // bailout: for/while-condition, variable is changed in while loop
6489  if (Token::Match(top->previous(), "for|while (") && Token::simpleMatch(top->link(), ") {")) {
6490 
6491  // Variable changed in 3rd for-expression
6492  if (Token::simpleMatch(top->previous(), "for (")) {
6493  if (top->astOperand2() && top->astOperand2()->astOperand2() &&
6494  findExpressionChanged(
6495  cond.vartok, top->astOperand2()->astOperand2(), top->link(), settings)) {
6496  if (settings.debugwarnings)
6497  bailout(tokenlist,
6498  errorLogger,
6499  tok,
6500  "variable '" + cond.vartok->expressionString() + "' used in loop");
6501  return;
6502  }
6503  }
6504 
6505  // Variable changed in loop code
6506  const Token* const start = top;
6507  const Token* const block = top->link()->next();
6508  const Token* const end = block->link();
6509 
6510  if (findExpressionChanged(cond.vartok, start, end, settings)) {
6511  // If its reassigned in loop then analyze from the end
6512  if (!Token::Match(tok, "%assign%|++|--") &&
6513  findExpression(cond.vartok->exprId(), start, end, [&](const Token* tok2) {
6514  return Token::Match(tok2->astParent(), "%assign%") && astIsLHS(tok2);
6515  })) {
6516  // Start at the end of the loop body
6517  Token* bodyTok = top->link()->next();
6518  reverse(bodyTok->link(), bodyTok, cond.vartok, values, tokenlist, errorLogger, settings);
6519  }
6520  if (settings.debugwarnings)
6521  bailout(tokenlist,
6522  errorLogger,
6523  tok,
6524  "variable '" + cond.vartok->expressionString() + "' used in loop");
6525  return;
6526  }
6527  }
6528 
6529  Token* startTok = nullptr;
6530  if (astIsRHS(tok))
6531  startTok = tok->astParent();
6532  else if (astIsLHS(tok))
6533  startTok = previousBeforeAstLeftmostLeaf(tok->astParent());
6534  if (!startTok)
6535  startTok = tok->previous();
6536 
6537  reverse(startTok, nullptr, cond.vartok, values, tokenlist, errorLogger, settings);
6538  });
6539  }
6540 
6541  static Token* skipNotAndCasts(Token* tok, bool* inverted = nullptr)
6542  {
6543  for (; tok->astParent(); tok = tok->astParent()) {
6544  if (Token::simpleMatch(tok->astParent(), "!")) {
6545  if (inverted)
6546  *inverted ^= true;
6547  continue;
6548  }
6549  if (Token::Match(tok->astParent(), "==|!=")) {
6550  const Token* sibling = tok->astSibling();
6551  if (sibling->hasKnownIntValue() && (astIsBool(tok) || astIsBool(sibling))) {
6552  const bool value = sibling->values().front().intvalue;
6553  if (inverted)
6554  *inverted ^= value == Token::simpleMatch(tok->astParent(), "!=");
6555  continue;
6556  }
6557  }
6558  if (tok->astParent()->isCast() && astIsBool(tok->astParent()))
6559  continue;
6560  return tok;
6561  }
6562  return tok;
6563  }
6564 
6565  static void fillFromPath(ProgramMemory& pm, const Token* top, MathLib::bigint path, const Settings& settings)
6566  {
6567  if (path < 1)
6568  return;
6569  visitAstNodes(top, [&](const Token* tok) {
6570  const ValueFlow::Value* v = ValueFlow::findValue(tok->values(), settings, [&](const ValueFlow::Value& v) {
6571  return v.path == path && isNonConditionalPossibleIntValue(v);
6572  });
6573  if (v == nullptr)
6575  pm.setValue(tok, *v);
6577  });
6578  }
6579 
6580  void afterCondition(TokenList& tokenlist,
6581  const SymbolDatabase& symboldatabase,
6582  ErrorLogger& errorLogger,
6583  const Settings& settings,
6584  const std::set<const Scope*>& skippedFunctions) const {
6585  traverseCondition(symboldatabase, settings, skippedFunctions, [&](const Condition& cond, Token* condTok, const Scope* scope) {
6586  Token* top = condTok->astTop();
6587 
6588  const MathLib::bigint path = cond.getPath();
6589  const bool allowKnown = path == 0;
6590 
6591  std::list<ValueFlow::Value> thenValues;
6592  std::list<ValueFlow::Value> elseValues;
6593 
6594  Token* ctx = cond.getContextAndValues(condTok, thenValues, elseValues);
6595 
6596  if (Token::Match(ctx->astParent(), "%oror%|&&")) {
6597  Token* parent = ctx->astParent();
6598  if (astIsRHS(ctx) && astIsLHS(parent) && parent->astParent() &&
6599  parent->str() == parent->astParent()->str())
6600  parent = parent->astParent();
6601  else if (!astIsLHS(ctx)) {
6602  parent = nullptr;
6603  }
6604  if (parent) {
6605  std::vector<Token*> nextExprs = {parent->astOperand2()};
6606  if (astIsLHS(parent) && parent->astParent() && parent->astParent()->str() == parent->str()) {
6607  nextExprs.push_back(parent->astParent()->astOperand2());
6608  }
6609  std::list<ValueFlow::Value> andValues;
6610  std::list<ValueFlow::Value> orValues;
6611  cond.getContextAndValues(condTok, andValues, orValues, true);
6612 
6613  const std::string& op(parent->str());
6614  std::list<ValueFlow::Value> values;
6615  if (op == "&&")
6616  values = std::move(andValues);
6617  else if (op == "||")
6618  values = std::move(orValues);
6619  if (allowKnown && (Token::Match(condTok, "==|!=") || cond.isBool()))
6620  changePossibleToKnown(values);
6621  if (astIsFloat(cond.vartok, false) ||
6622  (!cond.vartok->valueType() &&
6623  std::all_of(values.cbegin(), values.cend(), [](const ValueFlow::Value& v) {
6624  return v.isIntValue() || v.isFloatValue();
6625  })))
6626  values.remove_if([&](const ValueFlow::Value& v) {
6627  return v.isImpossible();
6628  });
6629  for (Token* start:nextExprs) {
6630  Analyzer::Result r = forward(start, cond.vartok, values, tokenlist, errorLogger, settings);
6632  return;
6633  }
6634  }
6635  }
6636 
6637  {
6638  const Token* tok2 = condTok;
6639  std::string op;
6640  bool mixedOperators = false;
6641  while (tok2->astParent()) {
6642  const Token* parent = tok2->astParent();
6643  if (Token::Match(parent, "%oror%|&&")) {
6644  if (op.empty()) {
6645  op = parent->str();
6646  } else if (op != parent->str()) {
6647  mixedOperators = true;
6648  break;
6649  }
6650  }
6651  if (parent->str() == "!") {
6652  op = (op == "&&" ? "||" : "&&");
6653  }
6654  tok2 = parent;
6655  }
6656 
6657  if (mixedOperators) {
6658  return;
6659  }
6660  }
6661 
6662  if (!top)
6663  return;
6664 
6665  if (top->previous()->isExpandedMacro()) {
6666  for (std::list<ValueFlow::Value>* values : {&thenValues, &elseValues}) {
6667  for (ValueFlow::Value& v : *values)
6668  v.macro = true;
6669  }
6670  }
6671 
6672  Token* condTop = ctx->astParent();
6673  {
6674  bool inverted2 = false;
6675  while (Token::Match(condTop, "%oror%|&&")) {
6676  Token* parent = skipNotAndCasts(condTop, &inverted2)->astParent();
6677  if (!parent)
6678  break;
6679  condTop = parent;
6680  }
6681  if (inverted2)
6682  std::swap(thenValues, elseValues);
6683  }
6684 
6685  if (!condTop)
6686  return;
6687 
6688  if (Token::simpleMatch(condTop, "?")) {
6689  Token* colon = condTop->astOperand2();
6690  forward(colon->astOperand1(), cond.vartok, thenValues, tokenlist, errorLogger, settings);
6691  forward(colon->astOperand2(), cond.vartok, elseValues, tokenlist, errorLogger, settings);
6692  // TODO: Handle after condition
6693  return;
6694  }
6695 
6696  if (condTop != top && condTop->str() != ";")
6697  return;
6698 
6699  if (!Token::Match(top->previous(), "if|while|for ("))
6700  return;
6701 
6702  if (top->previous()->str() == "for") {
6703  if (!Token::Match(condTok, "%comp%"))
6704  return;
6705  if (!Token::simpleMatch(condTok->astParent(), ";"))
6706  return;
6707  const Token* stepTok = getStepTok(top);
6708  if (cond.vartok->varId() == 0)
6709  return;
6710  if (!cond.vartok->variable())
6711  return;
6712  if (!Token::Match(stepTok, "++|--"))
6713  return;
6714  std::set<ValueFlow::Value::Bound> bounds;
6715  for (const ValueFlow::Value& v : thenValues) {
6716  if (v.bound != ValueFlow::Value::Bound::Point && v.isImpossible())
6717  continue;
6718  bounds.insert(v.bound);
6719  }
6720  if (Token::simpleMatch(stepTok, "++") && bounds.count(ValueFlow::Value::Bound::Lower) > 0)
6721  return;
6722  if (Token::simpleMatch(stepTok, "--") && bounds.count(ValueFlow::Value::Bound::Upper) > 0)
6723  return;
6724  const Token* childTok = condTok->astOperand1();
6725  if (!childTok)
6726  childTok = condTok->astOperand2();
6727  if (!childTok)
6728  return;
6729  if (childTok->varId() != cond.vartok->varId())
6730  return;
6731  const Token* startBlock = top->link()->next();
6732  if (isVariableChanged(startBlock,
6733  startBlock->link(),
6734  cond.vartok->varId(),
6735  cond.vartok->variable()->isGlobal(),
6736  settings))
6737  return;
6738  // Check if condition in for loop is always false
6739  const Token* initTok = getInitTok(top);
6740  ProgramMemory pm;
6741  fillFromPath(pm, initTok, path, settings);
6742  fillFromPath(pm, condTok, path, settings);
6743  execute(initTok, pm, nullptr, nullptr, settings);
6744  MathLib::bigint result = 1;
6745  execute(condTok, pm, &result, nullptr, settings);
6746  if (result == 0)
6747  return;
6748  // Remove condition since for condition is not redundant
6749  for (std::list<ValueFlow::Value>* values : {&thenValues, &elseValues}) {
6750  for (ValueFlow::Value& v : *values) {
6751  v.condition = nullptr;
6752  v.conditional = true;
6753  }
6754  }
6755  }
6756 
6757  bool deadBranch[] = {false, false};
6758  // start token of conditional code
6759  Token* startTokens[] = {nullptr, nullptr};
6760  // determine startToken(s)
6761  if (Token::simpleMatch(top->link(), ") {"))
6762  startTokens[0] = top->link()->next();
6763  if (Token::simpleMatch(top->link()->linkAt(1), "} else {"))
6764  startTokens[1] = top->link()->linkAt(1)->tokAt(2);
6765 
6766  int changeBlock = -1;
6767  int bailBlock = -1;
6768 
6769  for (int i = 0; i < 2; i++) {
6770  const Token* const startToken = startTokens[i];
6771  if (!startToken)
6772  continue;
6773  std::list<ValueFlow::Value>& values = (i == 0 ? thenValues : elseValues);
6774  if (allowKnown)
6775  valueFlowSetConditionToKnown(condTok, values, i == 0);
6776 
6777  Analyzer::Result r = forward(startTokens[i], startTokens[i]->link(), cond.vartok, values, tokenlist, errorLogger, settings);
6778  deadBranch[i] = r.terminate == Analyzer::Terminate::Escape;
6779  if (r.action.isModified() && !deadBranch[i])
6780  changeBlock = i;
6783  bailBlock = i;
6784  changeKnownToPossible(values);
6785  }
6786  if (changeBlock >= 0 && !Token::simpleMatch(top->previous(), "while (")) {
6787  if (settings.debugwarnings)
6788  bailout(tokenlist,
6789  errorLogger,
6790  startTokens[changeBlock]->link(),
6791  "valueFlowAfterCondition: " + cond.vartok->expressionString() +
6792  " is changed in conditional block");
6793  return;
6794  }
6795  if (bailBlock >= 0) {
6796  if (settings.debugwarnings)
6797  bailout(tokenlist,
6798  errorLogger,
6799  startTokens[bailBlock]->link(),
6800  "valueFlowAfterCondition: bailing in conditional block");
6801  return;
6802  }
6803 
6804  // After conditional code..
6805  if (Token::simpleMatch(top->link(), ") {")) {
6806  Token* after = top->link()->linkAt(1);
6807  bool dead_if = deadBranch[0];
6808  bool dead_else = deadBranch[1];
6809  const Token* unknownFunction = nullptr;
6810  if (condTok->astParent() && Token::Match(top->previous(), "while|for ("))
6811  dead_if = !isBreakScope(after);
6812  else if (!dead_if)
6813  dead_if = isReturnScope(after, settings.library, &unknownFunction);
6814 
6815  if (!dead_if && unknownFunction) {
6816  if (settings.debugwarnings)
6817  bailout(tokenlist, errorLogger, unknownFunction, "possible noreturn scope");
6818  return;
6819  }
6820 
6821  if (Token::simpleMatch(after, "} else {")) {
6822  after = after->linkAt(2);
6823  unknownFunction = nullptr;
6824  if (!dead_else)
6825  dead_else = isReturnScope(after, settings.library, &unknownFunction);
6826  if (!dead_else && unknownFunction) {
6827  if (settings.debugwarnings)
6828  bailout(tokenlist, errorLogger, unknownFunction, "possible noreturn scope");
6829  return;
6830  }
6831  }
6832 
6833  if (dead_if && dead_else)
6834  return;
6835 
6836  std::list<ValueFlow::Value> values;
6837  if (dead_if) {
6838  values = std::move(elseValues);
6839  } else if (dead_else) {
6840  values = std::move(thenValues);
6841  } else {
6842  std::copy_if(thenValues.cbegin(),
6843  thenValues.cend(),
6844  std::back_inserter(values),
6845  std::mem_fn(&ValueFlow::Value::isPossible));
6846  std::copy_if(elseValues.cbegin(),
6847  elseValues.cend(),
6848  std::back_inserter(values),
6849  std::mem_fn(&ValueFlow::Value::isPossible));
6850  }
6851 
6852  if (values.empty())
6853  return;
6854 
6855  if (dead_if || dead_else) {
6856  const Token* parent = condTok->astParent();
6857  // Skip the not operator
6858  while (Token::simpleMatch(parent, "!"))
6859  parent = parent->astParent();
6860  bool possible = false;
6861  if (Token::Match(parent, "&&|%oror%")) {
6862  const std::string& op(parent->str());
6863  while (parent && parent->str() == op)
6864  parent = parent->astParent();
6865  if (Token::simpleMatch(parent, "!") || Token::simpleMatch(parent, "== false"))
6866  possible = op == "||";
6867  else
6868  possible = op == "&&";
6869  }
6870  if (possible) {
6871  values.remove_if(std::mem_fn(&ValueFlow::Value::isImpossible));
6872  changeKnownToPossible(values);
6873  } else if (allowKnown) {
6874  valueFlowSetConditionToKnown(condTok, values, true);
6875  valueFlowSetConditionToKnown(condTok, values, false);
6876  }
6877  }
6878  if (values.empty())
6879  return;
6880  const bool isKnown = std::any_of(values.cbegin(), values.cend(), [&](const ValueFlow::Value& v) {
6881  return v.isKnown() || v.isImpossible();
6882  });
6883  if (isKnown && isBreakOrContinueScope(after)) {
6884  const Scope* loopScope = getLoopScope(cond.vartok);
6885  if (loopScope) {
6886  Analyzer::Result r = forward(after, loopScope->bodyEnd, cond.vartok, values, tokenlist, errorLogger, settings);
6888  return;
6889  if (r.action.isModified())
6890  return;
6891  auto* start = const_cast<Token*>(loopScope->bodyEnd);
6892  if (Token::simpleMatch(start, "} while (")) {
6893  start = start->tokAt(2);
6894  forward(start, start->link(), cond.vartok, values, tokenlist, errorLogger, settings);
6895  start = start->link();
6896  }
6897  values.remove_if(std::mem_fn(&ValueFlow::Value::isImpossible));
6898  changeKnownToPossible(values);
6899  }
6900  }
6901  forward(after, ValueFlow::getEndOfExprScope(cond.vartok, scope), cond.vartok, values, tokenlist, errorLogger, settings);
6902  }
6903  });
6904  }
6905  virtual ~ConditionHandler() = default;
6907 protected:
6908  ConditionHandler() = default;
6909 };
6910 
6912  TokenList& tokenlist,
6913  SymbolDatabase& symboldatabase,
6914  ErrorLogger& errorLogger,
6915  const Settings& settings,
6916  const std::set<const Scope*>& skippedFunctions)
6917 {
6918  handler->beforeCondition(tokenlist, symboldatabase, errorLogger, settings, skippedFunctions);
6919  handler->afterCondition(tokenlist, symboldatabase, errorLogger, settings, skippedFunctions);
6920 }
6921 
6923  std::vector<Condition> parse(const Token* tok, const Settings& /*settings*/) const override {
6924 
6925  std::vector<Condition> conds;
6926  parseCompareEachInt(tok, [&](const Token* vartok, ValueFlow::Value true_value, ValueFlow::Value false_value) {
6927  if (vartok->hasKnownIntValue())
6928  return;
6929  if (vartok->str() == "=" && vartok->astOperand1() && vartok->astOperand2())
6930  vartok = vartok->astOperand1();
6931  Condition cond;
6932  cond.true_values.push_back(std::move(true_value));
6933  cond.false_values.push_back(std::move(false_value));
6934  cond.vartok = vartok;
6935  conds.push_back(std::move(cond));
6936  });
6937  if (!conds.empty())
6938  return conds;
6939 
6940  const Token* vartok = nullptr;
6941 
6942  if (tok->str() == "!") {
6943  vartok = tok->astOperand1();
6944 
6945  } else if (tok->astParent() && (Token::Match(tok->astParent(), "%oror%|&&|?") ||
6946  Token::Match(tok->astParent()->previous(), "if|while ("))) {
6947  if (Token::simpleMatch(tok, "="))
6948  vartok = tok->astOperand1();
6949  else if (!Token::Match(tok, "%comp%|%assign%"))
6950  vartok = tok;
6951  }
6952 
6953  if (!vartok)
6954  return {};
6955  Condition cond;
6956  cond.true_values.emplace_back(tok, 0LL);
6957  cond.false_values.emplace_back(tok, 0LL);
6958  cond.vartok = vartok;
6959 
6960  return {std::move(cond)};
6961  }
6962 };
6963 
6965  bool match(const ValueFlow::Value& value) const override {
6966  return value.isIntValue();
6967  }
6969  {
6970  ValueFlow::Value result(value);
6972  result.setKnown();
6973  return result;
6974  }
6975 };
6976 
6978  return IntegralInferModel{};
6979 }
6980 
6981 static ValueFlow::Value inferCondition(const std::string& op, const Token* varTok, MathLib::bigint val)
6982 {
6983  if (!varTok)
6984  return ValueFlow::Value{};
6985  if (varTok->hasKnownIntValue())
6986  return ValueFlow::Value{};
6987  std::vector<ValueFlow::Value> r = infer(IntegralInferModel{}, op, varTok->values(), val);
6988  if (r.size() == 1 && r.front().isKnown())
6989  return r.front();
6990  return ValueFlow::Value{};
6991 }
6992 
6995  bool match(const ValueFlow::Value& value) const override {
6996  return value.valueType == getType();
6997  }
6999  {
7000  ValueFlow::Value result(value);
7001  result.valueType = getType();
7002  result.setKnown();
7003  return result;
7004  }
7005 };
7006 
7010  }
7011 };
7012 
7016  }
7017 };
7018 
7019 static bool isIntegralOnlyOperator(const Token* tok) {
7020  return Token::Match(tok, "%|<<|>>|&|^|~|%or%");
7021 }
7022 
7023 static bool isIntegralOrPointer(const Token* tok)
7024 {
7025  if (!tok)
7026  return false;
7027  if (astIsIntegral(tok, false))
7028  return true;
7029  if (astIsPointer(tok))
7030  return true;
7031  if (Token::Match(tok, "NULL|nullptr"))
7032  return true;
7033  if (tok->valueType())
7034  return false;
7035  // These operators only work on integers
7036  if (isIntegralOnlyOperator(tok))
7037  return true;
7038  if (isIntegralOnlyOperator(tok->astParent()))
7039  return true;
7040  if (Token::Match(tok, "+|-|*|/") && tok->isBinaryOp())
7042  return false;
7043 }
7044 
7045 static void valueFlowInferCondition(TokenList& tokenlist,
7046  const Settings& settings)
7047 {
7048  for (Token* tok = tokenlist.front(); tok; tok = tok->next()) {
7049  if (!tok->astParent())
7050  continue;
7051  if (tok->hasKnownIntValue())
7052  continue;
7053  if (Token::Match(tok, "%comp%|-") && tok->astOperand1() && tok->astOperand2()) {
7054  if (astIsIterator(tok->astOperand1()) || astIsIterator(tok->astOperand2())) {
7055  static const std::array<ValuePtr<InferModel>, 2> iteratorModels = {EndIteratorInferModel{},
7057  for (const ValuePtr<InferModel>& model : iteratorModels) {
7058  std::vector<ValueFlow::Value> result =
7059  infer(model, tok->str(), tok->astOperand1()->values(), tok->astOperand2()->values());
7060  for (ValueFlow::Value value : result) {
7062  setTokenValue(tok, std::move(value), settings);
7063  }
7064  }
7065  } else if (isIntegralOrPointer(tok->astOperand1()) && isIntegralOrPointer(tok->astOperand2())) {
7066  std::vector<ValueFlow::Value> result =
7067  infer(IntegralInferModel{}, tok->str(), tok->astOperand1()->values(), tok->astOperand2()->values());
7068  for (ValueFlow::Value& value : result) {
7069  setTokenValue(tok, std::move(value), settings);
7070  }
7071  }
7072  } else if (Token::Match(tok->astParent(), "?|&&|!|%oror%") ||
7073  Token::Match(tok->astParent()->previous(), "if|while (") ||
7074  (astIsPointer(tok) && isUsedAsBool(tok, settings))) {
7075  std::vector<ValueFlow::Value> result = infer(IntegralInferModel{}, "!=", tok->values(), 0);
7076  if (result.size() != 1)
7077  continue;
7078  ValueFlow::Value value = result.front();
7079  setTokenValue(tok, std::move(value), settings);
7080  }
7081  }
7082 }
7083 
7085 
7086  static bool isNegatedBool(const Token* tok)
7087  {
7088  if (!Token::simpleMatch(tok, "!"))
7089  return false;
7090  return (astIsBool(tok->astOperand1()));
7091  }
7092 
7093  static const Token* skipNot(const Token* tok)
7094  {
7095  if (!Token::simpleMatch(tok, "!"))
7096  return tok;
7097  return tok->astOperand1();
7098  }
7099 
7100  std::vector<Condition> parse(const Token* tok, const Settings& settings) const override
7101  {
7102  if (!Token::Match(tok, "%comp%"))
7103  return {};
7104  if (tok->hasKnownIntValue())
7105  return {};
7106  if (!tok->astOperand1() || tok->astOperand1()->hasKnownIntValue() || tok->astOperand1()->isLiteral())
7107  return {};
7108  if (!tok->astOperand2() || tok->astOperand2()->hasKnownIntValue() || tok->astOperand2()->isLiteral())
7109  return {};
7110  if (!isConstExpression(tok, settings.library))
7111  return {};
7112 
7113  std::vector<Condition> result;
7114  auto addCond = [&](const Token* lhsTok, const Token* rhsTok, bool inverted) {
7115  for (int i = 0; i < 2; i++) {
7116  const bool lhs = i == 0;
7117  const Token* vartok = lhs ? lhsTok : rhsTok;
7118  const Token* valuetok = lhs ? rhsTok : lhsTok;
7119  if (valuetok->exprId() == 0)
7120  continue;
7121  if (valuetok->hasKnownSymbolicValue(vartok))
7122  continue;
7123  if (vartok->hasKnownSymbolicValue(valuetok))
7124  continue;
7125  ValueFlow::Value true_value;
7126  ValueFlow::Value false_value;
7127  setConditionalValues(tok, !lhs, 0, true_value, false_value);
7128  setSymbolic(true_value, valuetok);
7129  setSymbolic(false_value, valuetok);
7130 
7131  Condition cond;
7132  cond.true_values = {std::move(true_value)};
7133  cond.false_values = {std::move(false_value)};
7134  cond.vartok = vartok;
7135  cond.inverted = inverted;
7136  result.push_back(std::move(cond));
7137  }
7138  };
7139  addCond(tok->astOperand1(), tok->astOperand2(), false);
7140  if (Token::Match(tok, "==|!=") && (isNegatedBool(tok->astOperand1()) || isNegatedBool(tok->astOperand2()))) {
7141  const Token* lhsTok = skipNot(tok->astOperand1());
7142  const Token* rhsTok = skipNot(tok->astOperand2());
7143  addCond(lhsTok, rhsTok, !(isNegatedBool(tok->astOperand1()) && isNegatedBool(tok->astOperand2())));
7144  }
7145  return result;
7146  }
7147 };
7148 
7149 static bool valueFlowForLoop2(const Token *tok,
7150  ProgramMemory *memory1,
7151  ProgramMemory *memory2,
7152  ProgramMemory *memoryAfter,
7153  const Settings& settings)
7154 {
7155  // for ( firstExpression ; secondExpression ; thirdExpression )
7156  const Token *firstExpression = tok->next()->astOperand2()->astOperand1();
7157  const Token *secondExpression = tok->next()->astOperand2()->astOperand2()->astOperand1();
7158  const Token *thirdExpression = tok->next()->astOperand2()->astOperand2()->astOperand2();
7159 
7160  ProgramMemory programMemory;
7161  MathLib::bigint result(0);
7162  bool error = false;
7163  execute(firstExpression, programMemory, &result, &error, settings);
7164  if (error)
7165  return false;
7166  execute(secondExpression, programMemory, &result, &error, settings);
7167  if (result == 0) // 2nd expression is false => no looping
7168  return false;
7169  if (error) {
7170  // If a variable is reassigned in second expression, return false
7171  bool reassign = false;
7172  visitAstNodes(secondExpression,
7173  [&](const Token *t) {
7174  if (t->str() == "=" && t->astOperand1() && programMemory.hasValue(t->astOperand1()->varId()))
7175  // TODO: investigate what variable is assigned.
7176  reassign = true;
7178  });
7179  if (reassign)
7180  return false;
7181  }
7182 
7183  ProgramMemory startMemory(programMemory);
7184  ProgramMemory endMemory;
7185 
7186  int maxcount = 10000;
7187  while (result != 0 && !error && --maxcount > 0) {
7188  endMemory = programMemory;
7189  execute(thirdExpression, programMemory, &result, &error, settings);
7190  if (!error)
7191  execute(secondExpression, programMemory, &result, &error, settings);
7192  }
7193 
7194  if (memory1)
7195  memory1->swap(startMemory);
7196  if (!error) {
7197  if (memory2)
7198  memory2->swap(endMemory);
7199  if (memoryAfter)
7200  memoryAfter->swap(programMemory);
7201  }
7202 
7203  return true;
7204 }
7205 
7206 static void valueFlowForLoopSimplify(Token* const bodyStart,
7207  const Token* expr,
7208  bool globalvar,
7209  const MathLib::bigint value,
7210  const TokenList& tokenlist,
7211  ErrorLogger& errorLogger,
7212  const Settings& settings)
7213 {
7214  // TODO: Refactor this to use arbitrary expressions
7215  assert(expr->varId() > 0);
7216  const Token * const bodyEnd = bodyStart->link();
7217 
7218  // Is variable modified inside for loop
7219  if (isVariableChanged(bodyStart, bodyEnd, expr->varId(), globalvar, settings))
7220  return;
7221 
7222  for (Token *tok2 = bodyStart->next(); tok2 != bodyEnd; tok2 = tok2->next()) {
7223  if (tok2->varId() == expr->varId()) {
7224  const Token * parent = tok2->astParent();
7225  while (parent) {
7226  const Token * const p = parent;
7227  parent = parent->astParent();
7228  if (!parent || parent->str() == ":")
7229  break;
7230  if (parent->str() == "?") {
7231  if (parent->astOperand2() != p)
7232  parent = nullptr;
7233  break;
7234  }
7235  }
7236  if (parent) {
7237  if (settings.debugwarnings)
7238  bailout(tokenlist, errorLogger, tok2, "For loop variable " + tok2->str() + " stopping on ?");
7239  continue;
7240  }
7241 
7242  ValueFlow::Value value1(value);
7243  value1.varId = tok2->varId();
7244  setTokenValue(tok2, std::move(value1), settings);
7245  }
7246 
7247  if (Token::Match(tok2, "%oror%|&&")) {
7248  const ProgramMemory programMemory(getProgramMemory(tok2->astTop(), expr, ValueFlow::Value(value), settings));
7249  if ((tok2->str() == "&&" && !conditionIsTrue(tok2->astOperand1(), programMemory, settings)) ||
7250  (tok2->str() == "||" && !conditionIsFalse(tok2->astOperand1(), programMemory, settings))) {
7251  // Skip second expression..
7252  Token *parent = tok2;
7253  while (parent && parent->str() == tok2->str())
7254  parent = parent->astParent();
7255  // Jump to end of condition
7256  if (parent && parent->str() == "(") {
7257  tok2 = parent->link();
7258  // cast
7259  if (Token::simpleMatch(tok2, ") ("))
7260  tok2 = tok2->linkAt(1);
7261  }
7262  }
7263  }
7264  const Token* vartok = expr;
7265  const Token* rml = nextAfterAstRightmostLeaf(vartok);
7266  if (rml)
7267  vartok = rml->str() == "]" ? rml : rml->previous();
7268  if (vartok->str() == "]" && vartok->link()->previous())
7269  vartok = vartok->link()->previous();
7270 
7271  if ((tok2->str() == "&&" &&
7272  conditionIsFalse(tok2->astOperand1(),
7273  getProgramMemory(tok2->astTop(), expr, ValueFlow::Value(value), settings),
7274  settings)) ||
7275  (tok2->str() == "||" &&
7276  conditionIsTrue(tok2->astOperand1(),
7277  getProgramMemory(tok2->astTop(), expr, ValueFlow::Value(value), settings),
7278  settings)))
7279  break;
7280 
7281  if (Token::simpleMatch(tok2, ") {")) {
7282  if (vartok->varId() && Token::findmatch(tok2->link(), "%varid%", tok2, vartok->varId())) {
7283  if (Token::findmatch(tok2, "continue|break|return", tok2->linkAt(1), vartok->varId())) {
7284  if (settings.debugwarnings)
7285  bailout(tokenlist, errorLogger, tok2, "For loop variable bailout on conditional continue|break|return");
7286  break;
7287  }
7288  if (settings.debugwarnings)
7289  bailout(tokenlist, errorLogger, tok2, "For loop variable skipping conditional scope");
7290  tok2 = tok2->next()->link();
7291  if (Token::simpleMatch(tok2, "} else {")) {
7292  if (Token::findmatch(tok2, "continue|break|return", tok2->linkAt(2), vartok->varId())) {
7293  if (settings.debugwarnings)
7294  bailout(tokenlist, errorLogger, tok2, "For loop variable bailout on conditional continue|break|return");
7295  break;
7296  }
7297  tok2 = tok2->linkAt(2);
7298  }
7299  }
7300  else {
7301  if (settings.debugwarnings)
7302  bailout(tokenlist, errorLogger, tok2, "For loop skipping {} code");
7303  tok2 = tok2->linkAt(1);
7304  if (Token::simpleMatch(tok2, "} else {"))
7305  tok2 = tok2->linkAt(2);
7306  }
7307  }
7308  }
7309 }
7310 
7311 static void valueFlowForLoopSimplifyAfter(Token* fortok, nonneg int varid, const MathLib::bigint num, const TokenList& tokenlist, ErrorLogger & errorLogger, const Settings& settings)
7312 {
7313  const Token *vartok = nullptr;
7314  for (const Token *tok = fortok; tok; tok = tok->next()) {
7315  if (tok->varId() == varid) {
7316  vartok = tok;
7317  break;
7318  }
7319  }
7320  if (!vartok || !vartok->variable())
7321  return;
7322 
7323  const Variable *var = vartok->variable();
7324  const Token *endToken = nullptr;
7325  if (var->isLocal())
7326  endToken = var->scope()->bodyEnd;
7327  else
7328  endToken = fortok->scope()->bodyEnd;
7329 
7330  Token* blockTok = fortok->linkAt(1)->linkAt(1);
7331  if (blockTok != endToken) {
7332  ValueFlow::Value v{num};
7333  v.errorPath.emplace_back(fortok,"After for loop, " + var->name() + " has value " + v.infoString());
7334 
7335  valueFlowForward(blockTok->next(), endToken, vartok, std::move(v), tokenlist, errorLogger, settings);
7336  }
7337 }
7338 
7339 static void valueFlowForLoop(TokenList &tokenlist, const SymbolDatabase& symboldatabase, ErrorLogger &errorLogger, const Settings &settings)
7340 {
7341  for (const Scope &scope : symboldatabase.scopeList) {
7342  if (scope.type != Scope::eFor)
7343  continue;
7344 
7345  auto* tok = const_cast<Token*>(scope.classDef);
7346  auto* const bodyStart = const_cast<Token*>(scope.bodyStart);
7347 
7348  if (!Token::simpleMatch(tok->next()->astOperand2(), ";") ||
7349  !Token::simpleMatch(tok->next()->astOperand2()->astOperand2(), ";"))
7350  continue;
7351 
7352  nonneg int varid;
7353  bool knownInitValue, partialCond;
7354  MathLib::bigint initValue, stepValue, lastValue;
7355 
7356  if (extractForLoopValues(tok, varid, knownInitValue, initValue, partialCond, stepValue, lastValue)) {
7357  const bool executeBody = !knownInitValue || initValue <= lastValue;
7358  const Token* vartok = Token::findmatch(tok, "%varid%", bodyStart, varid);
7359  if (executeBody && vartok) {
7360  std::list<ValueFlow::Value> initValues;
7361  initValues.emplace_back(initValue, ValueFlow::Value::Bound::Lower);
7362  initValues.push_back(ValueFlow::asImpossible(initValues.back()));
7363  Analyzer::Result result = valueFlowForward(bodyStart, bodyStart->link(), vartok, std::move(initValues), tokenlist, errorLogger, settings);
7364 
7365  if (!result.action.isModified()) {
7366  std::list<ValueFlow::Value> lastValues;
7367  lastValues.emplace_back(lastValue, ValueFlow::Value::Bound::Upper);
7368  lastValues.back().conditional = true;
7369  lastValues.push_back(ValueFlow::asImpossible(lastValues.back()));
7370  if (stepValue != 1)
7371  lastValues.pop_front();
7372  valueFlowForward(bodyStart, bodyStart->link(), vartok, std::move(lastValues), tokenlist, errorLogger, settings);
7373  }
7374  }
7375  const MathLib::bigint afterValue = executeBody ? lastValue + stepValue : initValue;
7376  valueFlowForLoopSimplifyAfter(tok, varid, afterValue, tokenlist, errorLogger, settings);
7377  } else {
7378  ProgramMemory mem1, mem2, memAfter;
7379  if (valueFlowForLoop2(tok, &mem1, &mem2, &memAfter, settings)) {
7380  for (const auto& p : mem1) {
7381  if (!p.second.isIntValue())
7382  continue;
7383  if (p.second.isImpossible())
7384  continue;
7385  if (p.first.tok->varId() == 0)
7386  continue;
7387  valueFlowForLoopSimplify(bodyStart, p.first.tok, false, p.second.intvalue, tokenlist, errorLogger, settings);
7388  }
7389  for (const auto& p : mem2) {
7390  if (!p.second.isIntValue())
7391  continue;
7392  if (p.second.isImpossible())
7393  continue;
7394  if (p.first.tok->varId() == 0)
7395  continue;
7396  valueFlowForLoopSimplify(bodyStart, p.first.tok, false, p.second.intvalue, tokenlist, errorLogger, settings);
7397  }
7398  for (const auto& p : memAfter) {
7399  if (!p.second.isIntValue())
7400  continue;
7401  if (p.second.isImpossible())
7402  continue;
7403  if (p.first.tok->varId() == 0)
7404  continue;
7405  valueFlowForLoopSimplifyAfter(tok, p.first.getExpressionId(), p.second.intvalue, tokenlist, errorLogger, settings);
7406  }
7407  }
7408  }
7409  }
7410 }
7411 
7413  std::unordered_map<nonneg int, ValueFlow::Value> values;
7414  std::unordered_map<nonneg int, const Variable*> vars;
7415 
7416  MultiValueFlowAnalyzer(const std::unordered_map<const Variable*, ValueFlow::Value>& args, const TokenList& t, const Settings& set)
7417  : ValueFlowAnalyzer(t, set) {
7418  for (const auto& p:args) {
7419  values[p.first->declarationId()] = p.second;
7420  vars[p.first->declarationId()] = p.first;
7421  }
7422  }
7423 
7424  virtual const std::unordered_map<nonneg int, const Variable*>& getVars() const {
7425  return vars;
7426  }
7427 
7428  const ValueFlow::Value* getValue(const Token* tok) const override {
7429  if (tok->varId() == 0)
7430  return nullptr;
7431  auto it = values.find(tok->varId());
7432  if (it == values.end())
7433  return nullptr;
7434  return &it->second;
7435  }
7436  ValueFlow::Value* getValue(const Token* tok) override {
7437  if (tok->varId() == 0)
7438  return nullptr;
7439  auto it = values.find(tok->varId());
7440  if (it == values.end())
7441  return nullptr;
7442  return &it->second;
7443  }
7444 
7445  void makeConditional() override {
7446  for (auto&& p:values) {
7447  p.second.conditional = true;
7448  }
7449  }
7450 
7451  void addErrorPath(const Token* tok, const std::string& s) override {
7452  for (auto&& p:values) {
7453  p.second.errorPath.emplace_back(tok, s);
7454  }
7455  }
7456 
7457  bool isAlias(const Token* tok, bool& inconclusive) const override {
7458  const auto range = SelectValueFromVarIdMapRange(&values);
7459 
7460  for (const auto& p:getVars()) {
7461  nonneg int const varid = p.first;
7462  const Variable* var = p.second;
7463  if (tok->varId() == varid)
7464  return true;
7465  if (isAliasOf(var, tok, varid, range, &inconclusive))
7466  return true;
7467  }
7468  return false;
7469  }
7470 
7471  bool lowerToPossible() override {
7472  for (auto&& p:values) {
7473  if (p.second.isImpossible())
7474  return false;
7475  p.second.changeKnownToPossible();
7476  }
7477  return true;
7478  }
7479  bool lowerToInconclusive() override {
7480  for (auto&& p:values) {
7481  if (p.second.isImpossible())
7482  return false;
7483  p.second.setInconclusive();
7484  }
7485  return true;
7486  }
7487 
7488  bool isConditional() const override {
7489  for (auto&& p:values) {
7490  if (p.second.conditional)
7491  return true;
7492  if (p.second.condition)
7493  return !p.second.isImpossible();
7494  }
7495  return false;
7496  }
7497 
7498  bool stopOnCondition(const Token* condTok) const override {
7499  if (isConditional())
7500  return true;
7501  if (!condTok->hasKnownIntValue() && values.count(condTok->varId()) == 0) {
7502  const auto& values_ = condTok->values();
7503  return std::any_of(values_.cbegin(), values_.cend(), [](const ValueFlow::Value& v) {
7504  return v.isSymbolicValue() && Token::Match(v.tokvalue, "%oror%|&&");
7505  });
7506  }
7507  return false;
7508  }
7509 
7510  bool updateScope(const Token* endBlock, bool /*modified*/) const override {
7511  const Scope* scope = endBlock->scope();
7512  if (!scope)
7513  return false;
7514  if (scope->type == Scope::eLambda) {
7515  return std::all_of(values.cbegin(), values.cend(), [](const std::pair<nonneg int, ValueFlow::Value>& p) {
7516  return p.second.isLifetimeValue();
7517  });
7518  }
7519  if (scope->type == Scope::eIf || scope->type == Scope::eElse || scope->type == Scope::eWhile ||
7520  scope->type == Scope::eFor) {
7521  auto pred = [](const ValueFlow::Value& value) {
7522  if (value.isKnown())
7523  return true;
7524  if (value.isImpossible())
7525  return true;
7526  if (value.isLifetimeValue())
7527  return true;
7528  return false;
7529  };
7530  if (std::all_of(values.cbegin(), values.cend(), std::bind(pred, std::bind(SelectMapValues{}, std::placeholders::_1))))
7531  return true;
7532  if (isConditional())
7533  return false;
7534  const Token* condTok = getCondTokFromEnd(endBlock);
7535  std::set<nonneg int> varids;
7536  std::transform(getVars().cbegin(), getVars().cend(), std::inserter(varids, varids.begin()), SelectMapKeys{});
7537  return bifurcate(condTok, varids, getSettings());
7538  }
7539 
7540  return false;
7541  }
7542 
7543  bool match(const Token* tok) const override {
7544  return values.count(tok->varId()) > 0;
7545  }
7546 
7547  ProgramState getProgramState() const override {
7548  ProgramState ps;
7549  for (const auto& p : values) {
7550  const Variable* var = vars.at(p.first);
7551  if (!var)
7552  continue;
7553  ps[var->nameToken()] = p.second;
7554  }
7555  return ps;
7556  }
7557 };
7558 
7559 template<class Key, class F>
7560 static bool productParams(const Settings& settings, const std::unordered_map<Key, std::list<ValueFlow::Value>>& vars, F f)
7561 {
7562  using Args = std::vector<std::unordered_map<Key, ValueFlow::Value>>;
7563  Args args(1);
7564  // Compute cartesian product of all arguments
7565  for (const auto& p:vars) {
7566  if (p.second.empty())
7567  continue;
7568  args.back()[p.first] = p.second.front();
7569  }
7570  bool bail = false;
7571  int max = settings.performanceValueFlowMaxSubFunctionArgs;
7572  for (const auto& p:vars) {
7573  if (args.size() > max) {
7574  bail = true;
7575  break;
7576  }
7577  if (p.second.empty())
7578  continue;
7579  std::for_each(std::next(p.second.begin()), p.second.end(), [&](const ValueFlow::Value& value) {
7580  Args new_args;
7581  for (auto arg:args) {
7582  if (value.path != 0) {
7583  for (const auto& q:arg) {
7584  if (q.first == p.first)
7585  continue;
7586  if (q.second.path == 0)
7587  continue;
7588  if (q.second.path != value.path)
7589  return;
7590  }
7591  }
7592  arg[p.first] = value;
7593  new_args.push_back(std::move(arg));
7594  }
7595  std::copy(new_args.cbegin(), new_args.cend(), std::back_inserter(args));
7596  });
7597  }
7598 
7599  if (args.size() > max) {
7600  bail = true;
7601  args.resize(max);
7602  }
7603 
7604  for (const auto& arg:args) {
7605  if (arg.empty())
7606  continue;
7607  // Make sure all arguments are the same path
7608  const MathLib::bigint path = arg.cbegin()->second.path;
7609  if (std::any_of(arg.cbegin(), arg.cend(), [&](const std::pair<Key, ValueFlow::Value>& p) {
7610  return p.second.path != path;
7611  }))
7612  continue;
7613  f(arg);
7614  }
7615  return !bail;
7616 }
7617 
7618 static void valueFlowInjectParameter(TokenList& tokenlist,
7619  ErrorLogger& errorLogger,
7620  const Settings& settings,
7621  const Scope* functionScope,
7622  const std::unordered_map<const Variable*, std::list<ValueFlow::Value>>& vars)
7623 {
7624  const bool r = productParams(settings, vars, [&](const std::unordered_map<const Variable*, ValueFlow::Value>& arg) {
7625  MultiValueFlowAnalyzer a(arg, tokenlist, settings);
7626  valueFlowGenericForward(const_cast<Token*>(functionScope->bodyStart), functionScope->bodyEnd, a, tokenlist, errorLogger, settings);
7627  });
7628  if (!r) {
7629  std::string fname = "<unknown>";
7630  if (const Function* f = functionScope->function)
7631  fname = f->name();
7632  if (settings.debugwarnings)
7633  bailout(tokenlist, errorLogger, functionScope->bodyStart, "Too many argument passed to " + fname);
7634  }
7635 }
7636 
7637 static void valueFlowInjectParameter(const TokenList& tokenlist,
7638  ErrorLogger& errorLogger,
7639  const Settings& settings,
7640  const Variable* arg,
7641  const Scope* functionScope,
7642  const std::list<ValueFlow::Value>& argvalues)
7643 {
7644  // Is argument passed by value or const reference, and is it a known non-class type?
7645  if (arg->isReference() && !arg->isConst() && !arg->isClass())
7646  return;
7647 
7648  // Set value in function scope..
7649  const nonneg int varid2 = arg->declarationId();
7650  if (!varid2)
7651  return;
7652 
7653  valueFlowForward(const_cast<Token*>(functionScope->bodyStart->next()),
7654  functionScope->bodyEnd,
7655  arg->nameToken(),
7656  argvalues,
7657  tokenlist,
7658  errorLogger,
7659  settings);
7660 }
7661 
7662 static void valueFlowSwitchVariable(const TokenList &tokenlist, const SymbolDatabase& symboldatabase, ErrorLogger &errorLogger, const Settings &settings)
7663 {
7664  for (const Scope &scope : symboldatabase.scopeList) {
7665  if (scope.type != Scope::ScopeType::eSwitch)
7666  continue;
7667  if (!Token::Match(scope.classDef, "switch ( %var% ) {"))
7668  continue;
7669  const Token *vartok = scope.classDef->tokAt(2);
7670  const Variable *var = vartok->variable();
7671  if (!var)
7672  continue;
7673 
7674  // bailout: global non-const variables
7675  if (!(var->isLocal() || var->isArgument()) && !var->isConst()) {
7676  if (settings.debugwarnings)
7677  bailout(tokenlist, errorLogger, vartok, "switch variable " + var->name() + " is global");
7678  continue;
7679  }
7680 
7681  for (const Token *tok = scope.bodyStart->next(); tok != scope.bodyEnd; tok = tok->next()) {
7682  if (tok->str() == "{") {
7683  tok = tok->link();
7684  continue;
7685  }
7686  if (Token::Match(tok, "case %num% :")) {
7687  std::list<ValueFlow::Value> values;
7688  values.emplace_back(MathLib::toBigNumber(tok->next()->str()));
7689  values.back().condition = tok;
7690  values.back().errorPath.emplace_back(tok, "case " + tok->next()->str() + ": " + vartok->str() + " is " + tok->next()->str() + " here.");
7691  bool known = false;
7692  if ((Token::simpleMatch(tok->previous(), "{") || Token::simpleMatch(tok->tokAt(-2), "break ;")) && !Token::Match(tok->tokAt(3), ";| case"))
7693  known = true;
7694  while (Token::Match(tok->tokAt(3), ";| case %num% :")) {
7695  known = false;
7696  tok = tok->tokAt(3);
7697  if (!tok->isName())
7698  tok = tok->next();
7699  values.emplace_back(MathLib::toBigNumber(tok->next()->str()));
7700  values.back().condition = tok;
7701  values.back().errorPath.emplace_back(tok, "case " + tok->next()->str() + ": " + vartok->str() + " is " + tok->next()->str() + " here.");
7702  }
7703  for (std::list<ValueFlow::Value>::const_iterator val = values.cbegin(); val != values.cend(); ++val) {
7704  valueFlowReverse(tokenlist,
7705  const_cast<Token*>(scope.classDef),
7706  vartok,
7707  *val,
7708  errorLogger,
7709  settings);
7710  }
7711  if (vartok->variable()->scope()) {
7712  if (known)
7713  values.back().setKnown();
7714 
7715  // FIXME We must check if there is a return. See #9276
7716  /*
7717  valueFlowForwardVariable(tok->tokAt(3),
7718  vartok->variable()->scope()->bodyEnd,
7719  vartok->variable(),
7720  vartok->varId(),
7721  values,
7722  values.back().isKnown(),
7723  false,
7724  tokenlist,
7725  errorLogger,
7726  settings);
7727  */
7728  }
7729  }
7730  }
7731  }
7732 }
7733 
7734 static std::list<ValueFlow::Value> getFunctionArgumentValues(const Token *argtok)
7735 {
7736  std::list<ValueFlow::Value> argvalues(argtok->values());
7737  removeImpossible(argvalues);
7738  if (argvalues.empty() && Token::Match(argtok, "%comp%|%oror%|&&|!")) {
7739  argvalues.emplace_back(0);
7740  argvalues.emplace_back(1);
7741  }
7742  return argvalues;
7743 }
7744 
7745 static void valueFlowLibraryFunction(Token *tok, const std::string &returnValue, const Settings &settings)
7746 {
7747  std::unordered_map<nonneg int, std::list<ValueFlow::Value>> argValues;
7748  int argn = 1;
7749  for (const Token *argtok : getArguments(tok->previous())) {
7750  argValues[argn] = getFunctionArgumentValues(argtok);
7751  argn++;
7752  }
7753  if (returnValue.find("arg") != std::string::npos && argValues.empty())
7754  return;
7755  productParams(settings, argValues, [&](const std::unordered_map<nonneg int, ValueFlow::Value>& arg) {
7756  ValueFlow::Value value = evaluateLibraryFunction(arg, returnValue, settings, tok->isCpp());
7757  if (value.isUninitValue())
7758  return;
7760  for (auto&& p : arg) {
7761  if (p.second.isPossible())
7762  kind = p.second.valueKind;
7763  if (p.second.isInconclusive()) {
7764  kind = p.second.valueKind;
7765  break;
7766  }
7767  }
7768  if (value.isImpossible() && kind != ValueFlow::Value::ValueKind::Known)
7769  return;
7770  if (!value.isImpossible())
7771  value.valueKind = kind;
7772  setTokenValue(tok, std::move(value), settings);
7773  });
7774 }
7775 
7776 template<class Iterator>
7778 {
7779  Iterator mBegin;
7780  Iterator mEnd;
7781 
7782  Iterator begin() const {
7783  return mBegin;
7784  }
7785 
7786  Iterator end() const {
7787  return mEnd;
7788  }
7789 };
7790 
7791 template<class Iterator>
7792 static IteratorRange<Iterator> MakeIteratorRange(Iterator start, Iterator last)
7793 {
7794  return {start, last};
7795 }
7796 
7797 static void valueFlowSubFunction(TokenList& tokenlist, SymbolDatabase& symboldatabase, ErrorLogger& errorLogger, const Settings& settings)
7798 {
7799  int id = 0;
7800  for (const Scope* scope : MakeIteratorRange(symboldatabase.functionScopes.crbegin(), symboldatabase.functionScopes.crend())) {
7801  const Function* function = scope->function;
7802  if (!function)
7803  continue;
7804  for (Token* tok = const_cast<Token*>(scope->bodyStart); tok != scope->bodyEnd; tok = tok->next()) {
7805  if (tok->isKeyword() || !Token::Match(tok, "%name% ("))
7806  continue;
7807 
7808  const Function * const calledFunction = tok->function();
7809  if (!calledFunction) {
7810  // library function?
7811  const std::string& returnValue(settings.library.returnValue(tok));
7812  if (!returnValue.empty())
7813  valueFlowLibraryFunction(tok->next(), returnValue, settings);
7814  continue;
7815  }
7816 
7817  const Scope * const calledFunctionScope = calledFunction->functionScope;
7818  if (!calledFunctionScope)
7819  continue;
7820 
7821  id++;
7822  std::unordered_map<const Variable*, std::list<ValueFlow::Value>> argvars;
7823  // TODO: Rewrite this. It does not work well to inject 1 argument at a time.
7824  const std::vector<const Token *> &callArguments = getArguments(tok);
7825  for (int argnr = 0U; argnr < callArguments.size(); ++argnr) {
7826  const Token *argtok = callArguments[argnr];
7827  // Get function argument
7828  const Variable * const argvar = calledFunction->getArgumentVar(argnr);
7829  if (!argvar)
7830  break;
7831 
7832  // passing value(s) to function
7833  std::list<ValueFlow::Value> argvalues(getFunctionArgumentValues(argtok));
7834 
7835  // Remove non-local lifetimes
7836  argvalues.remove_if([](const ValueFlow::Value& v) {
7837  if (v.isLifetimeValue())
7839  return false;
7840  });
7841  // Remove uninit values if argument is passed by value
7842  if (argtok->variable() && !argtok->variable()->isPointer() && argvalues.size() == 1 && argvalues.front().isUninitValue()) {
7843  if (CheckUninitVar::isVariableUsage(argtok, settings.library, false, CheckUninitVar::Alloc::NO_ALLOC, 0))
7844  continue;
7845  }
7846 
7847  if (argvalues.empty())
7848  continue;
7849 
7850  // Error path..
7851  for (ValueFlow::Value &v : argvalues) {
7852  const std::string nr = std::to_string(argnr + 1) + getOrdinalText(argnr + 1);
7853 
7854  v.errorPath.emplace_back(argtok,
7855  "Calling function '" +
7856  calledFunction->name() +
7857  "', " +
7858  nr +
7859  " argument '" +
7860  argtok->expressionString() +
7861  "' value is " +
7862  v.infoString());
7863  v.path = 256 * v.path + id % 256;
7864  // Change scope of lifetime values
7865  if (v.isLifetimeValue())
7867  }
7868 
7869  // passed values are not "known"..
7870  lowerToPossible(argvalues);
7871 
7872  argvars[argvar] = std::move(argvalues);
7873  }
7874  valueFlowInjectParameter(tokenlist, errorLogger, settings, calledFunctionScope, argvars);
7875  }
7876  }
7877 }
7878 
7879 static void valueFlowFunctionDefaultParameter(const TokenList& tokenlist, const SymbolDatabase& symboldatabase, ErrorLogger& errorLogger, const Settings& settings)
7880 {
7881  if (!tokenlist.isCPP())
7882  return;
7883 
7884  for (const Scope* scope : symboldatabase.functionScopes) {
7885  const Function* function = scope->function;
7886  if (!function)
7887  continue;
7888  for (std::size_t arg = function->minArgCount(); arg < function->argCount(); arg++) {
7889  const Variable* var = function->getArgumentVar(arg);
7890  if (var && var->hasDefault() && Token::Match(var->nameToken(), "%var% = %num%|%str% [,)]")) {
7891  const std::list<ValueFlow::Value> &values = var->nameToken()->tokAt(2)->values();
7892  std::list<ValueFlow::Value> argvalues;
7893  for (const ValueFlow::Value &value : values) {
7894  ValueFlow::Value v(value);
7895  v.defaultArg = true;
7897  if (v.isPossible())
7898  argvalues.push_back(std::move(v));
7899  }
7900  if (!argvalues.empty())
7901  valueFlowInjectParameter(tokenlist, errorLogger, settings, var, scope, argvalues);
7902  }
7903  }
7904  }
7905 }
7906 
7908 {
7909  if (!tok)
7910  return nullptr;
7911  auto it = std::find_if(tok->values().begin(), tok->values().end(), [&](const ValueFlow::Value& v) {
7912  return (v.isIntValue() || v.isContainerSizeValue() || v.isFloatValue()) && v.isKnown();
7913  });
7914  if (it == tok->values().end())
7915  return nullptr;
7916  return std::addressof(*it);
7917 }
7918 
7919 static const ValueFlow::Value* getKnownValueFromTokens(const std::vector<const Token*>& toks)
7920 {
7921  if (toks.empty())
7922  return nullptr;
7923  const ValueFlow::Value* result = getKnownValueFromToken(toks.front());
7924  if (!result)
7925  return nullptr;
7926  if (!std::all_of(std::next(toks.begin()), toks.end(), [&](const Token* tok) {
7927  return std::any_of(tok->values().begin(), tok->values().end(), [&](const ValueFlow::Value& v) {
7928  return v.equalValue(*result) && v.valueKind == result->valueKind;
7929  });
7930  }))
7931  return nullptr;
7932  return result;
7933 }
7934 
7935 static void setFunctionReturnValue(const Function* f, Token* tok, ValueFlow::Value v, const Settings& settings)
7936 {
7937  if (f->hasVirtualSpecifier()) {
7938  if (v.isImpossible())
7939  return;
7940  v.setPossible();
7941  } else if (!v.isImpossible()) {
7942  v.setKnown();
7943  }
7944  v.errorPath.emplace_back(tok, "Calling function '" + f->name() + "' returns " + v.toString());
7945  setTokenValue(tok, std::move(v), settings);
7946 }
7947 
7948 static void valueFlowFunctionReturn(TokenList &tokenlist, ErrorLogger &errorLogger, const Settings& settings)
7949 {
7950  for (Token *tok = tokenlist.back(); tok; tok = tok->previous()) {
7951  if (tok->str() != "(" || !tok->astOperand1() || tok->isCast())
7952  continue;
7953 
7954  const Function* function = nullptr;
7955  if (Token::Match(tok->previous(), "%name% ("))
7956  function = tok->previous()->function();
7957  else
7958  function = tok->astOperand1()->function();
7959  if (!function)
7960  continue;
7961  // TODO: Check if member variable is a pointer or reference
7962  if (function->isImplicitlyVirtual() && !function->hasFinalSpecifier())
7963  continue;
7964 
7965  if (tok->hasKnownValue())
7966  continue;
7967 
7968  std::vector<const Token*> returns = Function::findReturns(function);
7969  if (returns.empty())
7970  continue;
7971 
7972  if (const ValueFlow::Value* v = getKnownValueFromTokens(returns)) {
7973  setFunctionReturnValue(function, tok, *v, settings);
7974  continue;
7975  }
7976 
7977  // Arguments..
7978  std::vector<const Token*> arguments = getArguments(tok);
7979 
7980  ProgramMemory programMemory;
7981  for (std::size_t i = 0; i < arguments.size(); ++i) {
7982  const Variable * const arg = function->getArgumentVar(i);
7983  if (!arg) {
7984  if (settings.debugwarnings)
7985  bailout(tokenlist, errorLogger, tok, "function return; unhandled argument type");
7986  programMemory.clear();
7987  break;
7988  }
7989  const ValueFlow::Value* v = getKnownValueFromToken(arguments[i]);
7990  if (!v)
7991  continue;
7992  programMemory.setValue(arg->nameToken(), *v);
7993  }
7994  if (programMemory.empty() && !arguments.empty())
7995  continue;
7996  std::vector<ValueFlow::Value> values = execute(function->functionScope, programMemory, settings);
7997  for (const ValueFlow::Value& v : values) {
7998  if (v.isUninitValue())
7999  continue;
8000  setFunctionReturnValue(function, tok, v, settings);
8001  }
8002  }
8003 }
8004 
8005 static bool needsInitialization(const Variable* var)
8006 {
8007  if (!var)
8008  return false;
8009  if (var->hasDefault())
8010  return false;
8011  if (var->isPointer())
8012  return true;
8013  if (var->type() && var->type()->isUnionType())
8014  return false;
8015  if (!var->nameToken()->isCpp())
8016  return true;
8018  return true;
8019  if (var->valueType()) {
8020  if (var->valueType()->isPrimitive())
8021  return true;
8022  if (var->valueType()->type == ValueType::Type::POD)
8023  return true;
8024  if (var->valueType()->type == ValueType::Type::ITERATOR)
8025  return true;
8026  }
8027  return false;
8028 }
8029 
8030 static void addToErrorPath(ValueFlow::Value& value, const ValueFlow::Value& from)
8031 {
8032  std::unordered_set<const Token*> locations;
8033  std::transform(value.errorPath.cbegin(),
8034  value.errorPath.cend(),
8035  std::inserter(locations, locations.begin()),
8036  [](const ErrorPathItem& e) {
8037  return e.first;
8038  });
8039  if (from.condition && !value.condition)
8040  value.condition = from.condition;
8041  std::copy_if(from.errorPath.cbegin(),
8042  from.errorPath.cend(),
8043  std::back_inserter(value.errorPath),
8044  [&](const ErrorPathItem& e) {
8045  return locations.insert(e.first).second;
8046  });
8047 }
8048 
8049 static std::vector<Token*> findAllUsages(const Variable* var,
8050  Token* start, // cppcheck-suppress constParameterPointer // FP
8051  const Library& library)
8052 {
8053  // std::vector<Token*> result;
8054  const Scope* scope = var->scope();
8055  if (!scope)
8056  return {};
8057  return findTokensSkipDeadCode(library, start, scope->bodyEnd, [&](const Token* tok) {
8058  return tok->varId() == var->declarationId();
8059  });
8060 }
8061 
8062 static Token* findStartToken(const Variable* var, Token* start, const Library& library)
8063 {
8064  std::vector<Token*> uses = findAllUsages(var, start, library);
8065  if (uses.empty())
8066  return start;
8067  Token* first = uses.front();
8068  if (Token::findmatch(start, "goto|asm|setjmp|longjmp", first))
8069  return start;
8070  if (first != var->nameToken()) {
8071  // if this is lhs in assignment then set first to the first token in LHS expression
8072  Token* temp = first;
8073  while (Token::Match(temp->astParent(), "[&*(]") && precedes(temp->astParent(), temp))
8074  temp = temp->astParent();
8075  if (Token::simpleMatch(temp->astParent(), "=") && precedes(temp, temp->astParent()))
8076  first = temp;
8077  }
8078  // If there is only one usage
8079  if (uses.size() == 1)
8080  return first->previous();
8081  const Scope* scope = first->scope();
8082  // If first usage is in variable scope
8083  if (scope == var->scope()) {
8084  bool isLoopExpression = false;
8085  for (const Token* parent = first; parent; parent = parent->astParent()) {
8086  if (Token::simpleMatch(parent->astParent(), ";") &&
8087  Token::simpleMatch(parent->astParent()->astParent(), ";") &&
8088  Token::simpleMatch(parent->astParent()->astParent()->astParent(), "(") &&
8089  Token::simpleMatch(parent->astParent()->astParent()->astParent()->astOperand1(), "for (") &&
8090  parent == parent->astParent()->astParent()->astParent()->astOperand2()->astOperand2()->astOperand2()) {
8091  isLoopExpression = true;
8092  }
8093  }
8094  return isLoopExpression ? start : first->previous();
8095  }
8096  // If all uses are in the same scope
8097  if (std::all_of(uses.begin() + 1, uses.end(), [&](const Token* tok) {
8098  return tok->scope() == scope;
8099  }))
8100  return first->previous();
8101  // Compute the outer scope
8102  while (scope && scope->nestedIn != var->scope())
8103  scope = scope->nestedIn;
8104  if (!scope)
8105  return start;
8106  Token* tok = const_cast<Token*>(scope->bodyStart);
8107  if (!tok)
8108  return start;
8109  if (Token::simpleMatch(tok->tokAt(-2), "} else {"))
8110  tok = tok->linkAt(-2);
8111  if (Token::simpleMatch(tok->previous(), ") {"))
8112  return tok->linkAt(-1)->previous();
8113  return tok;
8114 }
8115 
8116 static void valueFlowUninit(TokenList& tokenlist, ErrorLogger& errorLogger, const Settings& settings)
8117 {
8118  for (Token *tok = tokenlist.front(); tok; tok = tok->next()) {
8119  if (!tok->scope()->isExecutable())
8120  continue;
8121  if (!Token::Match(tok, "%var% ;|["))
8122  continue;
8123  const Variable* var = tok->variable();
8124  if (!var)
8125  continue;
8126  if (var->nameToken() != tok || var->isInit())
8127  continue;
8128  if (!needsInitialization(var))
8129  continue;
8130  if (!var->isLocal() || var->isStatic() || var->isExtern() || var->isReference() || var->isThrow())
8131  continue;
8132 
8133  ValueFlow::Value uninitValue;
8134  uninitValue.setKnown();
8136  uninitValue.tokvalue = tok;
8137  if (var->isArray())
8138  uninitValue.indirect = var->dimensions().size();
8139 
8140  bool partial = false;
8141 
8142  Token* start = findStartToken(var, tok->next(), settings.library);
8143 
8144  std::map<Token*, ValueFlow::Value> partialReads;
8145  if (const Scope* scope = var->typeScope()) {
8146  if (Token::findsimplematch(scope->bodyStart, "union", scope->bodyEnd))
8147  continue;
8148  for (const Variable& memVar : scope->varlist) {
8149  if (!memVar.isPublic())
8150  continue;
8151  // Skip array since we can't track partial initialization from nested subexpressions
8152  if (memVar.isArray())
8153  continue;
8154  if (!needsInitialization(&memVar)) {
8155  if (!var->isPointer())
8156  partial = true;
8157  continue;
8158  }
8159  MemberExpressionAnalyzer analyzer(memVar.nameToken()->str(), tok, uninitValue, tokenlist, settings);
8160  valueFlowGenericForward(start, tok->scope()->bodyEnd, analyzer, tokenlist, errorLogger, settings);
8161 
8162  for (auto&& p : *analyzer.partialReads) {
8163  Token* tok2 = p.first;
8164  const ValueFlow::Value& v = p.second;
8165  // Try to insert into map
8166  auto pp = partialReads.insert(std::make_pair(tok2, v));
8167  ValueFlow::Value& v2 = pp.first->second;
8168  const bool inserted = pp.second;
8169  // Merge the two values if it is already in map
8170  if (!inserted) {
8171  if (v.valueType != v2.valueType)
8172  continue;
8173  addToErrorPath(v2, v);
8174  }
8175  v2.subexpressions.push_back(memVar.nameToken()->str());
8176  }
8177  }
8178  }
8179 
8180  for (auto&& p : partialReads) {
8181  Token* tok2 = p.first;
8182  ValueFlow::Value& v = p.second;
8183 
8184  setTokenValue(tok2, std::move(v), settings);
8185  }
8186 
8187  if (partial)
8188  continue;
8189 
8190  valueFlowForward(start, tok->scope()->bodyEnd, var->nameToken(), std::move(uninitValue), tokenlist, errorLogger, settings);
8191  }
8192 }
8193 
8194 static bool isContainerSizeChanged(const Token* expr,
8195  const Token* start,
8196  const Token* end,
8197  int indirect,
8198  const Settings& settings,
8199  int depth = 20);
8200 
8202  int indirect,
8203  const Settings& settings,
8204  int depth = 20)
8205 {
8206  if (!tok->valueType())
8207  return false;
8208  if (!astIsContainer(tok))
8209  return false;
8210  // If we are accessing an element then we are not changing the container size
8211  if (Token::Match(tok, "%name% . %name% (")) {
8212  const Library::Container::Yield yield = getLibraryContainer(tok)->getYield(tok->strAt(2));
8214  return false;
8215  }
8216  if (Token::simpleMatch(tok->astParent(), "["))
8217  return false;
8218 
8219  // address of variable
8220  const bool addressOf = tok->valueType()->pointer || (tok->astParent() && tok->astParent()->isUnaryOp("&"));
8221 
8222  int narg;
8223  const Token * ftok = getTokenArgumentFunction(tok, narg);
8224  if (!ftok)
8225  return false; // not a function => variable not changed
8226  const Function * fun = ftok->function();
8227  if (fun && !fun->isImplicitlyVirtual()) {
8228  const Variable *arg = fun->getArgumentVar(narg);
8229  if (arg) {
8230  const bool isPointer = addressOf || indirect > 0;
8231  if (!arg->isReference() && !isPointer)
8232  return false;
8233  if (!isPointer && arg->isConst())
8234  return false;
8235  if (arg->valueType() && arg->valueType()->constness == 1)
8236  return false;
8237  const Scope * scope = fun->functionScope;
8238  if (scope) {
8239  // Argument not used
8240  if (!arg->nameToken())
8241  return false;
8242  if (depth > 0)
8243  return isContainerSizeChanged(arg->nameToken(),
8244  scope->bodyStart,
8245  scope->bodyEnd,
8246  addressOf ? indirect + 1 : indirect,
8247  settings,
8248  depth - 1);
8249  }
8250  // Don't know => Safe guess
8251  return true;
8252  }
8253  }
8254 
8255  bool inconclusive = false;
8256  const bool isChanged = isVariableChangedByFunctionCall(tok, indirect, settings, &inconclusive);
8257  return (isChanged || inconclusive);
8258 }
8259 
8262  : ExpressionAnalyzer(expr, std::move(val), t, s)
8263  {}
8264 
8265  bool match(const Token* tok) const override {
8266  return tok->exprId() == expr->exprId() || (astIsIterator(tok) && isAliasOf(tok, expr->exprId()));
8267  }
8268 
8269  Action isWritable(const Token* tok, Direction /*d*/) const override
8270  {
8271  if (astIsIterator(tok))
8272  return Action::None;
8273  if (!getValue(tok))
8274  return Action::None;
8275  if (!tok->valueType())
8276  return Action::None;
8277  if (!astIsContainer(tok))
8278  return Action::None;
8279  const Token* parent = tok->astParent();
8280  const Library::Container* container = getLibraryContainer(tok);
8281 
8282  if (container->stdStringLike && Token::simpleMatch(parent, "+=") && astIsLHS(tok) && parent->astOperand2()) {
8283  const Token* rhs = parent->astOperand2();
8284  if (rhs->tokType() == Token::eString)
8286  const Library::Container* rhsContainer = getLibraryContainer(rhs);
8287  if (rhsContainer && rhsContainer->stdStringLike) {
8288  if (std::any_of(rhs->values().cbegin(), rhs->values().cend(), [&](const ValueFlow::Value &rhsval) {
8289  return rhsval.isKnown() && rhsval.isContainerSizeValue();
8290  }))
8292  }
8293  } else if (astIsLHS(tok) && Token::Match(tok->astParent(), ". %name% (")) {
8294  const Library::Container::Action action = container->getAction(tok->astParent()->strAt(1));
8296  std::vector<const Token*> args = getArguments(tok->tokAt(3));
8297  if (args.size() < 2)
8299  }
8300  }
8301  return Action::None;
8302  }
8303 
8304  void writeValue(ValueFlow::Value* val, const Token* tok, Direction d) const override {
8305  if (!val)
8306  return;
8307  if (!tok->astParent())
8308  return;
8309  if (!tok->valueType())
8310  return;
8311  if (!astIsContainer(tok))
8312  return;
8313  const Token* parent = tok->astParent();
8314  const Library::Container* container = getLibraryContainer(tok);
8315  int n = 0;
8316 
8317  if (container->stdStringLike && Token::simpleMatch(parent, "+=") && parent->astOperand2()) {
8318  const Token* rhs = parent->astOperand2();
8319  const Library::Container* rhsContainer = getLibraryContainer(rhs);
8320  if (rhs->tokType() == Token::eString)
8321  n = Token::getStrLength(rhs);
8322  else if (rhsContainer && rhsContainer->stdStringLike) {
8323  auto it = std::find_if(rhs->values().begin(), rhs->values().end(), [&](const ValueFlow::Value& rhsval) {
8324  return rhsval.isKnown() && rhsval.isContainerSizeValue();
8325  });
8326  if (it != rhs->values().end())
8327  n = it->intvalue;
8328  }
8329  } else if (astIsLHS(tok) && Token::Match(tok->astParent(), ". %name% (")) {
8330  const Library::Container::Action action = container->getAction(tok->astParent()->strAt(1));
8331  if (action == Library::Container::Action::PUSH)
8332  n = 1;
8333  if (action == Library::Container::Action::POP)
8334  n = -1;
8335  }
8336  if (d == Direction::Reverse)
8337  val->intvalue -= n;
8338  else
8339  val->intvalue += n;
8340  }
8341 
8342  int getIndirect(const Token* tok) const override
8343  {
8344  if (tok->valueType()) {
8345  return tok->valueType()->pointer;
8346  }
8347  return ValueFlowAnalyzer::getIndirect(tok);
8348  }
8349 
8350  Action isModified(const Token* tok) const override {
8351  Action read = Action::Read;
8352  // An iterator won't change the container size
8353  if (astIsIterator(tok))
8354  return read;
8355  if (Token::Match(tok->astParent(), "%assign%") && astIsLHS(tok))
8356  return Action::Invalid;
8357  if (isLikelyStreamRead(tok->astParent()))
8358  return Action::Invalid;
8360  return read | Action::Invalid;
8361  return read;
8362  }
8363 };
8364 
8365 static const Token* parseBinaryIntOp(const Token* expr,
8366  const std::function<std::vector<MathLib::bigint>(const Token*)>& eval,
8367  MathLib::bigint& known)
8368 {
8369  if (!expr)
8370  return nullptr;
8371  if (!expr->astOperand1() || !expr->astOperand2())
8372  return nullptr;
8373  if (expr->astOperand1()->exprId() == 0 && expr->astOperand2()->exprId() == 0)
8374  return nullptr;
8375  std::vector<MathLib::bigint> x1 = eval(expr->astOperand1());
8376  std::vector<MathLib::bigint> x2 = eval(expr->astOperand2());
8377  if (expr->astOperand1()->exprId() == 0 && x1.empty())
8378  return nullptr;
8379  if (expr->astOperand2()->exprId() == 0 && x2.empty())
8380  return nullptr;
8381  const Token* varTok = nullptr;
8382  if (!x1.empty() && x2.empty()) {
8383  varTok = expr->astOperand2();
8384  known = x1.front();
8385  } else if (x1.empty() && !x2.empty()) {
8386  varTok = expr->astOperand1();
8387  known = x2.front();
8388  }
8389  return varTok;
8390 }
8391 
8393  const std::function<std::vector<MathLib::bigint>(const Token*)>& eval,
8394  ValueFlow::Value& value)
8395 {
8396  if (!value.isIntValue() && !value.isIteratorValue() && !value.isSymbolicValue())
8397  return expr;
8398  if (value.isSymbolicValue() && !Token::Match(expr, "+|-"))
8399  return expr;
8400  MathLib::bigint intval;
8401  const Token* binaryTok = parseBinaryIntOp(expr, eval, intval);
8402  const bool rhs = astIsRHS(binaryTok);
8403  // If its on the rhs, then -1 multiplication is needed, which is not possible with simple delta analysis used currently for symbolic values
8404  if (value.isSymbolicValue() && rhs && Token::simpleMatch(expr, "-"))
8405  return expr;
8406  if (binaryTok && expr->str().size() == 1) {
8407  switch (expr->str()[0]) {
8408  case '+': {
8409  value.intvalue -= intval;
8410  return ValueFlow::solveExprValue(binaryTok, eval, value);
8411  }
8412  case '-': {
8413  if (rhs)
8414  value.intvalue = intval - value.intvalue;
8415  else
8416  value.intvalue += intval;
8417  return ValueFlow::solveExprValue(binaryTok, eval, value);
8418  }
8419  case '*': {
8420  if (intval == 0)
8421  break;
8422  value.intvalue /= intval;
8423  return ValueFlow::solveExprValue(binaryTok, eval, value);
8424  }
8425  case '^': {
8426  value.intvalue ^= intval;
8427  return ValueFlow::solveExprValue(binaryTok, eval, value);
8428  }
8429  }
8430  }
8431  return expr;
8432 }
8433 
8434 static const Token* solveExprValue(const Token* expr, ValueFlow::Value& value)
8435 {
8437  expr,
8438  [](const Token* tok) -> std::vector<MathLib::bigint> {
8439  if (tok->hasKnownIntValue())
8440  return {tok->values().front().intvalue};
8441  return {};
8442  },
8443  value);
8444 }
8445 
8446 static ValuePtr<Analyzer> makeAnalyzer(const Token* exprTok, ValueFlow::Value value, const TokenList& tokenlist, const Settings& settings)
8447 {
8448  if (value.isContainerSizeValue())
8449  return ContainerExpressionAnalyzer(exprTok, std::move(value), tokenlist, settings);
8450  const Token* expr = solveExprValue(exprTok, value);
8451  return ExpressionAnalyzer(expr, std::move(value), tokenlist, settings);
8452 }
8453 
8454 static ValuePtr<Analyzer> makeReverseAnalyzer(const Token* exprTok, ValueFlow::Value value, const TokenList& tokenlist, const Settings& settings)
8455 {
8456  if (value.isContainerSizeValue())
8457  return ContainerExpressionAnalyzer(exprTok, std::move(value), tokenlist, settings);
8458  return ExpressionAnalyzer(exprTok, std::move(value), tokenlist, settings);
8459 }
8460 
8461 bool ValueFlow::isContainerSizeChanged(const Token* tok, int indirect, const Settings& settings, int depth)
8462 {
8463  if (!tok)
8464  return false;
8465  if (!tok->valueType() || !tok->valueType()->container)
8466  return true;
8467  if (astIsLHS(tok) && Token::Match(tok->astParent(), "%assign%|<<"))
8468  return true;
8469  if (astIsLHS(tok) && Token::simpleMatch(tok->astParent(), "["))
8470  return tok->valueType()->container->stdAssociativeLike;
8471  const Library::Container::Action action = astContainerAction(tok);
8472  switch (action) {
8480  return true;
8482  // Is this an unknown member function call?
8483  if (astIsLHS(tok) && Token::Match(tok->astParent(), ". %name% (")) {
8484  const Library::Container::Yield yield = astContainerYield(tok);
8485  return yield == Library::Container::Yield::NO_YIELD;
8486  }
8487  break;
8492  break;
8493  }
8494  return isContainerSizeChangedByFunction(tok, indirect, settings, depth);
8495 }
8496 
8497 static bool isContainerSizeChanged(const Token* expr,
8498  const Token* start,
8499  const Token* end,
8500  int indirect,
8501  const Settings& settings,
8502  int depth)
8503 {
8504  for (const Token *tok = start; tok != end; tok = tok->next()) {
8505  if (tok->exprId() != expr->exprId() && !isAliasOf(tok, expr))
8506  continue;
8507  if (ValueFlow::isContainerSizeChanged(tok, indirect, settings, depth))
8508  return true;
8509  }
8510  return false;
8511 }
8512 
8513 static void valueFlowSmartPointer(TokenList &tokenlist, ErrorLogger & errorLogger, const Settings &settings)
8514 {
8515  for (Token *tok = tokenlist.front(); tok; tok = tok->next()) {
8516  if (!tok->scope())
8517  continue;
8518  if (!tok->scope()->isExecutable())
8519  continue;
8520  if (!astIsSmartPointer(tok))
8521  continue;
8522  if (tok->variable() && Token::Match(tok, "%var% (|{|;")) {
8523  const Variable* var = tok->variable();
8524  if (!var->isSmartPointer())
8525  continue;
8526  if (var->nameToken() == tok) {
8527  if (Token::Match(tok, "%var% (|{") && tok->next()->astOperand2() &&
8528  tok->next()->astOperand2()->str() != ",") {
8529  Token* inTok = tok->next()->astOperand2();
8530  const std::list<ValueFlow::Value>& values = inTok->values();
8531  const bool constValue = inTok->isNumber();
8532  valueFlowForwardAssign(inTok, var, values, constValue, true, tokenlist, errorLogger, settings);
8533 
8534  } else if (Token::Match(tok, "%var% ;")) {
8535  ValueFlow::Value v(0);
8536  v.setKnown();
8537  valueFlowForwardAssign(tok, var, {std::move(v)}, false, true, tokenlist, errorLogger, settings);
8538  }
8539  }
8540  } else if (astIsLHS(tok) && Token::Match(tok->astParent(), ". %name% (") &&
8541  tok->astParent()->originalName() != "->") {
8542  std::vector<const Variable*> vars = getVariables(tok);
8543  Token* ftok = tok->astParent()->tokAt(2);
8544  if (Token::simpleMatch(tok->astParent(), ". reset (")) {
8545  if (Token::simpleMatch(ftok, "( )")) {
8546  ValueFlow::Value v(0);
8547  v.setKnown();
8548  valueFlowForwardAssign(ftok, tok, std::move(vars), {std::move(v)}, false, tokenlist, errorLogger, settings);
8549  } else {
8550  tok->removeValues(std::mem_fn(&ValueFlow::Value::isIntValue));
8551  Token* inTok = ftok->astOperand2();
8552  if (!inTok)
8553  continue;
8554  const std::list<ValueFlow::Value>& values = inTok->values();
8555  valueFlowForwardAssign(inTok, tok, std::move(vars), values, false, tokenlist, errorLogger, settings);
8556  }
8557  } else if (Token::simpleMatch(tok->astParent(), ". release ( )")) {
8558  const Token* parent = ftok->astParent();
8559  bool hasParentReset = false;
8560  while (parent) {
8561  if (Token::Match(parent->tokAt(-2), ". release|reset (") &&
8562  parent->tokAt(-2)->astOperand1()->exprId() == tok->exprId()) {
8563  hasParentReset = true;
8564  break;
8565  }
8566  parent = parent->astParent();
8567  }
8568  if (hasParentReset)
8569  continue;
8570  ValueFlow::Value v(0);
8571  v.setKnown();
8572  valueFlowForwardAssign(ftok, tok, std::move(vars), {std::move(v)}, false, tokenlist, errorLogger, settings);
8573  } else if (Token::simpleMatch(tok->astParent(), ". get ( )")) {
8574  ValueFlow::Value v = makeSymbolic(tok);
8575  setTokenValue(tok->astParent()->tokAt(2), std::move(v), settings);
8576  }
8577  } else if (Token::Match(tok->previous(), "%name%|> (|{") && astIsSmartPointer(tok) &&
8578  astIsSmartPointer(tok->astOperand1())) {
8579  std::vector<const Token*> args = getArguments(tok);
8580  if (args.empty())
8581  continue;
8582  for (const ValueFlow::Value& v : args.front()->values())
8583  setTokenValue(tok, v, settings);
8584  }
8585  }
8586 }
8587 
8588 static Library::Container::Yield findIteratorYield(Token* tok, const Token** ftok, const Settings &settings)
8589 {
8590  auto yield = astContainerYield(tok, ftok);
8591  if (ftok && *ftok)
8592  return yield;
8593 
8594  if (!tok->astParent())
8595  return yield;
8596 
8597  //begin/end free functions
8598  return astFunctionYield(tok->astParent()->previous(), settings, ftok);
8599 }
8600 
8601 static void valueFlowIterators(TokenList &tokenlist, const Settings &settings)
8602 {
8603  for (Token *tok = tokenlist.front(); tok; tok = tok->next()) {
8604  if (!tok->scope())
8605  continue;
8606  if (!tok->scope()->isExecutable())
8607  continue;
8608  if (!astIsContainer(tok))
8609  continue;
8610  Token* ftok = nullptr;
8611  const Library::Container::Yield yield = findIteratorYield(tok, const_cast<const Token**>(&ftok), settings);
8612  if (ftok) {
8613  ValueFlow::Value v(0);
8614  v.setKnown();
8617  setTokenValue(ftok->next(), std::move(v), settings);
8618  } else if (yield == Library::Container::Yield::END_ITERATOR) {
8620  setTokenValue(ftok->next(), std::move(v), settings);
8621  }
8622  }
8623  }
8624 }
8625 
8626 static std::list<ValueFlow::Value> getIteratorValues(std::list<ValueFlow::Value> values, const ValueFlow::Value::ValueKind* kind = nullptr)
8627 {
8628  values.remove_if([&](const ValueFlow::Value& v) {
8629  if (kind && v.valueKind != *kind)
8630  return true;
8631  return !v.isIteratorValue();
8632  });
8633  return values;
8634 }
8635 
8637  std::vector<Condition> parse(const Token* tok, const Settings& /*settings*/) const override {
8638  Condition cond;
8639 
8640  if (Token::Match(tok, "==|!=")) {
8641  if (!tok->astOperand1() || !tok->astOperand2())
8642  return {};
8643 
8645  std::list<ValueFlow::Value> values = getIteratorValues(tok->astOperand1()->values(), &kind);
8646  if (!values.empty()) {
8647  cond.vartok = tok->astOperand2();
8648  } else {
8649  values = getIteratorValues(tok->astOperand2()->values(), &kind);
8650  if (!values.empty())
8651  cond.vartok = tok->astOperand1();
8652  }
8653  for (ValueFlow::Value& v:values) {
8654  v.setPossible();
8655  v.assumeCondition(tok);
8656  }
8657  cond.true_values = values;
8658  cond.false_values = std::move(values);
8659  }
8660 
8661  return {std::move(cond)};
8662  }
8663 };
8664 
8665 static void valueFlowIteratorInfer(TokenList &tokenlist, const Settings &settings)
8666 {
8667  for (Token *tok = tokenlist.front(); tok; tok = tok->next()) {
8668  if (!tok->scope())
8669  continue;
8670  if (!tok->scope()->isExecutable())
8671  continue;
8672  std::list<ValueFlow::Value> values = getIteratorValues(tok->values());
8673  values.remove_if([&](const ValueFlow::Value& v) {
8674  if (!v.isImpossible())
8675  return true;
8676  if (!v.condition)
8677  return true;
8679  return true;
8680  if (v.isIteratorEndValue() && v.intvalue <= 0)
8681  return true;
8682  if (v.isIteratorStartValue() && v.intvalue >= 0)
8683  return true;
8684  return false;
8685  });
8686  for (ValueFlow::Value& v:values) {
8687  v.setPossible();
8688  if (v.isIteratorStartValue())
8689  v.intvalue++;
8690  if (v.isIteratorEndValue())
8691  v.intvalue--;
8692  setTokenValue(tok, std::move(v), settings);
8693  }
8694  }
8695 }
8696 
8697 static std::vector<ValueFlow::Value> getContainerValues(const Token* tok)
8698 {
8699  std::vector<ValueFlow::Value> values;
8700  if (tok) {
8701  std::copy_if(tok->values().cbegin(),
8702  tok->values().cend(),
8703  std::back_inserter(values),
8705  }
8706  return values;
8707 }
8708 
8709 static ValueFlow::Value makeContainerSizeValue(std::size_t s, bool known = true)
8710 {
8711  ValueFlow::Value value(s);
8713  if (known)
8714  value.setKnown();
8715  return value;
8716 }
8717 
8718 static std::vector<ValueFlow::Value> makeContainerSizeValue(const Token* tok, bool known = true)
8719 {
8720  if (tok->hasKnownIntValue())
8721  return {makeContainerSizeValue(tok->values().front().intvalue, known)};
8722  return {};
8723 }
8724 
8725 static std::vector<ValueFlow::Value> getContainerSizeFromConstructorArgs(const std::vector<const Token*>& args,
8726  const Library::Container* container,
8727  bool known)
8728 {
8729  if (astIsIntegral(args[0], false)) { // { count, i } or { count }
8730  if (args.size() == 1 || (args.size() > 1 && !astIsIntegral(args[1], false)))
8731  return {makeContainerSizeValue(args[0], known)};
8732  } else if (astIsContainer(args[0]) && args.size() == 1) { // copy constructor
8733  return getContainerValues(args[0]);
8734  } else if (isIteratorPair(args)) {
8735  std::vector<ValueFlow::Value> result = getContainerValues(args[0]);
8736  if (!result.empty())
8737  return result;
8738  // (ptr, ptr + size)
8739  if (astIsPointer(args[0]) && args[0]->exprId() != 0) {
8740  // (ptr, ptr) is empty
8741  // TODO: Use lifetime values to check if it points to the same address
8742  if (args[0]->exprId() == args[1]->exprId())
8743  return {makeContainerSizeValue(std::size_t{0}, known)};
8744  // TODO: Insert iterator positions for pointers
8745  if (Token::simpleMatch(args[1], "+")) {
8746  nonneg int const eid = args[0]->exprId();
8747  const Token* vartok = args[1]->astOperand1();
8748  const Token* sizetok = args[1]->astOperand2();
8749  if (sizetok->exprId() == eid)
8750  std::swap(vartok, sizetok);
8751  if (vartok->exprId() == eid && sizetok->hasKnownIntValue())
8752  return {makeContainerSizeValue(sizetok, known)};
8753  }
8754  }
8755  } else if (container->stdStringLike) {
8756  if (astIsPointer(args[0])) {
8757  // TODO: Try to read size of string literal { "abc" }
8758  if (args.size() == 2 && astIsIntegral(args[1], false)) // { char*, count }
8759  return {makeContainerSizeValue(args[1], known)};
8760  } else if (astIsContainer(args[0])) {
8761  if (args.size() == 1) // copy constructor { str }
8762  return getContainerValues(args[0]);
8763  if (args.size() == 3) // { str, pos, count }
8764  return {makeContainerSizeValue(args[2], known)};
8765  // TODO: { str, pos }, { ..., alloc }
8766  }
8767  }
8768  return {};
8769 }
8770 
8771 static bool valueFlowIsSameContainerType(const ValueType& contType, const Token* tok, const Settings& settings)
8772 {
8773  if (!tok || !tok->valueType() || !tok->valueType()->containerTypeToken)
8774  return true;
8775 
8776  const ValueType tokType = ValueType::parseDecl(tok->valueType()->containerTypeToken, settings);
8777  return contType.isTypeEqual(&tokType) || tokType.type == ValueType::Type::UNKNOWN_TYPE;
8778 }
8779 
8780 static std::vector<ValueFlow::Value> getInitListSize(const Token* tok,
8781  const ValueType* valueType,
8782  const Settings& settings,
8783  bool known = true)
8784 {
8785  std::vector<const Token*> args = getArguments(tok);
8786  if (args.empty())
8787  return {makeContainerSizeValue(std::size_t{0}, known)};
8788  bool initList = true;
8789  // Try to disambiguate init list from constructor
8790  if (args.size() < 4) {
8791  initList = !isIteratorPair(args) && !(args.size() < 3 && astIsIntegral(args[0], false));
8792  const Token* containerTypeToken = valueType->containerTypeToken;
8793  if (valueType->container->stdStringLike) {
8794  initList = astIsGenericChar(args[0]) && !astIsPointer(args[0]);
8795  } else if (containerTypeToken) {
8796  ValueType vt = ValueType::parseDecl(containerTypeToken, settings);
8797  if (vt.pointer > 0 && astIsPointer(args[0]))
8798  initList = true;
8799  else if (vt.type == ValueType::ITERATOR && astIsIterator(args[0]))
8800  initList = true;
8801  else if (vt.isIntegral() && astIsIntegral(args[0], false))
8802  initList = true;
8803  else if (args.size() == 1 && valueFlowIsSameContainerType(vt, tok->astOperand2(), settings))
8804  initList = false; // copy ctor
8805  }
8806  }
8807  if (!initList)
8808  return getContainerSizeFromConstructorArgs(args, valueType->container, known);
8809  return {makeContainerSizeValue(args.size(), known)};
8810 }
8811 
8812 static std::vector<ValueFlow::Value> getContainerSizeFromConstructor(const Token* tok,
8813  const ValueType* valueType,
8814  const Settings& settings,
8815  bool known = true)
8816 {
8817  std::vector<const Token*> args = getArguments(tok);
8818  if (args.empty())
8819  return {makeContainerSizeValue(std::size_t{0}, known)};
8820  // Init list in constructor
8821  if (args.size() == 1 && Token::simpleMatch(args[0], "{"))
8822  return getInitListSize(args[0], valueType, settings, known);
8823  return getContainerSizeFromConstructorArgs(args, valueType->container, known);
8824 }
8825 
8826 static void valueFlowContainerSetTokValue(const TokenList& tokenlist, ErrorLogger& errorLogger, const Settings& settings, const Token* tok, Token* initList)
8827 {
8828  ValueFlow::Value value;
8830  value.tokvalue = initList;
8831  if (astIsContainerString(tok) && Token::simpleMatch(initList, "{") && Token::Match(initList->astOperand2(), "%str%")) {
8832  value.tokvalue = initList->astOperand2();
8833  }
8834  value.setKnown();
8835  Token* start = initList->link() ? initList->link() : initList->next();
8836  if (tok->variable() && tok->variable()->isConst()) {
8837  valueFlowForwardConst(start, tok->variable()->scope()->bodyEnd, tok->variable(), {std::move(value)}, settings);
8838  } else {
8839  valueFlowForward(start, tok, std::move(value), tokenlist, errorLogger, settings);
8840  }
8841 }
8842 
8843 static const Scope* getFunctionScope(const Scope* scope) {
8844  while (scope && scope->type != Scope::ScopeType::eFunction)
8845  scope = scope->nestedIn;
8846  return scope;
8847 }
8848 
8850 {
8851  if (tok->tokType() == Token::eString)
8852  return Token::getStrLength(tok);
8853  if (astIsGenericChar(tok) || tok->tokType() == Token::eChar)
8854  return 1;
8856  return v->intvalue;
8858  if (v->tokvalue != tok)
8859  return valueFlowGetStrLength(v->tokvalue);
8860  }
8861  return 0;
8862 }
8863 
8864 static void valueFlowContainerSize(const TokenList& tokenlist,
8865  const SymbolDatabase& symboldatabase,
8866  ErrorLogger& errorLogger,
8867  const Settings& settings,
8868  const std::set<const Scope*>& skippedFunctions)
8869 {
8870  // declaration
8871  for (const Variable *var : symboldatabase.variableList()) {
8872  if (!var)
8873  continue;
8874  if (!var->scope() || !var->scope()->bodyEnd || !var->scope()->bodyStart)
8875  continue;
8876  if (!var->valueType() || !var->valueType()->container)
8877  continue;
8878  if (!astIsContainer(var->nameToken()))
8879  continue;
8880  if (skippedFunctions.count(getFunctionScope(var->scope())))
8881  continue;
8882 
8883  bool known = true;
8884  int size = 0;
8885  const bool nonLocal = !var->isLocal() || var->isPointer() || var->isReference() || var->isStatic();
8886  bool constSize = var->isConst() && !nonLocal;
8887  bool staticSize = false;
8888  if (var->valueType()->container->size_templateArgNo >= 0) {
8889  staticSize = true;
8890  constSize = true;
8891  size = -1;
8892  if (var->dimensions().size() == 1) {
8893  const Dimension& dim = var->dimensions().front();
8894  if (dim.known) {
8895  size = dim.num;
8896  } else if (dim.tok && dim.tok->hasKnownIntValue()) {
8897  size = dim.tok->values().front().intvalue;
8898  }
8899  }
8900  if (size < 0)
8901  continue;
8902  }
8903  if (!staticSize && nonLocal)
8904  continue;
8905  Token* nameToken = const_cast<Token*>(var->nameToken());
8907  continue;
8908  if (!staticSize) {
8909  if (!Token::Match(nameToken, "%name% ;") &&
8910  !(Token::Match(nameToken, "%name% {") && Token::simpleMatch(nameToken->next()->link(), "} ;")) &&
8911  !Token::Match(nameToken, "%name% ("))
8912  continue;
8913  }
8914  if (nameToken->astTop() && Token::Match(nameToken->astTop()->previous(), "for|while"))
8915  known = !isVariableChanged(var, settings);
8916  std::vector<ValueFlow::Value> values{ValueFlow::Value{size}};
8918  if (known)
8919  values.back().setKnown();
8920  if (!staticSize) {
8921  if (Token::simpleMatch(nameToken->next(), "{")) {
8922  Token* initList = nameToken->next();
8923  valueFlowContainerSetTokValue(tokenlist, errorLogger, settings, nameToken, initList);
8924  values = getInitListSize(initList, var->valueType(), settings, known);
8925  } else if (Token::simpleMatch(nameToken->next(), "(")) {
8926  const Token* constructorArgs = nameToken->next();
8927  values = getContainerSizeFromConstructor(constructorArgs, var->valueType(), settings, known);
8928  }
8929  }
8930 
8931  if (constSize) {
8932  valueFlowForwardConst(nameToken->next(), var->scope()->bodyEnd, var, values, settings);
8933  continue;
8934  }
8935 
8936  for (const ValueFlow::Value& value : values) {
8937  valueFlowForward(nameToken->next(), var->nameToken(), value, tokenlist, errorLogger, settings);
8938  }
8939  }
8940 
8941  // after assignment
8942  for (const Scope *functionScope : symboldatabase.functionScopes) {
8943  for (auto* tok = const_cast<Token*>(functionScope->bodyStart); tok != functionScope->bodyEnd; tok = tok->next()) {
8944  if (Token::Match(tok, "%name%|;|{|} %var% = %str% ;")) {
8945  Token* containerTok = tok->next();
8946  if (containerTok->exprId() == 0)
8947  continue;
8948  if (containerTok->valueType() && containerTok->valueType()->container &&
8949  containerTok->valueType()->container->stdStringLike) {
8950  valueFlowContainerSetTokValue(tokenlist, errorLogger, settings, containerTok, containerTok->tokAt(2));
8951  ValueFlow::Value value(Token::getStrLength(containerTok->tokAt(2)));
8953  value.setKnown();
8954  valueFlowForward(containerTok->next(), containerTok, value, tokenlist, errorLogger, settings);
8955  }
8956  } else if (Token::Match(tok->previous(), ">|return (|{") && astIsContainer(tok) && getLibraryContainer(tok)->size_templateArgNo < 0) {
8957  std::vector<ValueFlow::Value> values;
8958  if (Token::simpleMatch(tok, "{")) {
8959  values = getInitListSize(tok, tok->valueType(), settings, true);
8960  ValueFlow::Value value;
8962  value.tokvalue = tok;
8963  value.setKnown();
8964  values.push_back(value);
8965  } else if (Token::simpleMatch(tok, "(")) {
8966  const Token* constructorArgs = tok;
8967  values = getContainerSizeFromConstructor(constructorArgs, tok->valueType(), settings, true);
8968  }
8969  for (const ValueFlow::Value& value : values)
8970  setTokenValue(tok, value, settings);
8971  } else if (Token::Match(tok, "%name%|;|{|}|> %var% = {") && Token::simpleMatch(tok->linkAt(3), "} ;")) {
8972  Token* containerTok = tok->next();
8973  if (containerTok->exprId() == 0)
8974  continue;
8975  if (astIsContainer(containerTok) && containerTok->valueType()->container->size_templateArgNo < 0) {
8976  std::vector<ValueFlow::Value> values =
8977  getInitListSize(tok->tokAt(3), containerTok->valueType(), settings);
8978  valueFlowContainerSetTokValue(tokenlist, errorLogger, settings, containerTok, tok->tokAt(3));
8979  for (const ValueFlow::Value& value : values)
8980  valueFlowForward(containerTok->next(), containerTok, value, tokenlist, errorLogger, settings);
8981  }
8982  } else if (Token::Match(tok, ". %name% (") && tok->astOperand1() && tok->astOperand1()->valueType() &&
8983  tok->astOperand1()->valueType()->container) {
8984  const Token* containerTok = tok->astOperand1();
8985  if (containerTok->exprId() == 0)
8986  continue;
8987  const Library::Container::Action action = containerTok->valueType()->container->getAction(tok->strAt(1));
8988  if (action == Library::Container::Action::CLEAR) {
8989  ValueFlow::Value value(0);
8991  value.setKnown();
8992  valueFlowForward(tok->next(), containerTok, std::move(value), tokenlist, errorLogger, settings);
8993  } else if (action == Library::Container::Action::RESIZE && tok->tokAt(2)->astOperand2() &&
8994  tok->tokAt(2)->astOperand2()->hasKnownIntValue()) {
8995  ValueFlow::Value value(tok->tokAt(2)->astOperand2()->values().front());
8997  value.setKnown();
8998  valueFlowForward(tok->linkAt(2), containerTok, std::move(value), tokenlist, errorLogger, settings);
8999  } else if (action == Library::Container::Action::PUSH && !isIteratorPair(getArguments(tok->tokAt(2)))) {
9000  ValueFlow::Value value(0);
9002  value.setImpossible();
9003  valueFlowForward(tok->linkAt(2), containerTok, std::move(value), tokenlist, errorLogger, settings);
9004  }
9005  } else if (Token::simpleMatch(tok, "+=") && astIsContainer(tok->astOperand1())) {
9006  const Token* containerTok = tok->astOperand1();
9007  const Token* valueTok = tok->astOperand2();
9008  MathLib::bigint size = valueFlowGetStrLength(valueTok);
9009  if (size == 0)
9010  continue;
9011  ValueFlow::Value value(size - 1);
9014  value.setImpossible();
9015  Token* next = nextAfterAstRightmostLeaf(tok);
9016  if (!next)
9017  next = tok->next();
9018  valueFlowForward(next, containerTok, value, tokenlist, errorLogger, settings);
9019  }
9020  }
9021  }
9022 }
9023 
9025  std::vector<Condition> parse(const Token* tok, const Settings& settings) const override
9026  {
9027  std::vector<Condition> conds;
9028  parseCompareEachInt(tok, [&](const Token* vartok, ValueFlow::Value true_value, ValueFlow::Value false_value) {
9030  if (!vartok)
9031  return;
9034  Condition cond;
9035  cond.true_values.push_back(std::move(true_value));
9036  cond.false_values.push_back(std::move(false_value));
9037  cond.vartok = vartok;
9038  conds.push_back(std::move(cond));
9039  });
9040  if (!conds.empty())
9041  return conds;
9042 
9043  const Token* vartok = nullptr;
9044 
9045  // Empty check
9046  if (tok->str() == "(") {
9048  // TODO: Handle .size()
9049  if (!vartok)
9050  return {};
9051  const Token *parent = tok->astParent();
9052  while (parent) {
9053  if (Token::Match(parent, "%comp%"))
9054  return {};
9055  parent = parent->astParent();
9056  }
9057  ValueFlow::Value value(tok, 0LL);
9059  Condition cond;
9060  cond.true_values.emplace_back(value);
9061  cond.false_values.emplace_back(std::move(value));
9062  cond.vartok = vartok;
9063  cond.inverted = true;
9064  return {std::move(cond)};
9065  }
9066  // String compare
9067  if (Token::Match(tok, "==|!=")) {
9068  const Token *strtok = nullptr;
9069  if (Token::Match(tok->astOperand1(), "%str%")) {
9070  strtok = tok->astOperand1();
9071  vartok = tok->astOperand2();
9072  } else if (Token::Match(tok->astOperand2(), "%str%")) {
9073  strtok = tok->astOperand2();
9074  vartok = tok->astOperand1();
9075  }
9076  if (!strtok)
9077  return {};
9078  if (!astIsContainer(vartok))
9079  return {};
9080  ValueFlow::Value value(tok, Token::getStrLength(strtok));
9082  Condition cond;
9083  cond.false_values.emplace_back(value);
9084  cond.true_values.emplace_back(std::move(value));
9085  cond.vartok = vartok;
9086  cond.impossible = false;
9087  return {std::move(cond)};
9088  }
9089  return {};
9090  }
9091 };
9092 
9093 static void valueFlowDynamicBufferSize(const TokenList& tokenlist, const SymbolDatabase& symboldatabase, ErrorLogger& errorLogger, const Settings& settings)
9094 {
9095  auto getBufferSizeFromAllocFunc = [&](const Token* funcTok) -> MathLib::bigint {
9096  MathLib::bigint sizeValue = -1;
9097  const Library::AllocFunc* allocFunc = settings.library.getAllocFuncInfo(funcTok);
9098  if (!allocFunc)
9099  allocFunc = settings.library.getReallocFuncInfo(funcTok);
9100  if (!allocFunc || allocFunc->bufferSize == Library::AllocFunc::BufferSize::none)
9101  return sizeValue;
9102 
9103  const std::vector<const Token*> args = getArguments(funcTok);
9104 
9105  const Token* const arg1 = (args.size() >= allocFunc->bufferSizeArg1) ? args[allocFunc->bufferSizeArg1 - 1] : nullptr;
9106  const Token* const arg2 = (args.size() >= allocFunc->bufferSizeArg2) ? args[allocFunc->bufferSizeArg2 - 1] : nullptr;
9107 
9108  switch (allocFunc->bufferSize) {
9110  break;
9112  if (arg1 && arg1->hasKnownIntValue())
9113  sizeValue = arg1->getKnownIntValue();
9114  break;
9116  if (arg1 && arg2 && arg1->hasKnownIntValue() && arg2->hasKnownIntValue())
9117  sizeValue = arg1->getKnownIntValue() * arg2->getKnownIntValue();
9118  break;
9120  if (arg1 && arg1->hasKnownValue()) {
9121  const ValueFlow::Value& value = arg1->values().back();
9122  if (value.isTokValue() && value.tokvalue->tokType() == Token::eString)
9123  sizeValue = Token::getStrLength(value.tokvalue) + 1; // Add one for the null terminator
9124  }
9125  break;
9126  }
9127  return sizeValue;
9128  };
9129 
9130  auto getBufferSizeFromNew = [&](const Token* newTok) -> MathLib::bigint {
9131  MathLib::bigint sizeValue = -1, numElem = -1;
9132 
9133  if (newTok && newTok->astOperand1()) { // number of elements
9134  const Token* bracTok = nullptr, *typeTok = nullptr;
9135  if (newTok->astOperand1()->str() == "[")
9136  bracTok = newTok->astOperand1();
9137  else if (Token::Match(newTok->astOperand1(), "(|{")) {
9138  if (newTok->astOperand1()->astOperand1() && newTok->astOperand1()->astOperand1()->str() == "[")
9139  bracTok = newTok->astOperand1()->astOperand1();
9140  else
9141  typeTok = newTok->astOperand1()->astOperand1();
9142  }
9143  else
9144  typeTok = newTok->astOperand1();
9145  if (bracTok && bracTok->astOperand2() && bracTok->astOperand2()->hasKnownIntValue())
9146  numElem = bracTok->astOperand2()->getKnownIntValue();
9147  else if (Token::Match(typeTok, "%type%"))
9148  numElem = 1;
9149  }
9150 
9151  if (numElem >= 0 && newTok->astParent() && newTok->astParent()->isAssignmentOp()) { // size of the allocated type
9152  const Token* typeTok = newTok->astParent()->astOperand1(); // TODO: implement fallback for e.g. "auto p = new Type;"
9153  if (!typeTok || !typeTok->varId())
9154  typeTok = newTok->astParent()->previous(); // hack for "int** z = ..."
9155  if (typeTok && typeTok->valueType()) {
9156  const MathLib::bigint typeSize = typeTok->valueType()->typeSize(settings.platform, typeTok->valueType()->pointer > 1);
9157  if (typeSize >= 0)
9158  sizeValue = numElem * typeSize;
9159  }
9160  }
9161  return sizeValue;
9162  };
9163 
9164  for (const Scope *functionScope : symboldatabase.functionScopes) {
9165  for (const Token *tok = functionScope->bodyStart; tok != functionScope->bodyEnd; tok = tok->next()) {
9166  if (!Token::Match(tok, "[;{}] %var% ="))
9167  continue;
9168 
9169  if (!tok->next()->variable())
9170  continue;
9171 
9172  const Token *rhs = tok->tokAt(2)->astOperand2();
9173  while (rhs && rhs->isCast())
9174  rhs = rhs->astOperand2() ? rhs->astOperand2() : rhs->astOperand1();
9175  if (!rhs)
9176  continue;
9177 
9178  const bool isNew = rhs->isCpp() && rhs->str() == "new";
9179  if (!isNew && !Token::Match(rhs->previous(), "%name% ("))
9180  continue;
9181 
9182  const MathLib::bigint sizeValue = isNew ? getBufferSizeFromNew(rhs) : getBufferSizeFromAllocFunc(rhs->previous());
9183  if (sizeValue < 0)
9184  continue;
9185 
9186  ValueFlow::Value value(sizeValue);
9187  value.errorPath.emplace_back(tok->tokAt(2), "Assign " + tok->strAt(1) + ", buffer with size " + std::to_string(sizeValue));
9189  value.setKnown();
9190  valueFlowForward(const_cast<Token*>(rhs), functionScope->bodyEnd, tok->next(), std::move(value), tokenlist, errorLogger, settings);
9191  }
9192  }
9193 }
9194 
9195 static bool getMinMaxValues(const ValueType *vt, const Platform &platform, MathLib::bigint &minValue, MathLib::bigint &maxValue)
9196 {
9197  if (!vt || !vt->isIntegral() || vt->pointer)
9198  return false;
9199 
9200  int bits;
9201  switch (vt->type) {
9202  case ValueType::Type::BOOL:
9203  bits = 1;
9204  break;
9205  case ValueType::Type::CHAR:
9206  bits = platform.char_bit;
9207  break;
9208  case ValueType::Type::SHORT:
9209  bits = platform.short_bit;
9210  break;
9211  case ValueType::Type::INT:
9212  bits = platform.int_bit;
9213  break;
9214  case ValueType::Type::LONG:
9215  bits = platform.long_bit;
9216  break;
9217  case ValueType::Type::LONGLONG:
9218  bits = platform.long_long_bit;
9219  break;
9220  default:
9221  return false;
9222  }
9223 
9224  if (bits == 1) {
9225  minValue = 0;
9226  maxValue = 1;
9227  } else if (bits < 62) {
9228  if (vt->sign == ValueType::Sign::UNSIGNED) {
9229  minValue = 0;
9230  maxValue = (1LL << bits) - 1;
9231  } else {
9232  minValue = -(1LL << (bits - 1));
9233  maxValue = (1LL << (bits - 1)) - 1;
9234  }
9235  } else if (bits == 64) {
9236  if (vt->sign == ValueType::Sign::UNSIGNED) {
9237  minValue = 0;
9238  maxValue = LLONG_MAX; // todo max unsigned value
9239  } else {
9240  minValue = LLONG_MIN;
9241  maxValue = LLONG_MAX;
9242  }
9243  } else {
9244  return false;
9245  }
9246 
9247  return true;
9248 }
9249 
9250 static bool getMinMaxValues(const std::string &typestr, const Settings &settings, bool cpp, MathLib::bigint &minvalue, MathLib::bigint &maxvalue)
9251 {
9252  TokenList typeTokens(&settings);
9253  std::istringstream istr(typestr+";");
9254  if (!typeTokens.createTokens(istr, cpp ? Standards::Language::CPP : Standards::Language::C))
9255  return false;
9256  typeTokens.simplifyPlatformTypes();
9257  typeTokens.simplifyStdType();
9258  const ValueType &vt = ValueType::parseDecl(typeTokens.front(), settings);
9259  return getMinMaxValues(&vt, settings.platform, minvalue, maxvalue);
9260 }
9261 
9262 static void valueFlowSafeFunctions(const TokenList& tokenlist, const SymbolDatabase& symboldatabase, ErrorLogger& errorLogger, const Settings& settings)
9263 {
9264  for (const Scope *functionScope : symboldatabase.functionScopes) {
9265  if (!functionScope->bodyStart)
9266  continue;
9267  const Function *function = functionScope->function;
9268  if (!function)
9269  continue;
9270 
9271  const bool safe = function->isSafe(settings);
9272  const bool all = safe && settings.platform.type != Platform::Type::Unspecified;
9273 
9274  for (const Variable &arg : function->argumentList) {
9275  if (!arg.nameToken() || !arg.valueType())
9276  continue;
9277 
9278  if (arg.valueType()->type == ValueType::Type::CONTAINER) {
9279  if (!safe)
9280  continue;
9281  std::list<ValueFlow::Value> argValues;
9282  argValues.emplace_back(0);
9283  argValues.back().valueType = ValueFlow::Value::ValueType::CONTAINER_SIZE;
9284  argValues.back().errorPath.emplace_back(arg.nameToken(), "Assuming " + arg.name() + " is empty");
9285  argValues.back().safe = true;
9286  argValues.emplace_back(1000000);
9287  argValues.back().valueType = ValueFlow::Value::ValueType::CONTAINER_SIZE;
9288  argValues.back().errorPath.emplace_back(arg.nameToken(), "Assuming " + arg.name() + " size is 1000000");
9289  argValues.back().safe = true;
9290  for (const ValueFlow::Value &value : argValues)
9291  valueFlowForward(const_cast<Token*>(functionScope->bodyStart), arg.nameToken(), value, tokenlist, errorLogger, settings);
9292  continue;
9293  }
9294 
9295  MathLib::bigint low, high;
9296  bool isLow = arg.nameToken()->getCppcheckAttribute(TokenImpl::CppcheckAttributes::Type::LOW, low);
9297  bool isHigh = arg.nameToken()->getCppcheckAttribute(TokenImpl::CppcheckAttributes::Type::HIGH, high);
9298 
9299  if (!isLow && !isHigh && !all)
9300  continue;
9301 
9302  const bool safeLow = !isLow;
9303  const bool safeHigh = !isHigh;
9304 
9305  if ((!isLow || !isHigh) && all) {
9306  MathLib::bigint minValue, maxValue;
9307  if (getMinMaxValues(arg.valueType(), settings.platform, minValue, maxValue)) {
9308  if (!isLow)
9309  low = minValue;
9310  if (!isHigh)
9311  high = maxValue;
9312  isLow = isHigh = true;
9313  } else if (arg.valueType()->type == ValueType::Type::FLOAT || arg.valueType()->type == ValueType::Type::DOUBLE || arg.valueType()->type == ValueType::Type::LONGDOUBLE) {
9314  std::list<ValueFlow::Value> argValues;
9315  argValues.emplace_back(0);
9316  argValues.back().valueType = ValueFlow::Value::ValueType::FLOAT;
9317  argValues.back().floatValue = isLow ? low : -1E25;
9318  argValues.back().errorPath.emplace_back(arg.nameToken(), "Safe checks: Assuming argument has value " + MathLib::toString(argValues.back().floatValue));
9319  argValues.back().safe = true;
9320  argValues.emplace_back(0);
9321  argValues.back().valueType = ValueFlow::Value::ValueType::FLOAT;
9322  argValues.back().floatValue = isHigh ? high : 1E25;
9323  argValues.back().errorPath.emplace_back(arg.nameToken(), "Safe checks: Assuming argument has value " + MathLib::toString(argValues.back().floatValue));
9324  argValues.back().safe = true;
9325  valueFlowForward(const_cast<Token*>(functionScope->bodyStart->next()),
9326  functionScope->bodyEnd,
9327  arg.nameToken(),
9328  std::move(argValues),
9329  tokenlist,
9330  errorLogger,
9331  settings);
9332  continue;
9333  }
9334  }
9335 
9336  std::list<ValueFlow::Value> argValues;
9337  if (isLow) {
9338  argValues.emplace_back(low);
9339  argValues.back().errorPath.emplace_back(arg.nameToken(), std::string(safeLow ? "Safe checks: " : "") + "Assuming argument has value " + std::to_string(low));
9340  argValues.back().safe = safeLow;
9341  }
9342  if (isHigh) {
9343  argValues.emplace_back(high);
9344  argValues.back().errorPath.emplace_back(arg.nameToken(), std::string(safeHigh ? "Safe checks: " : "") + "Assuming argument has value " + std::to_string(high));
9345  argValues.back().safe = safeHigh;
9346  }
9347 
9348  if (!argValues.empty())
9349  valueFlowForward(const_cast<Token*>(functionScope->bodyStart->next()),
9350  functionScope->bodyEnd,
9351  arg.nameToken(),
9352  std::move(argValues),
9353  tokenlist,
9354  errorLogger,
9355  settings);
9356  }
9357  }
9358 }
9359 
9360 static void valueFlowUnknownFunctionReturn(TokenList &tokenlist, const Settings &settings)
9361 {
9362  if (settings.checkUnknownFunctionReturn.empty())
9363  return;
9364  for (Token *tok = tokenlist.front(); tok; tok = tok->next()) {
9365  if (!tok->astParent() || tok->str() != "(" || !tok->previous()->isName())
9366  continue;
9367  if (settings.checkUnknownFunctionReturn.find(tok->previous()->str()) == settings.checkUnknownFunctionReturn.end())
9368  continue;
9369  std::vector<MathLib::bigint> unknownValues = settings.library.unknownReturnValues(tok->astOperand1());
9370  if (unknownValues.empty())
9371  continue;
9372 
9373  // Get min/max values for return type
9374  const std::string &typestr = settings.library.returnValueType(tok->previous());
9375  MathLib::bigint minvalue, maxvalue;
9376  if (!getMinMaxValues(typestr, settings, tok->isCpp(), minvalue, maxvalue))
9377  continue;
9378 
9379  for (MathLib::bigint value : unknownValues) {
9380  if (value < minvalue)
9381  value = minvalue;
9382  else if (value > maxvalue)
9383  value = maxvalue;
9384  setTokenValue(tok, ValueFlow::Value(value), settings);
9385  }
9386  }
9387 }
9388 
9389 static void valueFlowDebug(TokenList& tokenlist, ErrorLogger& errorLogger, const Settings& settings)
9390 {
9391  if (!settings.debugnormal && !settings.debugwarnings)
9392  return;
9393  for (Token* tok = tokenlist.front(); tok; tok = tok->next()) {
9394  if (tok->getTokenDebug() != TokenDebug::ValueFlow)
9395  continue;
9396  if (tok->astParent() && tok->astParent()->getTokenDebug() == TokenDebug::ValueFlow)
9397  continue;
9398  for (const ValueFlow::Value& v : tok->values()) {
9399  std::string msg = "The value is " + debugString(v);
9400  ErrorPath errorPath = v.errorPath;
9401  errorPath.insert(errorPath.end(), v.debugPath.cbegin(), v.debugPath.cend());
9402  errorPath.emplace_back(tok, "");
9403  errorLogger.reportErr({errorPath, &tokenlist, Severity::debug, "valueFlow", msg, CWE{0}, Certainty::normal});
9404  }
9405  }
9406 }
9407 
9409 {
9410  if (expr && expr->values().empty()) {
9411  valueFlowConstantFoldAST(expr->astOperand1(), settings);
9412  valueFlowConstantFoldAST(expr->astOperand2(), settings);
9413  valueFlowSetConstantValue(expr, settings);
9414  }
9415  return expr && expr->hasKnownValue() ? &expr->values().front() : nullptr;
9416 }
9417 
9422  const Settings& settings)
9424  {}
9425 
9430  std::set<const Scope*> skippedFunctions;
9431 };
9432 
9434  ValueFlowPass() = default;
9435  ValueFlowPass(const ValueFlowPass&) = default;
9436  // Name of pass
9437  virtual const char* name() const = 0;
9438  // Run the pass
9439  virtual void run(const ValueFlowState& state) const = 0;
9440  // Returns true if pass needs C++
9441  virtual bool cpp() const = 0;
9442  virtual ~ValueFlowPass() noexcept = default;
9443 };
9444 
9446  using Clock = std::chrono::steady_clock;
9447  using TimePoint = std::chrono::time_point<Clock>;
9448  explicit ValueFlowPassRunner(ValueFlowState state, TimerResultsIntf* timerResults = nullptr)
9449  : state(std::move(state)), stop(TimePoint::max()), timerResults(timerResults)
9450  {
9451  setSkippedFunctions();
9452  setStopTime();
9453  }
9454 
9455  bool run_once(std::initializer_list<ValuePtr<ValueFlowPass>> passes) const
9456  {
9457  return std::any_of(passes.begin(), passes.end(), [&](const ValuePtr<ValueFlowPass>& pass) {
9458  return run(pass);
9459  });
9460  }
9461 
9462  bool run(std::initializer_list<ValuePtr<ValueFlowPass>> passes) const
9463  {
9464  std::size_t values = 0;
9465  std::size_t n = state.settings.valueFlowMaxIterations;
9466  while (n > 0 && values != getTotalValues()) {
9467  values = getTotalValues();
9468  if (std::any_of(passes.begin(), passes.end(), [&](const ValuePtr<ValueFlowPass>& pass) {
9469  return run(pass);
9470  }))
9471  return true;
9472  --n;
9473  }
9474  if (state.settings.debugwarnings) {
9475  if (n == 0 && values != getTotalValues()) {
9476  ErrorMessage::FileLocation loc(state.tokenlist.getFiles()[0], 0, 0);
9477  ErrorMessage errmsg({std::move(loc)},
9478  emptyString,
9480  "ValueFlow maximum iterations exceeded",
9481  "valueFlowMaxIterations",
9483  state.errorLogger.reportErr(errmsg);
9484  }
9485  }
9486  return false;
9487  }
9488 
9489  bool run(const ValuePtr<ValueFlowPass>& pass) const
9490  {
9491  auto start = Clock::now();
9492  if (start > stop)
9493  return true;
9494  if (!state.tokenlist.isCPP() && pass->cpp())
9495  return false;
9496  if (timerResults) {
9497  Timer t(pass->name(), state.settings.showtime, timerResults);
9498  pass->run(state);
9499  } else {
9500  pass->run(state);
9501  }
9502  return false;
9503  }
9504 
9505  std::size_t getTotalValues() const
9506  {
9507  std::size_t n = 1;
9508  for (Token* tok = state.tokenlist.front(); tok; tok = tok->next())
9509  n += tok->values().size();
9510  return n;
9511  }
9512 
9514  {
9515  if (state.settings.performanceValueFlowMaxIfCount > 0) {
9516  for (const Scope* functionScope : state.symboldatabase.functionScopes) {
9517  int countIfScopes = 0;
9518  std::vector<const Scope*> scopes{functionScope};
9519  while (!scopes.empty()) {
9520  const Scope* s = scopes.back();
9521  scopes.pop_back();
9522  for (const Scope* s2 : s->nestedList) {
9523  scopes.emplace_back(s2);
9524  if (s2->type == Scope::ScopeType::eIf)
9525  ++countIfScopes;
9526  }
9527  }
9528  if (countIfScopes > state.settings.performanceValueFlowMaxIfCount) {
9529  state.skippedFunctions.emplace(functionScope);
9530 
9531  if (state.settings.severity.isEnabled(Severity::information)) {
9532  const std::string& functionName = functionScope->className;
9533  const std::list<ErrorMessage::FileLocation> callstack(
9534  1,
9535  ErrorMessage::FileLocation(functionScope->bodyStart, &state.tokenlist));
9536  const ErrorMessage errmsg(callstack,
9537  state.tokenlist.getSourceFilePath(),
9539  "Limiting ValueFlow analysis in function '" + functionName + "' since it is too complex. "
9540  "Please specify --check-level=exhaustive to perform full analysis.",
9541  "checkLevelNormal",
9543  state.errorLogger.reportErr(errmsg);
9544  }
9545  }
9546  }
9547  }
9548  }
9549 
9551  {
9552  if (state.settings.performanceValueFlowMaxTime >= 0)
9553  stop = Clock::now() + std::chrono::seconds{state.settings.performanceValueFlowMaxTime};
9554  }
9555 
9559 };
9560 
9561 template<class F>
9563  const char* mName = nullptr;
9564  bool mCPP = false;
9565  F mRun;
9566  ValueFlowPassAdaptor(const char* pname, bool pcpp, F prun) : ValueFlowPass(), mName(pname), mCPP(pcpp), mRun(prun) {}
9567  const char* name() const override {
9568  return mName;
9569  }
9570  void run(const ValueFlowState& state) const override
9571  {
9572  mRun(state.tokenlist, state.symboldatabase, state.errorLogger, state.settings, state.skippedFunctions);
9573  }
9574  bool cpp() const override {
9575  return mCPP;
9576  }
9577 };
9578 
9579 template<class F>
9581 {
9582  return {name, cpp, run};
9583 }
9584 
9585 #define VALUEFLOW_ADAPTOR(cpp, ...) \
9586  makeValueFlowPassAdaptor(#__VA_ARGS__, \
9587  (cpp), \
9588  [](TokenList& tokenlist, \
9589  SymbolDatabase& symboldatabase, \
9590  ErrorLogger& errorLogger, \
9591  const Settings& settings, \
9592  const std::set<const Scope*>& skippedFunctions) { \
9593  (void)tokenlist; \
9594  (void)symboldatabase; \
9595  (void)errorLogger; \
9596  (void)settings; \
9597  (void)skippedFunctions; \
9598  __VA_ARGS__; \
9599  })
9600 
9601 #define VFA(...) VALUEFLOW_ADAPTOR(false, __VA_ARGS__)
9602 #define VFA_CPP(...) VALUEFLOW_ADAPTOR(true, __VA_ARGS__)
9603 
9605  SymbolDatabase& symboldatabase,
9606  ErrorLogger& errorLogger,
9607  const Settings& settings,
9608  TimerResultsIntf* timerResults)
9609 {
9610  for (Token* tok = tokenlist.front(); tok; tok = tok->next())
9611  tok->clearValueFlow();
9612 
9613  // commas in init..
9614  for (Token* tok = tokenlist.front(); tok; tok = tok->next()) {
9615  if (tok->str() != "{" || !tok->astOperand1())
9616  continue;
9617  for (Token* tok2 = tok->next(); tok2 != tok->link(); tok2 = tok2->next()) {
9618  if (tok2->link() && Token::Match(tok2, "[{[(<]"))
9619  tok2 = tok2->link();
9620  else if (tok2->str() == ",")
9621  tok2->isInitComma(true);
9622  }
9623  }
9624 
9625  ValueFlowPassRunner runner{ValueFlowState{tokenlist, symboldatabase, errorLogger, settings}, timerResults};
9626  runner.run_once({
9627  VFA(valueFlowEnumValue(symboldatabase, settings)),
9628  VFA(valueFlowNumber(tokenlist, settings)),
9629  VFA(valueFlowString(tokenlist, settings)),
9630  VFA(valueFlowArray(tokenlist, settings)),
9631  VFA(valueFlowUnknownFunctionReturn(tokenlist, settings)),
9632  VFA(valueFlowGlobalConstVar(tokenlist, settings)),
9633  VFA(valueFlowEnumValue(symboldatabase, settings)),
9634  VFA(valueFlowGlobalStaticVar(tokenlist, settings)),
9635  VFA(valueFlowPointerAlias(tokenlist, settings)),
9636  VFA(valueFlowLifetime(tokenlist, errorLogger, settings)),
9637  VFA(valueFlowSymbolic(tokenlist, symboldatabase, errorLogger, settings)),
9638  VFA(valueFlowBitAnd(tokenlist, settings)),
9639  VFA(valueFlowSameExpressions(tokenlist, settings)),
9640  VFA(valueFlowConditionExpressions(tokenlist, symboldatabase, errorLogger, settings)),
9641  });
9642 
9643  runner.run({
9644  VFA(valueFlowImpossibleValues(tokenlist, settings)),
9645  VFA(valueFlowSymbolicOperators(symboldatabase, settings)),
9646  VFA(valueFlowCondition(SymbolicConditionHandler{}, tokenlist, symboldatabase, errorLogger, settings, skippedFunctions)),
9647  VFA(valueFlowSymbolicInfer(symboldatabase, settings)),
9648  VFA(valueFlowArrayBool(tokenlist, settings)),
9649  VFA(valueFlowArrayElement(tokenlist, settings)),
9650  VFA(valueFlowRightShift(tokenlist, settings)),
9651  VFA(valueFlowAfterAssign(tokenlist, symboldatabase, errorLogger, settings, skippedFunctions)),
9652  VFA_CPP(valueFlowAfterSwap(tokenlist, symboldatabase, errorLogger, settings)),
9653  VFA(valueFlowCondition(SimpleConditionHandler{}, tokenlist, symboldatabase, errorLogger, settings, skippedFunctions)),
9654  VFA(valueFlowInferCondition(tokenlist, settings)),
9655  VFA(valueFlowSwitchVariable(tokenlist, symboldatabase, errorLogger, settings)),
9656  VFA(valueFlowForLoop(tokenlist, symboldatabase, errorLogger, settings)),
9657  VFA(valueFlowSubFunction(tokenlist, symboldatabase, errorLogger, settings)),
9658  VFA(valueFlowFunctionReturn(tokenlist, errorLogger, settings)),
9659  VFA(valueFlowLifetime(tokenlist, errorLogger, settings)),
9660  VFA(valueFlowFunctionDefaultParameter(tokenlist, symboldatabase, errorLogger, settings)),
9661  VFA(valueFlowUninit(tokenlist, errorLogger, settings)),
9662  VFA_CPP(valueFlowAfterMove(tokenlist, symboldatabase, errorLogger, settings)),
9663  VFA_CPP(valueFlowSmartPointer(tokenlist, errorLogger, settings)),
9664  VFA_CPP(valueFlowIterators(tokenlist, settings)),
9665  VFA_CPP(
9666  valueFlowCondition(IteratorConditionHandler{}, tokenlist, symboldatabase, errorLogger, settings, skippedFunctions)),
9667  VFA_CPP(valueFlowIteratorInfer(tokenlist, settings)),
9668  VFA_CPP(valueFlowContainerSize(tokenlist, symboldatabase, errorLogger, settings, skippedFunctions)),
9669  VFA_CPP(
9670  valueFlowCondition(ContainerConditionHandler{}, tokenlist, symboldatabase, errorLogger, settings, skippedFunctions)),
9671  VFA(valueFlowSafeFunctions(tokenlist, symboldatabase, errorLogger, settings)),
9672  });
9673 
9674  runner.run_once({
9675  VFA(valueFlowDynamicBufferSize(tokenlist, symboldatabase, errorLogger, settings)),
9676  VFA(valueFlowDebug(tokenlist, errorLogger, settings)),
9677  });
9678 }
9679 
9681 {
9682  if (!condition)
9683  return "Either the condition is redundant";
9684  if (condition->str() == "case") {
9685  std::string expr;
9686  for (const Token *tok = condition; tok && tok->str() != ":"; tok = tok->next()) {
9687  expr += tok->str();
9688  if (Token::Match(tok, "%name%|%num% %name%|%num%"))
9689  expr += ' ';
9690  }
9691  return "Either the switch case '" + expr + "' is redundant";
9692  }
9693  return "Either the condition '" + condition->expressionString() + "' is redundant";
9694 }
9695 
9696 const ValueFlow::Value* ValueFlow::findValue(const std::list<ValueFlow::Value>& values,
9697  const Settings& settings,
9698  const std::function<bool(const ValueFlow::Value&)> &pred)
9699 {
9700  const ValueFlow::Value* ret = nullptr;
9701  for (const ValueFlow::Value& v : values) {
9702  if (pred(v)) {
9703  if (!ret || ret->isInconclusive() || (ret->condition && !v.isInconclusive()))
9704  ret = &v;
9705  if (!ret->isInconclusive() && !ret->condition)
9706  break;
9707  }
9708  }
9709  if (ret) {
9710  if (ret->isInconclusive() && !settings.certainty.isEnabled(Certainty::inconclusive))
9711  return nullptr;
9712  if (ret->condition && !settings.severity.isEnabled(Severity::warning))
9713  return nullptr;
9714  }
9715  return ret;
9716 }
9717 
9718 // TODO: returns a single value at most - no need for std::vector
9719 static std::vector<ValueFlow::Value> isOutOfBoundsImpl(const ValueFlow::Value& size,
9720  const Token* indexTok,
9721  bool condition)
9722 {
9723  if (!indexTok)
9724  return {};
9725  const ValueFlow::Value* indexValue = indexTok->getMaxValue(condition, size.path);
9726  if (!indexValue)
9727  return {};
9728  if (indexValue->intvalue >= size.intvalue)
9729  return {*indexValue};
9730  if (!condition)
9731  return {};
9732  // TODO: Use a better way to decide if the variable in unconstrained
9733  if (!indexTok->variable() || !indexTok->variable()->isArgument())
9734  return {};
9735  if (std::any_of(indexTok->values().cbegin(), indexTok->values().cend(), [&](const ValueFlow::Value& v) {
9736  return v.isSymbolicValue() && v.isPossible() && v.bound == ValueFlow::Value::Bound::Upper;
9737  }))
9738  return {};
9739  if (indexValue->bound != ValueFlow::Value::Bound::Lower)
9740  return {};
9742  return {};
9743  // Checking for underflow doesn't mean it could be out of bounds
9744  if (indexValue->intvalue == 0)
9745  return {};
9746  ValueFlow::Value value = inferCondition(">=", indexTok, indexValue->intvalue);
9747  if (!value.isKnown())
9748  return {};
9749  if (value.intvalue == 0)
9750  return {};
9751  value.intvalue = size.intvalue;
9753  return {std::move(value)};
9754 }
9755 
9756 // TODO: return single value at most - no need for std::vector
9757 std::vector<ValueFlow::Value> ValueFlow::isOutOfBounds(const Value& size, const Token* indexTok, bool possible)
9758 {
9759  ValueFlow::Value inBoundsValue = inferCondition("<", indexTok, size.intvalue);
9760  if (inBoundsValue.isKnown() && inBoundsValue.intvalue != 0)
9761  return {};
9762  std::vector<ValueFlow::Value> result = isOutOfBoundsImpl(size, indexTok, false);
9763  if (!result.empty())
9764  return result;
9765  if (!possible)
9766  return result;
9767  return isOutOfBoundsImpl(size, indexTok, true);
9768 }
bool astIsContainer(const Token *tok)
Definition: astutils.cpp:244
std::vector< const Token * > getArguments(const Token *ftok)
Get arguments (AST)
Definition: astutils.cpp:3078
bool isSameExpression(bool macro, const Token *tok1, const Token *tok2, const Settings &settings, bool pure, bool followVar, ErrorPath *errors)
Definition: astutils.cpp:1549
bool astIsPrimitive(const Token *tok)
Definition: astutils.cpp:186
bool astIsContainerView(const Token *tok)
Definition: astutils.cpp:254
bool astIsIntegral(const Token *tok, bool unknown)
Is expression of integral type?
Definition: astutils.cpp:194
bool exprDependsOnThis(const Token *expr, bool onVar, nonneg int depth)
Definition: astutils.cpp:1098
bool isTemporary(const Token *tok, const Library *library, bool unknown)
Definition: astutils.cpp:415
bool precedes(const Token *tok1, const Token *tok2)
If tok2 comes after tok1.
Definition: astutils.cpp:987
const Token * getTokenArgumentFunction(const Token *tok, int &argn)
Return the token to the function and the argument number.
Definition: astutils.cpp:2355
bool isUsedAsBool(const Token *const tok, const Settings &settings)
Is token used as boolean, that is to say cast to a bool, or used as a condition in a if/while/for.
Definition: astutils.cpp:1482
bool extractForLoopValues(const Token *forToken, nonneg int &varid, bool &knownInitValue, MathLib::bigint &initValue, bool &partialCond, MathLib::bigint &stepValue, MathLib::bigint &lastValue)
Extract for loop values: loopvar varid, init value, step value, last value (inclusive)
Definition: astutils.cpp:919
bool astIsPointer(const Token *tok)
Definition: astutils.cpp:220
bool isLikelyStreamRead(const Token *op)
do we see a likely write of rhs through overloaded operator s >> x; a & x;
Definition: astutils.cpp:3216
bool astIsContainerOwned(const Token *tok)
Definition: astutils.cpp:260
const Token * findExpressionChanged(const Token *expr, const Token *start, const Token *end, const Settings &settings, int depth)
Definition: astutils.cpp:3023
bool astIsLHS(const Token *tok)
Definition: astutils.cpp:784
bool isGlobalData(const Token *expr)
Definition: astutils.cpp:3509
bool isConstFunctionCall(const Token *ftok, const Library &library)
Definition: astutils.cpp:1964
bool astIsBool(const Token *tok)
Is expression of boolean type?
Definition: astutils.cpp:215
const Token * getArgumentStart(const Token *ftok)
Definition: astutils.cpp:3043
bool isScopeBracket(const Token *tok)
Definition: astutils.cpp:2268
bool isVariableDecl(const Token *tok)
Definition: astutils.cpp:396
static int getArgumentPos(const Token *ftok, const Token *tokToFind)
Definition: astutils.cpp:98
bool astIsGenericChar(const Token *tok)
Is expression a char according to valueType?
Definition: astutils.cpp:181
Token * getInitTok(Token *tok)
Definition: astutils.cpp:891
bool astIsUniqueSmartPointer(const Token *tok)
Definition: astutils.cpp:230
Library::Container::Action astContainerAction(const Token *tok, const Token **ftok)
Definition: astutils.cpp:287
Library::Container::Yield astFunctionYield(const Token *tok, const Settings &settings, const Token **ftok)
Definition: astutils.cpp:307
std::vector< const Token * > astFlatten(const Token *tok, const char *op)
Definition: astutils.cpp:110
bool astIsSmartPointer(const Token *tok)
Definition: astutils.cpp:225
Token * getCondTokFromEnd(Token *endBlock)
Definition: astutils.cpp:882
const Token * astParentSkipParens(const Token *tok)
Definition: astutils.cpp:557
bool isOppositeCond(bool isNot, const Token *const cond1, const Token *const cond2, const Settings &settings, bool pure, bool followVar, ErrorPath *errors)
Are two conditions opposite.
Definition: astutils.cpp:1780
bool astIsContainerString(const Token *tok)
Definition: astutils.cpp:264
bool astIsRHS(const Token *tok)
Definition: astutils.cpp:797
std::vector< ValueType > getParentValueTypes(const Token *tok, const Settings &settings, const Token **parent)
Definition: astutils.cpp:712
bool astIsFloat(const Token *tok, bool unknown)
Is expression of floating point type?
Definition: astutils.cpp:207
const Token * nextAfterAstRightmostLeaf(const Token *tok)
Definition: astutils.cpp:548
bool isThisChanged(const Token *tok, int indirect, const Settings &settings)
Definition: astutils.cpp:2917
bool astIsNonStringContainer(const Token *tok)
Definition: astutils.cpp:248
Token * getStepTok(Token *tok)
Definition: astutils.cpp:898
bool isIteratorPair(const std::vector< const Token * > &args)
Are the arguments a pair of iterators/pointers?
Definition: astutils.cpp:3117
bool isVariableChangedByFunctionCall(const Token *tok, int indirect, nonneg int varid, const Settings &settings, bool *inconclusive)
Is variable changed by function call? In case the answer of the question is inconclusive,...
Definition: astutils.cpp:2258
bool isReturnScope(const Token *const endToken, const Library &library, const Token **unknownFunc, bool functionScope)
Is scope a return scope (scope will unconditionally return)
Definition: astutils.cpp:2197
Token * findVariableChanged(Token *start, const Token *end, int indirect, const nonneg int exprid, bool globalvar, const Settings &settings, int depth)
Definition: astutils.cpp:2851
bool astIsUnsigned(const Token *tok)
Definition: astutils.cpp:202
bool astIsIterator(const Token *tok)
Definition: astutils.cpp:239
const Token * previousBeforeAstLeftmostLeaf(const Token *tok)
Definition: astutils.cpp:514
const Token * findExpressionChangedSkipDeadCode(const Token *expr, const Token *start, const Token *end, const Settings &settings, const std::function< std::vector< MathLib::bigint >(const Token *tok)> &evaluate, int depth)
Definition: astutils.cpp:3032
std::vector< const Variable * > getLHSVariables(const Token *tok)
Definition: astutils.cpp:3424
bool isConstExpression(const Token *tok, const Library &library)
Definition: astutils.cpp:2044
const Token * getLHSVariableToken(const Token *tok)
Definition: astutils.cpp:3466
const Token * getParentLifetime(const Token *tok)
Definition: astutils.cpp:596
SmallVector< ReferenceToken > followAllReferences(const Token *tok, bool temporary, bool inconclusive, ErrorPath errors, int depth)
Definition: astutils.cpp:1229
bool isLikelyStream(const Token *stream)
Definition: astutils.cpp:3199
Library::Container::Yield astContainerYield(const Token *tok, const Token **ftok)
Definition: astutils.cpp:297
bool isVariableChanged(const Token *tok, int indirect, const Settings &settings, int depth)
Definition: astutils.cpp:2541
void visitAstNodes(T *ast, const TFunc &visitor)
Visit AST nodes recursively.
Definition: astutils.h:54
const Token * findParent(const Token *tok, const TFunc &pred)
Definition: astutils.h:102
const Token * findAstNode(const Token *ast, const TFunc &pred)
Definition: astutils.h:88
R calculate(const std::string &s, const T &x, const T &y, bool *error=nullptr)
Definition: calculate.h:50
static bool isBool(const Variable *var)
Definition: checkbool.cpp:45
static int sign(const T v)
static const Token * isVariableUsage(const Token *vartok, const Library &library, bool pointer, Alloc alloc, int indirect=0)
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.
File name and line number.
Definition: errorlogger.h:55
Wrapper for error messages, provided by reportErr()
Definition: errorlogger.h:48
static std::vector< const Token * > findReturns(const Function *f)
const std::string & name() const
const Scope * functionScope
scope of function body
bool isSafe(const Settings &settings) const
static bool returnsReference(const Function *function, bool unknown=false, bool includeRValueRef=false)
const Variable * getArgumentVar(nonneg int num) const
bool isImplicitlyVirtual(bool defaultVal=false) const
check if this function is virtual in the base classes
const Token * constructorMemberInitialization() const
const Scope * nestedIn
Scope the function is declared in.
bool hasVirtualSpecifier() const
bool isConstructor() const
int size_templateArgNo
Definition: library.h:238
Action getAction(const std::string &function) const
Definition: library.h:248
Yield getYield(const std::string &function) const
Definition: library.h:255
bool stdAssociativeLike
Definition: library.h:241
Library definitions handling.
Definition: library.h:52
std::vector< MathLib::bigint > unknownReturnValues(const Token *ftok) const
Definition: library.cpp:1450
const Token * getContainerFromYield(const Token *tok, Container::Yield yield) const
Definition: library.cpp:1648
const std::string & returnValue(const Token *ftok) const
Definition: library.cpp:1420
const AllocFunc * getAllocFuncInfo(const Token *tok) const
get allocation info for function
Definition: library.cpp:1077
bool isScopeNoReturn(const Token *end, std::string *unknownFunc) const
Definition: library.cpp:1141
const AllocFunc * getReallocFuncInfo(const Token *tok) const
get reallocation info for function
Definition: library.cpp:1095
const Function * getFunction(const Token *ftok) const
Definition: library.cpp:1458
int returnValueContainer(const Token *ftok) const
Definition: library.cpp:1442
const ArgumentChecks::IteratorInfo * getArgIteratorInfo(const Token *ftok, int argnr) const
Definition: library.h:362
bool isNotLibraryFunction(const Token *ftok) const
Definition: library.cpp:1270
const std::string & returnValueType(const Token *ftok) const
Definition: library.cpp:1428
static std::string toString(T value)=delete
static biguint toBigUNumber(const std::string &str)
for conversion of numeric literals - for atoi-like conversions please use strToInt()
Definition: mathlib.cpp:289
long long bigint
Definition: mathlib.h:68
static const int bigint_bits
Definition: mathlib.h:70
static bigint toBigNumber(const std::string &str)
for conversion of numeric literals - for atoi-like conversions please use strToInt()
Definition: mathlib.cpp:368
static bool isFloat(const std::string &str)
Definition: mathlib.cpp:535
static bool isInt(const std::string &str)
Definition: mathlib.cpp:1007
static double toDoubleNumber(const std::string &str)
for conversion of numeric literals
Definition: mathlib.cpp:487
unsigned long long biguint
Definition: mathlib.h:69
static std::string stripDirectoryPart(const std::string &file)
Get filename without a directory path part.
Definition: path.cpp:302
Platform settings.
Definition: platform.h:43
nonneg int short_bit
bits in char
Definition: platform.h:86
nonneg int int_bit
bits in short
Definition: platform.h:87
std::size_t sizeof_long_long
Definition: platform.h:96
std::size_t sizeof_long_double
Definition: platform.h:99
nonneg int long_bit
bits in int
Definition: platform.h:88
std::size_t sizeof_short
Definition: platform.h:93
std::size_t sizeof_int
Definition: platform.h:94
std::size_t sizeof_pointer
Definition: platform.h:102
nonneg int char_bit
Definition: platform.h:85
long long signedCharMin() const
Definition: platform.h:183
std::size_t sizeof_float
Definition: platform.h:97
long long signedCharMax() const
Definition: platform.h:179
nonneg int long_long_bit
bits in long
Definition: platform.h:89
Type type
platform type
Definition: platform.h:118
std::size_t sizeof_double
Definition: platform.h:98
std::size_t sizeof_long
Definition: platform.h:95
std::size_t sizeof_wchar_t
Definition: platform.h:100
std::list< Function > functionList
const Token * enumType
bool isNestedIn(const Scope *outer) const
std::list< Variable > varlist
std::vector< Scope * > nestedList
ScopeType type
static Function * nestedInFunction(const Scope *scope)
std::vector< Enumerator > enumeratorList
Type * definedType
Function * function
function info for this function
bool isLoopScope() const
const Scope * nestedIn
const Token * classDef
class/struct/union/namespace token
bool isLocal() const
const Token * bodyStart
'{' token
const Token * bodyEnd
'}' token
nonneg int numConstructors
std::string className
bool isExecutable() const
SelectValueFromVarIdMapRange(const M *m)
Definition: valueflow.cpp:2405
std::unordered_map< nonneg int, ValueFlow::Value > M
Definition: valueflow.cpp:2366
This is just a container for general settings so that we don't need to pass individual values to func...
Definition: settings.h:95
CheckLevel checkLevel
Definition: settings.h:465
int performanceValueFlowMaxSubFunctionArgs
max number of sets of arguments to pass to subfuncions in valueflow
Definition: settings.h:264
Library library
Library.
Definition: settings.h:237
Platform platform
Definition: settings.h:255
bool debugnormal
Is –debug-normal given?
Definition: settings.h:174
bool daca
Are we running from DACA script?
Definition: settings.h:171
std::set< std::string > checkUnknownFunctionReturn
check unknown function return values
Definition: settings.h:144
SimpleEnableGroup< Certainty > certainty
Definition: settings.h:359
SimpleEnableGroup< Severity > severity
Definition: settings.h:358
bool debugwarnings
Is –debug-warnings given?
Definition: settings.h:183
Standards standards
Struct contains standards settings.
Definition: settings.h:366
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::list< Scope > scopeList
Information about all namespaces/classes/structures.
Definition: timer.h:70
const Token * back() const
get last token of list
Definition: tokenlist.h:128
void simplifyPlatformTypes()
Convert platform dependent types to standard types.
const std::string & getSourceFilePath() const
Definition: tokenlist.cpp:75
bool isCPP() const
void simplifyStdType()
Collapse compound standard types into a single token.
const Token * front() const
get first token of list
Definition: tokenlist.h:119
bool createTokens(std::istream &code, const std::string &file0)
Create tokens from code.
Definition: tokenlist.cpp:336
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
bool isUtf16() const
Definition: token.h:712
Token * astTop()
Definition: token.h:1416
bool hasKnownValue() const
Definition: token.cpp:2562
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
nonneg int exprId() const
Definition: token.h:883
bool isKeyword() const
Definition: token.h:358
bool isCChar() const
Definition: token.h:722
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:1099
bool addValue(const ValueFlow::Value &value)
Add token value.
Definition: token.cpp:2262
bool hasKnownIntValue() const
Definition: token.cpp:2553
const ValueFlow::Value * getMaxValue(bool condition, MathLib::bigint path=0) const
Definition: token.cpp:2626
MathLib::bigint getKnownIntValue() const
Definition: token.h:1218
void removeValues(std::function< bool(const ValueFlow::Value &)> pred)
Definition: token.h:1242
bool isExpandedMacro() const
Definition: token.h:455
bool isTemplateArg() const
Is current token a template argument?
Definition: token.h:748
static std::pair< const Token *, const Token * > typeDecl(const Token *tok, bool pointedToType=false)
Definition: token.cpp:2431
bool isArithmeticalOp() const
Definition: token.h:395
static nonneg int getStrSize(const Token *tok, const Settings &settings)
Definition: token.cpp:856
bool isIncompleteVar() const
Definition: token.h:573
bool isCpp() const
Definition: token.cpp:2752
bool isUniqueExprId() const
Definition: token.h:898
static nonneg int getStrLength(const Token *tok)
Definition: token.cpp:811
const ValueFlow::Value * getKnownValue(ValueFlow::Value::ValueType t) const
Definition: token.cpp:2586
static const ::Type * typeOf(const Token *tok, const Token **typeTok=nullptr)
Definition: token.cpp:2377
bool isUtf32() const
Definition: token.h:717
const ValueType * valueType() const
Definition: token.h:331
const std::string & strAt(int index) const
Definition: token.cpp:457
bool hasKnownSymbolicValue(const Token *tok) const
Definition: token.cpp:2575
const Enumerator * enumerator() const
Definition: token.h:1111
void astOperand1(Token *tok)
Definition: token.cpp:1490
bool isNumber() const
Definition: token.h:371
void function(const Function *f)
Associate this token with given function.
Definition: token.cpp:1127
bool isCMultiChar() const
Definition: token.h:727
nonneg int varId() const
Definition: token.h:870
std::string expressionString() const
Definition: token.cpp:1681
bool isCast() const
Definition: token.h:458
bool isUnaryOp(const std::string &s) const
Definition: token.h:413
bool isLiteral() const
Definition: token.h:368
void clearValueFlow()
Definition: token.h:1441
bool isInitComma() const
Definition: token.h:678
TokenDebug getTokenDebug() const
Definition: token.h:1475
bool isOp() const
Definition: token.h:380
static const Token * findsimplematch(const Token *const startTok, const char(&pattern)[count])
Definition: token.h:763
const Token * tokAt(int index) const
Definition: token.cpp:427
bool isConstOp() const
Definition: token.h:385
Token::Type tokType() const
Definition: token.h:343
void astOperand2(Token *tok)
Definition: token.cpp:1502
void scope(const Scope *s)
Associate this token with given scope.
Definition: token.h:1042
bool isLong() const
Definition: token.h:443
void link(Token *linkToToken)
Create link to given token.
Definition: token.h:1015
const Token * linkAt(int index) const
Definition: token.cpp:447
@ eString
Definition: token.h:162
@ eChar
Definition: token.h:162
@ eLogicalOp
Definition: token.h:163
@ eBitOp
Definition: token.h:163
@ eType
Definition: token.h:161
@ eIncDecOp
Definition: token.h:163
Token * previous()
Definition: token.h:862
bool isBinaryOp() const
Definition: token.h:410
void type(const ::Type *t)
Associate this token with given type.
Definition: token.cpp:2367
static std::string typeStr(const Token *tok)
Definition: token.cpp:2530
bool isAssignmentOp() const
Definition: token.h:401
bool isSplittedVarDeclEq() const
Definition: token.h:615
bool isUtf8() const
Definition: token.h:707
Token * astSibling()
Definition: token.h:1396
bool isStandardType() const
Definition: token.h:449
void variable(const Variable *v)
Associate this token with given variable.
Definition: token.h:1070
bool isComparisonOp() const
Definition: token.h:398
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
bool getCppcheckAttribute(TokenImpl::CppcheckAttributes::Type type, MathLib::bigint &value) const
Definition: token.h:539
void astParent(Token *tok)
Definition: token.cpp:1471
Information about a class type.
bool isStructType() const
const Token * classDef
Points to "class" token.
std::vector< BaseInfo > derivedFrom
std::string name() const
enum Type::NeedInitialization needInitialization
bool isClassType() const
const Scope * classScope
bool isUnionType() const
void setImpossible()
Definition: vfvalue.h:369
bool equalTo(const T &x) const
Definition: vfvalue.h:167
bool isIntValue() const
Definition: vfvalue.h:211
bool isSymbolicValue() const
Definition: vfvalue.h:244
bool isTokValue() const
Definition: vfvalue.h:214
void invertBound()
Definition: vfvalue.h:180
ErrorPath debugPath
Definition: vfvalue.h:284
Bound bound
The value bound
Definition: vfvalue.h:265
std::string toString() const
Definition: vfvalue.cpp:41
enum ValueFlow::Value::ValueType valueType
void changeKnownToPossible()
Definition: vfvalue.h:382
MathLib::bigint path
Path id.
Definition: vfvalue.h:307
bool isIteratorValue() const
Definition: vfvalue.h:235
std::string infoString() const
Definition: vfvalue.cpp:96
ErrorPath errorPath
Definition: vfvalue.h:282
bool isMovedValue() const
Definition: vfvalue.h:220
bool isFloatValue() const
Definition: vfvalue.h:217
bool conditional
Conditional value.
Definition: vfvalue.h:293
ValueKind
How known is this value.
Definition: vfvalue.h:338
@ Impossible
Listed values are impossible.
@ Known
Only listed values are possible.
@ Possible
This value is possible, other unlisted values may also be possible.
bool isLifetimeValue() const
Definition: vfvalue.h:229
long long varvalue
For calculated values - variable value that calculated value depends on.
Definition: vfvalue.h:277
bool defaultArg
Is this value passed as default parameter to the function?
Definition: vfvalue.h:299
bool isImpossible() const
Definition: vfvalue.h:365
double floatValue
float value
Definition: vfvalue.h:274
bool isUninitValue() const
Definition: vfvalue.h:223
bool isKnown() const
Definition: vfvalue.h:353
const Token * condition
Condition that this value depends on.
Definition: vfvalue.h:280
const Token * tokvalue
token value - the token that has the value.
Definition: vfvalue.h:271
long long intvalue
int value (or sometimes bool value?)
Definition: vfvalue.h:268
const Token * capturetok
Definition: vfvalue.h:315
nonneg int varId
For calculated values - varId that calculated value depends on.
Definition: vfvalue.h:287
void setPossible()
Definition: vfvalue.h:357
bool isNonValue() const
Definition: vfvalue.h:260
enum ValueFlow::Value::ValueKind valueKind
bool equalValue(const ValueFlow::Value &rhs) const
Definition: vfvalue.h:60
void invertRange()
Definition: vfvalue.h:187
bool isLocalLifetimeValue() const
Definition: vfvalue.h:248
bool isContainerSizeValue() const
Definition: vfvalue.h:226
std::list< ErrorPathItem > ErrorPath
Definition: vfvalue.h:43
enum ValueFlow::Value::LifetimeKind lifetimeKind
enum ValueFlow::Value::MoveKind moveKind
void setInconclusive(bool inconclusive=true)
Definition: vfvalue.h:373
void assumeCondition(const Token *tok)
Definition: vfvalue.cpp:36
enum ValueFlow::Value::LifetimeScope lifetimeScope
long long wideintvalue
int value before implicit truncation
Definition: vfvalue.h:310
void setKnown()
Definition: vfvalue.h:349
bool isSubFunctionLifetimeValue() const
Definition: vfvalue.h:256
bool isIteratorStartValue() const
Definition: vfvalue.h:238
bool isIteratorEndValue() const
Definition: vfvalue.h:241
bool isInconclusive() const
Definition: vfvalue.h:378
MoveKind
kind of moved
Definition: vfvalue.h:304
bool isPossible() const
Definition: vfvalue.h:361
std::vector< std::string > subexpressions
Definition: vfvalue.h:312
bool safe
value relies on safe checking
Definition: vfvalue.h:290
Value type.
bool isFloat() const
enum ValueType::Type type
const Library::Container * container
If the type is a container defined in a cfg file, this is the used.
nonneg int constness
bit 0=data, bit 1=*, bit 2=**
bool isTypeEqual(const ValueType *that) const
Check if type is the same ignoring const and references.
MathLib::bigint typeSize(const Platform &platform, bool p=false) const
Reference reference
Is the outermost indirection of this type a reference or rvalue.
const Library::SmartPointer * smartPointer
Smart pointer.
bool isIntegral() const
nonneg int pointer
0=>not pointer, 1=>*, 2=>**, 3=>***, etc
std::string originalTypeName
original type name as written in the source code.
const Token * containerTypeToken
The container type token.
const Scope * typeScope
if the type definition is seen this point out the type scope
static ValueType parseDecl(const Token *type, const Settings &settings)
enum ValueType::Sign sign
bool isPrimitive() const
std::string str() const
Information about a member variable.
bool hasDefault() const
Does variable have a default value.
bool isArgument() const
Is variable a function argument.
bool isEnumType() const
Determine whether it's an enumeration type.
bool isClass() const
Is variable a user defined (or unknown) type.
bool isExtern() const
Is variable extern.
bool isReference() const
Is reference variable.
bool dimensionKnown(nonneg int index_) const
Get array dimension known.
bool isRValueReference() const
Is reference variable.
bool isStlType() const
Checks if the variable is an STL type ('std::') E.g.
bool isLocal() const
Is variable local.
bool isSmartPointer() const
const Token * declEndToken() const
Get end token of variable declaration E.g.
const Type * type() const
Get Type pointer of known type.
const Scope * scope() const
Get Scope pointer of enclosing scope.
bool isThrow() const
Is variable a throw type.
const Scope * typeScope() const
Get Scope pointer of known type.
bool isGlobal() const
Is variable global.
bool isPublic() const
Is variable public.
const std::string & name() const
Get name string.
const Token * typeEndToken() const
Get type end token.
bool isConst() const
Is variable const.
MathLib::bigint dimension(nonneg int index_) const
Get array dimension length.
bool isArray() const
Is variable an array.
const Token * nameToken() const
Get name token.
nonneg int declarationId() const
Get declaration ID (varId used for variable in its declaration).
const Token * typeStartToken() const
Get type start token.
bool isInit() const
Is variable initialized in its declaration.
const std::vector< Dimension > & dimensions() const
Get array dimensions.
bool isPointer() const
Is pointer variable.
bool isStatic() const
Is variable static.
const ValueType * valueType() const
#define REQUIRES(msg,...)
Definition: config.h:124
static const std::string emptyString
Definition: config.h:127
#define nonneg
Definition: config.h:138
std::vector< MathLib::bigint > evaluateKnownValues(const Token *tok)
Definition: findtoken.h:37
std::vector< T * > findTokensSkipDeadCode(const Library &library, T *start, const Token *end, const Predicate &pred, const Evaluate &evaluate)
Definition: findtoken.h:172
Analyzer::Result valueFlowGenericForward(Token *start, const Token *end, const ValuePtr< Analyzer > &a, const TokenList &tokenList, ErrorLogger &errorLogger, const Settings &settings)
static bool nonLocal(const Variable *var, bool deref)
Definition: fwdanalysis.cpp:77
std::pair< const Token *, std::string > ErrorPathItem
Definition: errortypes.h:129
const Library::Container * getLibraryContainer(const Token *tok)
Definition: library.cpp:1715
std::list< ErrorPathItem > ErrorPath
Definition: errortypes.h:130
@ warning
Warning.
@ debug
Debug message.
@ information
Checking information.
@ error
Programming error.
std::vector< ValueFlow::Value > infer(const ValuePtr< InferModel > &model, const std::string &op, std::list< ValueFlow::Value > lhsValues, std::list< ValueFlow::Value > rhsValues)
Definition: infer.cpp:286
const Token * parseCompareInt(const Token *tok, Value &true_value, Value &false_value, const std::function< std::vector< MathLib::bigint >(const Token *)> &evaluate)
Definition: valueflow.cpp:350
bool isContainerSizeChanged(const Token *tok, int indirect, const Settings &settings, int depth=20)
Definition: valueflow.cpp:8461
std::string eitherTheConditionIsRedundant(const Token *condition)
Definition: valueflow.cpp:9680
CPPCHECKLIB Value getLifetimeObjValue(const Token *tok, bool inconclusive=false)
Definition: valueflow.cpp:3575
const Value * valueFlowConstantFoldAST(Token *expr, const Settings &settings)
Constant folding of expression. This can be used before the full ValueFlow has been executed (ValueFl...
Definition: valueflow.cpp:9408
CPPCHECKLIB ValuePtr< InferModel > makeIntegralInferModel()
Definition: valueflow.cpp:6977
const Value * findValue(const std::list< Value > &values, const Settings &settings, const std::function< bool(const Value &)> &pred)
std::vector< LifetimeToken > getLifetimeTokens(const Token *tok, const Settings &settings, bool escape=false, Value::ErrorPath errorPath=Value::ErrorPath{})
Definition: valueflow.cpp:3735
std::string lifetimeMessage(const Token *tok, const Value *val, Value::ErrorPath &errorPath)
Definition: valueflow.cpp:3490
void combineValueProperties(const Value &value1, const Value &value2, Value &result)
Definition: valueflow.cpp:424
bool isLifetimeBorrowed(const Token *tok, const Settings &settings)
Definition: valueflow.cpp:3907
const Token * getEndOfExprScope(const Token *tok, const Scope *defaultScope=nullptr, bool smallest=true)
Definition: valueflow.cpp:3974
const Variable * getLifetimeVariable(const Token *tok, Value::ErrorPath &errorPath, const Settings &settings, bool *addressOf=nullptr)
Definition: valueflow.cpp:3765
bool hasLifetimeToken(const Token *tok, const Token *lifetime, const Settings &settings)
Definition: valueflow.cpp:3742
const Token * solveExprValue(const Token *expr, const std::function< std::vector< MathLib::bigint >(const Token *)> &eval, Value &value)
Definition: valueflow.cpp:8392
std::vector< Value > isOutOfBounds(const Value &size, const Token *indexTok, bool possible=true)
Definition: valueflow.cpp:9757
size_t getSizeOf(const ValueType &vt, const Settings &settings, int maxRecursion=0)
Definition: valueflow.cpp:1197
Value asImpossible(Value v)
Definition: valueflow.cpp:6269
CPPCHECKLIB std::vector< Value > getLifetimeObjValues(const Token *tok, bool inconclusive=false, MathLib::bigint path=0)
Definition: valueflow.cpp:3528
void setValues(TokenList &tokenlist, SymbolDatabase &symboldatabase, ErrorLogger &errorLogger, const Settings &settings, TimerResultsIntf *timerResults)
Perform valueflow analysis.
Definition: valueflow.cpp:9604
bool conditionIsFalse(const Token *condition, ProgramMemory pm, const Settings &settings)
Is condition always false when variable has given value?
static ValueFlow::Value execute(const Token *expr, ProgramMemory &pm, const Settings &settings)
static ValueFlow::Value evaluate(const std::string &op, const ValueFlow::Value &lhs, const ValueFlow::Value &rhs)
ProgramMemory getProgramMemory(const Token *tok, const Token *expr, const ValueFlow::Value &value, const Settings &settings)
Get program memory by looking backwards from given token.
ValueFlow::Value evaluateLibraryFunction(const std::unordered_map< nonneg int, ValueFlow::Value > &args, const std::string &returnValue, const Settings &settings, bool cpp)
bool conditionIsTrue(const Token *condition, ProgramMemory pm, const Settings &settings)
Is condition always true when variable has given value?
void valueFlowGenericReverse(Token *start, const Token *end, const ValuePtr< Analyzer > &a, const TokenList &tokenlist, ErrorLogger &errorLogger, const Settings &settings)
bool isInternal() const
Definition: analyzer.h:103
bool matches() const
Definition: analyzer.h:107
bool isWrite() const
Definition: analyzer.h:71
bool isInconclusive() const
Definition: analyzer.h:79
bool isSymbolicMatch() const
Definition: analyzer.h:99
bool isModified() const
Definition: analyzer.h:87
bool isRead() const
Definition: analyzer.h:67
Terminate terminate
Definition: analyzer.h:140
void update(Result rhs)
Definition: analyzer.h:142
virtual bool lowerToInconclusive()=0
Lower any values to inconclusive.
virtual bool invalid() const
Definition: analyzer.h:188
std::list< ValueFlow::Value > true_values
Definition: valueflow.cpp:6295
Token * getContextAndValues(Token *condTok, std::list< ValueFlow::Value > &thenValues, std::list< ValueFlow::Value > &elseValues, bool known=false) const
Definition: valueflow.cpp:6324
MathLib::bigint getPath() const
Definition: valueflow.cpp:6318
std::list< ValueFlow::Value > false_values
Definition: valueflow.cpp:6296
static MathLib::bigint findPath(const std::list< ValueFlow::Value > &values)
Definition: valueflow.cpp:6305
void beforeCondition(TokenList &tokenlist, const SymbolDatabase &symboldatabase, ErrorLogger &errorLogger, const Settings &settings, const std::set< const Scope * > &skippedFunctions) const
Definition: valueflow.cpp:6432
virtual void reverse(Token *start, const Token *endToken, const Token *exprTok, const std::list< ValueFlow::Value > &values, TokenList &tokenlist, ErrorLogger &errorLogger, const Settings &settings, SourceLocation loc=SourceLocation::current()) const
Definition: valueflow.cpp:6383
ConditionHandler(const ConditionHandler &)=default
void afterCondition(TokenList &tokenlist, const SymbolDatabase &symboldatabase, ErrorLogger &errorLogger, const Settings &settings, const std::set< const Scope * > &skippedFunctions) const
Definition: valueflow.cpp:6580
static Token * skipNotAndCasts(Token *tok, bool *inverted=nullptr)
Definition: valueflow.cpp:6541
virtual std::vector< Condition > parse(const Token *tok, const Settings &settings) const =0
virtual Analyzer::Result forward(Token *start, const Token *stop, const Token *exprTok, const std::list< ValueFlow::Value > &values, TokenList &tokenlist, ErrorLogger &errorLogger, const Settings &settings, SourceLocation loc=SourceLocation::current()) const
Definition: valueflow.cpp:6360
ConditionHandler()=default
void traverseCondition(const SymbolDatabase &symboldatabase, const Settings &settings, const std::set< const Scope * > &skippedFunctions, const std::function< void(const Condition &cond, Token *tok, const Scope *scope)> &f) const
Definition: valueflow.cpp:6395
virtual Analyzer::Result forward(Token *top, const Token *exprTok, const std::list< ValueFlow::Value > &values, TokenList &tokenlist, ErrorLogger &errorLogger, const Settings &settings, SourceLocation loc=SourceLocation::current()) const
Definition: valueflow.cpp:6372
virtual ~ConditionHandler()=default
static void fillFromPath(ProgramMemory &pm, const Token *top, MathLib::bigint path, const Settings &settings)
Definition: valueflow.cpp:6565
std::vector< Condition > parse(const Token *tok, const Settings &settings) const override
Definition: valueflow.cpp:9025
Action isModified(const Token *tok) const override
Definition: valueflow.cpp:8350
void writeValue(ValueFlow::Value *val, const Token *tok, Direction d) const override
Definition: valueflow.cpp:8304
bool match(const Token *tok) const override
Definition: valueflow.cpp:8265
int getIndirect(const Token *tok) const override
Definition: valueflow.cpp:8342
ContainerExpressionAnalyzer(const Token *expr, ValueFlow::Value val, const TokenList &t, const Settings &s)
Definition: valueflow.cpp:8261
Action isWritable(const Token *tok, Direction) const override
Definition: valueflow.cpp:8269
Array dimension information.
const Token * tok
size token
MathLib::bigint num
(assumed) dimension length when size is a number, 0 if not known
bool known
Known size.
ValueFlow::Value::ValueType getType() const override
Definition: valueflow.cpp:7008
const Token * start
const Scope * scope
MathLib::bigint value
void setupExprVarIds(const Token *start, int depth=0)
Definition: valueflow.cpp:3296
ExpressionAnalyzer(const Token *e, ValueFlow::Value val, const TokenList &t, const Settings &s)
Definition: valueflow.cpp:3275
bool isVariable() const override
Definition: valueflow.cpp:3366
bool isGlobal() const override
Definition: valueflow.cpp:3362
static bool nonLocal(const Variable *var, bool deref)
Definition: valueflow.cpp:3291
Action isAliasModified(const Token *tok, int indirect) const override
Definition: valueflow.cpp:3370
bool invalid() const override
Definition: valueflow.cpp:3342
bool match(const Token *tok) const override
Definition: valueflow.cpp:3354
bool dependsOnThis() const override
Definition: valueflow.cpp:3358
virtual bool skipUniqueExprIds() const
Definition: valueflow.cpp:3338
const Token * expr
Definition: valueflow.cpp:3269
ProgramState getProgramState() const override
Definition: valueflow.cpp:3348
ValueFlow::Value yield(MathLib::bigint value) const override
Definition: valueflow.cpp:6968
bool match(const ValueFlow::Value &value) const override
Definition: valueflow.cpp:6965
Simple container to be thrown when internal error is detected.
Definition: errortypes.h:36
std::vector< Condition > parse(const Token *tok, const Settings &) const override
Definition: valueflow.cpp:8637
bool match(const ValueFlow::Value &value) const override
Definition: valueflow.cpp:6995
virtual ValueFlow::Value::ValueType getType() const =0
ValueFlow::Value yield(MathLib::bigint value) const override
Definition: valueflow.cpp:6998
Iterator mBegin
Definition: valueflow.cpp:7779
Iterator end() const
Definition: valueflow.cpp:7786
Iterator begin() const
Definition: valueflow.cpp:7782
Iterator mEnd
Definition: valueflow.cpp:7780
const Token * arguments
Definition: valueflow.cpp:4867
const Token * returnTok
Definition: valueflow.cpp:4868
bool isLambda() const
Definition: valueflow.cpp:4877
const Token * bodyTok
Definition: valueflow.cpp:4869
std::vector< const Token * > getCaptures() const
Definition: valueflow.cpp:4873
std::unordered_map< const Variable *, std::pair< const Token *, LifetimeCapture > > explicitCaptures
Definition: valueflow.cpp:4870
Lambda(const Token *tok)
Definition: valueflow.cpp:4830
const Token * capture
Definition: valueflow.cpp:4866
LifetimeCapture implicitCapture
Definition: valueflow.cpp:4871
BufferSize bufferSize
Definition: library.h:85
ValueFlow::Value::LifetimeKind type
Definition: valueflow.cpp:4106
bool byRef(Token *tok, const TokenList &tokenlist, ErrorLogger &errorLogger, const Settings &settings, SourceLocation loc=SourceLocation::current())
Definition: valueflow.cpp:4209
const Token * argtok
Definition: valueflow.cpp:4104
static void forEach(const TokenList &tokenlist, ErrorLogger &errorLogger, const Settings &settings, const std::vector< const Token * > &argtoks, const std::string &message, ValueFlow::Value::LifetimeKind type, F f)
Definition: valueflow.cpp:4124
bool byVal(Token *tok, const TokenList &tokenlist, ErrorLogger &errorLogger, const Settings &settings, Predicate pred, SourceLocation loc=SourceLocation::current())
Definition: valueflow.cpp:4227
bool byDerefCopy(Token *tok, const TokenList &tokenlist, ErrorLogger &errorLogger, const Settings &settings, SourceLocation loc=SourceLocation::current()) const
Definition: valueflow.cpp:4358
bool byRef(Token *tok, const TokenList &tokenlist, ErrorLogger &errorLogger, const Settings &settings, Predicate pred, SourceLocation loc=SourceLocation::current())
Definition: valueflow.cpp:4168
Token * forwardTok
Definition: valueflow.cpp:4377
void forwardLifetime(Token *tok, const TokenList &tokenlist, ErrorLogger &errorLogger, const Settings &settings)
Definition: valueflow.cpp:4378
LifetimeStore(const Token *argtok, std::string message, ValueFlow::Value::LifetimeKind type=ValueFlow::Value::LifetimeKind::Object, bool inconclusive=false)
Definition: valueflow.cpp:4113
std::string message
Definition: valueflow.cpp:4105
bool byDerefCopy(Token *tok, const TokenList &tokenlist, ErrorLogger &errorLogger, const Settings &settings, Predicate pred, SourceLocation loc=SourceLocation::current()) const
Definition: valueflow.cpp:4322
LifetimeStore()=default
bool byVal(Token *tok, const TokenList &tokenlist, ErrorLogger &errorLogger, const Settings &settings, SourceLocation loc=SourceLocation::current())
Definition: valueflow.cpp:4304
ErrorPath errorPath
Definition: valueflow.cpp:4107
static LifetimeStore fromFunctionArg(const Function *f, const Token *tok, const Variable *var, const TokenList &tokenlist, const Settings &settings, ErrorLogger &errorLogger)
Definition: valueflow.cpp:4144
bool submatch(const Token *tok, bool exact) const override
Definition: valueflow.cpp:3452
MemberExpressionAnalyzer(std::string varname, const Token *e, ValueFlow::Value val, const TokenList &t, const Settings &s)
Definition: valueflow.cpp:3448
void addErrorPath(const Token *tok, const std::string &s) override
Definition: valueflow.cpp:7451
virtual const std::unordered_map< nonneg int, const Variable * > & getVars() const
Definition: valueflow.cpp:7424
MultiValueFlowAnalyzer(const std::unordered_map< const Variable *, ValueFlow::Value > &args, const TokenList &t, const Settings &set)
Definition: valueflow.cpp:7416
bool match(const Token *tok) const override
Definition: valueflow.cpp:7543
bool stopOnCondition(const Token *condTok) const override
If analysis should stop on the condition.
Definition: valueflow.cpp:7498
std::unordered_map< nonneg int, const Variable * > vars
Definition: valueflow.cpp:7414
ProgramState getProgramState() const override
Definition: valueflow.cpp:7547
void makeConditional() override
Definition: valueflow.cpp:7445
const ValueFlow::Value * getValue(const Token *tok) const override
Definition: valueflow.cpp:7428
bool updateScope(const Token *endBlock, bool) const override
If the analysis is unsure whether to update a scope, this will return true if the analysis should bif...
Definition: valueflow.cpp:7510
std::unordered_map< nonneg int, ValueFlow::Value > values
Definition: valueflow.cpp:7413
bool lowerToInconclusive() override
Lower any values to inconclusive.
Definition: valueflow.cpp:7479
bool isConditional() const override
If the value is conditional.
Definition: valueflow.cpp:7488
bool lowerToPossible() override
Lower any values to possible.
Definition: valueflow.cpp:7471
bool isAlias(const Token *tok, bool &inconclusive) const override
Definition: valueflow.cpp:7457
ValueFlow::Value * getValue(const Token *tok) override
Definition: valueflow.cpp:7436
bool skipUniqueExprIds() const override
Definition: valueflow.cpp:3399
OppositeExpressionAnalyzer(bool pIsNot, const Token *e, ValueFlow::Value val, const TokenList &t, const Settings &s)
Definition: valueflow.cpp:3395
bool match(const Token *tok) const override
Definition: valueflow.cpp:3403
void assume(const Token *tok, bool b, bool isEmpty=false)
void removeModifiedVars(const Token *tok)
ProgramMemory get(const Token *tok, const Token *ctx, const ProgramMemory::Map &vars) const
void addState(const Token *tok, const ProgramMemory::Map &vars)
void setValue(const Token *expr, const ValueFlow::Value &value)
bool getContainerEmptyValue(nonneg int exprid, MathLib::bigint &result) const
std::unordered_map< ExprIdToken, ValueFlow::Value, ExprIdToken::Hash > Map
bool hasValue(nonneg int exprid)
bool empty() const
void swap(ProgramMemory &pm)
const Token * token
Definition: astutils.h:254
bool skipUniqueExprIds() const override
Definition: valueflow.cpp:3382
bool match(const Token *tok) const override
Definition: valueflow.cpp:3386
SameExpressionAnalyzer(const Token *e, ValueFlow::Value val, const TokenList &t, const Settings &s)
Definition: valueflow.cpp:3378
Iterator(const M::const_iterator &it)
Definition: valueflow.cpp:2375
friend bool operator!=(const Iterator &a, const Iterator &b)
Definition: valueflow.cpp:2396
friend bool operator==(const Iterator &a, const Iterator &b)
Definition: valueflow.cpp:2392
std::forward_iterator_tag iterator_category
Definition: valueflow.cpp:2369
std::vector< Condition > parse(const Token *tok, const Settings &) const override
Definition: valueflow.cpp:6923
T * end() const
Definition: valueflow.cpp:2354
T * begin() const
Definition: valueflow.cpp:2351
const std::unordered_map< nonneg int, const Variable * > & getVars() const
Definition: valueflow.cpp:3145
void addErrorPath(const Token *tok, const std::string &s) override
Definition: valueflow.cpp:3173
void makeConditional() override
Definition: valueflow.cpp:3160
bool useSymbolicValues() const override
Definition: valueflow.cpp:3164
std::unordered_map< nonneg int, const Variable * > varids
Definition: valueflow.cpp:3139
const std::unordered_map< nonneg int, const Variable * > & getAliasedVars() const
Definition: valueflow.cpp:3149
bool isAlias(const Token *tok, bool &inconclusive) const override
Definition: valueflow.cpp:3177
bool stopOnCondition(const Token *condTok) const override
If analysis should stop on the condition.
Definition: valueflow.cpp:3224
const ValueFlow::Value * getValue(const Token *) const override
Definition: valueflow.cpp:3153
bool lowerToPossible() override
Lower any values to possible.
Definition: valueflow.cpp:3203
bool lowerToInconclusive() override
Lower any values to inconclusive.
Definition: valueflow.cpp:3209
ValuePtr< Analyzer > reanalyze(Token *tok, const std::string &msg) const override
Return analyzer for expression at token.
Definition: valueflow.cpp:3261
SingleValueFlowAnalyzer(ValueFlow::Value v, const TokenList &t, const Settings &s)
Definition: valueflow.cpp:3143
bool isConditional() const override
If the value is conditional.
Definition: valueflow.cpp:3216
bool isGlobal() const override
Definition: valueflow.cpp:3195
ValueFlow::Value value
Definition: valueflow.cpp:3141
std::unordered_map< nonneg int, const Variable * > aliases
Definition: valueflow.cpp:3140
ValueFlow::Value * getValue(const Token *) override
Definition: valueflow.cpp:3156
bool updateScope(const Token *endBlock, bool) const override
If the analysis is unsure whether to update a scope, this will return true if the analysis should bif...
Definition: valueflow.cpp:3238
static SourceLocation current()
const char * function_name() const
const char * file_name() const
std::uint_least32_t line() const
enum Standards::cppstd_t cpp
ValueFlow::Value::ValueType getType() const override
Definition: valueflow.cpp:7014
SubExpressionAnalyzer(const Token *e, ValueFlow::Value val, const TokenList &t, const Settings &s)
Definition: valueflow.cpp:3413
virtual bool submatch(const Token *tok, bool exact=true) const =0
bool internalMatch(const Token *tok) const override
Definition: valueflow.cpp:3430
bool match(const Token *tok) const override
Definition: valueflow.cpp:3426
std::vector< std::pair< Token *, ValueFlow::Value > > PartialReadContainer
Definition: valueflow.cpp:3409
void internalUpdate(Token *tok, const ValueFlow::Value &v, Direction) override
Definition: valueflow.cpp:3434
ValuePtr< Analyzer > reanalyze(Token *, const std::string &) const override
Return analyzer for expression at token.
Definition: valueflow.cpp:3440
std::shared_ptr< PartialReadContainer > partialReads
Definition: valueflow.cpp:3411
bool isAlias(const Token *tok, bool &inconclusive) const override
Definition: valueflow.cpp:3419
static const Token * skipNot(const Token *tok)
Definition: valueflow.cpp:7093
static bool isNegatedBool(const Token *tok)
Definition: valueflow.cpp:7086
std::vector< Condition > parse(const Token *tok, const Settings &settings) const override
Definition: valueflow.cpp:7100
const Token * expr
Definition: valueflow.cpp:5729
SymbolicInferModel(const Token *tok)
Definition: valueflow.cpp:5730
bool match(const ValueFlow::Value &value) const override
Definition: valueflow.cpp:5733
ValueFlow::Value yield(MathLib::bigint value) const override
Definition: valueflow.cpp:5737
virtual void internalUpdate(Token *, const ValueFlow::Value &, Direction)
Definition: valueflow.cpp:3102
virtual bool useSymbolicValues() const
Definition: valueflow.cpp:2844
virtual Action isModified(const Token *tok) const
Definition: valueflow.cpp:2665
Action analyzeLifetime(const Token *tok) const
Definition: valueflow.cpp:2552
void update(Token *tok, Action a, Direction d) override
Update the state of the value.
Definition: valueflow.cpp:3107
Action analyzeMatch(const Token *tok, Direction d) const
Definition: valueflow.cpp:2905
Action analyze(const Token *tok, Direction d) const override
Analyze a token.
Definition: valueflow.cpp:2978
ValueFlowAnalyzer(const TokenList &t, const Settings &s)
Definition: valueflow.cpp:2505
std::unordered_map< nonneg int, const Token * > getSymbols(const Token *tok) const
Definition: valueflow.cpp:2574
void assume(const Token *tok, bool state, unsigned int flags) override
The condition that will be assumed during analysis.
Definition: valueflow.cpp:3056
virtual ProgramState getProgramState() const =0
bool isCPP() const
Definition: valueflow.cpp:2543
virtual bool isAlias(const Token *tok, bool &inconclusive) const =0
virtual Action isAliasModified(const Token *tok, int indirect=-1) const
Definition: valueflow.cpp:2700
virtual bool match(const Token *tok) const =0
virtual bool internalMatch(const Token *) const
Definition: valueflow.cpp:2516
static const std::string & getAssign(const Token *tok, Direction d)
Definition: valueflow.cpp:2745
bool isSameSymbolicValue(const Token *tok, ValueFlow::Value *value=nullptr) const
Definition: valueflow.cpp:2855
virtual ValueFlow::Value * getValue(const Token *tok)=0
virtual const ValueFlow::Value * getValue(const Token *tok) const =0
ValuePtr< Analyzer > reanalyze(Token *, const std::string &) const override
Return analyzer for expression at token.
Definition: valueflow.cpp:3133
virtual void addErrorPath(const Token *tok, const std::string &s)=0
std::vector< MathLib::bigint > evaluate(Evaluate e, const Token *tok, const Token *ctx=nullptr) const override
Try to evaluate the value of a token(most likely a condition)
Definition: valueflow.cpp:3034
virtual bool isVariable() const
Definition: valueflow.cpp:2539
const TokenList & tokenlist
Definition: valueflow.cpp:2501
virtual void makeConditional()=0
ConditionState analyzeCondition(const Token *tok, int depth=20) const
Definition: valueflow.cpp:2595
const Token * findMatch(const Token *tok) const
Definition: valueflow.cpp:2848
virtual void writeValue(ValueFlow::Value *value, const Token *tok, Direction d) const
Definition: valueflow.cpp:2801
std::vector< MathLib::bigint > evaluateInt(const Token *tok) const
Definition: valueflow.cpp:3027
const Settings & settings
Definition: valueflow.cpp:2502
Action isGlobalModified(const Token *tok) const
Definition: valueflow.cpp:2725
virtual int getIndirect(const Token *tok) const
Definition: valueflow.cpp:2526
virtual bool dependsOnThis() const
Definition: valueflow.cpp:2536
Action analyzeToken(const Token *ref, const Token *tok, Direction d, bool inconclusiveRef) const
Definition: valueflow.cpp:2924
virtual bool isGlobal() const
Definition: valueflow.cpp:2533
std::vector< MathLib::bigint > evaluateInt(const Token *tok, F getProgramMemory) const
Definition: valueflow.cpp:3007
virtual Action isWritable(const Token *tok, Direction d) const
Definition: valueflow.cpp:2752
ProgramMemory::Map ProgramState
Definition: valueflow.cpp:2522
ProgramMemoryState pms
Definition: valueflow.cpp:2503
virtual Action isThisModified(const Token *tok) const
Definition: valueflow.cpp:2719
const Settings & getSettings() const
Definition: valueflow.cpp:2547
void updateState(const Token *tok) override
Update the state of the program at the token.
Definition: valueflow.cpp:3095
bool cpp() const override
Definition: valueflow.cpp:9574
ValueFlowPassAdaptor(const char *pname, bool pcpp, F prun)
Definition: valueflow.cpp:9566
const char * name() const override
Definition: valueflow.cpp:9567
void run(const ValueFlowState &state) const override
Definition: valueflow.cpp:9570
bool run(std::initializer_list< ValuePtr< ValueFlowPass >> passes) const
Definition: valueflow.cpp:9462
std::chrono::steady_clock Clock
Definition: valueflow.cpp:9446
bool run(const ValuePtr< ValueFlowPass > &pass) const
Definition: valueflow.cpp:9489
std::size_t getTotalValues() const
Definition: valueflow.cpp:9505
bool run_once(std::initializer_list< ValuePtr< ValueFlowPass >> passes) const
Definition: valueflow.cpp:9455
ValueFlowState state
Definition: valueflow.cpp:9556
TimerResultsIntf * timerResults
Definition: valueflow.cpp:9558
std::chrono::time_point< Clock > TimePoint
Definition: valueflow.cpp:9447
ValueFlowPassRunner(ValueFlowState state, TimerResultsIntf *timerResults=nullptr)
Definition: valueflow.cpp:9448
virtual bool cpp() const =0
virtual ~ValueFlowPass() noexcept=default
ValueFlowPass()=default
virtual const char * name() const =0
ValueFlowPass(const ValueFlowPass &)=default
virtual void run(const ValueFlowState &state) const =0
ErrorLogger & errorLogger
Definition: valueflow.cpp:9428
ValueFlowState(TokenList &tokenlist, SymbolDatabase &symboldatabase, ErrorLogger &errorLogger, const Settings &settings)
Definition: valueflow.cpp:9419
TokenList & tokenlist
Definition: valueflow.cpp:9426
SymbolDatabase & symboldatabase
Definition: valueflow.cpp:9427
const Settings & settings
Definition: valueflow.cpp:9429
std::set< const Scope * > skippedFunctions
Definition: valueflow.cpp:9430
static std::vector< LifetimeToken > setInconclusive(std::vector< LifetimeToken > v, bool b)
Definition: valueflow.h:96
static std::vector< LifetimeToken > setAddressOf(std::vector< LifetimeToken > v, bool b)
Definition: valueflow.h:90
static const char * getOrdinalText(int i)
Definition: utils.h:189
std::array< T, sizeof...(Ts)+1 > makeArray(T x, Ts... xs)
Definition: utils.h:80
bool startsWith(const std::string &str, const char start[], std::size_t startlen)
Definition: utils.h:94
static const char * bool_to_string(bool b)
Definition: utils.h:345
bool contains(const Range &r, const T &x)
Definition: utils.h:62
static bool valueFlowForLoop2(const Token *tok, ProgramMemory *memory1, ProgramMemory *memory2, ProgramMemory *memoryAfter, const Settings &settings)
Definition: valueflow.cpp:7149
static void changeKnownToPossible(std::list< ValueFlow::Value > &values, int indirect=-1)
Definition: valueflow.cpp:180
static void valueFlowSetConditionToKnown(const Token *tok, std::list< ValueFlow::Value > &values, bool then)
Definition: valueflow.cpp:6248
static std::vector< ValueFlow::Value > isOutOfBoundsImpl(const ValueFlow::Value &size, const Token *indexTok, bool condition)
Definition: valueflow.cpp:9719
static bool isStdMoveOrStdForwarded(Token *tok, ValueFlow::Value::MoveKind *moveKind, Token **varTok=nullptr)
Definition: valueflow.cpp:5194
static bool isVariableInit(const Token *tok)
Definition: valueflow.cpp:6058
static void valueFlowBitAnd(TokenList &tokenlist, const Settings &settings)
Definition: valueflow.cpp:1723
static void valueFlowSymbolicOperators(const SymbolDatabase &symboldatabase, const Settings &settings)
Definition: valueflow.cpp:5634
static bool isTruncated(const ValueType *src, const ValueType *dst, const Settings &settings)
Definition: valueflow.cpp:5492
static void setValueUpperBound(ValueFlow::Value &value, bool upper)
Definition: valueflow.cpp:230
static bool isOpenParenthesisMemberFunctionCallOfVarId(const Token *openParenthesisToken, nonneg int varId)
Definition: valueflow.cpp:5224
static void valueFlowDebug(TokenList &tokenlist, ErrorLogger &errorLogger, const Settings &settings)
Definition: valueflow.cpp:9389
static void valueFlowGlobalConstVar(TokenList &tokenList, const Settings &settings)
Definition: valueflow.cpp:2071
static bool productParams(const Settings &settings, const std::unordered_map< Key, std::list< ValueFlow::Value >> &vars, F f)
Definition: valueflow.cpp:7560
static std::set< nonneg int > getVarIds(const Token *tok)
Definition: valueflow.cpp:5530
static std::vector< const Token * > getConditions(const Token *tok, const char *op)
Definition: valueflow.cpp:5364
static bool isCompatibleValues(const ValueFlow::Value &value1, const ValueFlow::Value &value2)
Definition: valueflow.cpp:559
static void valueFlowInjectParameter(TokenList &tokenlist, ErrorLogger &errorLogger, const Settings &settings, const Scope *functionScope, const std::unordered_map< const Variable *, std::list< ValueFlow::Value >> &vars)
Definition: valueflow.cpp:7618
static const ValueFlow::Value * getKnownValueFromToken(const Token *tok)
Definition: valueflow.cpp:7907
static std::vector< ValueFlow::LifetimeToken > getLifetimeTokens(const Token *tok, bool escape, ValueFlow::Value::ErrorPath errorPath, Predicate pred, const Settings &settings, int depth=20)
Definition: valueflow.cpp:3585
static bool isComputableValue(const Token *parent, const ValueFlow::Value &value)
Definition: valueflow.cpp:500
#define VFA(...)
Definition: valueflow.cpp:9601
static void valueFlowArrayElement(TokenList &tokenlist, const Settings &settings)
Definition: valueflow.cpp:1615
static bool isBreakOrContinueScope(const Token *endToken)
Definition: valueflow.cpp:5382
static const Token * parseBinaryIntOp(const Token *expr, const std::function< std::vector< MathLib::bigint >(const Token *)> &eval, MathLib::bigint &known)
Definition: valueflow.cpp:8365
static bool isContainerOfPointers(const Token *tok, const Settings &settings)
Definition: valueflow.cpp:4907
static SingleRange< T > MakeSingleRange(T &x)
Definition: valueflow.cpp:2360
static void valueFlowRightShift(TokenList &tokenList, const Settings &settings)
Definition: valueflow.cpp:1842
static void valueFlowAfterMove(const TokenList &tokenlist, const SymbolDatabase &symboldatabase, ErrorLogger &errorLogger, const Settings &settings)
Definition: valueflow.cpp:5251
static ValueFlow::Value::Bound findVarBound(const Variable *var, const Token *start, const Token *end, const Settings &settings)
Definition: valueflow.cpp:5852
static bool isCompatibleValueTypes(ValueFlow::Value::ValueType x, ValueFlow::Value::ValueType y)
Definition: valueflow.cpp:536
static void valueFlowGlobalStaticVar(TokenList &tokenList, const Settings &settings)
Definition: valueflow.cpp:2105
static const Token * findIncompleteVar(const Token *start, const Token *end)
Definition: valueflow.cpp:5332
static std::vector< const Variable * > getVariables(const Token *tok)
Definition: valueflow.cpp:6209
static const Token * getCastTypeStartToken(const Token *parent, const Settings &settings)
Definition: valueflow.cpp:467
static void valueFlowForLoopSimplify(Token *const bodyStart, const Token *expr, bool globalvar, const MathLib::bigint value, const TokenList &tokenlist, ErrorLogger &errorLogger, const Settings &settings)
Definition: valueflow.cpp:7206
static void valueFlowAfterAssign(TokenList &tokenlist, const SymbolDatabase &symboldatabase, ErrorLogger &errorLogger, const Settings &settings, const std::set< const Scope * > &skippedFunctions)
Definition: valueflow.cpp:6083
static const Token * getLifetimeToken(const Token *tok, ValueFlow::Value::ErrorPath &errorPath, const Settings &settings, bool *addressOf=nullptr)
Definition: valueflow.cpp:3752
static std::vector< MathLib::bigint > minUnsignedValue(const Token *tok, int depth=8)
Definition: valueflow.cpp:1894
static MathLib::bigint valueFlowGetStrLength(const Token *tok)
Definition: valueflow.cpp:8849
static bool isSaturated(MathLib::bigint value)
Definition: valueflow.cpp:291
static bool isDifferentType(const Token *src, const Token *dst)
Definition: valueflow.cpp:3887
static void valueFlowAfterSwap(const TokenList &tokenlist, const SymbolDatabase &symboldatabase, ErrorLogger &errorLogger, const Settings &settings)
Definition: valueflow.cpp:6220
static void valueFlowEnumValue(SymbolDatabase &symboldatabase, const Settings &settings)
Definition: valueflow.cpp:2044
static void valueFlowString(TokenList &tokenlist, const Settings &settings)
Definition: valueflow.cpp:1495
static Token * findOpenParentesisOfMove(Token *moveVarTok)
Definition: valueflow.cpp:5231
static bool isNonZero(const Token *tok)
Definition: valueflow.cpp:1564
static bool derefShared(const Token *tok)
Definition: valueflow.cpp:3563
static Analyzer::Result valueFlowForward(Token *startToken, const Token *endToken, const Token *exprTok, ValueFlow::Value value, const TokenList &tokenlist, ErrorLogger &errorLogger, const Settings &settings, SourceLocation loc=SourceLocation::current())
Definition: valueflow.cpp:2156
static nonneg int getSizeOfType(const Token *typeTok, const Settings &settings)
Definition: valueflow.cpp:1190
static void setSymbolic(ValueFlow::Value &value, const Token *tok)
Definition: valueflow.cpp:5514
static void valueFlowSafeFunctions(const TokenList &tokenlist, const SymbolDatabase &symboldatabase, ErrorLogger &errorLogger, const Settings &settings)
Definition: valueflow.cpp:9262
static bool isNumeric(const ValueFlow::Value &value)
Definition: valueflow.cpp:420
static void valueFlowCondition(const ValuePtr< ConditionHandler > &handler, TokenList &tokenlist, SymbolDatabase &symboldatabase, ErrorLogger &errorLogger, const Settings &settings, const std::set< const Scope * > &skippedFunctions)
Definition: valueflow.cpp:6911
static void valueFlowNumber(TokenList &tokenlist, const Settings &settings)
Definition: valueflow.cpp:1470
static ValueFlowPassAdaptor< F > makeValueFlowPassAdaptor(const char *name, bool cpp, F run)
Definition: valueflow.cpp:9580
static void setConditionalValues(const Token *tok, bool lhs, MathLib::bigint value, ValueFlow::Value &true_value, ValueFlow::Value &false_value)
Definition: valueflow.cpp:255
static void removeImpossible(std::list< ValueFlow::Value > &values, int indirect=-1)
Definition: valueflow.cpp:189
static void valueFlowLifetimeConstructor(Token *tok, const TokenList &tokenlist, ErrorLogger &errorLogger, const Settings &settings)
Definition: valueflow.cpp:4763
static bool bifurcateVariableChanged(const Variable *var, const std::set< nonneg int > &varids, const Token *start, const Token *end, const Settings &settings, int depth=20)
Definition: valueflow.cpp:2449
static void valueFlowSymbolic(const TokenList &tokenlist, const SymbolDatabase &symboldatabase, ErrorLogger &errorLogger, const Settings &settings)
Definition: valueflow.cpp:5541
static void insertImpossible(std::list< ValueFlow::Value > &values, const std::list< ValueFlow::Value > &input)
Definition: valueflow.cpp:6276
static void assignValueIfMutable(T &x, const U &y)
Definition: valueflow.cpp:2302
static std::string removeAssign(const std::string &assign)
Definition: valueflow.cpp:2284
static Library::Container::Yield findIteratorYield(Token *tok, const Token **ftok, const Settings &settings)
Definition: valueflow.cpp:8588
static void valueFlowDynamicBufferSize(const TokenList &tokenlist, const SymbolDatabase &symboldatabase, ErrorLogger &errorLogger, const Settings &settings)
Definition: valueflow.cpp:9093
static void valueFlowForwardConst(Token *start, const Token *end, const Variable *var, const ContainerOfValue &values, const Settings &settings, int=0)
Definition: valueflow.cpp:5786
static bool isContainerSizeChangedByFunction(const Token *tok, int indirect, const Settings &settings, int depth=20)
Definition: valueflow.cpp:8201
static size_t accumulateStructMembers(const Scope *scope, F f)
Definition: valueflow.cpp:1121
static void valueFlowSymbolicInfer(const SymbolDatabase &symboldatabase, const Settings &settings)
Definition: valueflow.cpp:5747
static ValueFlow::Value truncateImplicitConversion(Token *parent, const ValueFlow::Value &value, const Settings &settings)
Definition: valueflow.cpp:576
static bool isContainerSizeChanged(const Token *expr, const Token *start, const Token *end, int indirect, const Settings &settings, int depth=20)
Definition: valueflow.cpp:8497
static const Function * findConstructor(const Scope *scope, const Token *tok, const std::vector< const Token * > &args)
Definition: valueflow.cpp:4669
static ValueFlow::Value makeConditionValue(long long val, const Token *condTok, bool assume, bool impossible, const Settings &settings, SourceLocation loc=SourceLocation::current())
Definition: valueflow.cpp:5341
static std::vector< ValueFlow::Value > getContainerSizeFromConstructorArgs(const std::vector< const Token * > &args, const Library::Container *container, bool known)
Definition: valueflow.cpp:8725
#define VFA_CPP(...)
Definition: valueflow.cpp:9602
static void valueFlowUnknownFunctionReturn(TokenList &tokenlist, const Settings &settings)
Definition: valueflow.cpp:9360
static void valueFlowIteratorInfer(TokenList &tokenlist, const Settings &settings)
Definition: valueflow.cpp:8665
static const Token * isStrlenOf(const Token *tok, const Token *expr, int depth=10)
Definition: valueflow.cpp:5604
static void setTokenValueCast(Token *parent, const ValueType &valueType, const ValueFlow::Value &value, const Settings &settings)
Set token value for cast.
Definition: valueflow.cpp:1090
static ValueFlow::Value makeContainerSizeValue(std::size_t s, bool known=true)
Definition: valueflow.cpp:8709
static void setConditionalValue(ValueFlow::Value &value, const Token *tok, MathLib::bigint i)
Definition: valueflow.cpp:247
static void valueFlowFunctionDefaultParameter(const TokenList &tokenlist, const SymbolDatabase &symboldatabase, ErrorLogger &errorLogger, const Settings &settings)
Definition: valueflow.cpp:7879
static void valueFlowLifetimeUserConstructor(Token *tok, const Function *constructor, const std::string &name, const std::vector< const Token * > &args, const TokenList &tokenlist, ErrorLogger &errorLogger, const Settings &settings)
Definition: valueflow.cpp:4413
static bool isRangeForScope(const Scope *scope)
Definition: valueflow.cpp:3938
static std::string lifetimeType(const Token *tok, const ValueFlow::Value *val)
Definition: valueflow.cpp:3464
static bool isNonInvertibleOperation(const Token *tok)
Definition: valueflow.cpp:495
static void valueFlowIterators(TokenList &tokenlist, const Settings &settings)
Definition: valueflow.cpp:8601
static void valueFlowContainerSize(const TokenList &tokenlist, const SymbolDatabase &symboldatabase, ErrorLogger &errorLogger, const Settings &settings, const std::set< const Scope * > &skippedFunctions)
Definition: valueflow.cpp:8864
LifetimeCapture
Definition: valueflow.cpp:3462
static ValueFlow::Value makeSymbolic(const Token *tok, MathLib::bigint delta=0)
Definition: valueflow.cpp:5521
static bool isLifetimeOwned(const ValueType *vtParent)
Definition: valueflow.cpp:3784
static void setValueBound(ValueFlow::Value &value, const Token *tok, bool invert)
Definition: valueflow.cpp:238
static void valueFlowSmartPointer(TokenList &tokenlist, ErrorLogger &errorLogger, const Settings &settings)
Definition: valueflow.cpp:8513
static void valueFlowLifetimeFunction(Token *tok, const TokenList &tokenlist, ErrorLogger &errorLogger, const Settings &settings)
Definition: valueflow.cpp:4507
static void valueFlowContainerSetTokValue(const TokenList &tokenlist, ErrorLogger &errorLogger, const Settings &settings, const Token *tok, Token *initList)
Definition: valueflow.cpp:8826
static void setTokenValue(Token *tok, ValueFlow::Value value, const Settings &settings, SourceLocation loc=SourceLocation::current())
set ValueFlow value and perform calculations if possible
Definition: valueflow.cpp:619
static size_t getAlignOf(const ValueType &vt, const Settings &settings, int maxRecursion=0)
Definition: valueflow.cpp:1162
static bool hasUniqueOwnership(const Token *tok)
Definition: valueflow.cpp:3546
static void addToErrorPath(ValueFlow::Value &value, const ValueFlow::Value &from)
Definition: valueflow.cpp:8030
static bool isIntegralOrPointer(const Token *tok)
Definition: valueflow.cpp:7023
static void valueFlowArrayBool(TokenList &tokenlist, const Settings &settings)
Definition: valueflow.cpp:1582
static void valueFlowForLoop(TokenList &tokenlist, const SymbolDatabase &symboldatabase, ErrorLogger &errorLogger, const Settings &settings)
Definition: valueflow.cpp:7339
static std::list< ValueFlow::Value > getIteratorValues(std::list< ValueFlow::Value > values, const ValueFlow::Value::ValueKind *kind=nullptr)
Definition: valueflow.cpp:8626
static Analyzer::Result valueFlowForwardRecursive(Token *top, const Token *exprTok, std::list< ValueFlow::Value > values, const TokenList &tokenlist, ErrorLogger &errorLogger, const Settings &settings, SourceLocation loc=SourceLocation::current())
Definition: valueflow.cpp:2207
static bool isSameToken(const Token *tok1, const Token *tok2)
Definition: valueflow.cpp:1926
static ValueFlow::Value::MoveKind isMoveOrForward(const Token *tok)
Definition: valueflow.cpp:2330
static bool isBreakScope(const Token *const endToken)
Definition: valueflow.cpp:6260
static bool isLifetimeBorrowed(const ValueType *vt, const ValueType *vtParent)
Definition: valueflow.cpp:3816
static bool valueFlowIsSameContainerType(const ValueType &contType, const Token *tok, const Settings &settings)
Definition: valueflow.cpp:8771
static bool isConvertedToIntegral(const Token *tok, const Settings &settings)
Definition: valueflow.cpp:1915
static const Scope * getLoopScope(const Token *tok)
Definition: valueflow.cpp:5389
static bool isConvertedToView(const Token *tok, const Settings &settings)
Definition: valueflow.cpp:4897
static void setFunctionReturnValue(const Function *f, Token *tok, ValueFlow::Value v, const Settings &settings)
Definition: valueflow.cpp:7935
static void parseCompareEachInt(const Token *tok, const std::function< void(const Token *varTok, ValueFlow::Value true_value, ValueFlow::Value false_value)> &each, const std::function< std::vector< ValueFlow::Value >(const Token *)> &evaluate)
Definition: valueflow.cpp:296
static const Token * getOtherOperand(const Token *tok)
Definition: valueflow.cpp:1569
static void valueFlowForwardLifetime(Token *tok, const TokenList &tokenlist, ErrorLogger &errorLogger, const Settings &settings)
Definition: valueflow.cpp:4013
static void valueFlowUninit(TokenList &tokenlist, ErrorLogger &errorLogger, const Settings &settings)
Definition: valueflow.cpp:8116
static void valueFlowPointerAlias(TokenList &tokenlist, const Settings &settings)
Definition: valueflow.cpp:1692
static bool isNotLifetimeValue(const ValueFlow::Value &val)
Definition: valueflow.cpp:3779
static bool needsInitialization(const Variable *var)
Definition: valueflow.cpp:8005
static bool bifurcate(const Token *tok, const std::set< nonneg int > &varids, const Settings &settings, int depth=20)
Definition: valueflow.cpp:2470
static ValueFlow::Value inferCondition(const std::string &op, const Token *varTok, MathLib::bigint val)
Definition: valueflow.cpp:6981
static std::string debugString(const ValueFlow::Value &v)
Definition: valueflow.cpp:148
static void lowerToPossible(std::list< ValueFlow::Value > &values, int indirect=-1)
Definition: valueflow.cpp:198
static bool isScope(const Token *tok)
Definition: valueflow.cpp:4655
static bool hasBorrowingVariables(const std::list< Variable > &vars, const std::vector< const Token * > &args, int depth=10)
Definition: valueflow.cpp:4384
static void valueFlowReverse(Token *tok, const Token *const endToken, const Token *const varToken, std::list< ValueFlow::Value > values, const TokenList &tokenlist, ErrorLogger &errorLogger, const Settings &settings, SourceLocation loc=SourceLocation::current())
Definition: valueflow.cpp:2225
static std::list< ValueFlow::Value > truncateValues(std::list< ValueFlow::Value > values, const ValueType *dst, const ValueType *src, const Settings &settings)
Definition: valueflow.cpp:6014
static void valueFlowSwitchVariable(const TokenList &tokenlist, const SymbolDatabase &symboldatabase, ErrorLogger &errorLogger, const Settings &settings)
Definition: valueflow.cpp:7662
static ValuePtr< Analyzer > makeReverseAnalyzer(const Token *exprTok, ValueFlow::Value value, const TokenList &tokenlist, const Settings &settings)
Definition: valueflow.cpp:8454
static void changePossibleToKnown(std::list< ValueFlow::Value > &values, int indirect=-1)
Definition: valueflow.cpp:204
static void valueFlowForwardAssign(Token *const tok, const Token *expr, std::vector< const Variable * > vars, std::list< ValueFlow::Value > values, const bool init, const TokenList &tokenlist, ErrorLogger &errorLogger, const Settings &settings)
Definition: valueflow.cpp:5892
static const Token * skipCVRefs(const Token *tok, const Token *endTok)
Definition: valueflow.cpp:3838
static bool isConditionKnown(const Token *tok, bool then)
Definition: valueflow.cpp:2253
static void valueFlowLifetimeClassConstructor(Token *tok, const Type *t, const TokenList &tokenlist, ErrorLogger &errorLogger, const Settings &settings)
Definition: valueflow.cpp:4696
static void valueFlowImpossibleValues(TokenList &tokenList, const Settings &settings)
Definition: valueflow.cpp:1937
static void valueFlowLifetime(TokenList &tokenlist, ErrorLogger &errorLogger, const Settings &settings)
Definition: valueflow.cpp:4918
static T calculateAssign(const std::string &assign, const T &x, const U &y, bool *error=nullptr)
Definition: valueflow.cpp:2289
static bool evalAssignment(Value &lhsValue, const std::string &assign, const ValueFlow::Value &rhsValue)
Definition: valueflow.cpp:2312
static void valueFlowForLoopSimplifyAfter(Token *fortok, nonneg int varid, const MathLib::bigint num, const TokenList &tokenlist, ErrorLogger &errorLogger, const Settings &settings)
Definition: valueflow.cpp:7311
static void valueFlowFunctionReturn(TokenList &tokenlist, ErrorLogger &errorLogger, const Settings &settings)
Definition: valueflow.cpp:7948
static Token * findEndOfFunctionCallForParameter(Token *parameterToken)
Definition: valueflow.cpp:5239
static Token * valueFlowSetConstantValue(Token *tok, const Settings &settings)
Definition: valueflow.cpp:1256
static bool intersects(const C1 &c1, const C2 &c2)
Definition: valueflow.cpp:6071
static const std::string & invertAssign(const std::string &assign)
Definition: valueflow.cpp:2267
static Token * findStartToken(const Variable *var, Token *start, const Library &library)
Definition: valueflow.cpp:8062
static void setSourceLocation(ValueFlow::Value &v, SourceLocation ctx, const Token *tok, SourceLocation local=SourceLocation::current())
Definition: valueflow.cpp:167
static bool getExpressionRange(const Token *expr, MathLib::bigint *minvalue, MathLib::bigint *maxvalue)
Definition: valueflow.cpp:1790
static const Token * getEndOfVarScope(const Variable *var)
Definition: valueflow.cpp:3951
static size_t bitCeil(size_t x)
Definition: valueflow.cpp:1148
static long long truncateIntValue(long long value, size_t value_size, const ValueType::Sign dst_sign)
Definition: valueflow.cpp:607
static std::vector< ValueFlow::Value > getContainerSizeFromConstructor(const Token *tok, const ValueType *valueType, const Settings &settings, bool known=true)
Definition: valueflow.cpp:8812
static void valueFlowSameExpressions(TokenList &tokenlist, const Settings &settings)
Definition: valueflow.cpp:1754
static bool isDecayedPointer(const Token *tok)
Definition: valueflow.cpp:4882
static bool isNotEqual(std::pair< const Token *, const Token * > x, std::pair< const Token *, const Token * > y)
Definition: valueflow.cpp:3845
static void valueFlowArray(TokenList &tokenlist, const Settings &settings)
Definition: valueflow.cpp:1508
static const ValueFlow::Value * getKnownValueFromTokens(const std::vector< const Token * > &toks)
Definition: valueflow.cpp:7919
static std::vector< Token * > findAllUsages(const Variable *var, Token *start, const Library &library)
Definition: valueflow.cpp:8049
static const Token * solveExprValue(const Token *expr, ValueFlow::Value &value)
Definition: valueflow.cpp:8434
static void valueFlowInferCondition(TokenList &tokenlist, const Settings &settings)
Definition: valueflow.cpp:7045
#define bailout(tokenlist, errorLogger, tok, what)
Definition: valueflow.cpp:144
static const Scope * getFunctionScope(const Scope *scope)
Definition: valueflow.cpp:8843
static void valueFlowSubFunction(TokenList &tokenlist, SymbolDatabase &symboldatabase, ErrorLogger &errorLogger, const Settings &settings)
Definition: valueflow.cpp:7797
static void valueFlowConditionExpressions(const TokenList &tokenlist, const SymbolDatabase &symboldatabase, ErrorLogger &errorLogger, const Settings &settings)
Definition: valueflow.cpp:5400
static void valueFlowLibraryFunction(Token *tok, const std::string &returnValue, const Settings &settings)
Definition: valueflow.cpp:7745
static void bailoutInternal(const std::string &type, const TokenList &tokenlist, ErrorLogger &errorLogger, const Token *tok, const std::string &what, const std::string &file, int line, std::string function)
This is the ValueFlow component in Cppcheck.
Definition: valueflow.cpp:131
static ValuePtr< Analyzer > makeAnalyzer(const Token *exprTok, ValueFlow::Value value, const TokenList &tokenlist, const Settings &settings)
Definition: valueflow.cpp:8446
static bool isEscapeScope(const Token *tok, const Settings &settings, bool unknown=false)
Definition: valueflow.cpp:386
static std::list< ValueFlow::Value > getFunctionArgumentValues(const Token *argtok)
Definition: valueflow.cpp:7734
static bool isIntegralOnlyOperator(const Token *tok)
Definition: valueflow.cpp:7019
static bool isAliasOf(const Variable *var, const Token *tok, nonneg int varid, const V &values, bool *inconclusive=nullptr)
Definition: valueflow.cpp:2421
static IteratorRange< Iterator > MakeIteratorRange(Iterator start, Iterator last)
Definition: valueflow.cpp:7792
static Library::Container::Yield getContainerYield(Token *tok, const Settings &settings, Token **parent=nullptr)
Definition: valueflow.cpp:514
static std::vector< ValueFlow::Value > getContainerValues(const Token *tok)
Definition: valueflow.cpp:8697
static bool isInitialVarAssign(const Token *tok)
Definition: valueflow.cpp:5878
#define bailoutIncompleteVar(tokenlist, errorLogger, tok, what)
Definition: valueflow.cpp:146
static bool getMinMaxValues(const ValueType *vt, const Platform &platform, MathLib::bigint &minValue, MathLib::bigint &maxValue)
Definition: valueflow.cpp:9195
static bool isNonConditionalPossibleIntValue(const ValueFlow::Value &v)
Definition: valueflow.cpp:217
static ValueFlow::Value castValue(ValueFlow::Value value, const ValueType::Sign sign, nonneg int bit)
Definition: valueflow.cpp:400
static void insertNegateKnown(std::list< ValueFlow::Value > &values, const std::list< ValueFlow::Value > &input)
Definition: valueflow.cpp:6281
static std::vector< ValueFlow::Value > getInitListSize(const Token *tok, const ValueType *valueType, const Settings &settings, bool known=true)
Definition: valueflow.cpp:8780