1 /*
2  * Cppcheck - A tool for static C/C++ code analysis
3  * Copyright (C) 2007-2021 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 "checkuninitvar.h"
83 #include "config.h"
84 #include "errorlogger.h"
85 #include "errortypes.h"
86 #include "forwardanalyzer.h"
87 #include "library.h"
88 #include "mathlib.h"
89 #include "path.h"
90 #include "platform.h"
91 #include "programmemory.h"
92 #include "reverseanalyzer.h"
93 #include "settings.h"
94 #include "standards.h"
95 #include "symboldatabase.h"
96 #include "token.h"
97 #include "tokenlist.h"
98 #include "utils.h"
99 #include "valueptr.h"
100 
101 #include <algorithm>
102 #include <cassert>
103 #include <cmath>
104 #include <cstddef>
105 #include <cstdint>
106 #include <cstdlib>
107 #include <cstring>
108 #include <functional>
109 #include <iterator>
110 #include <limits>
111 #include <map>
112 #include <set>
113 #include <stack>
114 #include <stdexcept>
115 #include <string>
116 #include <tuple>
117 #include <type_traits>
118 #include <unordered_map>
119 #include <unordered_set>
120 #include <vector>
121 
bailoutInternal(const std::string & type,TokenList * tokenlist,ErrorLogger * errorLogger,const Token * tok,const std::string & what,const std::string & file,int line,std::string function)122 static void bailoutInternal(const std::string& type, TokenList *tokenlist, ErrorLogger *errorLogger, const Token *tok, const std::string &what, const std::string &file, int line, std::string function)
123 {
124     if (function.find("operator") != std::string::npos)
125         function = "(valueFlow)";
126     std::list<ErrorMessage::FileLocation> callstack(1, ErrorMessage::FileLocation(tok, tokenlist));
127     ErrorMessage errmsg(callstack, tokenlist->getSourceFilePath(), Severity::debug,
128                         Path::stripDirectoryPart(file) + ":" + MathLib::toString(line) + ":" + function + " bailout: " + what, type, Certainty::normal);
129     errorLogger->reportErr(errmsg);
130 }
131 
132 #if (defined __cplusplus) && __cplusplus >= 201103L
133 #define bailout2(type, tokenlist, errorLogger, tok, what) bailoutInternal(type, tokenlist, errorLogger, tok, what, __FILE__, __LINE__, __func__)
134 #elif (defined __GNUC__) || (defined __clang__) || (defined _MSC_VER)
135 #define bailout2(type, tokenlist, errorLogger, tok, what) bailoutInternal(type, tokenlist, errorLogger, tok, what, __FILE__, __LINE__, __FUNCTION__)
136 #else
137 #define bailout2(type, tokenlist, errorLogger, tok, what) bailoutInternal(type, tokenlist, errorLogger, tok, what, __FILE__, __LINE__, "(valueFlow)")
138 #endif
139 
140 #define bailout(tokenlist, errorLogger, tok, what) bailout2("valueFlowBailout", tokenlist, errorLogger, tok, what)
141 
142 #define bailoutIncompleteVar(tokenlist, errorLogger, tok, what) bailout2("valueFlowBailoutIncompleteVar", tokenlist, errorLogger, tok, what)
143 
changeKnownToPossible(std::list<ValueFlow::Value> & values,int indirect=-1)144 static void changeKnownToPossible(std::list<ValueFlow::Value> &values, int indirect=-1)
145 {
146     for (ValueFlow::Value& v: values) {
147         if (indirect >= 0 && v.indirect != indirect)
148             continue;
149         v.changeKnownToPossible();
150     }
151 }
152 
removeImpossible(std::list<ValueFlow::Value> & values,int indirect=-1)153 static void removeImpossible(std::list<ValueFlow::Value>& values, int indirect = -1)
154 {
155     values.remove_if([&](const ValueFlow::Value& v) {
156         if (indirect >= 0 && v.indirect != indirect)
157             return false;
158         return v.isImpossible();
159     });
160 }
161 
lowerToPossible(std::list<ValueFlow::Value> & values,int indirect=-1)162 static void lowerToPossible(std::list<ValueFlow::Value>& values, int indirect = -1)
163 {
164     changeKnownToPossible(values, indirect);
165     removeImpossible(values, indirect);
166 }
167 
changePossibleToKnown(std::list<ValueFlow::Value> & values,int indirect=-1)168 static void changePossibleToKnown(std::list<ValueFlow::Value>& values, int indirect = -1)
169 {
170     for (ValueFlow::Value& v : values) {
171         if (indirect >= 0 && v.indirect != indirect)
172             continue;
173         if (!v.isPossible())
174             continue;
175         if (v.bound != ValueFlow::Value::Bound::Point)
176             continue;
177         v.setKnown();
178     }
179 }
180 
setValueUpperBound(ValueFlow::Value & value,bool upper)181 static void setValueUpperBound(ValueFlow::Value& value, bool upper)
182 {
183     if (upper)
184         value.bound = ValueFlow::Value::Bound::Upper;
185     else
186         value.bound = ValueFlow::Value::Bound::Lower;
187 }
188 
setValueBound(ValueFlow::Value & value,const Token * tok,bool invert)189 static void setValueBound(ValueFlow::Value& value, const Token* tok, bool invert)
190 {
191     if (Token::Match(tok, "<|<=")) {
192         setValueUpperBound(value, !invert);
193     } else if (Token::Match(tok, ">|>=")) {
194         setValueUpperBound(value, invert);
195     }
196 }
197 
setConditionalValues(const Token * tok,bool lhs,MathLib::bigint value,ValueFlow::Value & true_value,ValueFlow::Value & false_value)198 static void setConditionalValues(const Token* tok,
199                                  bool lhs,
200                                  MathLib::bigint value,
201                                  ValueFlow::Value& true_value,
202                                  ValueFlow::Value& false_value)
203 {
204     if (Token::Match(tok, "==|!=|>=|<=")) {
205         true_value = ValueFlow::Value{tok, value};
206         const char* greaterThan = ">=";
207         const char* lessThan = "<=";
208         if (lhs)
209             std::swap(greaterThan, lessThan);
210         if (Token::simpleMatch(tok, greaterThan, strlen(greaterThan))) {
211             false_value = ValueFlow::Value{tok, value - 1};
212         } else if (Token::simpleMatch(tok, lessThan, strlen(lessThan))) {
213             false_value = ValueFlow::Value{tok, value + 1};
214         } else {
215             false_value = ValueFlow::Value{tok, value};
216         }
217     } else {
218         const char* greaterThan = ">";
219         const char* lessThan = "<";
220         if (lhs)
221             std::swap(greaterThan, lessThan);
222         if (Token::simpleMatch(tok, greaterThan, strlen(greaterThan))) {
223             true_value = ValueFlow::Value{tok, value + 1};
224             false_value = ValueFlow::Value{tok, value};
225         } else if (Token::simpleMatch(tok, lessThan, strlen(lessThan))) {
226             true_value = ValueFlow::Value{tok, value - 1};
227             false_value = ValueFlow::Value{tok, value};
228         }
229     }
230     setValueBound(true_value, tok, lhs);
231     setValueBound(false_value, tok, !lhs);
232 }
233 
isSaturated(MathLib::bigint value)234 static bool isSaturated(MathLib::bigint value)
235 {
236     return value == std::numeric_limits<MathLib::bigint>::max() || value == std::numeric_limits<MathLib::bigint>::min();
237 }
238 
parseCompareInt(const Token * tok,ValueFlow::Value & true_value,ValueFlow::Value & false_value,const std::function<std::vector<MathLib::bigint> (const Token *)> & evaluate)239 const Token *parseCompareInt(const Token *tok, ValueFlow::Value &true_value, ValueFlow::Value &false_value, const std::function<std::vector<MathLib::bigint>(const Token*)>& evaluate)
240 {
241     if (!tok->astOperand1() || !tok->astOperand2())
242         return nullptr;
243     if (tok->isComparisonOp()) {
244         std::vector<MathLib::bigint> value1 = evaluate(tok->astOperand1());
245         std::vector<MathLib::bigint> value2 = evaluate(tok->astOperand2());
246         if (!value1.empty() && !value2.empty()) {
247             if (tok->astOperand1()->hasKnownIntValue())
248                 value2.clear();
249             if (tok->astOperand2()->hasKnownIntValue())
250                 value1.clear();
251         }
252         if (!value1.empty()) {
253             if (isSaturated(value1.front()))
254                 return nullptr;
255             setConditionalValues(tok, true, value1.front(), true_value, false_value);
256             return tok->astOperand2();
257         } else if (!value2.empty()) {
258             if (isSaturated(value2.front()))
259                 return nullptr;
260             setConditionalValues(tok, false, value2.front(), true_value, false_value);
261             return tok->astOperand1();
262         }
263     }
264     return nullptr;
265 }
266 
parseCompareInt(const Token * tok,ValueFlow::Value & true_value,ValueFlow::Value & false_value)267 const Token *parseCompareInt(const Token *tok, ValueFlow::Value &true_value, ValueFlow::Value &false_value)
268 {
269     return parseCompareInt(tok, true_value, false_value, [](const Token* t) -> std::vector<MathLib::bigint> {
270         if (t->hasKnownIntValue())
271             return {t->values().front().intvalue};
272         return std::vector<MathLib::bigint>{};
273     });
274 }
275 
isEscapeScope(const Token * tok,TokenList * tokenlist,bool unknown=false)276 static bool isEscapeScope(const Token* tok, TokenList * tokenlist, bool unknown = false)
277 {
278     if (!Token::simpleMatch(tok, "{"))
279         return false;
280     // TODO this search for termTok in all subscopes. It should check the end of the scope.
281     const Token * termTok = Token::findmatch(tok, "return|continue|break|throw|goto", tok->link());
282     if (termTok && termTok->scope() == tok->scope())
283         return true;
284     std::string unknownFunction;
285     if (tokenlist && tokenlist->getSettings()->library.isScopeNoReturn(tok->link(), &unknownFunction))
286         return unknownFunction.empty() || unknown;
287     return false;
288 }
289 
castValue(ValueFlow::Value value,const ValueType::Sign sign,nonneg int bit)290 static ValueFlow::Value castValue(ValueFlow::Value value, const ValueType::Sign sign, nonneg int bit)
291 {
292     if (value.isFloatValue()) {
293         value.valueType = ValueFlow::Value::ValueType::INT;
294         if (value.floatValue >= std::numeric_limits<int>::min() && value.floatValue <= std::numeric_limits<int>::max()) {
295             value.intvalue = value.floatValue;
296         } else { // don't perform UB
297             value.intvalue = 0;
298         }
299     }
300     if (bit < MathLib::bigint_bits) {
301         const MathLib::biguint one = 1;
302         value.intvalue &= (one << bit) - 1;
303         if (sign == ValueType::Sign::SIGNED && value.intvalue & (one << (bit - 1))) {
304             value.intvalue |= ~((one << bit) - 1ULL);
305         }
306     }
307     return value;
308 }
309 
isNumeric(const ValueFlow::Value & value)310 static bool isNumeric(const ValueFlow::Value& value) {
311     return value.isIntValue() || value.isFloatValue();
312 }
313 
combineValueProperties(const ValueFlow::Value & value1,const ValueFlow::Value & value2,ValueFlow::Value * result)314 static void combineValueProperties(const ValueFlow::Value &value1, const ValueFlow::Value &value2, ValueFlow::Value *result)
315 {
316     if (value1.isKnown() && value2.isKnown())
317         result->setKnown();
318     else if (value1.isImpossible() || value2.isImpossible())
319         result->setImpossible();
320     else if (value1.isInconclusive() || value2.isInconclusive())
321         result->setInconclusive();
322     else
323         result->setPossible();
324     if (value1.isSymbolicValue()) {
325         result->valueType = value1.valueType;
326         result->tokvalue = value1.tokvalue;
327     }
328     if (value2.isSymbolicValue()) {
329         result->valueType = value2.valueType;
330         result->tokvalue = value2.tokvalue;
331     }
332     if (value1.isIteratorValue())
333         result->valueType = value1.valueType;
334     if (value2.isIteratorValue())
335         result->valueType = value2.valueType;
336     result->condition = value1.condition ? value1.condition : value2.condition;
337     result->varId = (value1.varId != 0) ? value1.varId : value2.varId;
338     result->varvalue = (result->varId == value1.varId) ? value1.varvalue : value2.varvalue;
339     result->errorPath = (value1.errorPath.empty() ? value2 : value1).errorPath;
340     result->safe = value1.safe || value2.safe;
341     if (value1.bound == ValueFlow::Value::Bound::Point || value2.bound == ValueFlow::Value::Bound::Point) {
342         if (value1.bound == ValueFlow::Value::Bound::Upper || value2.bound == ValueFlow::Value::Bound::Upper)
343             result->bound = ValueFlow::Value::Bound::Upper;
344         if (value1.bound == ValueFlow::Value::Bound::Lower || value2.bound == ValueFlow::Value::Bound::Lower)
345             result->bound = ValueFlow::Value::Bound::Lower;
346     }
347     if (value1.path != value2.path)
348         result->path = -1;
349     else
350         result->path = value1.path;
351 }
352 
getCastTypeStartToken(const Token * parent)353 static const Token *getCastTypeStartToken(const Token *parent)
354 {
355     // TODO: This might be a generic utility function?
356     if (!parent || parent->str() != "(")
357         return nullptr;
358     if (!parent->astOperand2() && Token::Match(parent,"( %name%"))
359         return parent->next();
360     if (parent->astOperand2() && Token::Match(parent->astOperand1(), "const_cast|dynamic_cast|reinterpret_cast|static_cast <"))
361         return parent->astOperand1()->tokAt(2);
362     return nullptr;
363 }
364 
isComputableValue(const Token * parent,const ValueFlow::Value & value)365 static bool isComputableValue(const Token* parent, const ValueFlow::Value& value)
366 {
367     const bool noninvertible = parent->isComparisonOp() || Token::Match(parent, "%|/|&|%or%");
368     if (noninvertible && value.isImpossible())
369         return false;
370     if (!value.isIntValue() && !value.isFloatValue() && !value.isTokValue() && !value.isIteratorValue())
371         return false;
372     if (value.isIteratorValue() && !Token::Match(parent, "+|-"))
373         return false;
374     if (value.isTokValue() && (!parent->isComparisonOp() || value.tokvalue->tokType() != Token::eString))
375         return false;
376     return true;
377 }
378 
379 template<class T>
isEqual(T x,T y)380 static bool isEqual(T x, T y)
381 {
382     return x == y;
383 }
384 
385 template<>
isEqual(double x,double y)386 bool isEqual<double>(double x, double y)
387 {
388     const double diff = (x > y) ? x - y : y - x;
389     return !((diff / 2) < diff);
390 }
391 
392 template<class T>
isZero(T x)393 static bool isZero(T x)
394 {
395     return isEqual<T>(x, T(0));
396 }
397 
398 template<class R, class T>
calculate(const std::string & s,const T & x,const T & y,bool * error=nullptr)399 static R calculate(const std::string& s, const T& x, const T& y, bool* error = nullptr)
400 {
401     auto wrap = [](T z) {
402         return R{z};
403     };
404     switch (MathLib::encodeMultiChar(s)) {
405     case '+':
406         return wrap(x + y);
407     case '-':
408         return wrap(x - y);
409     case '*':
410         return wrap(x * y);
411     case '/':
412         if (isZero(y)) {
413             if (error)
414                 *error = true;
415             return R{};
416         }
417         return wrap(x / y);
418     case '%':
419         if (isZero(y)) {
420             if (error)
421                 *error = true;
422             return R{};
423         }
424         return wrap(MathLib::bigint(x) % MathLib::bigint(y));
425     case '&':
426         return wrap(MathLib::bigint(x) & MathLib::bigint(y));
427     case '|':
428         return wrap(MathLib::bigint(x) | MathLib::bigint(y));
429     case '^':
430         return wrap(MathLib::bigint(x) ^ MathLib::bigint(y));
431     case '>':
432         return wrap(x > y);
433     case '<':
434         return wrap(x < y);
435     case '<<':
436         if (y >= sizeof(MathLib::bigint) * 8 || y < 0 || x < 0) {
437             if (error)
438                 *error = true;
439             return R{};
440         }
441         return wrap(MathLib::bigint(x) << MathLib::bigint(y));
442     case '>>':
443         if (y >= sizeof(MathLib::bigint) * 8 || y < 0 || x < 0) {
444             if (error)
445                 *error = true;
446             return R{};
447         }
448         return wrap(MathLib::bigint(x) >> MathLib::bigint(y));
449     case '&&':
450         return wrap(!isZero(x) && !isZero(y));
451     case '||':
452         return wrap(!isZero(x) || !isZero(y));
453     case '==':
454         return wrap(isEqual(x, y));
455     case '!=':
456         return wrap(!isEqual(x, y));
457     case '>=':
458         return wrap(x >= y);
459     case '<=':
460         return wrap(x <= y);
461     }
462     throw InternalError(nullptr, "Unknown operator: " + s);
463 }
464 
465 template<class T>
calculate(const std::string & s,const T & x,const T & y,bool * error=nullptr)466 static T calculate(const std::string& s, const T& x, const T& y, bool* error = nullptr)
467 {
468     return calculate<T, T>(s, x, y, error);
469 }
470 
471 /** Set token value for cast */
472 static void setTokenValueCast(Token *parent, const ValueType &valueType, const ValueFlow::Value &value, const Settings *settings);
473 
isCompatibleValueTypes(ValueFlow::Value::ValueType x,ValueFlow::Value::ValueType y)474 static bool isCompatibleValueTypes(ValueFlow::Value::ValueType x, ValueFlow::Value::ValueType y)
475 {
476     static const std::unordered_map<ValueFlow::Value::ValueType,
477                                     std::unordered_set<ValueFlow::Value::ValueType, EnumClassHash>,
478                                     EnumClassHash>
479     compatibleTypes = {
480         {ValueFlow::Value::ValueType::INT,
481          {ValueFlow::Value::ValueType::FLOAT,
482           ValueFlow::Value::ValueType::SYMBOLIC,
483           ValueFlow::Value::ValueType::TOK}},
484         {ValueFlow::Value::ValueType::FLOAT, {ValueFlow::Value::ValueType::INT}},
485         {ValueFlow::Value::ValueType::TOK, {ValueFlow::Value::ValueType::INT}},
486         {ValueFlow::Value::ValueType::ITERATOR_START, {ValueFlow::Value::ValueType::INT}},
487         {ValueFlow::Value::ValueType::ITERATOR_END, {ValueFlow::Value::ValueType::INT}},
488     };
489     if (x == y)
490         return true;
491     auto it = compatibleTypes.find(x);
492     if (it == compatibleTypes.end())
493         return false;
494     return it->second.count(y) > 0;
495 }
496 
isCompatibleValues(const ValueFlow::Value & value1,const ValueFlow::Value & value2)497 static bool isCompatibleValues(const ValueFlow::Value& value1, const ValueFlow::Value& value2)
498 {
499     if (value1.isSymbolicValue() && value2.isSymbolicValue() && value1.tokvalue->exprId() != value2.tokvalue->exprId())
500         return false;
501     if (!isCompatibleValueTypes(value1.valueType, value2.valueType))
502         return false;
503     if (value1.isKnown() || value2.isKnown())
504         return true;
505     if (value1.isImpossible() || value2.isImpossible())
506         return false;
507     if (value1.varId == 0 || value2.varId == 0)
508         return true;
509     if (value1.varId == value2.varId && value1.varvalue == value2.varvalue && value1.isIntValue() && value2.isIntValue())
510         return true;
511     return false;
512 }
513 
truncateImplicitConversion(Token * parent,const ValueFlow::Value & value,const Settings * settings)514 static ValueFlow::Value truncateImplicitConversion(Token* parent, const ValueFlow::Value& value, const Settings* settings)
515 {
516     if (!value.isIntValue() && !value.isFloatValue())
517         return value;
518     if (!parent)
519         return value;
520     if (!parent->isBinaryOp())
521         return value;
522     if (!parent->isConstOp())
523         return value;
524     if (!astIsIntegral(parent->astOperand1(), false))
525         return value;
526     if (!astIsIntegral(parent->astOperand2(), false))
527         return value;
528     const ValueType* vt1 = parent->astOperand1()->valueType();
529     const ValueType* vt2 = parent->astOperand2()->valueType();
530     // If the sign is the same there is no truncation
531     if (vt1->sign == vt2->sign)
532         return value;
533     size_t n1 = ValueFlow::getSizeOf(*vt1, settings);
534     size_t n2 = ValueFlow::getSizeOf(*vt2, settings);
535     ValueType::Sign sign = ValueType::Sign::UNSIGNED;
536     if (n1 < n2)
537         sign = vt2->sign;
538     else if (n1 > n2)
539         sign = vt1->sign;
540     ValueFlow::Value v = castValue(value, sign, std::max(n1, n2) * 8);
541     v.wideintvalue = value.intvalue;
542     return v;
543 }
544 
545 /** set ValueFlow value and perform calculations if possible */
setTokenValue(Token * tok,ValueFlow::Value value,const Settings * settings)546 static void setTokenValue(Token* tok, ValueFlow::Value value, const Settings* settings)
547 {
548     // Skip setting values that are too big since its ambiguous
549     if (!value.isImpossible() && value.isIntValue() && value.intvalue < 0 && astIsUnsigned(tok) &&
550         ValueFlow::getSizeOf(*tok->valueType(), settings) >= sizeof(MathLib::bigint))
551         return;
552 
553     if (!value.isImpossible() && value.isIntValue())
554         value = truncateImplicitConversion(tok->astParent(), value, settings);
555 
556     if (!tok->addValue(value))
557         return;
558 
559     if (value.path < 0)
560         return;
561 
562     Token *parent = tok->astParent();
563     if (!parent)
564         return;
565 
566     if (Token::simpleMatch(parent, "=") && astIsRHS(tok) && !value.isLifetimeValue()) {
567         setTokenValue(parent, value, settings);
568         return;
569     }
570 
571     if (value.isContainerSizeValue()) {
572         // .empty, .size, +"abc", +'a'
573         if (Token::Match(parent, "+|==|!=") && parent->astOperand1() && parent->astOperand2()) {
574             for (const ValueFlow::Value &value1 : parent->astOperand1()->values()) {
575                 if (value1.isImpossible())
576                     continue;
577                 for (const ValueFlow::Value &value2 : parent->astOperand2()->values()) {
578                     if (value2.isImpossible())
579                         continue;
580                     if (value1.path != value2.path)
581                         continue;
582                     ValueFlow::Value result;
583                     if (Token::Match(parent, "%comp%"))
584                         result.valueType = ValueFlow::Value::ValueType::INT;
585                     else
586                         result.valueType = ValueFlow::Value::ValueType::CONTAINER_SIZE;
587 
588                     if (value1.isContainerSizeValue() && value2.isContainerSizeValue())
589                         result.intvalue = calculate(parent->str(), value1.intvalue, value2.intvalue);
590                     else if (value1.isContainerSizeValue() && value2.isTokValue() && value2.tokvalue->tokType() == Token::eString)
591                         result.intvalue = calculate(parent->str(), value1.intvalue, MathLib::bigint(Token::getStrLength(value2.tokvalue)));
592                     else if (value2.isContainerSizeValue() && value1.isTokValue() && value1.tokvalue->tokType() == Token::eString)
593                         result.intvalue = calculate(parent->str(), MathLib::bigint(Token::getStrLength(value1.tokvalue)), value2.intvalue);
594                     else
595                         continue;
596 
597                     combineValueProperties(value1, value2, &result);
598 
599                     if (Token::simpleMatch(parent, "==") && result.intvalue)
600                         continue;
601                     if (Token::simpleMatch(parent, "!=") && !result.intvalue)
602                         continue;
603 
604                     setTokenValue(parent, result, settings);
605                 }
606             }
607         }
608 
609         else if (Token::Match(parent, ". %name% (") && parent->astParent() == parent->tokAt(2) &&
610                  parent->astOperand1() && parent->astOperand1()->valueType()) {
611             const Library::Container *c = parent->astOperand1()->valueType()->container;
612             const Library::Container::Yield yields = c ? c->getYield(parent->strAt(1)) : Library::Container::Yield::NO_YIELD;
613             if (yields == Library::Container::Yield::SIZE) {
614                 ValueFlow::Value v(value);
615                 v.valueType = ValueFlow::Value::ValueType::INT;
616                 setTokenValue(parent->astParent(), v, settings);
617             } else if (yields == Library::Container::Yield::EMPTY) {
618                 ValueFlow::Value v(value);
619                 v.intvalue = !v.intvalue;
620                 v.valueType = ValueFlow::Value::ValueType::INT;
621                 setTokenValue(parent->astParent(), v, settings);
622             }
623         } else if (Token::Match(parent->previous(), "%name% (")) {
624             if (const Library::Function* f = settings->library.getFunction(parent->previous())) {
625                 if (f->containerYield == Library::Container::Yield::SIZE) {
626                     ValueFlow::Value v(value);
627                     v.valueType = ValueFlow::Value::ValueType::INT;
628                     setTokenValue(parent, v, settings);
629                 } else if (f->containerYield == Library::Container::Yield::EMPTY) {
630                     ValueFlow::Value v(value);
631                     v.intvalue = !v.intvalue;
632                     v.valueType = ValueFlow::Value::ValueType::INT;
633                     setTokenValue(parent, v, settings);
634                 }
635             }
636         }
637 
638         return;
639     }
640 
641     if (value.isLifetimeValue()) {
642         if (!isLifetimeBorrowed(parent, settings))
643             return;
644         if (value.lifetimeKind == ValueFlow::Value::LifetimeKind::Iterator && astIsIterator(parent)) {
645             setTokenValue(parent,value,settings);
646         } else if (astIsPointer(tok) && astIsPointer(parent) && !parent->isUnaryOp("*") &&
647                    (parent->isArithmeticalOp() || parent->isCast())) {
648             setTokenValue(parent,value,settings);
649         }
650         return;
651     }
652 
653     if (value.isUninitValue()) {
654         ValueFlow::Value pvalue = value;
655         if (parent->isUnaryOp("&")) {
656             pvalue.indirect++;
657             setTokenValue(parent, pvalue, settings);
658         } else if (Token::Match(parent, ". %var%") && parent->astOperand1() == tok) {
659             if (parent->originalName() == "->" && pvalue.indirect > 0)
660                 pvalue.indirect--;
661             setTokenValue(parent->astOperand2(), pvalue, settings);
662         } else if (Token::Match(parent->astParent(), ". %var%") && parent->astParent()->astOperand1() == parent) {
663             if (parent->astParent()->originalName() == "->" && pvalue.indirect > 0)
664                 pvalue.indirect--;
665             setTokenValue(parent->astParent()->astOperand2(), pvalue, settings);
666         } else if (parent->isUnaryOp("*") && pvalue.indirect > 0) {
667             pvalue.indirect--;
668             setTokenValue(parent, pvalue, settings);
669         }
670         return;
671     }
672 
673     // cast..
674     if (const Token *castType = getCastTypeStartToken(parent)) {
675         if (((tok->valueType() == nullptr && value.isImpossible()) || astIsPointer(tok)) &&
676             value.valueType == ValueFlow::Value::ValueType::INT &&
677             Token::simpleMatch(parent->astOperand1(), "dynamic_cast"))
678             return;
679         const ValueType &valueType = ValueType::parseDecl(castType, settings);
680         if (value.isImpossible() && value.isIntValue() && value.intvalue < 0 && astIsUnsigned(tok) &&
681             valueType.sign == ValueType::SIGNED && tok->valueType() &&
682             ValueFlow::getSizeOf(*tok->valueType(), settings) >= ValueFlow::getSizeOf(valueType, settings))
683             return;
684         setTokenValueCast(parent, valueType, value, settings);
685     }
686 
687     else if (parent->str() == ":") {
688         setTokenValue(parent,value,settings);
689     }
690 
691     else if (parent->str() == "?" && tok->str() == ":" && tok == parent->astOperand2() && parent->astOperand1()) {
692         // is condition always true/false?
693         if (parent->astOperand1()->hasKnownValue()) {
694             const ValueFlow::Value &condvalue = parent->astOperand1()->values().front();
695             const bool cond(condvalue.isTokValue() || (condvalue.isIntValue() && condvalue.intvalue != 0));
696             if (cond && !tok->astOperand1()) { // true condition, no second operator
697                 setTokenValue(parent, condvalue, settings);
698             } else {
699                 const Token *op = cond ? tok->astOperand1() : tok->astOperand2();
700                 if (!op) // #7769 segmentation fault at setTokenValue()
701                     return;
702                 const std::list<ValueFlow::Value> &values = op->values();
703                 if (std::find(values.begin(), values.end(), value) != values.end())
704                     setTokenValue(parent, value, settings);
705             }
706         } else if (!value.isImpossible()) {
707             // is condition only depending on 1 variable?
708             // cppcheck-suppress[variableScope] #8541
709             nonneg int varId = 0;
710             bool ret = false;
711             visitAstNodes(parent->astOperand1(),
712                           [&](const Token *t) {
713                 if (t->varId()) {
714                     if (varId > 0 || value.varId != 0)
715                         ret = true;
716                     varId = t->varId();
717                 } else if (t->str() == "(" && Token::Match(t->previous(), "%name%"))
718                     ret = true; // function call
719                 return ret ? ChildrenToVisit::done : ChildrenToVisit::op1_and_op2;
720             });
721             if (ret)
722                 return;
723 
724             ValueFlow::Value v(value);
725             v.conditional = true;
726             v.changeKnownToPossible();
727 
728             setTokenValue(parent, v, settings);
729         }
730     }
731 
732     else if (parent->str() == "?" && value.isIntValue() && tok == parent->astOperand1() && value.isKnown() &&
733              parent->astOperand2() && parent->astOperand2()->astOperand1() && parent->astOperand2()->astOperand2()) {
734         const std::list<ValueFlow::Value> &values = (value.intvalue == 0
735                 ? parent->astOperand2()->astOperand2()->values()
736                 : parent->astOperand2()->astOperand1()->values());
737 
738         for (const ValueFlow::Value &v : values)
739             setTokenValue(parent, v, settings);
740     }
741 
742     // Calculations..
743     else if ((parent->isArithmeticalOp() || parent->isComparisonOp() || (parent->tokType() == Token::eBitOp) || (parent->tokType() == Token::eLogicalOp)) &&
744              parent->astOperand1() &&
745              parent->astOperand2()) {
746 
747         const bool noninvertible = parent->isComparisonOp() || Token::Match(parent, "%|/|&|%or%");
748 
749         // Skip operators with impossible values that are not invertible
750         if (noninvertible && value.isImpossible())
751             return;
752 
753         // known result when a operand is 0.
754         if (Token::Match(parent, "[&*]") && value.isKnown() && value.isIntValue() && value.intvalue==0) {
755             setTokenValue(parent, value, settings);
756             return;
757         }
758 
759         // known result when a operand is true.
760         if (Token::simpleMatch(parent, "&&") && value.isKnown() && value.isIntValue() && value.intvalue==0) {
761             setTokenValue(parent, value, settings);
762             return;
763         }
764 
765         // known result when a operand is false.
766         if (Token::simpleMatch(parent, "||") && value.isKnown() && value.isIntValue() && value.intvalue!=0) {
767             setTokenValue(parent, value, settings);
768             return;
769         }
770 
771         for (const ValueFlow::Value &value1 : parent->astOperand1()->values()) {
772             if (!isComputableValue(parent, value1))
773                 continue;
774             for (const ValueFlow::Value &value2 : parent->astOperand2()->values()) {
775                 if (value1.path != value2.path)
776                     continue;
777                 if (!isComputableValue(parent, value2))
778                     continue;
779                 if (value1.isIteratorValue() && value2.isIteratorValue())
780                     continue;
781                 if (!isCompatibleValues(value1, value2))
782                     continue;
783                 ValueFlow::Value result(0);
784                 combineValueProperties(value1, value2, &result);
785                 if (astIsFloat(parent, false)) {
786                     if (!result.isIntValue() && !result.isFloatValue())
787                         continue;
788                     result.valueType = ValueFlow::Value::ValueType::FLOAT;
789                 }
790                 const double floatValue1 = value1.isFloatValue() ? value1.floatValue : value1.intvalue;
791                 const double floatValue2 = value2.isFloatValue() ? value2.floatValue : value2.intvalue;
792                 const MathLib::bigint intValue1 =
793                     value1.isFloatValue() ? static_cast<MathLib::bigint>(value1.floatValue) : value1.intvalue;
794                 const MathLib::bigint intValue2 =
795                     value2.isFloatValue() ? static_cast<MathLib::bigint>(value2.floatValue) : value2.intvalue;
796                 if ((value1.isFloatValue() || value2.isFloatValue()) && Token::Match(parent, "&|^|%|<<|>>|==|!=|%or%"))
797                     continue;
798                 if (Token::Match(parent, "==|!=")) {
799                     if ((value1.isIntValue() && value2.isTokValue()) || (value1.isTokValue() && value2.isIntValue())) {
800                         if (parent->str() == "==")
801                             result.intvalue = 0;
802                         else if (parent->str() == "!=")
803                             result.intvalue = 1;
804                     } else if (value1.isIntValue() && value2.isIntValue()) {
805                         bool error = false;
806                         result.intvalue = calculate(parent->str(), intValue1, intValue2, &error);
807                         if (error)
808                             continue;
809                     } else {
810                         continue;
811                     }
812                     setTokenValue(parent, result, settings);
813                 } else if (Token::Match(parent, "%op%")) {
814                     if (Token::Match(parent, "%comp%")) {
815                         if (!result.isFloatValue() && !value1.isIntValue() && !value2.isIntValue())
816                             continue;
817                     } else {
818                         if (value1.isTokValue() || value2.isTokValue())
819                             break;
820                     }
821                     bool error = false;
822                     if (result.isFloatValue()) {
823                         result.floatValue = calculate(parent->str(), floatValue1, floatValue2, &error);
824                     } else {
825                         result.intvalue = calculate(parent->str(), intValue1, intValue2, &error);
826                     }
827                     if (error)
828                         continue;
829                     // If the bound comes from the second value then invert the bound when subtracting
830                     if (Token::simpleMatch(parent, "-") && value2.bound == result.bound &&
831                         value2.bound != ValueFlow::Value::Bound::Point)
832                         result.invertBound();
833                     setTokenValue(parent, result, settings);
834                 }
835             }
836         }
837     }
838 
839     // !
840     else if (parent->str() == "!") {
841         for (const ValueFlow::Value &val : tok->values()) {
842             if (!val.isIntValue())
843                 continue;
844             if (val.isImpossible() && val.intvalue != 0)
845                 continue;
846             ValueFlow::Value v(val);
847             v.intvalue = !v.intvalue;
848             setTokenValue(parent, v, settings);
849         }
850     }
851 
852     // ~
853     else if (parent->str() == "~") {
854         for (const ValueFlow::Value &val : tok->values()) {
855             if (!val.isIntValue())
856                 continue;
857             ValueFlow::Value v(val);
858             v.intvalue = ~v.intvalue;
859             int bits = 0;
860             if (settings &&
861                 tok->valueType() &&
862                 tok->valueType()->sign == ValueType::Sign::UNSIGNED &&
863                 tok->valueType()->pointer == 0) {
864                 if (tok->valueType()->type == ValueType::Type::INT)
865                     bits = settings->int_bit;
866                 else if (tok->valueType()->type == ValueType::Type::LONG)
867                     bits = settings->long_bit;
868             }
869             if (bits > 0 && bits < MathLib::bigint_bits)
870                 v.intvalue &= (((MathLib::biguint)1)<<bits) - 1;
871             setTokenValue(parent, v, settings);
872         }
873     }
874 
875     // unary minus
876     else if (parent->isUnaryOp("-")) {
877         for (const ValueFlow::Value &val : tok->values()) {
878             if (!val.isIntValue() && !val.isFloatValue())
879                 continue;
880             ValueFlow::Value v(val);
881             if (v.isIntValue()) {
882                 if (v.intvalue == LLONG_MIN)
883                     // Value can't be inverted
884                     continue;
885                 v.intvalue = -v.intvalue;
886             } else
887                 v.floatValue = -v.floatValue;
888             v.invertBound();
889             setTokenValue(parent, v, settings);
890         }
891     }
892 
893     // increment
894     else if (parent->str() == "++") {
895         for (const ValueFlow::Value &val : tok->values()) {
896             if (!val.isIntValue() && !val.isFloatValue())
897                 continue;
898             ValueFlow::Value v(val);
899             if (parent == tok->previous()) {
900                 if (v.isIntValue())
901                     v.intvalue = v.intvalue + 1;
902                 else
903                     v.floatValue = v.floatValue + 1.0;
904             }
905             setTokenValue(parent, v, settings);
906         }
907     }
908 
909     // decrement
910     else if (parent->str() == "--") {
911         for (const ValueFlow::Value &val : tok->values()) {
912             if (!val.isIntValue() && !val.isFloatValue())
913                 continue;
914             ValueFlow::Value v(val);
915             if (parent == tok->previous()) {
916                 if (v.isIntValue())
917                     v.intvalue = v.intvalue - 1;
918                 else
919                     v.floatValue = v.floatValue - 1.0;
920             }
921             setTokenValue(parent, v, settings);
922         }
923     }
924 
925     // Array element
926     else if (parent->str() == "[" && parent->isBinaryOp()) {
927         for (const ValueFlow::Value &value1 : parent->astOperand1()->values()) {
928             if (!value1.isTokValue())
929                 continue;
930             for (const ValueFlow::Value &value2 : parent->astOperand2()->values()) {
931                 if (!value2.isIntValue())
932                     continue;
933                 if (value1.varId == 0 || value2.varId == 0 ||
934                     (value1.varId == value2.varId && value1.varvalue == value2.varvalue)) {
935                     ValueFlow::Value result(0);
936                     result.condition = value1.condition ? value1.condition : value2.condition;
937                     result.setInconclusive(value1.isInconclusive() | value2.isInconclusive());
938                     result.varId = (value1.varId != 0) ? value1.varId : value2.varId;
939                     result.varvalue = (result.varId == value1.varId) ? value1.intvalue : value2.intvalue;
940                     if (value1.valueKind == value2.valueKind)
941                         result.valueKind = value1.valueKind;
942                     if (value1.tokvalue->tokType() == Token::eString) {
943                         const std::string s = value1.tokvalue->strValue();
944                         const MathLib::bigint index = value2.intvalue;
945                         if (index == s.size()) {
946                             result.intvalue = 0;
947                             setTokenValue(parent, result, settings);
948                         } else if (index >= 0 && index < s.size()) {
949                             result.intvalue = s[index];
950                             setTokenValue(parent, result, settings);
951                         }
952                     } else if (value1.tokvalue->str() == "{") {
953                         MathLib::bigint index = value2.intvalue;
954                         const Token *element = value1.tokvalue->next();
955                         while (index > 0 && element->str() != "}") {
956                             if (element->str() == ",")
957                                 --index;
958                             if (Token::Match(element, "[{}()[]]"))
959                                 break;
960                             element = element->next();
961                         }
962                         if (Token::Match(element, "%num% [,}]")) {
963                             result.intvalue = MathLib::toLongNumber(element->str());
964                             setTokenValue(parent, result, settings);
965                         }
966                     }
967                 }
968             }
969         }
970     }
971 
972     else if (Token::Match(parent, ":: %name%") && parent->astOperand2() == tok) {
973         setTokenValue(parent, value, settings);
974     }
975 }
976 
setTokenValueCast(Token * parent,const ValueType & valueType,const ValueFlow::Value & value,const Settings * settings)977 static void setTokenValueCast(Token *parent, const ValueType &valueType, const ValueFlow::Value &value, const Settings *settings)
978 {
979     if (valueType.pointer || value.isImpossible())
980         setTokenValue(parent,value,settings);
981     else if (valueType.type == ValueType::Type::CHAR)
982         setTokenValue(parent, castValue(value, valueType.sign, settings->char_bit), settings);
983     else if (valueType.type == ValueType::Type::SHORT)
984         setTokenValue(parent, castValue(value, valueType.sign, settings->short_bit), settings);
985     else if (valueType.type == ValueType::Type::INT)
986         setTokenValue(parent, castValue(value, valueType.sign, settings->int_bit), settings);
987     else if (valueType.type == ValueType::Type::LONG)
988         setTokenValue(parent, castValue(value, valueType.sign, settings->long_bit), settings);
989     else if (valueType.type == ValueType::Type::LONGLONG)
990         setTokenValue(parent, castValue(value, valueType.sign, settings->long_long_bit), settings);
991     else if (valueType.isFloat() && isNumeric(value)) {
992         ValueFlow::Value floatValue = value;
993         floatValue.valueType = ValueFlow::Value::ValueType::FLOAT;
994         if (value.isIntValue())
995             floatValue.floatValue = value.intvalue;
996         setTokenValue(parent, floatValue, settings);
997     } else if (value.isIntValue()) {
998         const long long charMax = settings->signedCharMax();
999         const long long charMin = settings->signedCharMin();
1000         if (charMin <= value.intvalue && value.intvalue <= charMax) {
1001             // unknown type, but value is small so there should be no truncation etc
1002             setTokenValue(parent,value,settings);
1003         }
1004     }
1005 }
1006 
getSizeOfType(const Token * typeTok,const Settings * settings)1007 static nonneg int getSizeOfType(const Token *typeTok, const Settings *settings)
1008 {
1009     const ValueType &valueType = ValueType::parseDecl(typeTok, settings);
1010     if (valueType.pointer > 0)
1011         return settings->sizeof_pointer;
1012     if (valueType.type == ValueType::Type::BOOL || valueType.type == ValueType::Type::CHAR)
1013         return 1;
1014     if (valueType.type == ValueType::Type::SHORT)
1015         return settings->sizeof_short;
1016     if (valueType.type == ValueType::Type::INT)
1017         return settings->sizeof_int;
1018     if (valueType.type == ValueType::Type::LONG)
1019         return settings->sizeof_long;
1020     if (valueType.type == ValueType::Type::LONGLONG)
1021         return settings->sizeof_long_long;
1022     if (valueType.type == ValueType::Type::WCHAR_T)
1023         return settings->sizeof_wchar_t;
1024 
1025     return 0;
1026 }
1027 
getSizeOf(const ValueType & vt,const Settings * settings)1028 size_t ValueFlow::getSizeOf(const ValueType &vt, const Settings *settings)
1029 {
1030     if (vt.pointer)
1031         return settings->sizeof_pointer;
1032     if (vt.type == ValueType::Type::CHAR)
1033         return 1;
1034     if (vt.type == ValueType::Type::SHORT)
1035         return settings->sizeof_short;
1036     if (vt.type == ValueType::Type::WCHAR_T)
1037         return settings->sizeof_wchar_t;
1038     if (vt.type == ValueType::Type::INT)
1039         return settings->sizeof_int;
1040     if (vt.type == ValueType::Type::LONG)
1041         return settings->sizeof_long;
1042     if (vt.type == ValueType::Type::LONGLONG)
1043         return settings->sizeof_long_long;
1044     if (vt.type == ValueType::Type::FLOAT)
1045         return settings->sizeof_float;
1046     if (vt.type == ValueType::Type::DOUBLE)
1047         return settings->sizeof_double;
1048     if (vt.type == ValueType::Type::LONGDOUBLE)
1049         return settings->sizeof_long_double;
1050 
1051     return 0;
1052 }
1053 
1054 // Handle various constants..
valueFlowSetConstantValue(Token * tok,const Settings * settings,bool cpp)1055 static Token * valueFlowSetConstantValue(Token *tok, const Settings *settings, bool cpp)
1056 {
1057     if ((tok->isNumber() && MathLib::isInt(tok->str())) || (tok->tokType() == Token::eChar)) {
1058         try {
1059             ValueFlow::Value value(MathLib::toLongNumber(tok->str()));
1060             if (!tok->isTemplateArg())
1061                 value.setKnown();
1062             setTokenValue(tok, value, settings);
1063         } catch (const std::exception & /*e*/) {
1064             // Bad character literal
1065         }
1066     } else if (tok->isNumber() && MathLib::isFloat(tok->str())) {
1067         ValueFlow::Value value;
1068         value.valueType = ValueFlow::Value::ValueType::FLOAT;
1069         value.floatValue = MathLib::toDoubleNumber(tok->str());
1070         if (!tok->isTemplateArg())
1071             value.setKnown();
1072         setTokenValue(tok, value, settings);
1073     } else if (tok->enumerator() && tok->enumerator()->value_known) {
1074         ValueFlow::Value value(tok->enumerator()->value);
1075         if (!tok->isTemplateArg())
1076             value.setKnown();
1077         setTokenValue(tok, value, settings);
1078     } else if (tok->str() == "NULL" || (cpp && tok->str() == "nullptr")) {
1079         ValueFlow::Value value(0);
1080         if (!tok->isTemplateArg())
1081             value.setKnown();
1082         setTokenValue(tok, value, settings);
1083     } else if (Token::simpleMatch(tok, "sizeof (")) {
1084         if (tok->next()->astOperand2() && !tok->next()->astOperand2()->isLiteral() && tok->next()->astOperand2()->valueType() &&
1085             tok->next()->astOperand2()->valueType()->pointer == 0 && // <- TODO this is a bailout, abort when there are array->pointer conversions
1086             !tok->next()->astOperand2()->valueType()->isEnum()) { // <- TODO this is a bailout, handle enum with non-int types
1087             const size_t sz = ValueFlow::getSizeOf(*tok->next()->astOperand2()->valueType(), settings);
1088             if (sz) {
1089                 ValueFlow::Value value(sz);
1090                 value.setKnown();
1091                 setTokenValue(tok->next(), value, settings);
1092                 return tok->linkAt(1);
1093             }
1094         }
1095 
1096         const Token *tok2 = tok->tokAt(2);
1097         // skip over tokens to find variable or type
1098         while (Token::Match(tok2, "%name% ::|.|[")) {
1099             if (tok2->next()->str() == "[")
1100                 tok2 = tok2->linkAt(1)->next();
1101             else
1102                 tok2 = tok2->tokAt(2);
1103         }
1104         if (Token::simpleMatch(tok, "sizeof ( *")) {
1105             const ValueType *vt = tok->tokAt(2)->valueType();
1106             const size_t sz = vt ? ValueFlow::getSizeOf(*vt, settings) : 0;
1107             if (sz > 0) {
1108                 ValueFlow::Value value(sz);
1109                 if (!tok2->isTemplateArg() && settings->platformType != cppcheck::Platform::Unspecified)
1110                     value.setKnown();
1111                 setTokenValue(tok->next(), value, settings);
1112             }
1113         } else if (tok2->enumerator() && tok2->enumerator()->scope) {
1114             long long size = settings->sizeof_int;
1115             const Token * type = tok2->enumerator()->scope->enumType;
1116             if (type) {
1117                 size = getSizeOfType(type, settings);
1118                 if (size == 0)
1119                     tok->linkAt(1);
1120             }
1121             ValueFlow::Value value(size);
1122             if (!tok2->isTemplateArg() && settings->platformType != cppcheck::Platform::Unspecified)
1123                 value.setKnown();
1124             setTokenValue(tok, value, settings);
1125             setTokenValue(tok->next(), value, settings);
1126         } else if (tok2->type() && tok2->type()->isEnumType()) {
1127             long long size = settings->sizeof_int;
1128             if (tok2->type()->classScope) {
1129                 const Token * type = tok2->type()->classScope->enumType;
1130                 if (type) {
1131                     size = getSizeOfType(type, settings);
1132                 }
1133             }
1134             ValueFlow::Value value(size);
1135             if (!tok2->isTemplateArg() && settings->platformType != cppcheck::Platform::Unspecified)
1136                 value.setKnown();
1137             setTokenValue(tok, value, settings);
1138             setTokenValue(tok->next(), value, settings);
1139         } else if (Token::Match(tok, "sizeof ( %var% ) / sizeof (") && tok->next()->astParent() == tok->tokAt(4)) {
1140             // Get number of elements in array
1141             const Token *sz1 = tok->tokAt(2);
1142             const Token *sz2 = tok->tokAt(7);
1143             const nonneg int varid1 = sz1->varId();
1144             if (varid1 &&
1145                 sz1->variable() &&
1146                 sz1->variable()->isArray() &&
1147                 !sz1->variable()->dimensions().empty() &&
1148                 sz1->variable()->dimensionKnown(0) &&
1149                 (Token::Match(sz2, "* %varid% )", varid1) || Token::Match(sz2, "%varid% [ 0 ] )", varid1))) {
1150                 ValueFlow::Value value(sz1->variable()->dimension(0));
1151                 if (!tok2->isTemplateArg() && settings->platformType != cppcheck::Platform::Unspecified)
1152                     value.setKnown();
1153                 setTokenValue(tok->tokAt(4), value, settings);
1154             }
1155         } else if (Token::Match(tok2, "%var% )")) {
1156             const Variable *var = tok2->variable();
1157             // only look for single token types (no pointers or references yet)
1158             if (var && var->typeStartToken() == var->typeEndToken()) {
1159                 // find the size of the type
1160                 size_t size = 0;
1161                 if (var->isEnumType()) {
1162                     size = settings->sizeof_int;
1163                     if (var->type()->classScope && var->type()->classScope->enumType)
1164                         size = getSizeOfType(var->type()->classScope->enumType, settings);
1165                 } else if (var->valueType()) {
1166                     size = ValueFlow::getSizeOf(*var->valueType(), settings);
1167                 } else if (!var->type()) {
1168                     size = getSizeOfType(var->typeStartToken(), settings);
1169                 }
1170                 // find the number of elements
1171                 size_t count = 1;
1172                 for (size_t i = 0; i < var->dimensions().size(); ++i) {
1173                     if (var->dimensionKnown(i))
1174                         count *= var->dimension(i);
1175                     else
1176                         count = 0;
1177                 }
1178                 if (size && count > 0) {
1179                     ValueFlow::Value value(count * size);
1180                     if (settings->platformType != cppcheck::Platform::Unspecified)
1181                         value.setKnown();
1182                     setTokenValue(tok, value, settings);
1183                     setTokenValue(tok->next(), value, settings);
1184                 }
1185             }
1186         } else if (tok2->tokType() == Token::eString) {
1187             size_t sz = Token::getStrSize(tok2, settings);
1188             if (sz > 0) {
1189                 ValueFlow::Value value(sz);
1190                 value.setKnown();
1191                 setTokenValue(const_cast<Token *>(tok->next()), value, settings);
1192             }
1193         } else if (tok2->tokType() == Token::eChar) {
1194             nonneg int sz = 0;
1195             if (cpp && settings->standards.cpp >= Standards::CPP20 && tok2->isUtf8())
1196                 sz = 1;
1197             else if (tok2->isUtf16())
1198                 sz = 2;
1199             else if (tok2->isUtf32())
1200                 sz = 4;
1201             else if (tok2->isLong())
1202                 sz = settings->sizeof_wchar_t;
1203             else if ((tok2->isCChar() && !cpp) || (tok2->isCMultiChar()))
1204                 sz = settings->sizeof_int;
1205             else
1206                 sz = 1;
1207 
1208             if (sz > 0) {
1209                 ValueFlow::Value value(sz);
1210                 value.setKnown();
1211                 setTokenValue(tok->next(), value, settings);
1212             }
1213         } else if (!tok2->type()) {
1214             const ValueType &vt = ValueType::parseDecl(tok2,settings);
1215             const size_t sz = ValueFlow::getSizeOf(vt, settings);
1216             if (sz > 0) {
1217                 ValueFlow::Value value(sz);
1218                 if (!tok2->isTemplateArg() && settings->platformType != cppcheck::Platform::Unspecified)
1219                     value.setKnown();
1220                 setTokenValue(tok->next(), value, settings);
1221             }
1222         }
1223         // skip over enum
1224         tok = tok->linkAt(1);
1225     }
1226     return tok->next();
1227 }
1228 
1229 
valueFlowNumber(TokenList * tokenlist)1230 static void valueFlowNumber(TokenList *tokenlist)
1231 {
1232     for (Token *tok = tokenlist->front(); tok;) {
1233         tok = valueFlowSetConstantValue(tok, tokenlist->getSettings(), tokenlist->isCPP());
1234     }
1235 
1236     if (tokenlist->isCPP()) {
1237         for (Token *tok = tokenlist->front(); tok; tok = tok->next()) {
1238             if (tok->isName() && !tok->varId() && Token::Match(tok, "false|true")) {
1239                 ValueFlow::Value value(tok->str() == "true");
1240                 if (!tok->isTemplateArg())
1241                     value.setKnown();
1242                 setTokenValue(tok, value, tokenlist->getSettings());
1243             } else if (Token::Match(tok, "[(,] NULL [,)]")) {
1244                 // NULL function parameters are not simplified in the
1245                 // normal tokenlist
1246                 ValueFlow::Value value(0);
1247                 if (!tok->isTemplateArg())
1248                     value.setKnown();
1249                 setTokenValue(tok->next(), value, tokenlist->getSettings());
1250             }
1251         }
1252     }
1253 }
1254 
valueFlowString(TokenList * tokenlist)1255 static void valueFlowString(TokenList *tokenlist)
1256 {
1257     for (Token *tok = tokenlist->front(); tok; tok = tok->next()) {
1258         if (tok->tokType() == Token::eString) {
1259             ValueFlow::Value strvalue;
1260             strvalue.valueType = ValueFlow::Value::ValueType::TOK;
1261             strvalue.tokvalue = tok;
1262             strvalue.setKnown();
1263             setTokenValue(tok, strvalue, tokenlist->getSettings());
1264         }
1265     }
1266 }
1267 
valueFlowArray(TokenList * tokenlist)1268 static void valueFlowArray(TokenList *tokenlist)
1269 {
1270     std::map<nonneg int, const Token *> constantArrays;
1271 
1272     for (Token *tok = tokenlist->front(); tok; tok = tok->next()) {
1273         if (tok->varId() > 0) {
1274             // array
1275             const std::map<nonneg int, const Token *>::const_iterator it = constantArrays.find(tok->varId());
1276             if (it != constantArrays.end()) {
1277                 ValueFlow::Value value;
1278                 value.valueType = ValueFlow::Value::ValueType::TOK;
1279                 value.tokvalue = it->second;
1280                 value.setKnown();
1281                 setTokenValue(tok, value, tokenlist->getSettings());
1282             }
1283 
1284             // pointer = array
1285             else if (tok->variable() &&
1286                      tok->variable()->isArray() &&
1287                      Token::simpleMatch(tok->astParent(), "=") &&
1288                      tok == tok->astParent()->astOperand2() &&
1289                      tok->astParent()->astOperand1() &&
1290                      tok->astParent()->astOperand1()->variable() &&
1291                      tok->astParent()->astOperand1()->variable()->isPointer()) {
1292                 ValueFlow::Value value;
1293                 value.valueType = ValueFlow::Value::ValueType::TOK;
1294                 value.tokvalue = tok;
1295                 value.setKnown();
1296                 setTokenValue(tok, value, tokenlist->getSettings());
1297             }
1298             continue;
1299         }
1300 
1301         if (Token::Match(tok, "const %type% %var% [ %num%| ] = {")) {
1302             const Token *vartok = tok->tokAt(2);
1303             const Token *rhstok = vartok->next()->link()->tokAt(2);
1304             constantArrays[vartok->varId()] = rhstok;
1305             tok = rhstok->link();
1306             continue;
1307         }
1308 
1309         else if (Token::Match(tok, "const char %var% [ %num%| ] = %str% ;")) {
1310             const Token *vartok = tok->tokAt(2);
1311             const Token *strtok = vartok->next()->link()->tokAt(2);
1312             constantArrays[vartok->varId()] = strtok;
1313             tok = strtok->next();
1314             continue;
1315         }
1316     }
1317 }
1318 
isNonZero(const Token * tok)1319 static bool isNonZero(const Token *tok)
1320 {
1321     return tok && (!tok->hasKnownIntValue() || tok->values().front().intvalue != 0);
1322 }
1323 
getOtherOperand(const Token * tok)1324 static const Token *getOtherOperand(const Token *tok)
1325 {
1326     if (!tok)
1327         return nullptr;
1328     if (!tok->astParent())
1329         return nullptr;
1330     if (tok->astParent()->astOperand1() != tok)
1331         return tok->astParent()->astOperand1();
1332     if (tok->astParent()->astOperand2() != tok)
1333         return tok->astParent()->astOperand2();
1334     return nullptr;
1335 }
1336 
valueFlowArrayBool(TokenList * tokenlist)1337 static void valueFlowArrayBool(TokenList *tokenlist)
1338 {
1339     for (Token *tok = tokenlist->front(); tok; tok = tok->next()) {
1340         if (tok->hasKnownIntValue())
1341             continue;
1342         const Variable *var = nullptr;
1343         bool known = false;
1344         std::list<ValueFlow::Value>::const_iterator val =
1345             std::find_if(tok->values().begin(), tok->values().end(), std::mem_fn(&ValueFlow::Value::isTokValue));
1346         if (val == tok->values().end()) {
1347             var = tok->variable();
1348             known = true;
1349         } else {
1350             var = val->tokvalue->variable();
1351             known = val->isKnown();
1352         }
1353         if (!var)
1354             continue;
1355         if (!var->isArray() || var->isArgument() || var->isStlType())
1356             continue;
1357         if (isNonZero(getOtherOperand(tok)) && Token::Match(tok->astParent(), "%comp%"))
1358             continue;
1359         // TODO: Check for function argument
1360         if ((astIsBool(tok->astParent()) && !Token::Match(tok->astParent(), "(|%name%")) ||
1361             (tok->astParent() && Token::Match(tok->astParent()->previous(), "if|while|for ("))) {
1362             ValueFlow::Value value{1};
1363             if (known)
1364                 value.setKnown();
1365             setTokenValue(tok, value, tokenlist->getSettings());
1366         }
1367     }
1368 }
1369 
valueFlowPointerAlias(TokenList * tokenlist)1370 static void valueFlowPointerAlias(TokenList *tokenlist)
1371 {
1372     for (Token *tok = tokenlist->front(); tok; tok = tok->next()) {
1373         // not address of
1374         if (!tok->isUnaryOp("&"))
1375             continue;
1376 
1377         // parent should be a '='
1378         if (!Token::simpleMatch(tok->astParent(), "="))
1379             continue;
1380 
1381         // child should be some buffer or variable
1382         const Token *vartok = tok->astOperand1();
1383         while (vartok) {
1384             if (vartok->str() == "[")
1385                 vartok = vartok->astOperand1();
1386             else if (vartok->str() == "." || vartok->str() == "::")
1387                 vartok = vartok->astOperand2();
1388             else
1389                 break;
1390         }
1391         if (!(vartok && vartok->variable() && !vartok->variable()->isPointer()))
1392             continue;
1393 
1394         ValueFlow::Value value;
1395         value.valueType = ValueFlow::Value::ValueType::TOK;
1396         value.tokvalue = tok;
1397         setTokenValue(tok, value, tokenlist->getSettings());
1398     }
1399 }
1400 
valueFlowUninitPointerAliasDeref(TokenList * tokenlist)1401 static void valueFlowUninitPointerAliasDeref(TokenList *tokenlist)
1402 {
1403     for (Token *tok = tokenlist->front(); tok; tok = tok->next()) {
1404         if (!tok->isUnaryOp("*"))
1405             continue;
1406         if (!astIsPointer(tok->astOperand1()))
1407             continue;
1408 
1409         const Token* lifeTok = nullptr;
1410         ErrorPath errorPath;
1411         for (const ValueFlow::Value& v:tok->astOperand1()->values()) {
1412             if (!v.isLocalLifetimeValue())
1413                 continue;
1414             lifeTok = v.tokvalue;
1415             errorPath = v.errorPath;
1416         }
1417         if (!lifeTok)
1418             continue;
1419         if (lifeTok->varId() == 0)
1420             continue;
1421         const Variable * var = lifeTok->variable();
1422         if (!var)
1423             continue;
1424         if (!var->isConst() && isVariableChanged(lifeTok->next(), tok, lifeTok->varId(), !var->isLocal(), tokenlist->getSettings(), tokenlist->isCPP()))
1425             continue;
1426         for (const ValueFlow::Value& v:lifeTok->values()) {
1427             // Forward uninit values since not all values can be forwarded directly
1428             if (!v.isUninitValue())
1429                 continue;
1430             ValueFlow::Value value = v;
1431             value.errorPath.insert(value.errorPath.begin(), errorPath.begin(), errorPath.end());
1432             setTokenValue(tok, value, tokenlist->getSettings());
1433         }
1434     }
1435 }
1436 
valueFlowBitAnd(TokenList * tokenlist)1437 static void valueFlowBitAnd(TokenList *tokenlist)
1438 {
1439     for (Token *tok = tokenlist->front(); tok; tok = tok->next()) {
1440         if (tok->str() != "&")
1441             continue;
1442 
1443         if (tok->hasKnownValue())
1444             continue;
1445 
1446         if (!tok->astOperand1() || !tok->astOperand2())
1447             continue;
1448 
1449         MathLib::bigint number;
1450         if (MathLib::isInt(tok->astOperand1()->str()))
1451             number = MathLib::toLongNumber(tok->astOperand1()->str());
1452         else if (MathLib::isInt(tok->astOperand2()->str()))
1453             number = MathLib::toLongNumber(tok->astOperand2()->str());
1454         else
1455             continue;
1456 
1457         int bit = 0;
1458         while (bit <= (MathLib::bigint_bits - 2) && ((((MathLib::bigint)1) << bit) < number))
1459             ++bit;
1460 
1461         if ((((MathLib::bigint)1) << bit) == number) {
1462             setTokenValue(tok, ValueFlow::Value(0), tokenlist->getSettings());
1463             setTokenValue(tok, ValueFlow::Value(number), tokenlist->getSettings());
1464         }
1465     }
1466 }
1467 
valueFlowSameExpressions(TokenList * tokenlist)1468 static void valueFlowSameExpressions(TokenList *tokenlist)
1469 {
1470     for (Token *tok = tokenlist->front(); tok; tok = tok->next()) {
1471         if (tok->hasKnownIntValue())
1472             continue;
1473 
1474         if (!tok->astOperand1() || !tok->astOperand2())
1475             continue;
1476 
1477         if (tok->astOperand1()->isLiteral() || tok->astOperand2()->isLiteral())
1478             continue;
1479 
1480         if (!astIsIntegral(tok->astOperand1(), false) && !astIsIntegral(tok->astOperand2(), false))
1481             continue;
1482 
1483         ValueFlow::Value val;
1484 
1485         if (Token::Match(tok, "==|>=|<=|/")) {
1486             val = ValueFlow::Value(1);
1487             val.setKnown();
1488         }
1489 
1490         if (Token::Match(tok, "!=|>|<|%|-")) {
1491             val = ValueFlow::Value(0);
1492             val.setKnown();
1493         }
1494 
1495         if (!val.isKnown())
1496             continue;
1497 
1498         if (isSameExpression(tokenlist->isCPP(), false, tok->astOperand1(), tok->astOperand2(), tokenlist->getSettings()->library, true, true, &val.errorPath)) {
1499             setTokenValue(tok, val, tokenlist->getSettings());
1500         }
1501     }
1502 }
1503 
getExpressionRange(const Token * expr,MathLib::bigint * minvalue,MathLib::bigint * maxvalue)1504 static bool getExpressionRange(const Token *expr, MathLib::bigint *minvalue, MathLib::bigint *maxvalue)
1505 {
1506     if (expr->hasKnownIntValue()) {
1507         if (minvalue)
1508             *minvalue = expr->values().front().intvalue;
1509         if (maxvalue)
1510             *maxvalue = expr->values().front().intvalue;
1511         return true;
1512     }
1513 
1514     if (expr->str() == "&" && expr->astOperand1() && expr->astOperand2()) {
1515         MathLib::bigint vals[4];
1516         bool lhsHasKnownRange = getExpressionRange(expr->astOperand1(), &vals[0], &vals[1]);
1517         bool rhsHasKnownRange = getExpressionRange(expr->astOperand2(), &vals[2], &vals[3]);
1518         if (!lhsHasKnownRange && !rhsHasKnownRange)
1519             return false;
1520         if (!lhsHasKnownRange || !rhsHasKnownRange) {
1521             if (minvalue)
1522                 *minvalue = lhsHasKnownRange ? vals[0] : vals[2];
1523             if (maxvalue)
1524                 *maxvalue = lhsHasKnownRange ? vals[1] : vals[3];
1525         } else {
1526             if (minvalue)
1527                 *minvalue = vals[0] & vals[2];
1528             if (maxvalue)
1529                 *maxvalue = vals[1] & vals[3];
1530         }
1531         return true;
1532     }
1533 
1534     if (expr->str() == "%" && expr->astOperand1() && expr->astOperand2()) {
1535         MathLib::bigint vals[4];
1536         if (!getExpressionRange(expr->astOperand2(), &vals[2], &vals[3]))
1537             return false;
1538         if (vals[2] <= 0)
1539             return false;
1540         bool lhsHasKnownRange = getExpressionRange(expr->astOperand1(), &vals[0], &vals[1]);
1541         if (lhsHasKnownRange && vals[0] < 0)
1542             return false;
1543         // If lhs has unknown value, it must be unsigned
1544         if (!lhsHasKnownRange && (!expr->astOperand1()->valueType() || expr->astOperand1()->valueType()->sign != ValueType::Sign::UNSIGNED))
1545             return false;
1546         if (minvalue)
1547             *minvalue = 0;
1548         if (maxvalue)
1549             *maxvalue = vals[3] - 1;
1550         return true;
1551     }
1552 
1553     return false;
1554 }
1555 
valueFlowRightShift(TokenList * tokenList,const Settings * settings)1556 static void valueFlowRightShift(TokenList *tokenList, const Settings* settings)
1557 {
1558     for (Token *tok = tokenList->front(); tok; tok = tok->next()) {
1559         if (tok->str() != ">>")
1560             continue;
1561 
1562         if (tok->hasKnownValue())
1563             continue;
1564 
1565         if (!tok->astOperand1() || !tok->astOperand2())
1566             continue;
1567 
1568         if (!tok->astOperand2()->hasKnownValue())
1569             continue;
1570 
1571         const MathLib::bigint rhsvalue = tok->astOperand2()->values().front().intvalue;
1572         if (rhsvalue < 0)
1573             continue;
1574 
1575         if (!tok->astOperand1()->valueType() || !tok->astOperand1()->valueType()->isIntegral())
1576             continue;
1577 
1578         if (!tok->astOperand2()->valueType() || !tok->astOperand2()->valueType()->isIntegral())
1579             continue;
1580 
1581         MathLib::bigint lhsmax=0;
1582         if (!getExpressionRange(tok->astOperand1(), nullptr, &lhsmax))
1583             continue;
1584         if (lhsmax < 0)
1585             continue;
1586         int lhsbits;
1587         if ((tok->astOperand1()->valueType()->type == ValueType::Type::CHAR) ||
1588             (tok->astOperand1()->valueType()->type == ValueType::Type::SHORT) ||
1589             (tok->astOperand1()->valueType()->type == ValueType::Type::WCHAR_T) ||
1590             (tok->astOperand1()->valueType()->type == ValueType::Type::BOOL) ||
1591             (tok->astOperand1()->valueType()->type == ValueType::Type::INT))
1592             lhsbits = settings->int_bit;
1593         else if (tok->astOperand1()->valueType()->type == ValueType::Type::LONG)
1594             lhsbits = settings->long_bit;
1595         else if (tok->astOperand1()->valueType()->type == ValueType::Type::LONGLONG)
1596             lhsbits = settings->long_long_bit;
1597         else
1598             continue;
1599         if (rhsvalue >= lhsbits || rhsvalue >= MathLib::bigint_bits || (1ULL << rhsvalue) <= lhsmax)
1600             continue;
1601 
1602         ValueFlow::Value val(0);
1603         val.setKnown();
1604         setTokenValue(tok, val, tokenList->getSettings());
1605     }
1606 }
1607 
minUnsignedValue(const Token * tok,int depth=8)1608 static std::vector<MathLib::bigint> minUnsignedValue(const Token* tok, int depth = 8)
1609 {
1610     std::vector<MathLib::bigint> result = {};
1611     if (!tok)
1612         return result;
1613     if (depth < 0)
1614         return result;
1615     if (tok->hasKnownIntValue()) {
1616         result = {tok->values().front().intvalue};
1617     } else if (!Token::Match(tok, "-|%|&|^") && tok->isConstOp() && tok->astOperand1() && tok->astOperand2()) {
1618         std::vector<MathLib::bigint> op1 = minUnsignedValue(tok->astOperand1(), depth - 1);
1619         std::vector<MathLib::bigint> op2 = minUnsignedValue(tok->astOperand2(), depth - 1);
1620         if (!op1.empty() && !op2.empty()) {
1621             result = calculate<std::vector<MathLib::bigint>>(tok->str(), op1.front(), op2.front());
1622         }
1623     }
1624     if (result.empty() && astIsUnsigned(tok))
1625         result = {0};
1626     return result;
1627 }
1628 
valueFlowImpossibleValues(TokenList * tokenList,const Settings * settings)1629 static void valueFlowImpossibleValues(TokenList* tokenList, const Settings* settings)
1630 {
1631     for (Token* tok = tokenList->front(); tok; tok = tok->next()) {
1632         if (tok->hasKnownIntValue())
1633             continue;
1634         if (astIsUnsigned(tok) && !astIsPointer(tok)) {
1635             std::vector<MathLib::bigint> minvalue = minUnsignedValue(tok);
1636             if (minvalue.empty())
1637                 continue;
1638             ValueFlow::Value value{std::max<MathLib::bigint>(0, minvalue.front()) - 1};
1639             value.bound = ValueFlow::Value::Bound::Upper;
1640             value.setImpossible();
1641             setTokenValue(tok, value, settings);
1642         }
1643         if (Token::simpleMatch(tok, "%") && tok->astOperand2() && tok->astOperand2()->hasKnownIntValue()) {
1644             ValueFlow::Value value{tok->astOperand2()->values().front()};
1645             value.bound = ValueFlow::Value::Bound::Lower;
1646             value.setImpossible();
1647             setTokenValue(tok, value, settings);
1648         } else if (Token::Match(tok, "abs|labs|llabs|fabs|fabsf|fabsl (")) {
1649             ValueFlow::Value value{-1};
1650             value.bound = ValueFlow::Value::Bound::Upper;
1651             value.setImpossible();
1652             setTokenValue(tok->next(), value, settings);
1653         }
1654     }
1655 }
1656 
valueFlowEnumValue(SymbolDatabase * symboldatabase,const Settings * settings)1657 static void valueFlowEnumValue(SymbolDatabase * symboldatabase, const Settings * settings)
1658 {
1659 
1660     for (Scope & scope : symboldatabase->scopeList) {
1661         if (scope.type != Scope::eEnum)
1662             continue;
1663         MathLib::bigint value = 0;
1664         bool prev_enum_is_known = true;
1665 
1666         for (Enumerator & enumerator : scope.enumeratorList) {
1667             if (enumerator.start) {
1668                 Token *rhs = enumerator.start->previous()->astOperand2();
1669                 ValueFlow::valueFlowConstantFoldAST(rhs, settings);
1670                 if (rhs && rhs->hasKnownIntValue()) {
1671                     enumerator.value = rhs->values().front().intvalue;
1672                     enumerator.value_known = true;
1673                     value = enumerator.value + 1;
1674                     prev_enum_is_known = true;
1675                 } else
1676                     prev_enum_is_known = false;
1677             } else if (prev_enum_is_known) {
1678                 enumerator.value = value++;
1679                 enumerator.value_known = true;
1680             }
1681         }
1682     }
1683 }
1684 
valueFlowGlobalConstVar(TokenList * tokenList,const Settings * settings)1685 static void valueFlowGlobalConstVar(TokenList* tokenList, const Settings *settings)
1686 {
1687     // Get variable values...
1688     std::map<const Variable*, ValueFlow::Value> vars;
1689     for (const Token* tok = tokenList->front(); tok; tok = tok->next()) {
1690         if (!tok->variable())
1691             continue;
1692         // Initialization...
1693         if (tok == tok->variable()->nameToken() &&
1694             !tok->variable()->isVolatile() &&
1695             !tok->variable()->isArgument() &&
1696             tok->variable()->isConst() &&
1697             tok->valueType() &&
1698             tok->valueType()->isIntegral() &&
1699             tok->valueType()->pointer == 0 &&
1700             tok->valueType()->constness == 1 &&
1701             Token::Match(tok, "%name% =") &&
1702             tok->next()->astOperand2() &&
1703             tok->next()->astOperand2()->hasKnownIntValue()) {
1704             vars[tok->variable()] = tok->next()->astOperand2()->values().front();
1705         }
1706     }
1707 
1708     // Set values..
1709     for (Token* tok = tokenList->front(); tok; tok = tok->next()) {
1710         if (!tok->variable())
1711             continue;
1712         std::map<const Variable*, ValueFlow::Value>::const_iterator var = vars.find(tok->variable());
1713         if (var == vars.end())
1714             continue;
1715         setTokenValue(tok, var->second, settings);
1716     }
1717 }
1718 
valueFlowGlobalStaticVar(TokenList * tokenList,const Settings * settings)1719 static void valueFlowGlobalStaticVar(TokenList *tokenList, const Settings *settings)
1720 {
1721     // Get variable values...
1722     std::map<const Variable *, ValueFlow::Value> vars;
1723     for (const Token *tok = tokenList->front(); tok; tok = tok->next()) {
1724         if (!tok->variable())
1725             continue;
1726         // Initialization...
1727         if (tok == tok->variable()->nameToken() &&
1728             tok->variable()->isStatic() &&
1729             !tok->variable()->isConst() &&
1730             tok->valueType() &&
1731             tok->valueType()->isIntegral() &&
1732             tok->valueType()->pointer == 0 &&
1733             tok->valueType()->constness == 0 &&
1734             Token::Match(tok, "%name% =") &&
1735             tok->next()->astOperand2() &&
1736             tok->next()->astOperand2()->hasKnownIntValue()) {
1737             vars[tok->variable()] = tok->next()->astOperand2()->values().front();
1738         } else {
1739             // If variable is written anywhere in TU then remove it from vars
1740             if (!tok->astParent())
1741                 continue;
1742             if (Token::Match(tok->astParent(), "++|--|&") && !tok->astParent()->astOperand2())
1743                 vars.erase(tok->variable());
1744             else if (tok->astParent()->isAssignmentOp()) {
1745                 if (tok == tok->astParent()->astOperand1())
1746                     vars.erase(tok->variable());
1747                 else if (tokenList->isCPP() && Token::Match(tok->astParent()->tokAt(-2), "& %name% ="))
1748                     vars.erase(tok->variable());
1749             } else if (isLikelyStreamRead(tokenList->isCPP(), tok->astParent())) {
1750                 vars.erase(tok->variable());
1751             } else if (Token::Match(tok->astParent(), "[(,]"))
1752                 vars.erase(tok->variable());
1753         }
1754     }
1755 
1756     // Set values..
1757     for (Token *tok = tokenList->front(); tok; tok = tok->next()) {
1758         if (!tok->variable())
1759             continue;
1760         std::map<const Variable *, ValueFlow::Value>::const_iterator var = vars.find(tok->variable());
1761         if (var == vars.end())
1762             continue;
1763         setTokenValue(tok, var->second, settings);
1764     }
1765 }
1766 
1767 static Analyzer::Result valueFlowForward(Token* startToken,
1768                                          const Token* endToken,
1769                                          const Token* exprTok,
1770                                          std::list<ValueFlow::Value> values,
1771                                          TokenList* const tokenlist,
1772                                          const Settings* settings);
1773 
1774 static void valueFlowReverse(TokenList* tokenlist,
1775                              Token* tok,
1776                              const Token* const varToken,
1777                              ValueFlow::Value val,
1778                              ValueFlow::Value val2,
1779                              ErrorLogger* errorLogger,
1780                              const Settings* settings);
1781 
isConditionKnown(const Token * tok,bool then)1782 static bool isConditionKnown(const Token* tok, bool then)
1783 {
1784     const char* op = "||";
1785     if (then)
1786         op = "&&";
1787     const Token* parent = tok->astParent();
1788     while (parent && (parent->str() == op || parent->str() == "!"))
1789         parent = parent->astParent();
1790     return (parent && parent->str() == "(");
1791 }
1792 
invertAssign(const std::string & assign)1793 static const std::string& invertAssign(const std::string& assign)
1794 {
1795     static std::unordered_map<std::string, std::string> lookup = {{"=", "="},
1796         {"+=", "-="},
1797         {"-=", "+="},
1798         {"*=", "/="},
1799         {"/=", "*="},
1800         {"<<=", ">>="},
1801         {">>=", "<<="},
1802         {"^=", "^="}};
1803     static std::string empty;
1804     auto it = lookup.find(assign);
1805     if (it == lookup.end())
1806         return empty;
1807     else
1808         return it->second;
1809 }
1810 
removeAssign(const std::string & assign)1811 static std::string removeAssign(const std::string& assign) {
1812     return std::string{assign.begin(), assign.end() - 1};
1813 }
1814 
1815 template<class T, class U>
calculateAssign(const std::string & assign,const T & x,const U & y,bool * error=nullptr)1816 static T calculateAssign(const std::string& assign, const T& x, const U& y, bool* error = nullptr)
1817 {
1818     if (assign.empty() || assign.back() != '=') {
1819         if (error)
1820             *error = true;
1821         return T{};
1822     }
1823     if (assign == "=")
1824         return y;
1825     return calculate<T, T>(removeAssign(assign), x, y, error);
1826 }
1827 
1828 template<class T, class U>
assignValueIfMutable(T & x,const U & y)1829 static void assignValueIfMutable(T& x, const U& y)
1830 {
1831     x = y;
1832 }
1833 
1834 template<class T, class U>
assignValueIfMutable(const T &,const U &)1835 static void assignValueIfMutable(const T&, const U&)
1836 {}
1837 
1838 template<class Value, REQUIRES("Value must ValueFlow::Value", std::is_convertible<Value&, const ValueFlow::Value&> )>
evalAssignment(Value & lhsValue,const std::string & assign,const ValueFlow::Value & rhsValue)1839 static bool evalAssignment(Value& lhsValue, const std::string& assign, const ValueFlow::Value& rhsValue)
1840 {
1841     bool error = false;
1842     if (lhsValue.isSymbolicValue() && rhsValue.isIntValue()) {
1843         if (assign != "+=" && assign != "-=")
1844             return false;
1845         assignValueIfMutable(lhsValue.intvalue, calculateAssign(assign, lhsValue.intvalue, rhsValue.intvalue, &error));
1846     } else if (lhsValue.isIntValue() && rhsValue.isIntValue()) {
1847         assignValueIfMutable(lhsValue.intvalue, calculateAssign(assign, lhsValue.intvalue, rhsValue.intvalue, &error));
1848     } else if (lhsValue.isFloatValue() && rhsValue.isIntValue()) {
1849         assignValueIfMutable(lhsValue.floatValue,
1850                              calculateAssign(assign, lhsValue.floatValue, rhsValue.intvalue, &error));
1851     } else {
1852         return false;
1853     }
1854     return !error;
1855 }
1856 
1857 template<class T>
1858 struct SingleRange {
1859     T* x;
beginSingleRange1860     T* begin() const {
1861         return x;
1862     }
endSingleRange1863     T* end() const {
1864         return x+1;
1865     }
1866 };
1867 
1868 template<class T>
MakeSingleRange(T & x)1869 SingleRange<T> MakeSingleRange(T& x)
1870 {
1871     return {&x};
1872 }
1873 
1874 class SelectValueFromVarIdMapRange {
1875     using M = std::unordered_map<nonneg int, ValueFlow::Value>;
1876 
1877     struct Iterator {
1878         using iterator_category = std::forward_iterator_tag;
1879         using value_type = const ValueFlow::Value;
1880         using pointer = value_type *;
1881         using reference = value_type &;
1882 
IteratorSelectValueFromVarIdMapRange::Iterator1883         explicit Iterator(const M::const_iterator &it)
1884             : mIt(it) {}
1885 
operator *SelectValueFromVarIdMapRange::Iterator1886         reference operator*() const {
1887             return mIt->second;
1888         }
1889 
operator ->SelectValueFromVarIdMapRange::Iterator1890         pointer operator->() {
1891             return &mIt->second;
1892         }
1893 
operator ++SelectValueFromVarIdMapRange::Iterator1894         Iterator &operator++() {
1895             // cppcheck-suppress postfixOperator - forward iterator needs to perform post-increment
1896             mIt++;
1897             return *this;
1898         }
1899 
operator ==(const Iterator & a,const Iterator & b)1900         friend bool operator==(const Iterator &a, const Iterator &b) {
1901             return a.mIt == b.mIt;
1902         }
1903 
operator !=(const Iterator & a,const Iterator & b)1904         friend bool operator!=(const Iterator &a, const Iterator &b) {
1905             return a.mIt != b.mIt;
1906         }
1907 
1908     private:
1909         M::const_iterator mIt;
1910     };
1911 
1912 public:
SelectValueFromVarIdMapRange(const M * m)1913     explicit SelectValueFromVarIdMapRange(const M *m)
1914         : mMap(m) {}
1915 
begin() const1916     Iterator begin() const {
1917         return Iterator(mMap->begin());
1918     }
end() const1919     Iterator end() const {
1920         return Iterator(mMap->end());
1921     }
1922 
1923 private:
1924     const M *mMap;
1925 };
1926 
1927 // Check if its an alias of the variable or is being aliased to this variable
1928 template<typename V>
isAliasOf(const Variable * var,const Token * tok,nonneg int varid,const V & values,bool * inconclusive=nullptr)1929 static bool isAliasOf(const Variable * var, const Token *tok, nonneg int varid, const V& values, bool* inconclusive = nullptr)
1930 {
1931     if (tok->varId() == varid)
1932         return false;
1933     if (tok->varId() == 0)
1934         return false;
1935     if (isAliasOf(tok, varid, inconclusive))
1936         return true;
1937     if (var && !var->isPointer())
1938         return false;
1939     // Search through non value aliases
1940     for (const ValueFlow::Value &val : values) {
1941         if (!val.isNonValue())
1942             continue;
1943         if (val.isInconclusive())
1944             continue;
1945         if (val.isLifetimeValue() && !val.isLocalLifetimeValue())
1946             continue;
1947         if (val.isLifetimeValue() && val.lifetimeKind != ValueFlow::Value::LifetimeKind::Address)
1948             continue;
1949         if (!Token::Match(val.tokvalue, ".|&|*|%var%"))
1950             continue;
1951         if (astHasVar(val.tokvalue, tok->varId()))
1952             return true;
1953     }
1954     return false;
1955 }
1956 
1957 static bool bifurcate(const Token* tok, const std::set<nonneg int>& varids, const Settings* settings, int depth = 20);
1958 
bifurcateVariableChanged(const Variable * var,const std::set<nonneg int> & varids,const Token * start,const Token * end,const Settings * settings,int depth=20)1959 static bool bifurcateVariableChanged(const Variable* var,
1960                                      const std::set<nonneg int>& varids,
1961                                      const Token* start,
1962                                      const Token* end,
1963                                      const Settings* settings,
1964                                      int depth = 20)
1965 {
1966     bool result = false;
1967     const Token* tok = start;
1968     while ((tok = findVariableChanged(
1969                 tok->next(), end, var->isPointer(), var->declarationId(), var->isGlobal(), settings, true))) {
1970         if (Token::Match(tok->astParent(), "%assign%")) {
1971             if (!bifurcate(tok->astParent()->astOperand2(), varids, settings, depth - 1))
1972                 return true;
1973         } else {
1974             result = true;
1975         }
1976     }
1977     return result;
1978 }
1979 
bifurcate(const Token * tok,const std::set<nonneg int> & varids,const Settings * settings,int depth)1980 static bool bifurcate(const Token* tok, const std::set<nonneg int>& varids, const Settings* settings, int depth)
1981 {
1982     if (depth < 0)
1983         return false;
1984     if (!tok)
1985         return true;
1986     if (tok->hasKnownIntValue())
1987         return true;
1988     if (Token::Match(tok, "%cop%"))
1989         return bifurcate(tok->astOperand1(), varids, settings, depth) && bifurcate(tok->astOperand2(), varids, settings, depth);
1990     if (Token::Match(tok, "%var%")) {
1991         if (varids.count(tok->varId()) > 0)
1992             return true;
1993         const Variable* var = tok->variable();
1994         if (!var)
1995             return false;
1996         const Token* start = var->declEndToken();
1997         if (!start)
1998             return false;
1999         if (start->strAt(-1) == ")" || start->strAt(-1) == "}")
2000             return false;
2001         if (Token::Match(start, "; %varid% =", var->declarationId()))
2002             start = start->tokAt(2);
2003         if (var->isConst() || !bifurcateVariableChanged(var, varids, start, tok, settings, depth))
2004             return var->isArgument() || bifurcate(start->astOperand2(), varids, settings, depth - 1);
2005         return false;
2006     }
2007     return false;
2008 }
2009 
2010 struct ValueFlowAnalyzer : Analyzer {
2011     const TokenList* tokenlist;
2012     ProgramMemoryState pms;
2013 
ValueFlowAnalyzerValueFlowAnalyzer2014     ValueFlowAnalyzer() : tokenlist(nullptr), pms(nullptr) {}
2015 
ValueFlowAnalyzerValueFlowAnalyzer2016     explicit ValueFlowAnalyzer(const TokenList* t) : tokenlist(t), pms(tokenlist->getSettings()) {}
2017 
2018     virtual const ValueFlow::Value* getValue(const Token* tok) const = 0;
2019     virtual ValueFlow::Value* getValue(const Token* tok) = 0;
2020 
2021     virtual void makeConditional() = 0;
2022 
2023     virtual void addErrorPath(const Token* tok, const std::string& s) = 0;
2024 
2025     virtual bool match(const Token* tok) const = 0;
2026 
2027     virtual bool isAlias(const Token* tok, bool& inconclusive) const = 0;
2028 
2029     using ProgramState = std::unordered_map<nonneg int, ValueFlow::Value>;
2030 
2031     virtual ProgramState getProgramState() const = 0;
2032 
getValueTypeValueFlowAnalyzer2033     virtual const ValueType* getValueType(const Token*) const {
2034         return nullptr;
2035     }
getIndirectValueFlowAnalyzer2036     virtual int getIndirect(const Token* tok) const {
2037         const ValueFlow::Value* value = getValue(tok);
2038         if (value)
2039             return value->indirect;
2040         return 0;
2041     }
2042 
isGlobalValueFlowAnalyzer2043     virtual bool isGlobal() const {
2044         return false;
2045     }
dependsOnThisValueFlowAnalyzer2046     virtual bool dependsOnThis() const {
2047         return false;
2048     }
2049 
invalidValueFlowAnalyzer2050     virtual bool invalid() const {
2051         return false;
2052     }
2053 
isCPPValueFlowAnalyzer2054     bool isCPP() const {
2055         return tokenlist->isCPP();
2056     }
2057 
getSettingsValueFlowAnalyzer2058     const Settings* getSettings() const {
2059         return tokenlist->getSettings();
2060     }
2061 
2062     struct ConditionState {
2063         bool dependent = true;
2064         bool unknown = true;
2065 
isUnknownDependentValueFlowAnalyzer::ConditionState2066         bool isUnknownDependent() const {
2067             return unknown && dependent;
2068         }
2069     };
2070 
getSymbolsValueFlowAnalyzer2071     std::unordered_map<nonneg int, const Token*> getSymbols(const Token* tok) const
2072     {
2073         std::unordered_map<nonneg int, const Token*> result;
2074         if (!tok)
2075             return result;
2076         for (const ValueFlow::Value& v : tok->values()) {
2077             if (!v.isSymbolicValue())
2078                 continue;
2079             if (v.isImpossible())
2080                 continue;
2081             if (!v.tokvalue)
2082                 continue;
2083             if (v.tokvalue->exprId() == 0)
2084                 continue;
2085             if (match(v.tokvalue))
2086                 continue;
2087             result[v.tokvalue->exprId()] = v.tokvalue;
2088         }
2089         return result;
2090     }
2091 
analyzeConditionValueFlowAnalyzer2092     ConditionState analyzeCondition(const Token* tok, int depth = 20) const
2093     {
2094         ConditionState result;
2095         if (!tok)
2096             return result;
2097         if (depth < 0)
2098             return result;
2099         depth--;
2100         if (analyze(tok, Direction::Forward).isRead()) {
2101             result.dependent = true;
2102             result.unknown = false;
2103             return result;
2104         } else if (tok->hasKnownIntValue() || tok->isLiteral()) {
2105             result.dependent = false;
2106             result.unknown = false;
2107             return result;
2108         } else if (Token::Match(tok, "%cop%")) {
2109             if (isLikelyStream(isCPP(), tok->astOperand1())) {
2110                 result.dependent = false;
2111                 return result;
2112             }
2113             ConditionState lhs = analyzeCondition(tok->astOperand1(), depth - 1);
2114             if (lhs.isUnknownDependent())
2115                 return lhs;
2116             ConditionState rhs = analyzeCondition(tok->astOperand2(), depth - 1);
2117             if (rhs.isUnknownDependent())
2118                 return rhs;
2119             if (Token::Match(tok, "%comp%"))
2120                 result.dependent = lhs.dependent && rhs.dependent;
2121             else
2122                 result.dependent = lhs.dependent || rhs.dependent;
2123             result.unknown = lhs.unknown || rhs.unknown;
2124             return result;
2125         } else if (Token::Match(tok->previous(), "%name% (")) {
2126             std::vector<const Token*> args = getArguments(tok->previous());
2127             if (Token::Match(tok->tokAt(-2), ". %name% (")) {
2128                 args.push_back(tok->tokAt(-2)->astOperand1());
2129             }
2130             result.dependent = std::any_of(args.begin(), args.end(), [&](const Token* arg) {
2131                 ConditionState cs = analyzeCondition(arg, depth - 1);
2132                 return cs.dependent;
2133             });
2134             if (result.dependent) {
2135                 // Check if we can evaluate the function
2136                 if (!evaluate(Evaluate::Integral, tok).empty())
2137                     result.unknown = false;
2138             }
2139             return result;
2140         } else {
2141             std::unordered_map<nonneg int, const Token*> symbols = getSymbols(tok);
2142             result.dependent = false;
2143             for (auto&& p : symbols) {
2144                 const Token* arg = p.second;
2145                 ConditionState cs = analyzeCondition(arg, depth - 1);
2146                 result.dependent = cs.dependent;
2147                 if (result.dependent)
2148                     break;
2149             }
2150             if (result.dependent) {
2151                 // Check if we can evaluate the token
2152                 if (!evaluate(Evaluate::Integral, tok).empty())
2153                     result.unknown = false;
2154             }
2155             return result;
2156         }
2157     }
2158 
isModifiedValueFlowAnalyzer2159     virtual Action isModified(const Token* tok) const {
2160         Action read = Action::Read;
2161         bool inconclusive = false;
2162         if (isVariableChangedByFunctionCall(tok, getIndirect(tok), getSettings(), &inconclusive))
2163             return read | Action::Invalid;
2164         if (inconclusive)
2165             return read | Action::Inconclusive;
2166         if (isVariableChanged(tok, getIndirect(tok), getSettings(), isCPP())) {
2167             if (Token::Match(tok->astParent(), "*|[|.|++|--"))
2168                 return read | Action::Invalid;
2169             const ValueFlow::Value* value = getValue(tok);
2170             // Check if its assigned to the same value
2171             if (value && !value->isImpossible() && Token::simpleMatch(tok->astParent(), "=") && astIsLHS(tok) &&
2172                 astIsIntegral(tok->astParent()->astOperand2(), false)) {
2173                 std::vector<int> result = evaluate(Evaluate::Integral, tok->astParent()->astOperand2());
2174                 if (!result.empty() && value->equalTo(result.front()))
2175                     return Action::Idempotent;
2176             }
2177             return Action::Invalid;
2178         }
2179         return read;
2180     }
2181 
isAliasModifiedValueFlowAnalyzer2182     virtual Action isAliasModified(const Token* tok) const {
2183         // Lambda function call
2184         if (Token::Match(tok, "%var% ("))
2185             // TODO: Check if modified in the lambda function
2186             return Action::Invalid;
2187         int indirect = 0;
2188         if (tok->valueType())
2189             indirect = tok->valueType()->pointer;
2190         if (isVariableChanged(tok, indirect, getSettings(), isCPP()))
2191             return Action::Invalid;
2192         return Action::None;
2193     }
2194 
isThisModifiedValueFlowAnalyzer2195     virtual Action isThisModified(const Token* tok) const {
2196         if (isThisChanged(tok, 0, getSettings(), isCPP()))
2197             return Action::Invalid;
2198         return Action::None;
2199     }
2200 
getAssignValueFlowAnalyzer2201     static const std::string& getAssign(const Token* tok, Direction d)
2202     {
2203         if (d == Direction::Forward)
2204             return tok->str();
2205         else
2206             return invertAssign(tok->str());
2207     }
2208 
isWritableValueFlowAnalyzer2209     virtual Action isWritable(const Token* tok, Direction d) const {
2210         const ValueFlow::Value* value = getValue(tok);
2211         if (!value)
2212             return Action::None;
2213         if (!(value->isIntValue() || value->isFloatValue() || value->isSymbolicValue()))
2214             return Action::None;
2215         const Token* parent = tok->astParent();
2216         // Only if its invertible
2217         if (value->isImpossible() && !Token::Match(parent, "+=|-=|*=|++|--"))
2218             return Action::None;
2219 
2220         if (parent && parent->isAssignmentOp() && astIsLHS(tok) &&
2221             parent->astOperand2()->hasKnownValue()) {
2222             const Token* rhs = parent->astOperand2();
2223             const ValueFlow::Value* rhsValue = rhs->getKnownValue(ValueFlow::Value::ValueType::INT);
2224             Action a;
2225             if (!rhsValue || !evalAssignment(*value, getAssign(parent, d), *rhsValue))
2226                 a = Action::Invalid;
2227             else
2228                 a = Action::Write;
2229             if (parent->str() != "=") {
2230                 a |= Action::Read;
2231             } else {
2232                 if (rhsValue && !value->isImpossible() && value->equalValue(*rhsValue))
2233                     a = Action::Idempotent;
2234                 a |= Action::Incremental;
2235             }
2236             return a;
2237         }
2238 
2239         // increment/decrement
2240         if (Token::Match(tok->astParent(), "++|--")) {
2241             return Action::Read | Action::Write | Action::Incremental;
2242         }
2243         return Action::None;
2244     }
2245 
writeValueValueFlowAnalyzer2246     virtual void writeValue(ValueFlow::Value* value, const Token* tok, Direction d) const {
2247         if (!value)
2248             return;
2249         if (!tok->astParent())
2250             return;
2251         if (tok->astParent()->isAssignmentOp()) {
2252             const ValueFlow::Value* rhsValue =
2253                 tok->astParent()->astOperand2()->getKnownValue(ValueFlow::Value::ValueType::INT);
2254             assert(rhsValue);
2255             if (evalAssignment(*value, getAssign(tok->astParent(), d), *rhsValue)) {
2256                 const std::string info("Compound assignment '" + tok->astParent()->str() + "', assigned value is " +
2257                                        value->infoString());
2258                 if (tok->astParent()->str() == "=")
2259                     value->errorPath.clear();
2260                 value->errorPath.emplace_back(tok, info);
2261             } else {
2262                 assert(false && "Writable value cannot be evaluated");
2263                 // TODO: Don't set to zero
2264                 value->intvalue = 0;
2265             }
2266         } else if (tok->astParent()->tokType() == Token::eIncDecOp) {
2267             bool inc = tok->astParent()->str() == "++";
2268             std::string opName(inc ? "incremented" : "decremented");
2269             if (d == Direction::Reverse)
2270                 inc = !inc;
2271             value->intvalue += (inc ? 1 : -1);
2272             const std::string info(tok->str() + " is " + opName + "', new value is " + value->infoString());
2273             value->errorPath.emplace_back(tok, info);
2274         }
2275     }
2276 
useSymbolicValuesValueFlowAnalyzer2277     virtual bool useSymbolicValues() const {
2278         return true;
2279     }
2280 
isSameSymbolicValueValueFlowAnalyzer2281     bool isSameSymbolicValue(const Token* tok, ErrorPath* errorPath = nullptr) const
2282     {
2283         if (!useSymbolicValues())
2284             return false;
2285         for (const ValueFlow::Value& v : tok->values()) {
2286             if (!v.isSymbolicValue())
2287                 continue;
2288             if (!v.isKnown())
2289                 continue;
2290             if (v.intvalue != 0)
2291                 continue;
2292             if (match(v.tokvalue)) {
2293                 if (errorPath)
2294                     errorPath->insert(errorPath->end(), v.errorPath.begin(), v.errorPath.end());
2295                 return true;
2296             }
2297         }
2298         return false;
2299     }
2300 
analyzeMatchValueFlowAnalyzer2301     Action analyzeMatch(const Token* tok, Direction d) const {
2302         const Token* parent = tok->astParent();
2303         if (astIsPointer(tok) && (Token::Match(parent, "*|[") || (parent && parent->originalName() == "->")) && getIndirect(tok) <= 0)
2304             return Action::Read;
2305 
2306         Action w = isWritable(tok, d);
2307         if (w != Action::None)
2308             return w;
2309 
2310         // Check for modifications by function calls
2311         return isModified(tok);
2312     }
2313 
analyzeTokenValueFlowAnalyzer2314     Action analyzeToken(const Token* ref, const Token* tok, Direction d, bool inconclusiveRef) const {
2315         if (!ref)
2316             return Action::None;
2317         // If its an inconclusiveRef then ref != tok
2318         assert(!inconclusiveRef || ref != tok);
2319         bool inconclusive = false;
2320         if (match(ref)) {
2321             if (inconclusiveRef) {
2322                 Action a = isModified(tok);
2323                 if (a.isModified() || a.isInconclusive())
2324                     return Action::Inconclusive;
2325             } else {
2326                 return analyzeMatch(tok, d) | Action::Match;
2327             }
2328         } else if (ref->isUnaryOp("*")) {
2329             const Token* lifeTok = nullptr;
2330             for (const ValueFlow::Value& v:ref->astOperand1()->values()) {
2331                 if (!v.isLocalLifetimeValue())
2332                     continue;
2333                 if (lifeTok)
2334                     return Action::None;
2335                 lifeTok = v.tokvalue;
2336             }
2337             if (lifeTok && match(lifeTok)) {
2338                 Action a = Action::Read;
2339                 if (isModified(tok).isModified())
2340                     a = Action::Invalid;
2341                 if (Token::Match(tok->astParent(), "%assign%") && astIsLHS(tok))
2342                     a |= Action::Invalid;
2343                 if (inconclusiveRef && a.isModified())
2344                     return Action::Inconclusive;
2345                 return a;
2346             }
2347             return Action::None;
2348 
2349         } else if (isAlias(ref, inconclusive)) {
2350             inconclusive |= inconclusiveRef;
2351             Action a = isAliasModified(tok);
2352             if (inconclusive && a.isModified())
2353                 return Action::Inconclusive;
2354             else
2355                 return a;
2356         } else if (isSameSymbolicValue(ref)) {
2357             return Action::Read | Action::SymbolicMatch;
2358         }
2359         return Action::None;
2360     }
2361 
analyzeValueFlowAnalyzer2362     virtual Action analyze(const Token* tok, Direction d) const OVERRIDE {
2363         if (invalid())
2364             return Action::Invalid;
2365         // Follow references
2366         std::vector<ReferenceToken> refs = followAllReferences(tok);
2367         const bool inconclusiveRefs = refs.size() != 1;
2368         for (const ReferenceToken& ref:refs) {
2369             Action a = analyzeToken(ref.token, tok, d, inconclusiveRefs);
2370             if (a != Action::None)
2371                 return a;
2372         }
2373 
2374         if (dependsOnThis() && exprDependsOnThis(tok))
2375             return isThisModified(tok);
2376 
2377         // bailout: global non-const variables
2378         if (isGlobal() && Token::Match(tok, "%name% (") && !Token::simpleMatch(tok->linkAt(1), ") {")) {
2379             if (tok->function()) {
2380                 if (!tok->function()->isConstexpr() && !isConstFunctionCall(tok, getSettings()->library))
2381                     return Action::Invalid;
2382             } else if (getSettings()->library.getFunction(tok)) {
2383                 // Assume library function doesn't modify user-global variables
2384                 return Action::None;
2385             } else {
2386                 return Action::Invalid;
2387             }
2388         }
2389         return Action::None;
2390     }
2391 
evaluateValueFlowAnalyzer2392     virtual std::vector<int> evaluate(Evaluate e, const Token* tok, const Token* ctx = nullptr) const OVERRIDE {
2393         if (e == Evaluate::Integral) {
2394             if (tok->hasKnownIntValue())
2395                 return {static_cast<int>(tok->values().front().intvalue)};
2396             std::vector<int> result;
2397             ProgramMemory pm = pms.get(tok, ctx, getProgramState());
2398             if (Token::Match(tok, "&&|%oror%")) {
2399                 if (conditionIsTrue(tok, pm))
2400                     result.push_back(1);
2401                 if (conditionIsFalse(tok, pm))
2402                     result.push_back(0);
2403             } else {
2404                 MathLib::bigint out = 0;
2405                 bool error = false;
2406                 execute(tok, &pm, &out, &error);
2407                 if (!error)
2408                     result.push_back(out);
2409             }
2410 
2411             return result;
2412         } else if (e == Evaluate::ContainerEmpty) {
2413             const ValueFlow::Value* value = ValueFlow::findValue(tok->values(), nullptr, [](const ValueFlow::Value& v) {
2414                 return v.isKnown() && v.isContainerSizeValue();
2415             });
2416             if (value)
2417                 return {value->intvalue == 0};
2418             ProgramMemory pm = pms.get(tok, ctx, getProgramState());
2419             MathLib::bigint out = 0;
2420             if (pm.getContainerEmptyValue(tok->exprId(), &out))
2421                 return {static_cast<int>(out)};
2422             return {};
2423         } else {
2424             return {};
2425         }
2426     }
2427 
assumeValueFlowAnalyzer2428     virtual void assume(const Token* tok, bool state, unsigned int flags) OVERRIDE {
2429         // Update program state
2430         pms.removeModifiedVars(tok);
2431         pms.addState(tok, getProgramState());
2432         pms.assume(tok, state, flags & Assume::ContainerEmpty);
2433 
2434         bool isCondBlock = false;
2435         const Token* parent = tok->astParent();
2436         if (parent) {
2437             isCondBlock = Token::Match(parent->previous(), "if|while (");
2438         }
2439 
2440         if (isCondBlock) {
2441             const Token* startBlock = parent->link()->next();
2442             if (Token::simpleMatch(startBlock, ";") && Token::simpleMatch(parent->tokAt(-2), "} while ("))
2443                 startBlock = parent->linkAt(-2);
2444             const Token* endBlock = startBlock->link();
2445             pms.removeModifiedVars(endBlock);
2446             if (state)
2447                 pms.addState(endBlock->previous(), getProgramState());
2448             else if (Token::simpleMatch(endBlock, "} else {"))
2449                 pms.addState(endBlock->linkAt(2)->previous(), getProgramState());
2450         }
2451 
2452         if (!(flags & Assume::Quiet)) {
2453             if (flags & Assume::ContainerEmpty) {
2454                 std::string s = state ? "empty" : "not empty";
2455                 addErrorPath(tok, "Assuming container is " + s);
2456             } else {
2457                 std::string s = state ? "true" : "false";
2458                 addErrorPath(tok, "Assuming condition is " + s);
2459             }
2460         }
2461         if (!(flags & Assume::Absolute))
2462             makeConditional();
2463     }
2464 
updateValueFlowAnalyzer2465     virtual void update(Token* tok, Action a, Direction d) OVERRIDE {
2466         ValueFlow::Value* value = getValue(tok);
2467         if (!value)
2468             return;
2469         ValueFlow::Value localValue;
2470         if (a.isSymbolicMatch()) {
2471             // Make a copy of the value to modify it
2472             localValue = *value;
2473             value = &localValue;
2474             isSameSymbolicValue(tok, &value->errorPath);
2475         }
2476         // Read first when moving forward
2477         if (d == Direction::Forward && a.isRead())
2478             setTokenValue(tok, *value, getSettings());
2479         if (a.isInconclusive())
2480             lowerToInconclusive();
2481         if (a.isWrite() && tok->astParent()) {
2482             writeValue(value, tok, d);
2483         }
2484         // Read last when moving in reverse
2485         if (d == Direction::Reverse && a.isRead())
2486             setTokenValue(tok, *value, getSettings());
2487     }
2488 
reanalyzeValueFlowAnalyzer2489     virtual ValuePtr<Analyzer> reanalyze(Token*, const std::string&) const OVERRIDE {
2490         return {};
2491     }
2492 };
2493 
2494 ValuePtr<Analyzer> makeAnalyzer(const Token* exprTok, ValueFlow::Value value, const TokenList* tokenlist);
2495 
2496 struct SingleValueFlowAnalyzer : ValueFlowAnalyzer {
2497     std::unordered_map<nonneg int, const Variable*> varids;
2498     std::unordered_map<nonneg int, const Variable*> aliases;
2499     ValueFlow::Value value;
2500 
SingleValueFlowAnalyzerSingleValueFlowAnalyzer2501     SingleValueFlowAnalyzer() : ValueFlowAnalyzer() {}
2502 
SingleValueFlowAnalyzerSingleValueFlowAnalyzer2503     SingleValueFlowAnalyzer(const ValueFlow::Value& v, const TokenList* t) : ValueFlowAnalyzer(t), value(v) {}
2504 
getVarsSingleValueFlowAnalyzer2505     const std::unordered_map<nonneg int, const Variable*>& getVars() const {
2506         return varids;
2507     }
2508 
getAliasedVarsSingleValueFlowAnalyzer2509     const std::unordered_map<nonneg int, const Variable*>& getAliasedVars() const {
2510         return aliases;
2511     }
2512 
getValueSingleValueFlowAnalyzer2513     virtual const ValueFlow::Value* getValue(const Token*) const OVERRIDE {
2514         return &value;
2515     }
getValueSingleValueFlowAnalyzer2516     virtual ValueFlow::Value* getValue(const Token*) OVERRIDE {
2517         return &value;
2518     }
2519 
makeConditionalSingleValueFlowAnalyzer2520     virtual void makeConditional() OVERRIDE {
2521         value.conditional = true;
2522     }
2523 
useSymbolicValuesSingleValueFlowAnalyzer2524     virtual bool useSymbolicValues() const OVERRIDE
2525     {
2526         if (value.isUninitValue())
2527             return false;
2528         return true;
2529     }
2530 
addErrorPathSingleValueFlowAnalyzer2531     virtual void addErrorPath(const Token* tok, const std::string& s) OVERRIDE {
2532         value.errorPath.emplace_back(tok, s);
2533     }
2534 
isAliasSingleValueFlowAnalyzer2535     virtual bool isAlias(const Token* tok, bool& inconclusive) const OVERRIDE {
2536         if (value.isLifetimeValue())
2537             return false;
2538         for (const auto& m: {
2539             std::ref(getVars()), std::ref(getAliasedVars())
2540         }) {
2541             for (const auto& p:m.get()) {
2542                 nonneg int varid = p.first;
2543                 const Variable* var = p.second;
2544                 if (tok->varId() == varid)
2545                     return true;
2546                 if (isAliasOf(var, tok, varid, MakeSingleRange(value), &inconclusive))
2547                     return true;
2548             }
2549         }
2550         return false;
2551     }
2552 
isGlobalSingleValueFlowAnalyzer2553     virtual bool isGlobal() const OVERRIDE {
2554         for (const auto&p:getVars()) {
2555             const Variable* var = p.second;
2556             if (!var->isLocal() && !var->isArgument() && !var->isConst())
2557                 return true;
2558         }
2559         return false;
2560     }
2561 
lowerToPossibleSingleValueFlowAnalyzer2562     virtual bool lowerToPossible() OVERRIDE {
2563         if (value.isImpossible())
2564             return false;
2565         value.changeKnownToPossible();
2566         return true;
2567     }
lowerToInconclusiveSingleValueFlowAnalyzer2568     virtual bool lowerToInconclusive() OVERRIDE {
2569         if (value.isImpossible())
2570             return false;
2571         value.setInconclusive();
2572         return true;
2573     }
2574 
isConditionalSingleValueFlowAnalyzer2575     virtual bool isConditional() const OVERRIDE {
2576         if (value.conditional)
2577             return true;
2578         if (value.condition)
2579             return !value.isKnown() && !value.isImpossible();
2580         return false;
2581     }
2582 
stopOnConditionSingleValueFlowAnalyzer2583     virtual bool stopOnCondition(const Token* condTok) const OVERRIDE
2584     {
2585         if (value.isNonValue())
2586             return false;
2587         if (value.isImpossible())
2588             return false;
2589         if (isConditional() && !value.isKnown() && !value.isImpossible())
2590             return true;
2591         ConditionState cs = analyzeCondition(condTok);
2592         return cs.isUnknownDependent();
2593     }
2594 
updateScopeSingleValueFlowAnalyzer2595     virtual bool updateScope(const Token* endBlock, bool) const OVERRIDE {
2596         const Scope* scope = endBlock->scope();
2597         if (!scope)
2598             return false;
2599         if (scope->type == Scope::eLambda) {
2600             return value.isLifetimeValue();
2601         } else if (scope->type == Scope::eIf || scope->type == Scope::eElse || scope->type == Scope::eWhile ||
2602                    scope->type == Scope::eFor) {
2603             if (value.isKnown() || value.isImpossible())
2604                 return true;
2605             if (value.isLifetimeValue())
2606                 return true;
2607             if (isConditional())
2608                 return false;
2609             const Token* condTok = getCondTokFromEnd(endBlock);
2610             std::set<nonneg int> varids2;
2611             std::transform(getVars().begin(), getVars().end(), std::inserter(varids2, varids2.begin()), SelectMapKeys{});
2612             return bifurcate(condTok, varids2, getSettings());
2613         }
2614 
2615         return false;
2616     }
2617 
reanalyzeSingleValueFlowAnalyzer2618     virtual ValuePtr<Analyzer> reanalyze(Token* tok, const std::string& msg) const OVERRIDE {
2619         ValueFlow::Value newValue = value;
2620         newValue.errorPath.emplace_back(tok, msg);
2621         return makeAnalyzer(tok, newValue, tokenlist);
2622     }
2623 };
2624 
2625 struct ExpressionAnalyzer : SingleValueFlowAnalyzer {
2626     const Token* expr;
2627     bool local;
2628     bool unknown;
2629     bool dependOnThis;
2630 
ExpressionAnalyzerExpressionAnalyzer2631     ExpressionAnalyzer() : SingleValueFlowAnalyzer(), expr(nullptr), local(true), unknown(false), dependOnThis(false) {}
2632 
ExpressionAnalyzerExpressionAnalyzer2633     ExpressionAnalyzer(const Token* e, const ValueFlow::Value& val, const TokenList* t)
2634         : SingleValueFlowAnalyzer(val, t), expr(e), local(true), unknown(false), dependOnThis(false) {
2635 
2636         assert(e && e->exprId() != 0 && "Not a valid expression");
2637         dependOnThis = exprDependsOnThis(expr);
2638         setupExprVarIds(expr);
2639         if (val.isSymbolicValue())
2640             setupExprVarIds(val.tokvalue);
2641     }
2642 
getValueTypeExpressionAnalyzer2643     virtual const ValueType* getValueType(const Token*) const OVERRIDE {
2644         return expr->valueType();
2645     }
2646 
nonLocalExpressionAnalyzer2647     static bool nonLocal(const Variable* var, bool deref) {
2648         return !var || (!var->isLocal() && !var->isArgument()) || (deref && var->isArgument() && var->isPointer()) ||
2649                var->isStatic() || var->isReference() || var->isExtern();
2650     }
2651 
setupExprVarIdsExpressionAnalyzer2652     void setupExprVarIds(const Token* start, int depth = 0) {
2653         const int maxDepth = 4;
2654         if (depth > maxDepth)
2655             return;
2656         visitAstNodes(start, [&](const Token* tok) {
2657             for (const ValueFlow::Value& v : tok->values()) {
2658                 if (!(v.isLocalLifetimeValue() || (astIsPointer(tok) && v.isSymbolicValue() && v.isKnown())))
2659                     continue;
2660                 if (!v.tokvalue)
2661                     continue;
2662                 if (v.tokvalue == tok)
2663                     continue;
2664                 setupExprVarIds(v.tokvalue, depth + 1);
2665             }
2666             if (depth == 0 && tok->varId() == 0 && !tok->function() && tok->isName() && tok->previous()->str() != ".") {
2667                 // unknown variable
2668                 unknown = true;
2669                 return ChildrenToVisit::none;
2670             }
2671             if (tok->varId() > 0) {
2672                 varids[tok->varId()] = tok->variable();
2673                 if (!Token::simpleMatch(tok->previous(), ".")) {
2674                     const Variable* var = tok->variable();
2675                     if (var && var->isReference() && var->isLocal() && Token::Match(var->nameToken(), "%var% [=(]") &&
2676                         !isGlobalData(var->nameToken()->next()->astOperand2(), isCPP()))
2677                         return ChildrenToVisit::none;
2678                     const bool deref = tok->astParent() &&
2679                                        (tok->astParent()->isUnaryOp("*") ||
2680                                         (tok->astParent()->str() == "[" && tok == tok->astParent()->astOperand1()));
2681                     local &= !nonLocal(tok->variable(), deref);
2682                 }
2683             }
2684             return ChildrenToVisit::op1_and_op2;
2685         });
2686     }
2687 
invalidExpressionAnalyzer2688     virtual bool invalid() const OVERRIDE {
2689         return unknown;
2690     }
2691 
getProgramStateExpressionAnalyzer2692     virtual ProgramState getProgramState() const OVERRIDE {
2693         ProgramState ps;
2694         ps[expr->exprId()] = value;
2695         return ps;
2696     }
2697 
matchExpressionAnalyzer2698     virtual bool match(const Token* tok) const OVERRIDE {
2699         return tok->exprId() == expr->exprId();
2700     }
2701 
dependsOnThisExpressionAnalyzer2702     virtual bool dependsOnThis() const OVERRIDE {
2703         return dependOnThis;
2704     }
2705 
isGlobalExpressionAnalyzer2706     virtual bool isGlobal() const OVERRIDE {
2707         return !local;
2708     }
2709 };
2710 
2711 struct OppositeExpressionAnalyzer : ExpressionAnalyzer {
2712     bool isNot;
2713 
OppositeExpressionAnalyzerOppositeExpressionAnalyzer2714     OppositeExpressionAnalyzer() : ExpressionAnalyzer(), isNot(false) {}
2715 
OppositeExpressionAnalyzerOppositeExpressionAnalyzer2716     OppositeExpressionAnalyzer(bool pIsNot, const Token* e, const ValueFlow::Value& val, const TokenList* t)
2717         : ExpressionAnalyzer(e, val, t), isNot(pIsNot)
2718     {}
2719 
matchOppositeExpressionAnalyzer2720     virtual bool match(const Token* tok) const OVERRIDE {
2721         return isOppositeCond(isNot, isCPP(), expr, tok, getSettings()->library, true, true);
2722     }
2723 };
2724 
valueFlowForwardExpression(Token * startToken,const Token * endToken,const Token * exprTok,const std::list<ValueFlow::Value> & values,const TokenList * const tokenlist,const Settings * settings)2725 static Analyzer::Result valueFlowForwardExpression(Token* startToken,
2726                                                    const Token* endToken,
2727                                                    const Token* exprTok,
2728                                                    const std::list<ValueFlow::Value>& values,
2729                                                    const TokenList* const tokenlist,
2730                                                    const Settings* settings)
2731 {
2732     Analyzer::Result result{};
2733     for (const ValueFlow::Value& v : values) {
2734         ExpressionAnalyzer a(exprTok, v, tokenlist);
2735         result.update(valueFlowGenericForward(startToken, endToken, a, settings));
2736     }
2737     return result;
2738 }
2739 
parseBinaryIntOp(const Token * expr,MathLib::bigint & known)2740 static const Token* parseBinaryIntOp(const Token* expr, MathLib::bigint& known)
2741 {
2742     if (!expr)
2743         return nullptr;
2744     if (!expr->astOperand1() || !expr->astOperand2())
2745         return nullptr;
2746     if (expr->astOperand1()->exprId() == 0 && !expr->astOperand1()->hasKnownIntValue())
2747         return nullptr;
2748     if (expr->astOperand2()->exprId() == 0 && !expr->astOperand2()->hasKnownIntValue())
2749         return nullptr;
2750     const Token* knownTok = nullptr;
2751     const Token* varTok = nullptr;
2752     if (expr->astOperand1()->hasKnownIntValue() && !expr->astOperand2()->hasKnownIntValue()) {
2753         varTok = expr->astOperand2();
2754         knownTok = expr->astOperand1();
2755     } else if (expr->astOperand2()->hasKnownIntValue() && !expr->astOperand1()->hasKnownIntValue()) {
2756         varTok = expr->astOperand1();
2757         knownTok = expr->astOperand2();
2758     }
2759     if (knownTok)
2760         known = knownTok->values().front().intvalue;
2761     return varTok;
2762 }
2763 
solveExprValue(const Token * expr,ValueFlow::Value & value)2764 static const Token* solveExprValue(const Token* expr, ValueFlow::Value& value)
2765 {
2766     if (!value.isIntValue() && !value.isIteratorValue() && !value.isSymbolicValue())
2767         return expr;
2768     if (value.isSymbolicValue() && !Token::Match(expr, "+|-"))
2769         return expr;
2770     MathLib::bigint intval;
2771     const Token* binaryTok = parseBinaryIntOp(expr, intval);
2772     if (binaryTok && expr->str().size() == 1) {
2773         switch (expr->str()[0]) {
2774         case '+': {
2775             value.intvalue -= intval;
2776             return solveExprValue(binaryTok, value);
2777         }
2778         case '-': {
2779             value.intvalue += intval;
2780             return solveExprValue(binaryTok, value);
2781         }
2782         case '*': {
2783             if (intval == 0)
2784                 break;
2785             value.intvalue /= intval;
2786             return solveExprValue(binaryTok, value);
2787         }
2788         case '^': {
2789             value.intvalue ^= intval;
2790             return solveExprValue(binaryTok, value);
2791         }
2792         }
2793     }
2794     return expr;
2795 }
2796 
makeAnalyzer(const Token * exprTok,ValueFlow::Value value,const TokenList * tokenlist)2797 ValuePtr<Analyzer> makeAnalyzer(const Token* exprTok, ValueFlow::Value value, const TokenList* tokenlist)
2798 {
2799     const Token* expr = solveExprValue(exprTok, value);
2800     return ExpressionAnalyzer(expr, value, tokenlist);
2801 }
2802 
valueFlowForward(Token * startToken,const Token * endToken,const Token * exprTok,std::list<ValueFlow::Value> values,TokenList * const tokenlist,const Settings * settings)2803 static Analyzer::Result valueFlowForward(Token* startToken,
2804                                          const Token* endToken,
2805                                          const Token* exprTok,
2806                                          std::list<ValueFlow::Value> values,
2807                                          TokenList* const tokenlist,
2808                                          const Settings* settings)
2809 {
2810     Analyzer::Result result{};
2811     for (const ValueFlow::Value& v : values) {
2812         result.update(valueFlowGenericForward(startToken, endToken, makeAnalyzer(exprTok, v, tokenlist), settings));
2813     }
2814     return result;
2815 }
2816 
valueFlowForward(Token * top,const Token * exprTok,const std::list<ValueFlow::Value> & values,TokenList * const tokenlist,const Settings * settings)2817 static Analyzer::Result valueFlowForward(Token* top,
2818                                          const Token* exprTok,
2819                                          const std::list<ValueFlow::Value>& values,
2820                                          TokenList* const tokenlist,
2821                                          const Settings* settings)
2822 {
2823     Analyzer::Result result{};
2824     for (const ValueFlow::Value& v : values) {
2825         result.update(valueFlowGenericForward(top, makeAnalyzer(exprTok, v, tokenlist), settings));
2826     }
2827     return result;
2828 }
2829 
valueFlowReverse(Token * tok,const Token * const endToken,const Token * const varToken,const std::list<ValueFlow::Value> & values,TokenList * tokenlist,const Settings * settings)2830 static void valueFlowReverse(Token* tok,
2831                              const Token* const endToken,
2832                              const Token* const varToken,
2833                              const std::list<ValueFlow::Value>& values,
2834                              TokenList* tokenlist,
2835                              const Settings* settings)
2836 {
2837     for (const ValueFlow::Value& v : values) {
2838         ExpressionAnalyzer a(varToken, v, tokenlist);
2839         valueFlowGenericReverse(tok, endToken, a, settings);
2840     }
2841 }
2842 
valueFlowReverse(TokenList * tokenlist,Token * tok,const Token * const varToken,ValueFlow::Value val,ValueFlow::Value val2,ErrorLogger *,const Settings * settings)2843 static void valueFlowReverse(TokenList* tokenlist,
2844                              Token* tok,
2845                              const Token* const varToken,
2846                              ValueFlow::Value val,
2847                              ValueFlow::Value val2,
2848                              ErrorLogger* /*errorLogger*/,
2849                              const Settings* settings)
2850 {
2851     std::list<ValueFlow::Value> values = {val};
2852     if (val2.varId != 0)
2853         values.push_back(val2);
2854     valueFlowReverse(tok, nullptr, varToken, values, tokenlist, settings);
2855 }
2856 
isUniqueSmartPointer(const Token * tok)2857 static bool isUniqueSmartPointer(const Token* tok)
2858 {
2859     if (!astIsSmartPointer(tok))
2860         return false;
2861     if (!tok->valueType()->smartPointer)
2862         return false;
2863     return tok->valueType()->smartPointer->unique;
2864 }
2865 
lifetimeType(const Token * tok,const ValueFlow::Value * val)2866 std::string lifetimeType(const Token *tok, const ValueFlow::Value *val)
2867 {
2868     std::string result;
2869     if (!val)
2870         return "object";
2871     switch (val->lifetimeKind) {
2872     case ValueFlow::Value::LifetimeKind::Lambda:
2873         result = "lambda";
2874         break;
2875     case ValueFlow::Value::LifetimeKind::Iterator:
2876         result = "iterator";
2877         break;
2878     case ValueFlow::Value::LifetimeKind::Object:
2879     case ValueFlow::Value::LifetimeKind::SubObject:
2880     case ValueFlow::Value::LifetimeKind::Address:
2881         if (astIsPointer(tok))
2882             result = "pointer";
2883         else
2884             result = "object";
2885         break;
2886     }
2887     return result;
2888 }
2889 
lifetimeMessage(const Token * tok,const ValueFlow::Value * val,ErrorPath & errorPath)2890 std::string lifetimeMessage(const Token *tok, const ValueFlow::Value *val, ErrorPath &errorPath)
2891 {
2892     const Token *tokvalue = val ? val->tokvalue : nullptr;
2893     const Variable *tokvar = tokvalue ? tokvalue->variable() : nullptr;
2894     const Token *vartok = tokvar ? tokvar->nameToken() : nullptr;
2895     std::string type = lifetimeType(tok, val);
2896     std::string msg = type;
2897     if (vartok) {
2898         errorPath.emplace_back(vartok, "Variable created here.");
2899         const Variable * var = vartok->variable();
2900         if (var) {
2901             switch (val->lifetimeKind) {
2902             case ValueFlow::Value::LifetimeKind::SubObject:
2903             case ValueFlow::Value::LifetimeKind::Object:
2904             case ValueFlow::Value::LifetimeKind::Address:
2905                 if (type == "pointer")
2906                     msg += " to local variable";
2907                 else
2908                     msg += " that points to local variable";
2909                 break;
2910             case ValueFlow::Value::LifetimeKind::Lambda:
2911                 msg += " that captures local variable";
2912                 break;
2913             case ValueFlow::Value::LifetimeKind::Iterator:
2914                 msg += " to local container";
2915                 break;
2916             }
2917             msg += " '" + var->name() + "'";
2918         }
2919     }
2920     return msg;
2921 }
2922 
getLifetimeObjValues(const Token * tok,bool inconclusive,bool subfunction)2923 std::vector<ValueFlow::Value> getLifetimeObjValues(const Token *tok, bool inconclusive, bool subfunction)
2924 {
2925     std::vector<ValueFlow::Value> result;
2926     auto pred = [&](const ValueFlow::Value &v) {
2927         if (!v.isLocalLifetimeValue() && !(subfunction && v.isSubFunctionLifetimeValue()))
2928             return false;
2929         if (!inconclusive && v.isInconclusive())
2930             return false;
2931         if (!v.tokvalue->variable())
2932             return false;
2933         return true;
2934     };
2935     std::copy_if(tok->values().begin(), tok->values().end(), std::back_inserter(result), pred);
2936     return result;
2937 }
2938 
getLifetimeObjValue(const Token * tok,bool inconclusive)2939 ValueFlow::Value getLifetimeObjValue(const Token *tok, bool inconclusive)
2940 {
2941     std::vector<ValueFlow::Value> values = getLifetimeObjValues(tok, inconclusive, false);
2942     // There should only be one lifetime
2943     if (values.size() != 1)
2944         return ValueFlow::Value{};
2945     return values.front();
2946 }
2947 
2948 template<class Predicate>
getLifetimeTokens(const Token * tok,bool escape,ValueFlow::Value::ErrorPath errorPath,Predicate pred,int depth=20)2949 static std::vector<LifetimeToken> getLifetimeTokens(const Token* tok,
2950                                                     bool escape,
2951                                                     ValueFlow::Value::ErrorPath errorPath,
2952                                                     Predicate pred,
2953                                                     int depth = 20)
2954 {
2955     if (!tok)
2956         return std::vector<LifetimeToken> {};
2957     const Variable *var = tok->variable();
2958     if (pred(tok))
2959         return {{tok, std::move(errorPath)}};
2960     if (depth < 0)
2961         return {{tok, std::move(errorPath)}};
2962     if (var && var->declarationId() == tok->varId()) {
2963         if (var->isReference() || var->isRValueReference()) {
2964             if (!var->declEndToken())
2965                 return {{tok, true, std::move(errorPath)}};
2966             if (var->isArgument()) {
2967                 errorPath.emplace_back(var->declEndToken(), "Passed to reference.");
2968                 return {{tok, true, std::move(errorPath)}};
2969             } else if (Token::simpleMatch(var->declEndToken(), "=")) {
2970                 errorPath.emplace_back(var->declEndToken(), "Assigned to reference.");
2971                 const Token *vartok = var->declEndToken()->astOperand2();
2972                 const bool temporary = isTemporary(true, vartok, nullptr, true);
2973                 const bool nonlocal = var->isStatic() || var->isGlobal();
2974                 if (vartok == tok || (nonlocal && temporary) ||
2975                     (!escape && (var->isConst() || var->isRValueReference()) && temporary))
2976                     return {{tok, true, std::move(errorPath)}};
2977                 if (vartok)
2978                     return getLifetimeTokens(vartok, escape, std::move(errorPath), pred, depth - 1);
2979             } else if (Token::simpleMatch(var->nameToken()->astParent(), ":") &&
2980                        var->nameToken()->astParent()->astParent() &&
2981                        Token::simpleMatch(var->nameToken()->astParent()->astParent()->previous(), "for (")) {
2982                 errorPath.emplace_back(var->nameToken(), "Assigned to reference.");
2983                 const Token* vartok = var->nameToken();
2984                 if (vartok == tok)
2985                     return {{tok, true, std::move(errorPath)}};
2986                 const Token* contok = var->nameToken()->astParent()->astOperand2();
2987                 if (astIsContainer(contok))
2988                     return getLifetimeTokens(contok, escape, std::move(errorPath), pred, depth - 1);
2989                 else
2990                     return std::vector<LifetimeToken>{};
2991             } else {
2992                 return std::vector<LifetimeToken> {};
2993             }
2994         }
2995     } else if (Token::Match(tok->previous(), "%name% (")) {
2996         const Function *f = tok->previous()->function();
2997         if (f) {
2998             if (!Function::returnsReference(f))
2999                 return {{tok, std::move(errorPath)}};
3000             std::vector<LifetimeToken> result;
3001             std::vector<const Token*> returns = Function::findReturns(f);
3002             for (const Token* returnTok : returns) {
3003                 if (returnTok == tok)
3004                     continue;
3005                 for (LifetimeToken& lt : getLifetimeTokens(returnTok, escape, errorPath, pred, depth - returns.size())) {
3006                     const Token* argvarTok = lt.token;
3007                     const Variable* argvar = argvarTok->variable();
3008                     if (!argvar)
3009                         continue;
3010                     if (argvar->isArgument() && (argvar->isReference() || argvar->isRValueReference())) {
3011                         int n = getArgumentPos(argvar, f);
3012                         if (n < 0)
3013                             return std::vector<LifetimeToken> {};
3014                         std::vector<const Token*> args = getArguments(tok->previous());
3015                         // TODO: Track lifetimes of default parameters
3016                         if (n >= args.size())
3017                             return std::vector<LifetimeToken> {};
3018                         const Token* argTok = args[n];
3019                         lt.errorPath.emplace_back(returnTok, "Return reference.");
3020                         lt.errorPath.emplace_back(tok->previous(), "Called function passing '" + argTok->expressionString() + "'.");
3021                         std::vector<LifetimeToken> arglts = LifetimeToken::setInconclusive(
3022                             getLifetimeTokens(argTok, escape, std::move(lt.errorPath), pred, depth - returns.size()),
3023                             returns.size() > 1);
3024                         result.insert(result.end(), arglts.begin(), arglts.end());
3025                     }
3026                 }
3027             }
3028             return result;
3029         } else if (Token::Match(tok->tokAt(-2), ". %name% (") && tok->tokAt(-2)->originalName() != "->" && astIsContainer(tok->tokAt(-2)->astOperand1())) {
3030             const Library::Container* library = getLibraryContainer(tok->tokAt(-2)->astOperand1());
3031             Library::Container::Yield y = library->getYield(tok->previous()->str());
3032             if (y == Library::Container::Yield::AT_INDEX || y == Library::Container::Yield::ITEM) {
3033                 errorPath.emplace_back(tok->previous(), "Accessing container.");
3034                 return LifetimeToken::setAddressOf(
3035                     getLifetimeTokens(tok->tokAt(-2)->astOperand1(), escape, std::move(errorPath), pred, depth - 1),
3036                     false);
3037             }
3038         }
3039     } else if (Token::Match(tok, ".|::|[") || tok->isUnaryOp("*")) {
3040 
3041         const Token *vartok = tok;
3042         if (tok->isUnaryOp("*"))
3043             vartok = tok->astOperand1();
3044         while (vartok) {
3045             if (vartok->str() == "[" || vartok->originalName() == "->")
3046                 vartok = vartok->astOperand1();
3047             else if (vartok->str() == "." || vartok->str() == "::")
3048                 vartok = vartok->astOperand2();
3049             else
3050                 break;
3051         }
3052 
3053         if (!vartok)
3054             return {{tok, std::move(errorPath)}};
3055         const Variable *tokvar = vartok->variable();
3056         const bool isContainer = astIsContainer(vartok) && !astIsPointer(vartok);
3057         if (!isUniqueSmartPointer(vartok) && !isContainer &&
3058             !(tokvar && tokvar->isArray() && !tokvar->isArgument()) &&
3059             (Token::Match(vartok->astParent(), "[|*") || vartok->astParent()->originalName() == "->")) {
3060             for (const ValueFlow::Value &v : vartok->values()) {
3061                 if (!v.isLocalLifetimeValue())
3062                     continue;
3063                 if (v.tokvalue == tok)
3064                     continue;
3065                 errorPath.insert(errorPath.end(), v.errorPath.begin(), v.errorPath.end());
3066                 return getLifetimeTokens(v.tokvalue, escape, std::move(errorPath), pred, depth - 1);
3067             }
3068         } else {
3069             return LifetimeToken::setAddressOf(getLifetimeTokens(vartok, escape, std::move(errorPath), pred, depth - 1),
3070                                                !(astIsContainer(vartok) && Token::simpleMatch(vartok->astParent(), "[")));
3071         }
3072     }
3073     return {{tok, std::move(errorPath)}};
3074 }
3075 
getLifetimeTokens(const Token * tok,bool escape,ValueFlow::Value::ErrorPath errorPath)3076 std::vector<LifetimeToken> getLifetimeTokens(const Token* tok, bool escape, ValueFlow::Value::ErrorPath errorPath)
3077 {
3078     return getLifetimeTokens(tok, escape, std::move(errorPath), [](const Token*) {
3079         return false;
3080     });
3081 }
3082 
hasLifetimeToken(const Token * tok,const Token * lifetime)3083 bool hasLifetimeToken(const Token* tok, const Token* lifetime)
3084 {
3085     bool result = false;
3086     getLifetimeTokens(tok, false, ValueFlow::Value::ErrorPath{}, [&](const Token* tok2) {
3087         result = tok2->exprId() == lifetime->exprId();
3088         return result;
3089     });
3090     return result;
3091 }
3092 
getLifetimeToken(const Token * tok,ValueFlow::Value::ErrorPath & errorPath,bool * addressOf=nullptr)3093 static const Token* getLifetimeToken(const Token* tok, ValueFlow::Value::ErrorPath& errorPath, bool* addressOf = nullptr)
3094 {
3095     std::vector<LifetimeToken> lts = getLifetimeTokens(tok);
3096     if (lts.size() != 1)
3097         return nullptr;
3098     if (lts.front().inconclusive)
3099         return nullptr;
3100     if (addressOf)
3101         *addressOf = lts.front().addressOf;
3102     errorPath.insert(errorPath.end(), lts.front().errorPath.begin(), lts.front().errorPath.end());
3103     return lts.front().token;
3104 }
3105 
getLifetimeVariable(const Token * tok,ValueFlow::Value::ErrorPath & errorPath,bool * addressOf)3106 const Variable* getLifetimeVariable(const Token* tok, ValueFlow::Value::ErrorPath& errorPath, bool* addressOf)
3107 {
3108     const Token* tok2 = getLifetimeToken(tok, errorPath, addressOf);
3109     if (tok2 && tok2->variable())
3110         return tok2->variable();
3111     return nullptr;
3112 }
3113 
getLifetimeVariable(const Token * tok)3114 const Variable* getLifetimeVariable(const Token* tok)
3115 {
3116     ValueFlow::Value::ErrorPath errorPath;
3117     return getLifetimeVariable(tok, errorPath, nullptr);
3118 }
3119 
isNotLifetimeValue(const ValueFlow::Value & val)3120 static bool isNotLifetimeValue(const ValueFlow::Value& val)
3121 {
3122     return !val.isLifetimeValue();
3123 }
3124 
isLifetimeOwned(const ValueType * vt,const ValueType * vtParent)3125 static bool isLifetimeOwned(const ValueType *vt, const ValueType *vtParent)
3126 {
3127     if (!vtParent)
3128         return false;
3129     if (!vt) {
3130         if (vtParent->type == ValueType::CONTAINER)
3131             return true;
3132         return false;
3133     }
3134     if (vt->type != ValueType::UNKNOWN_TYPE && vtParent->type != ValueType::UNKNOWN_TYPE) {
3135         if (vt->pointer != vtParent->pointer)
3136             return true;
3137         if (vt->type != vtParent->type) {
3138             if (vtParent->type == ValueType::RECORD)
3139                 return true;
3140             if (vtParent->type == ValueType::CONTAINER)
3141                 return true;
3142         }
3143     }
3144 
3145     return false;
3146 }
3147 
isLifetimeBorrowed(const ValueType * vt,const ValueType * vtParent)3148 static bool isLifetimeBorrowed(const ValueType *vt, const ValueType *vtParent)
3149 {
3150     if (!vtParent)
3151         return false;
3152     if (!vt)
3153         return false;
3154     if (vt->pointer > 0 && vt->pointer == vtParent->pointer)
3155         return true;
3156     if (vt->type != ValueType::UNKNOWN_TYPE && vtParent->type != ValueType::UNKNOWN_TYPE && vtParent->container == vt->container) {
3157         if (vtParent->pointer > vt->pointer)
3158             return true;
3159         if (vtParent->pointer < vt->pointer && vtParent->isIntegral())
3160             return true;
3161         if (vtParent->str() == vt->str())
3162             return true;
3163         if (vtParent->pointer == vt->pointer && vtParent->type == vt->type && vtParent->isIntegral())
3164             // sign conversion
3165             return true;
3166     }
3167 
3168     return false;
3169 }
3170 
skipCVRefs(const Token * tok,const Token * endTok)3171 static const Token* skipCVRefs(const Token* tok, const Token* endTok)
3172 {
3173     while (tok != endTok && Token::Match(tok, "const|volatile|auto|&|&&"))
3174         tok = tok->next();
3175     return tok;
3176 }
3177 
isNotEqual(std::pair<const Token *,const Token * > x,std::pair<const Token *,const Token * > y)3178 static bool isNotEqual(std::pair<const Token*, const Token*> x, std::pair<const Token*, const Token*> y)
3179 {
3180     const Token* start1 = x.first;
3181     const Token* start2 = y.first;
3182     if (start1 == nullptr || start2 == nullptr)
3183         return false;
3184     while (start1 != x.second && start2 != y.second) {
3185         const Token* tok1 = skipCVRefs(start1, x.second);
3186         if (tok1 != start1) {
3187             start1 = tok1;
3188             continue;
3189         }
3190         const Token* tok2 = skipCVRefs(start2, y.second);
3191         if (tok2 != start2) {
3192             start2 = tok2;
3193             continue;
3194         }
3195         if (start1->str() != start2->str())
3196             return true;
3197         start1 = start1->next();
3198         start2 = start2->next();
3199     }
3200     start1 = skipCVRefs(start1, x.second);
3201     start2 = skipCVRefs(start2, y.second);
3202     return !(start1 == x.second && start2 == y.second);
3203 }
isNotEqual(std::pair<const Token *,const Token * > x,const std::string & y)3204 static bool isNotEqual(std::pair<const Token*, const Token*> x, const std::string& y)
3205 {
3206     TokenList tokenList(nullptr);
3207     std::istringstream istr(y);
3208     tokenList.createTokens(istr);
3209     return isNotEqual(x, std::make_pair(tokenList.front(), tokenList.back()));
3210 }
isNotEqual(std::pair<const Token *,const Token * > x,const ValueType * y)3211 static bool isNotEqual(std::pair<const Token*, const Token*> x, const ValueType* y)
3212 {
3213     if (y == nullptr)
3214         return false;
3215     if (y->originalTypeName.empty())
3216         return false;
3217     return isNotEqual(x, y->originalTypeName);
3218 }
3219 
isDifferentType(const Token * src,const Token * dst)3220 static bool isDifferentType(const Token* src, const Token* dst)
3221 {
3222     const Type* t = Token::typeOf(src);
3223     const Type* parentT = Token::typeOf(dst);
3224     if (t && parentT) {
3225         if (t->classDef && parentT->classDef && t->classDef != parentT->classDef)
3226             return true;
3227     } else {
3228         std::pair<const Token*, const Token*> decl = Token::typeDecl(src);
3229         std::pair<const Token*, const Token*> parentdecl = Token::typeDecl(dst);
3230         if (isNotEqual(decl, parentdecl))
3231             return true;
3232         if (isNotEqual(decl, dst->valueType()))
3233             return true;
3234         if (isNotEqual(parentdecl, src->valueType()))
3235             return true;
3236     }
3237     return false;
3238 }
3239 
isLifetimeBorrowed(const Token * tok,const Settings * settings)3240 bool isLifetimeBorrowed(const Token *tok, const Settings *settings)
3241 {
3242     if (!tok)
3243         return true;
3244     if (tok->str() == ",")
3245         return true;
3246     if (!tok->astParent())
3247         return true;
3248     if (!Token::Match(tok->astParent()->previous(), "%name% (") && !Token::simpleMatch(tok->astParent(), ",")) {
3249         if (!Token::simpleMatch(tok, "{")) {
3250             const ValueType *vt = tok->valueType();
3251             const ValueType *vtParent = tok->astParent()->valueType();
3252             if (isLifetimeBorrowed(vt, vtParent))
3253                 return true;
3254             if (isLifetimeOwned(vt, vtParent))
3255                 return false;
3256         }
3257         if (Token::Match(tok->astParent(), "return|(|{|%assign%")) {
3258             if (isDifferentType(tok, tok->astParent()))
3259                 return false;
3260         }
3261     } else if (Token::Match(tok->astParent()->tokAt(-3), "%var% . push_back|push_front|insert|push (") &&
3262                astIsContainer(tok->astParent()->tokAt(-3))) {
3263         const ValueType *vt = tok->valueType();
3264         const ValueType *vtCont = tok->astParent()->tokAt(-3)->valueType();
3265         if (!vtCont->containerTypeToken)
3266             return true;
3267         ValueType vtParent = ValueType::parseDecl(vtCont->containerTypeToken, settings);
3268         if (isLifetimeBorrowed(vt, &vtParent))
3269             return true;
3270         if (isLifetimeOwned(vt, &vtParent))
3271             return false;
3272     }
3273 
3274     return true;
3275 }
3276 
3277 static void valueFlowLifetimeFunction(Token *tok, TokenList *tokenlist, ErrorLogger *errorLogger, const Settings *settings);
3278 
3279 static void valueFlowLifetimeConstructor(Token *tok,
3280                                          TokenList *tokenlist,
3281                                          ErrorLogger *errorLogger,
3282                                          const Settings *settings);
3283 
getEndOfVarScope(const Token * tok,const std::vector<const Variable * > & vars)3284 static const Token* getEndOfVarScope(const Token* tok, const std::vector<const Variable*>& vars)
3285 {
3286     const Token* endOfVarScope = nullptr;
3287     for (const Variable* var : vars) {
3288         if (var && (var->isLocal() || var->isArgument()))
3289             endOfVarScope = var->typeStartToken()->scope()->bodyEnd;
3290         else if (!endOfVarScope)
3291             endOfVarScope = tok->scope()->bodyEnd;
3292     }
3293     return endOfVarScope;
3294 }
3295 
valueFlowForwardLifetime(Token * tok,TokenList * tokenlist,ErrorLogger * errorLogger,const Settings * settings)3296 static void valueFlowForwardLifetime(Token * tok, TokenList *tokenlist, ErrorLogger *errorLogger, const Settings *settings)
3297 {
3298     // Forward lifetimes to constructed variable
3299     if (Token::Match(tok->previous(), "%var% {")) {
3300         std::list<ValueFlow::Value> values = tok->values();
3301         values.remove_if(&isNotLifetimeValue);
3302         valueFlowForward(nextAfterAstRightmostLeaf(tok),
3303                          getEndOfVarScope(tok, {tok->variable()}),
3304                          tok->previous(),
3305                          values,
3306                          tokenlist,
3307                          settings);
3308         return;
3309     }
3310     Token *parent = tok->astParent();
3311     while (parent && parent->str() == ",")
3312         parent = parent->astParent();
3313     if (!parent)
3314         return;
3315     // Assignment
3316     if (parent->str() == "=" && (!parent->astParent() || Token::simpleMatch(parent->astParent(), ";"))) {
3317         // Rhs values..
3318         if (!parent->astOperand2() || parent->astOperand2()->values().empty())
3319             return;
3320 
3321         if (!isLifetimeBorrowed(parent->astOperand2(), settings))
3322             return;
3323 
3324         std::vector<const Variable*> vars = getLHSVariables(parent);
3325 
3326         const Token* endOfVarScope = getEndOfVarScope(tok, vars);
3327 
3328         // Only forward lifetime values
3329         std::list<ValueFlow::Value> values = parent->astOperand2()->values();
3330         values.remove_if(&isNotLifetimeValue);
3331 
3332         // Skip RHS
3333         const Token *nextExpression = nextAfterAstRightmostLeaf(parent);
3334 
3335         if (Token::Match(parent->astOperand1(), ".|[|(") && parent->astOperand1()->exprId() > 0) {
3336             valueFlowForwardExpression(
3337                 const_cast<Token*>(nextExpression), endOfVarScope, parent->astOperand1(), values, tokenlist, settings);
3338 
3339             for (ValueFlow::Value& val : values) {
3340                 if (val.lifetimeKind == ValueFlow::Value::LifetimeKind::Address)
3341                     val.lifetimeKind = ValueFlow::Value::LifetimeKind::SubObject;
3342             }
3343         }
3344         for (const Variable* var : vars) {
3345             valueFlowForward(
3346                 const_cast<Token*>(nextExpression), endOfVarScope, var->nameToken(), values, tokenlist, settings);
3347 
3348             if (tok->astTop() && Token::simpleMatch(tok->astTop()->previous(), "for (") &&
3349                 Token::simpleMatch(tok->astTop()->link(), ") {")) {
3350                 Token* start = tok->astTop()->link()->next();
3351                 valueFlowForward(start, start->link(), var->nameToken(), values, tokenlist, settings);
3352             }
3353         }
3354         // Constructor
3355     } else if (Token::simpleMatch(parent, "{") && !isScopeBracket(parent)) {
3356         valueFlowLifetimeConstructor(parent, tokenlist, errorLogger, settings);
3357         valueFlowForwardLifetime(parent, tokenlist, errorLogger, settings);
3358         // Function call
3359     } else if (Token::Match(parent->previous(), "%name% (")) {
3360         valueFlowLifetimeFunction(parent->previous(), tokenlist, errorLogger, settings);
3361         valueFlowForwardLifetime(parent, tokenlist, errorLogger, settings);
3362         // Variable
3363     } else if (tok->variable()) {
3364         const Variable *var = tok->variable();
3365         const Token *endOfVarScope = var->scope()->bodyEnd;
3366 
3367         std::list<ValueFlow::Value> values = tok->values();
3368         const Token *nextExpression = nextAfterAstRightmostLeaf(parent);
3369         // Only forward lifetime values
3370         values.remove_if(&isNotLifetimeValue);
3371         valueFlowForward(const_cast<Token*>(nextExpression), endOfVarScope, tok, values, tokenlist, settings);
3372         // Cast
3373     } else if (parent->isCast()) {
3374         std::list<ValueFlow::Value> values = tok->values();
3375         // Only forward lifetime values
3376         values.remove_if(&isNotLifetimeValue);
3377         for (const ValueFlow::Value& value:values)
3378             setTokenValue(parent, value, tokenlist->getSettings());
3379         valueFlowForwardLifetime(parent, tokenlist, errorLogger, settings);
3380     }
3381 }
3382 
3383 struct LifetimeStore {
3384     const Token *argtok;
3385     std::string message;
3386     ValueFlow::Value::LifetimeKind type;
3387     ErrorPath errorPath;
3388     bool inconclusive;
3389     bool forward;
3390 
3391     struct Context {
3392         Token* tok;
3393         TokenList* tokenlist;
3394         ErrorLogger* errorLogger;
3395         const Settings* settings;
3396     };
3397 
LifetimeStoreLifetimeStore3398     LifetimeStore()
3399         : argtok(nullptr), message(), type(), errorPath(), inconclusive(false), forward(true), mContext(nullptr)
3400     {}
3401 
LifetimeStoreLifetimeStore3402     LifetimeStore(const Token* argtok,
3403                   const std::string& message,
3404                   ValueFlow::Value::LifetimeKind type = ValueFlow::Value::LifetimeKind::Object,
3405                   bool inconclusive = false)
3406         : argtok(argtok),
3407         message(message),
3408         type(type),
3409         errorPath(),
3410         inconclusive(inconclusive),
3411         forward(true),
3412         mContext(nullptr)
3413     {}
3414 
3415     template<class F>
forEachLifetimeStore3416     static void forEach(const std::vector<const Token*>& argtoks,
3417                         const std::string& message,
3418                         ValueFlow::Value::LifetimeKind type,
3419                         F f) {
3420         std::map<const Token*, Context> forwardToks;
3421         for (const Token* arg : argtoks) {
3422             LifetimeStore ls{arg, message, type};
3423             Context c{};
3424             ls.mContext = &c;
3425             ls.forward = false;
3426             f(ls);
3427             if (c.tok)
3428                 forwardToks[c.tok] = c;
3429         }
3430         for (const auto& p : forwardToks) {
3431             const Context& c = p.second;
3432             valueFlowForwardLifetime(c.tok, c.tokenlist, c.errorLogger, c.settings);
3433         }
3434     }
3435 
fromFunctionArgLifetimeStore3436     static LifetimeStore fromFunctionArg(const Function * f, Token *tok, const Variable *var, TokenList *tokenlist, ErrorLogger *errorLogger) {
3437         if (!var)
3438             return LifetimeStore{};
3439         if (!var->isArgument())
3440             return LifetimeStore{};
3441         int n = getArgumentPos(var, f);
3442         if (n < 0)
3443             return LifetimeStore{};
3444         std::vector<const Token *> args = getArguments(tok);
3445         if (n >= args.size()) {
3446             if (tokenlist->getSettings()->debugwarnings)
3447                 bailout(tokenlist,
3448                         errorLogger,
3449                         tok,
3450                         "Argument mismatch: Function '" + tok->str() + "' returning lifetime from argument index " +
3451                         std::to_string(n) + " but only " + std::to_string(args.size()) +
3452                         " arguments are available.");
3453             return LifetimeStore{};
3454         }
3455         const Token *argtok2 = args[n];
3456         return LifetimeStore{argtok2, "Passed to '" + tok->expressionString() + "'.", ValueFlow::Value::LifetimeKind::Object};
3457     }
3458 
3459     template<class Predicate>
byRefLifetimeStore3460     bool byRef(Token* tok, TokenList* tokenlist, ErrorLogger* errorLogger, const Settings* settings, Predicate pred) const {
3461         if (!argtok)
3462             return false;
3463         bool update = false;
3464         for (const LifetimeToken& lt : getLifetimeTokens(argtok)) {
3465             if (!settings->certainty.isEnabled(Certainty::inconclusive) && lt.inconclusive)
3466                 continue;
3467             ErrorPath er = errorPath;
3468             er.insert(er.end(), lt.errorPath.begin(), lt.errorPath.end());
3469             if (!lt.token)
3470                 return false;
3471             if (!pred(lt.token))
3472                 return false;
3473             er.emplace_back(argtok, message);
3474 
3475             ValueFlow::Value value;
3476             value.valueType = ValueFlow::Value::ValueType::LIFETIME;
3477             value.lifetimeScope = ValueFlow::Value::LifetimeScope::Local;
3478             value.tokvalue = lt.token;
3479             value.errorPath = std::move(er);
3480             value.lifetimeKind = type;
3481             value.setInconclusive(lt.inconclusive || inconclusive);
3482             // Don't add the value a second time
3483             if (std::find(tok->values().begin(), tok->values().end(), value) != tok->values().end())
3484                 return false;
3485             setTokenValue(tok, value, tokenlist->getSettings());
3486             update = true;
3487         }
3488         if (update && forward)
3489             forwardLifetime(tok, tokenlist, errorLogger, settings);
3490         return update;
3491     }
3492 
byRefLifetimeStore3493     bool byRef(Token* tok, TokenList* tokenlist, ErrorLogger* errorLogger, const Settings* settings) const {
3494         return byRef(tok, tokenlist, errorLogger, settings, [](const Token*) {
3495             return true;
3496         });
3497     }
3498 
3499     template<class Predicate>
byValLifetimeStore3500     bool byVal(Token* tok, TokenList* tokenlist, ErrorLogger* errorLogger, const Settings* settings, Predicate pred) const {
3501         if (!argtok)
3502             return false;
3503         bool update = false;
3504         if (argtok->values().empty()) {
3505             ErrorPath er;
3506             er.emplace_back(argtok, message);
3507             const Variable *var = getLifetimeVariable(argtok, er);
3508             if (var && var->isArgument()) {
3509                 ValueFlow::Value value;
3510                 value.valueType = ValueFlow::Value::ValueType::LIFETIME;
3511                 value.lifetimeScope = ValueFlow::Value::LifetimeScope::Argument;
3512                 value.tokvalue = var->nameToken();
3513                 value.errorPath = er;
3514                 value.lifetimeKind = type;
3515                 value.setInconclusive(inconclusive);
3516                 // Don't add the value a second time
3517                 if (std::find(tok->values().begin(), tok->values().end(), value) != tok->values().end())
3518                     return false;
3519                 setTokenValue(tok, value, tokenlist->getSettings());
3520                 update = true;
3521             }
3522         }
3523         for (const ValueFlow::Value &v : argtok->values()) {
3524             if (!v.isLifetimeValue())
3525                 continue;
3526             const Token *tok3 = v.tokvalue;
3527             for (const LifetimeToken& lt : getLifetimeTokens(tok3)) {
3528                 if (!settings->certainty.isEnabled(Certainty::inconclusive) && lt.inconclusive)
3529                     continue;
3530                 ErrorPath er = v.errorPath;
3531                 er.insert(er.end(), lt.errorPath.begin(), lt.errorPath.end());
3532                 if (!lt.token)
3533                     return false;
3534                 if (!pred(lt.token))
3535                     return false;
3536                 er.emplace_back(argtok, message);
3537                 er.insert(er.end(), errorPath.begin(), errorPath.end());
3538 
3539                 ValueFlow::Value value;
3540                 value.valueType = ValueFlow::Value::ValueType::LIFETIME;
3541                 value.lifetimeScope = v.lifetimeScope;
3542                 value.path = v.path;
3543                 value.tokvalue = lt.token;
3544                 value.errorPath = std::move(er);
3545                 value.lifetimeKind = type;
3546                 value.setInconclusive(lt.inconclusive || v.isInconclusive() || inconclusive);
3547                 // Don't add the value a second time
3548                 if (std::find(tok->values().begin(), tok->values().end(), value) != tok->values().end())
3549                     continue;
3550                 setTokenValue(tok, value, tokenlist->getSettings());
3551                 update = true;
3552             }
3553         }
3554         if (update && forward)
3555             forwardLifetime(tok, tokenlist, errorLogger, settings);
3556         return update;
3557     }
3558 
byValLifetimeStore3559     bool byVal(Token* tok, TokenList* tokenlist, ErrorLogger* errorLogger, const Settings* settings) const {
3560         return byVal(tok, tokenlist, errorLogger, settings, [](const Token*) {
3561             return true;
3562         });
3563     }
3564 
3565     template<class Predicate>
byDerefCopyLifetimeStore3566     void byDerefCopy(Token *tok, TokenList *tokenlist, ErrorLogger *errorLogger, const Settings *settings, Predicate pred) const {
3567         if (!settings->certainty.isEnabled(Certainty::inconclusive) && inconclusive)
3568             return;
3569         if (!argtok)
3570             return;
3571         for (const ValueFlow::Value &v : argtok->values()) {
3572             if (!v.isLifetimeValue())
3573                 continue;
3574             const Token *tok2 = v.tokvalue;
3575             ErrorPath er = v.errorPath;
3576             const Variable *var = getLifetimeVariable(tok2, er);
3577             er.insert(er.end(), errorPath.begin(), errorPath.end());
3578             if (!var)
3579                 continue;
3580             for (const Token *tok3 = tok; tok3 && tok3 != var->declEndToken(); tok3 = tok3->previous()) {
3581                 if (tok3->varId() == var->declarationId()) {
3582                     LifetimeStore{tok3, message, type, inconclusive}.byVal(tok, tokenlist, errorLogger, settings, pred);
3583                     break;
3584                 }
3585             }
3586         }
3587     }
3588 
byDerefCopyLifetimeStore3589     void byDerefCopy(Token *tok, TokenList *tokenlist, ErrorLogger *errorLogger, const Settings *settings) const {
3590         byDerefCopy(tok, tokenlist, errorLogger, settings, [](const Token *) {
3591             return true;
3592         });
3593     }
3594 
3595 private:
3596     Context* mContext;
forwardLifetimeLifetimeStore3597     void forwardLifetime(Token* tok, TokenList* tokenlist, ErrorLogger* errorLogger, const Settings* settings) const {
3598         if (mContext) {
3599             mContext->tok = tok;
3600             mContext->tokenlist = tokenlist;
3601             mContext->errorLogger = errorLogger;
3602             mContext->settings = settings;
3603         }
3604         valueFlowForwardLifetime(tok, tokenlist, errorLogger, settings);
3605     }
3606 };
3607 
valueFlowLifetimeFunction(Token * tok,TokenList * tokenlist,ErrorLogger * errorLogger,const Settings * settings)3608 static void valueFlowLifetimeFunction(Token *tok, TokenList *tokenlist, ErrorLogger *errorLogger, const Settings *settings)
3609 {
3610     if (!Token::Match(tok, "%name% ("))
3611         return;
3612     int returnContainer = settings->library.returnValueContainer(tok);
3613     if (returnContainer >= 0) {
3614         std::vector<const Token *> args = getArguments(tok);
3615         for (int argnr = 1; argnr <= args.size(); ++argnr) {
3616             const Library::ArgumentChecks::IteratorInfo *i = settings->library.getArgIteratorInfo(tok, argnr);
3617             if (!i)
3618                 continue;
3619             if (i->container != returnContainer)
3620                 continue;
3621             const Token * const argTok = args[argnr - 1];
3622             bool forward = false;
3623             for (ValueFlow::Value val : argTok->values()) {
3624                 if (!val.isLifetimeValue())
3625                     continue;
3626                 val.errorPath.emplace_back(argTok, "Passed to '" + tok->str() + "'.");
3627                 setTokenValue(tok->next(), val, settings);
3628                 forward = true;
3629             }
3630             // Check if lifetime is available to avoid adding the lifetime twice
3631             if (forward) {
3632                 valueFlowForwardLifetime(tok, tokenlist, errorLogger, settings);
3633                 break;
3634             }
3635         }
3636     } else if (Token::Match(tok->tokAt(-2), "std :: ref|cref|tie|front_inserter|back_inserter")) {
3637         for (const Token *argtok : getArguments(tok)) {
3638             LifetimeStore{argtok, "Passed to '" + tok->str() + "'.", ValueFlow::Value::LifetimeKind::Object}.byRef(
3639                 tok->next(), tokenlist, errorLogger, settings);
3640         }
3641     } else if (Token::Match(tok->tokAt(-2), "std :: make_tuple|tuple_cat|make_pair|make_reverse_iterator|next|prev|move|bind")) {
3642         for (const Token *argtok : getArguments(tok)) {
3643             LifetimeStore{argtok, "Passed to '" + tok->str() + "'.", ValueFlow::Value::LifetimeKind::Object}.byVal(
3644                 tok->next(), tokenlist, errorLogger, settings);
3645         }
3646     } else if (Token::Match(tok->tokAt(-2), "%var% . push_back|push_front|insert|push|assign") &&
3647                astIsContainer(tok->tokAt(-2))) {
3648         Token *vartok = tok->tokAt(-2);
3649         std::vector<const Token *> args = getArguments(tok);
3650         std::size_t n = args.size();
3651         if (n > 1 && Token::typeStr(args[n - 2]) == Token::typeStr(args[n - 1]) &&
3652             (((astIsIterator(args[n - 2]) && astIsIterator(args[n - 1])) ||
3653               (astIsPointer(args[n - 2]) && astIsPointer(args[n - 1]))))) {
3654             LifetimeStore{args.back(), "Added to container '" + vartok->str() + "'.", ValueFlow::Value::LifetimeKind::Object}.byDerefCopy(
3655                 vartok, tokenlist, errorLogger, settings);
3656         } else if (!args.empty() && isLifetimeBorrowed(args.back(), settings)) {
3657             LifetimeStore{args.back(), "Added to container '" + vartok->str() + "'.", ValueFlow::Value::LifetimeKind::Object}.byVal(
3658                 vartok, tokenlist, errorLogger, settings);
3659         }
3660     } else if (tok->function()) {
3661         const Function *f = tok->function();
3662         if (Function::returnsReference(f))
3663             return;
3664         std::vector<const Token*> returns = Function::findReturns(f);
3665         const bool inconclusive = returns.size() > 1;
3666         bool update = false;
3667         for (const Token* returnTok : returns) {
3668             if (returnTok == tok)
3669                 continue;
3670             const Variable *returnVar = getLifetimeVariable(returnTok);
3671             if (returnVar && returnVar->isArgument() && (returnVar->isConst() || !isVariableChanged(returnVar, settings, tokenlist->isCPP()))) {
3672                 LifetimeStore ls = LifetimeStore::fromFunctionArg(f, tok, returnVar, tokenlist, errorLogger);
3673                 ls.inconclusive = inconclusive;
3674                 ls.forward = false;
3675                 update |= ls.byVal(tok->next(), tokenlist, errorLogger, settings);
3676             }
3677             for (const ValueFlow::Value &v : returnTok->values()) {
3678                 if (!v.isLifetimeValue())
3679                     continue;
3680                 if (!v.tokvalue)
3681                     continue;
3682                 const Variable *var = v.tokvalue->variable();
3683                 LifetimeStore ls = LifetimeStore::fromFunctionArg(f, tok, var, tokenlist, errorLogger);
3684                 if (!ls.argtok)
3685                     continue;
3686                 ls.forward = false;
3687                 ls.inconclusive = inconclusive;
3688                 ls.errorPath = v.errorPath;
3689                 ls.errorPath.emplace_front(returnTok, "Return " + lifetimeType(returnTok, &v) + ".");
3690                 if (!v.isArgumentLifetimeValue() && (var->isReference() || var->isRValueReference())) {
3691                     update |= ls.byRef(tok->next(), tokenlist, errorLogger, settings);
3692                 } else if (v.isArgumentLifetimeValue()) {
3693                     update |= ls.byVal(tok->next(), tokenlist, errorLogger, settings);
3694                 }
3695             }
3696         }
3697         if (update)
3698             valueFlowForwardLifetime(tok->next(), tokenlist, errorLogger, settings);
3699     }
3700 }
3701 
valueFlowLifetimeConstructor(Token * tok,const Type * t,TokenList * tokenlist,ErrorLogger * errorLogger,const Settings * settings)3702 static void valueFlowLifetimeConstructor(Token* tok,
3703                                          const Type* t,
3704                                          TokenList* tokenlist,
3705                                          ErrorLogger* errorLogger,
3706                                          const Settings* settings)
3707 {
3708     if (!Token::Match(tok, "(|{"))
3709         return;
3710     if (!t) {
3711         if (tok->valueType() && tok->valueType()->type != ValueType::RECORD)
3712             return;
3713         // If the type is unknown then assume it captures by value in the
3714         // constructor, but make each lifetime inconclusive
3715         std::vector<const Token*> args = getArguments(tok);
3716         LifetimeStore::forEach(
3717             args, "Passed to initializer list.", ValueFlow::Value::LifetimeKind::SubObject, [&](LifetimeStore& ls) {
3718             ls.inconclusive = true;
3719             ls.byVal(tok, tokenlist, errorLogger, settings);
3720         });
3721         return;
3722     }
3723     const Scope* scope = t->classScope;
3724     if (!scope)
3725         return;
3726     // Only support aggregate constructors for now
3727     if (scope->numConstructors == 0 && t->derivedFrom.empty() && (t->isClassType() || t->isStructType())) {
3728         std::vector<const Token*> args = getArguments(tok);
3729         auto it = scope->varlist.begin();
3730         LifetimeStore::forEach(args,
3731                                "Passed to constructor of '" + t->name() + "'.",
3732                                ValueFlow::Value::LifetimeKind::SubObject,
3733                                [&](const LifetimeStore& ls) {
3734             if (it == scope->varlist.end())
3735                 return;
3736             const Variable& var = *it;
3737             if (var.isReference() || var.isRValueReference()) {
3738                 ls.byRef(tok, tokenlist, errorLogger, settings);
3739             } else {
3740                 ls.byVal(tok, tokenlist, errorLogger, settings);
3741             }
3742             it++;
3743         });
3744     }
3745 }
3746 
hasInitList(const Token * tok)3747 static bool hasInitList(const Token* tok)
3748 {
3749     if (astIsPointer(tok))
3750         return true;
3751     if (astIsContainer(tok)) {
3752         const Library::Container * library = getLibraryContainer(tok);
3753         if (!library)
3754             return false;
3755         return library->hasInitializerListConstructor;
3756     }
3757     return false;
3758 }
3759 
valueFlowLifetimeConstructor(Token * tok,TokenList * tokenlist,ErrorLogger * errorLogger,const Settings * settings)3760 static void valueFlowLifetimeConstructor(Token* tok, TokenList* tokenlist, ErrorLogger* errorLogger, const Settings* settings)
3761 {
3762     if (!Token::Match(tok, "(|{"))
3763         return;
3764     Token* parent = tok->astParent();
3765     while (Token::simpleMatch(parent, ","))
3766         parent = parent->astParent();
3767     if (Token::simpleMatch(parent, "{") && hasInitList(parent->astParent())) {
3768         valueFlowLifetimeConstructor(tok, Token::typeOf(parent->previous()), tokenlist, errorLogger, settings);
3769     } else if (Token::simpleMatch(tok, "{") && hasInitList(parent)) {
3770         std::vector<const Token *> args = getArguments(tok);
3771         // Assume range constructor if passed a pair of iterators
3772         if (astIsContainer(parent) && args.size() == 2 && astIsIterator(args[0]) && astIsIterator(args[1])) {
3773             LifetimeStore::forEach(
3774                 args, "Passed to initializer list.", ValueFlow::Value::LifetimeKind::SubObject, [&](const LifetimeStore& ls) {
3775                 ls.byDerefCopy(tok, tokenlist, errorLogger, settings);
3776             });
3777         } else {
3778             LifetimeStore::forEach(args,
3779                                    "Passed to initializer list.",
3780                                    ValueFlow::Value::LifetimeKind::SubObject,
3781                                    [&](const LifetimeStore& ls) {
3782                 ls.byVal(tok, tokenlist, errorLogger, settings);
3783             });
3784         }
3785     } else {
3786         valueFlowLifetimeConstructor(tok, Token::typeOf(tok->previous()), tokenlist, errorLogger, settings);
3787     }
3788 }
3789 
3790 struct Lambda {
3791     enum class Capture {
3792         Undefined,
3793         ByValue,
3794         ByReference
3795     };
LambdaLambda3796     explicit Lambda(const Token * tok)
3797         : capture(nullptr), arguments(nullptr), returnTok(nullptr), bodyTok(nullptr), explicitCaptures(), implicitCapture(Capture::Undefined) {
3798         if (!Token::simpleMatch(tok, "[") || !tok->link())
3799             return;
3800         capture = tok;
3801 
3802         if (Token::simpleMatch(capture->link(), "] (")) {
3803             arguments = capture->link()->next();
3804         }
3805         const Token * afterArguments = arguments ? arguments->link()->next() : capture->link()->next();
3806         if (afterArguments && afterArguments->originalName() == "->") {
3807             returnTok = afterArguments->next();
3808             bodyTok = Token::findsimplematch(returnTok, "{");
3809         } else if (Token::simpleMatch(afterArguments, "{")) {
3810             bodyTok = afterArguments;
3811         }
3812         for (const Token* c:getCaptures()) {
3813             if (c->variable()) {
3814                 explicitCaptures[c->variable()] = std::make_pair(c, Capture::ByValue);
3815             } else if (c->isUnaryOp("&") && Token::Match(c->astOperand1(), "%var%")) {
3816                 explicitCaptures[c->astOperand1()->variable()] = std::make_pair(c->astOperand1(), Capture::ByReference);
3817             } else {
3818                 const std::string& s = c->expressionString();
3819                 if (s == "=")
3820                     implicitCapture = Capture::ByValue;
3821                 else if (s == "&")
3822                     implicitCapture = Capture::ByReference;
3823             }
3824         }
3825     }
3826 
3827     const Token * capture;
3828     const Token * arguments;
3829     const Token * returnTok;
3830     const Token * bodyTok;
3831     std::unordered_map<const Variable*, std::pair<const Token*, Capture>> explicitCaptures;
3832     Capture implicitCapture;
3833 
getCapturesLambda3834     std::vector<const Token*> getCaptures() {
3835         return getArguments(capture);
3836     }
3837 
isLambdaLambda3838     bool isLambda() const {
3839         return capture && bodyTok;
3840     }
3841 };
3842 
isDecayedPointer(const Token * tok)3843 static bool isDecayedPointer(const Token *tok)
3844 {
3845     if (!tok)
3846         return false;
3847     if (!tok->astParent())
3848         return false;
3849     if (astIsPointer(tok->astParent()) && !Token::simpleMatch(tok->astParent(), "return"))
3850         return true;
3851     if (tok->astParent()->isConstOp())
3852         return true;
3853     if (!Token::simpleMatch(tok->astParent(), "return"))
3854         return false;
3855     return astIsPointer(tok->astParent());
3856 }
3857 
valueFlowLifetime(TokenList * tokenlist,SymbolDatabase *,ErrorLogger * errorLogger,const Settings * settings)3858 static void valueFlowLifetime(TokenList *tokenlist, SymbolDatabase*, ErrorLogger *errorLogger, const Settings *settings)
3859 {
3860     for (Token *tok = tokenlist->front(); tok; tok = tok->next()) {
3861         if (!tok->scope())
3862             continue;
3863         if (tok->scope()->type == Scope::eGlobal)
3864             continue;
3865         Lambda lam(tok);
3866         // Lamdas
3867         if (lam.isLambda()) {
3868             const Scope * bodyScope = lam.bodyTok->scope();
3869 
3870             std::set<const Scope *> scopes;
3871             // Avoid capturing a variable twice
3872             std::set<nonneg int> varids;
3873 
3874             auto isImplicitCapturingVariable = [&](const Token *varTok) {
3875                 const Variable *var = varTok->variable();
3876                 if (!var)
3877                     return false;
3878                 if (varids.count(var->declarationId()) > 0)
3879                     return false;
3880                 if (!var->isLocal() && !var->isArgument())
3881                     return false;
3882                 const Scope *scope = var->scope();
3883                 if (!scope)
3884                     return false;
3885                 if (scopes.count(scope) > 0)
3886                     return false;
3887                 if (scope->isNestedIn(bodyScope))
3888                     return false;
3889                 scopes.insert(scope);
3890                 varids.insert(var->declarationId());
3891                 return true;
3892             };
3893 
3894             bool update = false;
3895             auto captureVariable = [&](const Token* tok2, Lambda::Capture c, std::function<bool(const Token*)> pred) {
3896                 if (varids.count(tok->varId()) > 0)
3897                     return;
3898                 ErrorPath errorPath;
3899                 if (c == Lambda::Capture::ByReference) {
3900                     LifetimeStore ls{
3901                         tok2, "Lambda captures variable by reference here.", ValueFlow::Value::LifetimeKind::Lambda};
3902                     ls.forward = false;
3903                     update |= ls.byRef(tok, tokenlist, errorLogger, settings, pred);
3904                 } else if (c == Lambda::Capture::ByValue) {
3905                     LifetimeStore ls{
3906                         tok2, "Lambda captures variable by value here.", ValueFlow::Value::LifetimeKind::Lambda};
3907                     ls.forward = false;
3908                     update |= ls.byVal(tok, tokenlist, errorLogger, settings, pred);
3909                     pred(tok2);
3910                 }
3911             };
3912 
3913             // Handle explicit capture
3914             for (const auto& p:lam.explicitCaptures) {
3915                 const Variable* var = p.first;
3916                 if (!var)
3917                     continue;
3918                 const Token* tok2 = p.second.first;
3919                 Lambda::Capture c = p.second.second;
3920                 captureVariable(tok2, c, [](const Token*) {
3921                     return true;
3922                 });
3923                 varids.insert(var->declarationId());
3924             }
3925 
3926             for (const Token * tok2 = lam.bodyTok; tok2 != lam.bodyTok->link(); tok2 = tok2->next()) {
3927                 if (!tok2->variable())
3928                     continue;
3929                 captureVariable(tok2, lam.implicitCapture, isImplicitCapturingVariable);
3930             }
3931             if (update)
3932                 valueFlowForwardLifetime(tok, tokenlist, errorLogger, settings);
3933         }
3934         // address of
3935         else if (tok->isUnaryOp("&")) {
3936             for (const LifetimeToken& lt : getLifetimeTokens(tok->astOperand1())) {
3937                 if (!settings->certainty.isEnabled(Certainty::inconclusive) && lt.inconclusive)
3938                     continue;
3939                 ErrorPath errorPath = lt.errorPath;
3940                 errorPath.emplace_back(tok, "Address of variable taken here.");
3941 
3942                 ValueFlow::Value value;
3943                 value.valueType = ValueFlow::Value::ValueType::LIFETIME;
3944                 value.lifetimeScope = ValueFlow::Value::LifetimeScope::Local;
3945                 value.tokvalue = lt.token;
3946                 value.errorPath = std::move(errorPath);
3947                 if (lt.addressOf || astIsPointer(lt.token) || !Token::Match(lt.token->astParent(), ".|["))
3948                     value.lifetimeKind = ValueFlow::Value::LifetimeKind::Address;
3949                 value.setInconclusive(lt.inconclusive);
3950                 setTokenValue(tok, value, tokenlist->getSettings());
3951 
3952                 valueFlowForwardLifetime(tok, tokenlist, errorLogger, settings);
3953             }
3954         }
3955         // container lifetimes
3956         else if (astIsContainer(tok)) {
3957             Token * parent = astParentSkipParens(tok);
3958             if (!Token::Match(parent, ". %name% ("))
3959                 continue;
3960 
3961             bool isContainerOfPointers = true;
3962             const Token* containerTypeToken = tok->valueType()->containerTypeToken;
3963             if (containerTypeToken) {
3964                 ValueType vt = ValueType::parseDecl(containerTypeToken, settings);
3965                 isContainerOfPointers = vt.pointer > 0;
3966             }
3967 
3968             ValueFlow::Value master;
3969             master.valueType = ValueFlow::Value::ValueType::LIFETIME;
3970             master.lifetimeScope = ValueFlow::Value::LifetimeScope::Local;
3971 
3972             if (astIsIterator(parent->tokAt(2))) {
3973                 master.errorPath.emplace_back(parent->tokAt(2), "Iterator to container is created here.");
3974                 master.lifetimeKind = ValueFlow::Value::LifetimeKind::Iterator;
3975             } else if ((astIsPointer(parent->tokAt(2)) && !isContainerOfPointers) ||
3976                        Token::Match(parent->next(), "data|c_str")) {
3977                 master.errorPath.emplace_back(parent->tokAt(2), "Pointer to container is created here.");
3978                 master.lifetimeKind = ValueFlow::Value::LifetimeKind::Object;
3979             } else {
3980                 continue;
3981             }
3982 
3983             std::vector<const Token*> toks = {};
3984             if (tok->isUnaryOp("*") || parent->originalName() == "->") {
3985                 for (const ValueFlow::Value& v : tok->values()) {
3986                     if (!v.isSymbolicValue())
3987                         continue;
3988                     if (v.isKnown())
3989                         continue;
3990                     if (v.intvalue != 0)
3991                         continue;
3992                     if (!v.tokvalue)
3993                         continue;
3994                     toks.push_back(v.tokvalue);
3995                 }
3996             } else {
3997                 toks = {tok};
3998             }
3999 
4000             for (const Token* tok2 : toks) {
4001                 for (const ReferenceToken& rt : followAllReferences(tok2, false)) {
4002                     ValueFlow::Value value = master;
4003                     value.tokvalue = rt.token;
4004                     value.errorPath.insert(value.errorPath.begin(), rt.errors.begin(), rt.errors.end());
4005                     setTokenValue(parent->tokAt(2), value, tokenlist->getSettings());
4006 
4007                     if (!rt.token->variable()) {
4008                         LifetimeStore ls = LifetimeStore{
4009                             rt.token, master.errorPath.back().second, ValueFlow::Value::LifetimeKind::Object};
4010                         ls.byRef(parent->tokAt(2), tokenlist, errorLogger, settings);
4011                     }
4012                 }
4013             }
4014             valueFlowForwardLifetime(parent->tokAt(2), tokenlist, errorLogger, settings);
4015         }
4016         // Check constructors
4017         else if (Token::Match(tok, "=|return|%type%|%var% {")) {
4018             valueFlowLifetimeConstructor(tok->next(), tokenlist, errorLogger, settings);
4019         }
4020         // Check function calls
4021         else if (Token::Match(tok, "%name% (")) {
4022             valueFlowLifetimeFunction(tok, tokenlist, errorLogger, settings);
4023         }
4024         // Check variables
4025         else if (tok->variable()) {
4026             ErrorPath errorPath;
4027             const Variable * var = getLifetimeVariable(tok, errorPath);
4028             if (!var)
4029                 continue;
4030             if (var->nameToken() == tok)
4031                 continue;
4032             if (var->isArray() && !var->isStlType() && !var->isArgument() && isDecayedPointer(tok)) {
4033                 errorPath.emplace_back(tok, "Array decayed to pointer here.");
4034 
4035                 ValueFlow::Value value;
4036                 value.valueType = ValueFlow::Value::ValueType::LIFETIME;
4037                 value.lifetimeScope = ValueFlow::Value::LifetimeScope::Local;
4038                 value.tokvalue = var->nameToken();
4039                 value.errorPath = errorPath;
4040                 setTokenValue(tok, value, tokenlist->getSettings());
4041 
4042                 valueFlowForwardLifetime(tok, tokenlist, errorLogger, settings);
4043             }
4044         }
4045         // Forward any lifetimes
4046         else if (std::any_of(tok->values().begin(), tok->values().end(), std::mem_fn(&ValueFlow::Value::isLifetimeValue))) {
4047             valueFlowForwardLifetime(tok, tokenlist, errorLogger, settings);
4048         }
4049     }
4050 }
4051 
isStdMoveOrStdForwarded(Token * tok,ValueFlow::Value::MoveKind * moveKind,Token ** varTok=nullptr)4052 static bool isStdMoveOrStdForwarded(Token * tok, ValueFlow::Value::MoveKind * moveKind, Token ** varTok = nullptr)
4053 {
4054     if (tok->str() != "std")
4055         return false;
4056     ValueFlow::Value::MoveKind kind = ValueFlow::Value::MoveKind::NonMovedVariable;
4057     Token * variableToken = nullptr;
4058     if (Token::Match(tok, "std :: move ( %var% )")) {
4059         variableToken = tok->tokAt(4);
4060         kind = ValueFlow::Value::MoveKind::MovedVariable;
4061     } else if (Token::simpleMatch(tok, "std :: forward <")) {
4062         const Token * const leftAngle = tok->tokAt(3);
4063         Token * rightAngle = leftAngle->link();
4064         if (Token::Match(rightAngle, "> ( %var% )")) {
4065             variableToken = rightAngle->tokAt(2);
4066             kind = ValueFlow::Value::MoveKind::ForwardedVariable;
4067         }
4068     }
4069     if (!variableToken)
4070         return false;
4071     if (variableToken->strAt(2) == ".") // Only partially moved
4072         return false;
4073     if (variableToken->valueType() && variableToken->valueType()->type >= ValueType::Type::VOID)
4074         return false;
4075     if (moveKind != nullptr)
4076         *moveKind = kind;
4077     if (varTok != nullptr)
4078         *varTok = variableToken;
4079     return true;
4080 }
4081 
isOpenParenthesisMemberFunctionCallOfVarId(const Token * openParenthesisToken,nonneg int varId)4082 static bool isOpenParenthesisMemberFunctionCallOfVarId(const Token * openParenthesisToken, nonneg int varId)
4083 {
4084     const Token * varTok = openParenthesisToken->tokAt(-3);
4085     return Token::Match(varTok, "%varid% . %name% (", varId) &&
4086            varTok->next()->originalName() == emptyString;
4087 }
4088 
findOpenParentesisOfMove(const Token * moveVarTok)4089 static const Token * findOpenParentesisOfMove(const Token * moveVarTok)
4090 {
4091     const Token * tok = moveVarTok;
4092     while (tok && tok->str() != "(")
4093         tok = tok->previous();
4094     return tok;
4095 }
4096 
findEndOfFunctionCallForParameter(const Token * parameterToken)4097 static const Token * findEndOfFunctionCallForParameter(const Token * parameterToken)
4098 {
4099     if (!parameterToken)
4100         return nullptr;
4101     const Token * parent = parameterToken->astParent();
4102     while (parent && !parent->isOp() && parent->str() != "(")
4103         parent = parent->astParent();
4104     if (!parent)
4105         return nullptr;
4106     return nextAfterAstRightmostLeaf(parent);
4107 }
4108 
valueFlowAfterMove(TokenList * tokenlist,SymbolDatabase * symboldatabase,const Settings * settings)4109 static void valueFlowAfterMove(TokenList* tokenlist, SymbolDatabase* symboldatabase, const Settings* settings)
4110 {
4111     if (!tokenlist->isCPP() || settings->standards.cpp < Standards::CPP11)
4112         return;
4113     for (const Scope * scope : symboldatabase->functionScopes) {
4114         if (!scope)
4115             continue;
4116         const Token * start = scope->bodyStart;
4117         if (scope->function) {
4118             const Token * memberInitializationTok = scope->function->constructorMemberInitialization();
4119             if (memberInitializationTok)
4120                 start = memberInitializationTok;
4121         }
4122 
4123         for (Token* tok = const_cast<Token*>(start); tok != scope->bodyEnd; tok = tok->next()) {
4124             Token * varTok;
4125             if (Token::Match(tok, "%var% . reset|clear (") && tok->next()->originalName() == emptyString) {
4126                 varTok = tok;
4127                 ValueFlow::Value value;
4128                 value.valueType = ValueFlow::Value::ValueType::MOVED;
4129                 value.moveKind = ValueFlow::Value::MoveKind::NonMovedVariable;
4130                 value.errorPath.emplace_back(tok, "Calling " + tok->next()->expressionString() + " makes " + tok->str() + " 'non-moved'");
4131                 value.setKnown();
4132                 std::list<ValueFlow::Value> values;
4133                 values.push_back(value);
4134 
4135                 const Variable *var = varTok->variable();
4136                 if (!var || (!var->isLocal() && !var->isArgument()))
4137                     continue;
4138                 const Token * const endOfVarScope = var->scope()->bodyEnd;
4139                 setTokenValue(varTok, value, settings);
4140                 valueFlowForward(varTok->next(), endOfVarScope, varTok, values, tokenlist, settings);
4141                 continue;
4142             }
4143             ValueFlow::Value::MoveKind moveKind;
4144             if (!isStdMoveOrStdForwarded(tok, &moveKind, &varTok))
4145                 continue;
4146             const nonneg int varId = varTok->varId();
4147             // x is not MOVED after assignment if code is:  x = ... std::move(x) .. ;
4148             const Token *parent = tok->astParent();
4149             while (parent && parent->str() != "=" && parent->str() != "return" &&
4150                    !(parent->str() == "(" && isOpenParenthesisMemberFunctionCallOfVarId(parent, varId)))
4151                 parent = parent->astParent();
4152             if (parent &&
4153                 (parent->str() == "return" || // MOVED in return statement
4154                  parent->str() == "(")) // MOVED in self assignment, isOpenParenthesisMemberFunctionCallOfVarId == true
4155                 continue;
4156             if (parent && parent->astOperand1() && parent->astOperand1()->varId() == varId)
4157                 continue;
4158             const Variable *var = varTok->variable();
4159             if (!var)
4160                 continue;
4161             const Token * const endOfVarScope = var->scope()->bodyEnd;
4162 
4163             ValueFlow::Value value;
4164             value.valueType = ValueFlow::Value::ValueType::MOVED;
4165             value.moveKind = moveKind;
4166             if (moveKind == ValueFlow::Value::MoveKind::MovedVariable)
4167                 value.errorPath.emplace_back(tok, "Calling std::move(" + varTok->str() + ")");
4168             else // if (moveKind == ValueFlow::Value::ForwardedVariable)
4169                 value.errorPath.emplace_back(tok, "Calling std::forward(" + varTok->str() + ")");
4170             value.setKnown();
4171             std::list<ValueFlow::Value> values;
4172             values.push_back(value);
4173             const Token * openParentesisOfMove = findOpenParentesisOfMove(varTok);
4174             const Token * endOfFunctionCall = findEndOfFunctionCallForParameter(openParentesisOfMove);
4175             if (endOfFunctionCall)
4176                 valueFlowForward(
4177                     const_cast<Token*>(endOfFunctionCall), endOfVarScope, varTok, values, tokenlist, settings);
4178         }
4179     }
4180 }
4181 
findIncompleteVar(const Token * start,const Token * end)4182 static const Token* findIncompleteVar(const Token* start, const Token* end)
4183 {
4184     for (const Token* tok = start; tok != end; tok = tok->next()) {
4185         if (tok->isIncompleteVar())
4186             return tok;
4187     }
4188     return nullptr;
4189 }
4190 
makeConditionValue(long long val,const Token * condTok,bool assume)4191 static ValueFlow::Value makeConditionValue(long long val, const Token* condTok, bool assume)
4192 {
4193     ValueFlow::Value v(val);
4194     v.setKnown();
4195     v.condition = condTok;
4196     if (assume)
4197         v.errorPath.emplace_back(condTok, "Assuming condition '" + condTok->expressionString() + "' is true");
4198     else
4199         v.errorPath.emplace_back(condTok, "Assuming condition '" + condTok->expressionString() + "' is false");
4200     return v;
4201 }
4202 
getConditions(const Token * tok,const char * op)4203 static std::vector<const Token*> getConditions(const Token* tok, const char* op)
4204 {
4205     std::vector<const Token*> conds = {tok};
4206     if (tok->str() == op) {
4207         std::vector<const Token*> args = astFlatten(tok, op);
4208         std::copy_if(args.begin(), args.end(), std::back_inserter(conds), [&](const Token* tok2) {
4209             if (tok2->exprId() == 0)
4210                 return false;
4211             if (tok2->hasKnownIntValue())
4212                 return false;
4213             return true;
4214         });
4215     }
4216     return conds;
4217 }
4218 
4219 //
valueFlowConditionExpressions(TokenList * tokenlist,SymbolDatabase * symboldatabase,ErrorLogger * errorLogger,const Settings * settings)4220 static void valueFlowConditionExpressions(TokenList *tokenlist, SymbolDatabase* symboldatabase, ErrorLogger *errorLogger, const Settings *settings)
4221 {
4222     for (const Scope * scope : symboldatabase->functionScopes) {
4223         if (const Token* incompleteTok = findIncompleteVar(scope->bodyStart, scope->bodyEnd)) {
4224             if (incompleteTok->isIncompleteVar()) {
4225                 if (settings->debugwarnings)
4226                     bailoutIncompleteVar(tokenlist, errorLogger, incompleteTok, "Skipping function due to incomplete variable " + incompleteTok->str());
4227                 break;
4228             }
4229         }
4230 
4231         for (const Token* tok = scope->bodyStart; tok != scope->bodyEnd; tok = tok->next()) {
4232             if (!Token::simpleMatch(tok, "if ("))
4233                 continue;
4234             Token * parenTok = tok->next();
4235             if (!Token::simpleMatch(parenTok->link(), ") {"))
4236                 continue;
4237             Token * blockTok = parenTok->link()->tokAt(1);
4238             const Token* condTok = parenTok->astOperand2();
4239             if (condTok->exprId() == 0)
4240                 continue;
4241             if (condTok->hasKnownIntValue())
4242                 continue;
4243             if (!isConstExpression(condTok, settings->library, true, tokenlist->isCPP()))
4244                 continue;
4245             const bool is1 = (condTok->isComparisonOp() || condTok->tokType() == Token::eLogicalOp || astIsBool(condTok));
4246 
4247             Token* startTok = blockTok;
4248             // Inner condition
4249             {
4250                 for (const Token* condTok2 : getConditions(condTok, "&&")) {
4251                     if (is1) {
4252                         ExpressionAnalyzer a1(condTok2, makeConditionValue(1, condTok2, true), tokenlist);
4253                         valueFlowGenericForward(startTok, startTok->link(), a1, settings);
4254                     }
4255 
4256                     OppositeExpressionAnalyzer a2(true, condTok2, makeConditionValue(0, condTok2, true), tokenlist);
4257                     valueFlowGenericForward(startTok, startTok->link(), a2, settings);
4258                 }
4259             }
4260 
4261             std::vector<const Token*> conds = getConditions(condTok, "||");
4262 
4263             // Check else block
4264             if (Token::simpleMatch(startTok->link(), "} else {")) {
4265                 startTok = startTok->link()->tokAt(2);
4266                 for (const Token* condTok2:conds) {
4267                     ExpressionAnalyzer a1(condTok2, makeConditionValue(0, condTok2, false), tokenlist);
4268                     valueFlowGenericForward(startTok, startTok->link(), a1, settings);
4269 
4270                     if (is1) {
4271                         OppositeExpressionAnalyzer a2(true, condTok2, makeConditionValue(1, condTok2, false), tokenlist);
4272                         valueFlowGenericForward(startTok, startTok->link(), a2, settings);
4273                     }
4274                 }
4275             }
4276 
4277             // Check if the block terminates early
4278             if (isEscapeScope(blockTok, tokenlist)) {
4279                 for (const Token* condTok2:conds) {
4280                     ExpressionAnalyzer a1(condTok2, makeConditionValue(0, condTok2, false), tokenlist);
4281                     valueFlowGenericForward(startTok->link()->next(), scope->bodyEnd, a1, settings);
4282 
4283                     if (is1) {
4284                         OppositeExpressionAnalyzer a2(true, condTok2, makeConditionValue(1, condTok2, false), tokenlist);
4285                         valueFlowGenericForward(startTok->link()->next(), scope->bodyEnd, a2, settings);
4286                     }
4287                 }
4288             }
4289 
4290         }
4291     }
4292 }
4293 
isTruncated(const ValueType * src,const ValueType * dst,const Settings * settings)4294 static bool isTruncated(const ValueType* src, const ValueType* dst, const Settings* settings)
4295 {
4296     if (src->pointer > 0 || dst->pointer > 0)
4297         return src->pointer != dst->pointer;
4298     if (src->smartPointer && dst->smartPointer)
4299         return false;
4300     if ((src->isIntegral() && dst->isIntegral()) || (src->isFloat() && dst->isFloat())) {
4301         size_t srcSize = ValueFlow::getSizeOf(*src, settings);
4302         size_t dstSize = ValueFlow::getSizeOf(*dst, settings);
4303         if (srcSize > dstSize)
4304             return true;
4305         if (srcSize == dstSize && src->sign != dst->sign)
4306             return true;
4307     } else if (src->type == dst->type) {
4308         if (src->type == ValueType::Type::RECORD)
4309             return src->typeScope != dst->typeScope;
4310     } else {
4311         return true;
4312     }
4313     return false;
4314 }
4315 
setSymbolic(ValueFlow::Value & value,const Token * tok)4316 static void setSymbolic(ValueFlow::Value& value, const Token* tok)
4317 {
4318     value.valueType = ValueFlow::Value::ValueType::SYMBOLIC;
4319     value.tokvalue = tok;
4320 }
4321 
makeSymbolic(const Token * tok,MathLib::bigint delta=0)4322 static ValueFlow::Value makeSymbolic(const Token* tok, MathLib::bigint delta = 0)
4323 {
4324     ValueFlow::Value value;
4325     value.setKnown();
4326     setSymbolic(value, tok);
4327     value.intvalue = delta;
4328     return value;
4329 }
4330 
valueFlowSymbolic(TokenList * tokenlist,SymbolDatabase * symboldatabase)4331 static void valueFlowSymbolic(TokenList* tokenlist, SymbolDatabase* symboldatabase)
4332 {
4333     for (const Scope* scope : symboldatabase->functionScopes) {
4334         for (Token* tok = const_cast<Token*>(scope->bodyStart); tok != scope->bodyEnd; tok = tok->next()) {
4335             if (!Token::simpleMatch(tok, "="))
4336                 continue;
4337             if (tok->astParent())
4338                 continue;
4339             if (!tok->astOperand1())
4340                 continue;
4341             if (!tok->astOperand2())
4342                 continue;
4343             if (tok->astOperand1()->hasKnownIntValue())
4344                 continue;
4345             if (tok->astOperand2()->hasKnownIntValue())
4346                 continue;
4347             if (tok->astOperand1()->exprId() == 0)
4348                 continue;
4349             if (tok->astOperand2()->exprId() == 0)
4350                 continue;
4351             if (!isConstExpression(tok->astOperand2(), tokenlist->getSettings()->library, true, tokenlist->isCPP()))
4352                 continue;
4353             if (tok->astOperand1()->valueType() && tok->astOperand2()->valueType()) {
4354                 if (isTruncated(
4355                         tok->astOperand2()->valueType(), tok->astOperand1()->valueType(), tokenlist->getSettings()))
4356                     continue;
4357             } else if (isDifferentType(tok->astOperand2(), tok->astOperand1())) {
4358                 continue;
4359             }
4360 
4361             Token* start = nextAfterAstRightmostLeaf(tok);
4362             const Token* end = scope->bodyEnd;
4363 
4364             ValueFlow::Value rhs = makeSymbolic(tok->astOperand2());
4365             rhs.errorPath.emplace_back(tok,
4366                                        tok->astOperand1()->expressionString() + " is assigned '" +
4367                                        tok->astOperand2()->expressionString() + "' here.");
4368             valueFlowForward(start, end, tok->astOperand1(), {rhs}, tokenlist, tokenlist->getSettings());
4369 
4370             ValueFlow::Value lhs = makeSymbolic(tok->astOperand1());
4371             lhs.errorPath.emplace_back(tok,
4372                                        tok->astOperand1()->expressionString() + " is assigned '" +
4373                                        tok->astOperand2()->expressionString() + "' here.");
4374             valueFlowForward(start, end, tok->astOperand2(), {lhs}, tokenlist, tokenlist->getSettings());
4375         }
4376     }
4377 }
4378 
valueFlowSymbolicAbs(TokenList * tokenlist,SymbolDatabase * symboldatabase)4379 static void valueFlowSymbolicAbs(TokenList* tokenlist, SymbolDatabase* symboldatabase)
4380 {
4381     for (const Scope* scope : symboldatabase->functionScopes) {
4382         for (Token* tok = const_cast<Token*>(scope->bodyStart); tok != scope->bodyEnd; tok = tok->next()) {
4383             if (!Token::Match(tok, "abs|labs|llabs|fabs|fabsf|fabsl ("))
4384                 continue;
4385             if (tok->hasKnownIntValue())
4386                 continue;
4387 
4388             const Token* arg = tok->next()->astOperand2();
4389             if (!arg)
4390                 continue;
4391             ValueFlow::Value c = inferCondition(">=", arg, 0);
4392             if (!c.isKnown())
4393                 continue;
4394 
4395             ValueFlow::Value v = makeSymbolic(arg);
4396             v.errorPath = c.errorPath;
4397             v.errorPath.emplace_back(tok, "Passed to " + tok->str());
4398             if (c.intvalue == 0)
4399                 v.setImpossible();
4400             else
4401                 v.setKnown();
4402             setTokenValue(tok->next(), v, tokenlist->getSettings());
4403         }
4404     }
4405 }
4406 
4407 template<class Predicate, class Compare>
getCompareValue(const std::list<ValueFlow::Value> & values,Predicate pred,Compare compare)4408 static const ValueFlow::Value* getCompareValue(const std::list<ValueFlow::Value>& values,
4409                                                Predicate pred,
4410                                                Compare compare)
4411 {
4412     const ValueFlow::Value* result = nullptr;
4413     for (const ValueFlow::Value& value : values) {
4414         if (!pred(value))
4415             continue;
4416         if (result)
4417             result = &std::min(value, *result, [compare](const ValueFlow::Value& x, const ValueFlow::Value& y) {
4418                 return compare(x.intvalue, y.intvalue);
4419             });
4420         else
4421             result = &value;
4422     }
4423     return result;
4424 }
4425 
4426 struct Interval {
4427     std::vector<MathLib::bigint> minvalue = {};
4428     std::vector<MathLib::bigint> maxvalue = {};
4429     std::vector<const ValueFlow::Value*> minRef = {};
4430     std::vector<const ValueFlow::Value*> maxRef = {};
4431 
setMinValueInterval4432     void setMinValue(MathLib::bigint x, const ValueFlow::Value* ref = nullptr)
4433     {
4434         minvalue = {x};
4435         if (ref)
4436             minRef = {ref};
4437     }
4438 
setMaxValueInterval4439     void setMaxValue(MathLib::bigint x, const ValueFlow::Value* ref = nullptr)
4440     {
4441         maxvalue = {x};
4442         if (ref)
4443             maxRef = {ref};
4444     }
4445 
isLessThanInterval4446     bool isLessThan(MathLib::bigint x, std::vector<const ValueFlow::Value*>* ref = nullptr) const
4447     {
4448         if (!this->maxvalue.empty() && this->maxvalue.front() < x) {
4449             if (ref)
4450                 *ref = maxRef;
4451             return true;
4452         }
4453         return false;
4454     }
4455 
isGreaterThanInterval4456     bool isGreaterThan(MathLib::bigint x, std::vector<const ValueFlow::Value*>* ref = nullptr) const
4457     {
4458         if (!this->minvalue.empty() && this->minvalue.front() > x) {
4459             if (ref)
4460                 *ref = minRef;
4461             return true;
4462         }
4463         return false;
4464     }
4465 
isScalarInterval4466     bool isScalar() const {
4467         return minvalue.size() == 1 && minvalue == maxvalue;
4468     }
4469 
emptyInterval4470     bool empty() const {
4471         return minvalue.empty() && maxvalue.empty();
4472     }
4473 
isScalarOrEmptyInterval4474     bool isScalarOrEmpty() const {
4475         return empty() || isScalar();
4476     }
4477 
getScalarInterval4478     MathLib::bigint getScalar() const
4479     {
4480         assert(isScalar());
4481         return minvalue.front();
4482     }
4483 
getScalarRefInterval4484     std::vector<const ValueFlow::Value*> getScalarRef() const
4485     {
4486         assert(isScalar());
4487         if (!minRef.empty())
4488             return minRef;
4489         if (!maxRef.empty())
4490             return maxRef;
4491         return {};
4492     }
4493 
fromIntInterval4494     static Interval fromInt(MathLib::bigint x, const ValueFlow::Value* ref = nullptr)
4495     {
4496         Interval result;
4497         result.setMinValue(x, ref);
4498         result.setMaxValue(x, ref);
4499         return result;
4500     }
4501 
4502     template<class Predicate>
fromValuesInterval4503     static Interval fromValues(const std::list<ValueFlow::Value>& values, Predicate predicate)
4504     {
4505         Interval result;
4506         const ValueFlow::Value* minValue = getCompareValue(values, predicate, std::less<MathLib::bigint>{});
4507         if (minValue) {
4508             if (minValue->isImpossible() && minValue->bound == ValueFlow::Value::Bound::Upper)
4509                 result.setMinValue(minValue->intvalue + 1, minValue);
4510             if (minValue->isPossible() && minValue->bound == ValueFlow::Value::Bound::Lower)
4511                 result.setMinValue(minValue->intvalue, minValue);
4512             if (minValue->isKnown())
4513                 return Interval::fromInt(minValue->intvalue, minValue);
4514         }
4515         const ValueFlow::Value* maxValue = getCompareValue(values, predicate, std::greater<MathLib::bigint>{});
4516         if (maxValue) {
4517             if (maxValue->isImpossible() && maxValue->bound == ValueFlow::Value::Bound::Lower)
4518                 result.setMaxValue(maxValue->intvalue - 1, maxValue);
4519             if (maxValue->isPossible() && maxValue->bound == ValueFlow::Value::Bound::Upper)
4520                 result.setMaxValue(maxValue->intvalue, maxValue);
4521             assert(!maxValue->isKnown());
4522         }
4523         return result;
4524     }
4525 
fromValuesInterval4526     static Interval fromValues(const std::list<ValueFlow::Value>& values)
4527     {
4528         return Interval::fromValues(values, [](const ValueFlow::Value&) {
4529             return true;
4530         });
4531     }
4532 
4533     template<class F>
applyInterval4534     static std::vector<MathLib::bigint> apply(const std::vector<MathLib::bigint>& x,
4535                                               const std::vector<MathLib::bigint>& y,
4536                                               F f)
4537     {
4538         if (x.empty())
4539             return {};
4540         if (y.empty())
4541             return {};
4542         return {f(x.front(), y.front())};
4543     }
4544 
mergeInterval4545     static std::vector<const ValueFlow::Value*> merge(std::vector<const ValueFlow::Value*> x,
4546                                                       const std::vector<const ValueFlow::Value*>& y)
4547     {
4548         x.insert(x.end(), y.begin(), y.end());
4549         return x;
4550     }
4551 
operator -(const Interval & lhs,const Interval & rhs)4552     friend Interval operator-(const Interval& lhs, const Interval& rhs)
4553     {
4554         Interval result;
4555         result.minvalue = Interval::apply(lhs.minvalue, rhs.maxvalue, std::minus<MathLib::bigint>{});
4556         result.maxvalue = Interval::apply(lhs.maxvalue, rhs.minvalue, std::minus<MathLib::bigint>{});
4557         if (!result.minvalue.empty())
4558             result.minRef = merge(lhs.minRef, rhs.maxRef);
4559         if (!result.maxvalue.empty())
4560             result.maxRef = merge(lhs.maxRef, rhs.minRef);
4561         return result;
4562     }
4563 
equalInterval4564     static std::vector<int> equal(const Interval& lhs,
4565                                   const Interval& rhs,
4566                                   std::vector<const ValueFlow::Value*>* ref = nullptr)
4567     {
4568         if (!lhs.isScalar())
4569             return {};
4570         if (!rhs.isScalar())
4571             return {};
4572         if (ref)
4573             *ref = merge(lhs.minRef, rhs.minRef);
4574         return {lhs.minvalue == rhs.minvalue};
4575     }
4576 
compareInterval4577     static std::vector<int> compare(const Interval& lhs,
4578                                     const Interval& rhs,
4579                                     std::vector<const ValueFlow::Value*>* ref = nullptr)
4580     {
4581         Interval diff = lhs - rhs;
4582         if (diff.isGreaterThan(0, ref))
4583             return {1};
4584         if (diff.isLessThan(0, ref))
4585             return {-1};
4586         std::vector<int> eq = Interval::equal(lhs, rhs, ref);
4587         if (!eq.empty() && eq.front() != 0)
4588             return {0};
4589         return {};
4590     }
4591 };
4592 
addToErrorPath(ValueFlow::Value & value,const std::vector<const ValueFlow::Value * > & refs)4593 static void addToErrorPath(ValueFlow::Value& value, const std::vector<const ValueFlow::Value*>& refs)
4594 {
4595     for (const ValueFlow::Value* ref : refs) {
4596         value.errorPath.insert(value.errorPath.end(), ref->errorPath.begin(), ref->errorPath.end());
4597     }
4598 }
4599 
setValueKind(ValueFlow::Value & value,const std::vector<const ValueFlow::Value * > & refs)4600 static void setValueKind(ValueFlow::Value& value, const std::vector<const ValueFlow::Value*>& refs)
4601 {
4602     bool isPossible = false;
4603     bool isInconclusive = false;
4604     for (const ValueFlow::Value* ref : refs) {
4605         if (ref->isPossible())
4606             isPossible = true;
4607         if (ref->isInconclusive())
4608             isInconclusive = true;
4609     }
4610     if (isInconclusive)
4611         value.setInconclusive();
4612     else if (isPossible)
4613         value.setPossible();
4614     else
4615         value.setKnown();
4616 }
4617 
4618 struct InferModel {
4619     virtual bool match(const ValueFlow::Value& value) const = 0;
4620     virtual ValueFlow::Value yield(MathLib::bigint value) const = 0;
~InferModelInferModel4621     virtual ~InferModel() {}
4622 };
4623 
inferNotEqual(const std::list<ValueFlow::Value> & values,MathLib::bigint x)4624 static bool inferNotEqual(const std::list<ValueFlow::Value>& values, MathLib::bigint x)
4625 {
4626     return std::any_of(values.begin(), values.end(), [&](const ValueFlow::Value& value) {
4627         return value.isImpossible() && value.intvalue == x;
4628     });
4629 }
4630 
infer(const ValuePtr<InferModel> & model,const std::string & op,std::list<ValueFlow::Value> lhsValues,std::list<ValueFlow::Value> rhsValues)4631 static std::vector<ValueFlow::Value> infer(const ValuePtr<InferModel>& model,
4632                                            const std::string& op,
4633                                            std::list<ValueFlow::Value> lhsValues,
4634                                            std::list<ValueFlow::Value> rhsValues)
4635 {
4636     std::vector<ValueFlow::Value> result;
4637     auto notMatch = [&](const ValueFlow::Value& value) {
4638         return !model->match(value);
4639     };
4640     lhsValues.remove_if(notMatch);
4641     rhsValues.remove_if(notMatch);
4642     if (lhsValues.empty() || rhsValues.empty())
4643         return result;
4644 
4645     Interval lhs = Interval::fromValues(lhsValues);
4646     Interval rhs = Interval::fromValues(rhsValues);
4647 
4648     if (op == "-") {
4649         Interval diff = lhs - rhs;
4650         if (diff.isScalar()) {
4651             std::vector<const ValueFlow::Value*> refs = diff.getScalarRef();
4652             ValueFlow::Value value(diff.getScalar());
4653             addToErrorPath(value, refs);
4654             setValueKind(value, refs);
4655             result.push_back(value);
4656         } else {
4657             if (!diff.minvalue.empty()) {
4658                 ValueFlow::Value value(diff.minvalue.front() - 1);
4659                 value.setImpossible();
4660                 value.bound = ValueFlow::Value::Bound::Upper;
4661                 addToErrorPath(value, diff.minRef);
4662                 result.push_back(value);
4663             }
4664             if (!diff.maxvalue.empty()) {
4665                 ValueFlow::Value value(diff.maxvalue.front() + 1);
4666                 value.setImpossible();
4667                 value.bound = ValueFlow::Value::Bound::Lower;
4668                 addToErrorPath(value, diff.maxRef);
4669                 result.push_back(value);
4670             }
4671         }
4672     } else if ((op == "!=" || op == "==") && lhs.isScalarOrEmpty() && rhs.isScalarOrEmpty()) {
4673         if (lhs.isScalar() && rhs.isScalar()) {
4674             std::vector<const ValueFlow::Value*> refs = Interval::merge(lhs.getScalarRef(), rhs.getScalarRef());
4675             ValueFlow::Value value(calculate(op, lhs.getScalar(), rhs.getScalar()));
4676             addToErrorPath(value, refs);
4677             setValueKind(value, refs);
4678             result.push_back(value);
4679         } else {
4680             std::vector<const ValueFlow::Value*> refs;
4681             if (lhs.isScalar() && inferNotEqual(rhsValues, lhs.getScalar()))
4682                 refs = lhs.getScalarRef();
4683             else if (rhs.isScalar() && inferNotEqual(lhsValues, rhs.getScalar()))
4684                 refs = rhs.getScalarRef();
4685             if (!refs.empty()) {
4686                 ValueFlow::Value value(op == "!=");
4687                 addToErrorPath(value, refs);
4688                 setValueKind(value, refs);
4689                 result.push_back(value);
4690             }
4691         }
4692     } else {
4693         std::vector<const ValueFlow::Value*> refs;
4694         std::vector<int> r = Interval::compare(lhs, rhs, &refs);
4695         if (!r.empty()) {
4696             int x = r.front();
4697             ValueFlow::Value value(calculate(op, x, 0));
4698             addToErrorPath(value, refs);
4699             setValueKind(value, refs);
4700             result.push_back(value);
4701         }
4702     }
4703 
4704     return result;
4705 }
4706 
infer(const ValuePtr<InferModel> & model,const std::string & op,MathLib::bigint lhs,std::list<ValueFlow::Value> rhsValues)4707 static std::vector<ValueFlow::Value> infer(const ValuePtr<InferModel>& model,
4708                                            const std::string& op,
4709                                            MathLib::bigint lhs,
4710                                            std::list<ValueFlow::Value> rhsValues)
4711 {
4712     return infer(model, op, {model->yield(lhs)}, std::move(rhsValues));
4713 }
4714 
infer(const ValuePtr<InferModel> & model,const std::string & op,std::list<ValueFlow::Value> lhsValues,MathLib::bigint rhs)4715 static std::vector<ValueFlow::Value> infer(const ValuePtr<InferModel>& model,
4716                                            const std::string& op,
4717                                            std::list<ValueFlow::Value> lhsValues,
4718                                            MathLib::bigint rhs)
4719 {
4720     return infer(model, op, std::move(lhsValues), {model->yield(rhs)});
4721 }
4722 
4723 struct SymbolicInferModel : InferModel {
4724     const Token* expr;
SymbolicInferModelSymbolicInferModel4725     explicit SymbolicInferModel(const Token* tok) : expr(tok) {
4726         assert(expr->exprId() != 0);
4727     }
matchSymbolicInferModel4728     virtual bool match(const ValueFlow::Value& value) const OVERRIDE
4729     {
4730         return value.isSymbolicValue() && value.tokvalue && value.tokvalue->exprId() == expr->exprId();
4731     }
yieldSymbolicInferModel4732     virtual ValueFlow::Value yield(MathLib::bigint value) const OVERRIDE
4733     {
4734         ValueFlow::Value result(value);
4735         result.valueType = ValueFlow::Value::ValueType::SYMBOLIC;
4736         result.tokvalue = expr;
4737         result.setKnown();
4738         return result;
4739     }
4740 };
4741 
valueFlowSymbolicInfer(TokenList * tokenlist,SymbolDatabase * symboldatabase)4742 static void valueFlowSymbolicInfer(TokenList* tokenlist, SymbolDatabase* symboldatabase)
4743 {
4744     for (const Scope* scope : symboldatabase->functionScopes) {
4745         for (Token* tok = const_cast<Token*>(scope->bodyStart); tok != scope->bodyEnd; tok = tok->next()) {
4746             if (!Token::Match(tok, "-|%comp%"))
4747                 continue;
4748             if (tok->hasKnownIntValue())
4749                 continue;
4750             if (!tok->astOperand1())
4751                 continue;
4752             if (!tok->astOperand2())
4753                 continue;
4754             if (tok->astOperand1()->exprId() == 0)
4755                 continue;
4756             if (tok->astOperand2()->exprId() == 0)
4757                 continue;
4758             if (tok->astOperand1()->hasKnownIntValue())
4759                 continue;
4760             if (tok->astOperand2()->hasKnownIntValue())
4761                 continue;
4762             if (astIsFloat(tok->astOperand1(), false))
4763                 continue;
4764             if (astIsFloat(tok->astOperand2(), false))
4765                 continue;
4766 
4767             SymbolicInferModel leftModel{tok->astOperand1()};
4768             std::vector<ValueFlow::Value> values = infer(leftModel, tok->str(), 0, tok->astOperand2()->values());
4769             if (values.empty()) {
4770                 SymbolicInferModel rightModel{tok->astOperand2()};
4771                 values = infer(rightModel, tok->str(), tok->astOperand1()->values(), 0);
4772             }
4773             for (const ValueFlow::Value& value : values) {
4774                 setTokenValue(tok, value, tokenlist->getSettings());
4775             }
4776         }
4777     }
4778 }
4779 
valueFlowForwardAssign(Token * const tok,const Token * expr,std::vector<const Variable * > vars,std::list<ValueFlow::Value> values,const bool init,TokenList * const tokenlist,ErrorLogger * const errorLogger,const Settings * const settings)4780 static void valueFlowForwardAssign(Token* const tok,
4781                                    const Token* expr,
4782                                    std::vector<const Variable*> vars,
4783                                    std::list<ValueFlow::Value> values,
4784                                    const bool init,
4785                                    TokenList* const tokenlist,
4786                                    ErrorLogger* const errorLogger,
4787                                    const Settings* const settings)
4788 {
4789     if (Token::simpleMatch(tok->astParent(), "return"))
4790         return;
4791     const Token* endOfVarScope = getEndOfVarScope(tok, vars);
4792     if (std::any_of(values.begin(), values.end(), std::mem_fn(&ValueFlow::Value::isLifetimeValue))) {
4793         valueFlowForwardLifetime(tok, tokenlist, errorLogger, settings);
4794         values.remove_if(std::mem_fn(&ValueFlow::Value::isLifetimeValue));
4795     }
4796     if (std::all_of(
4797             vars.begin(), vars.end(), [&](const Variable* var) {
4798         return !var->isPointer() && !var->isSmartPointer();
4799     }))
4800         values.remove_if(std::mem_fn(&ValueFlow::Value::isTokValue));
4801     if (tok->astParent()) {
4802         for (ValueFlow::Value& value : values) {
4803             std::string valueKind;
4804             if (value.valueKind == ValueFlow::Value::ValueKind::Impossible) {
4805                 if (value.bound == ValueFlow::Value::Bound::Point)
4806                     valueKind = "never ";
4807                 else if (value.bound == ValueFlow::Value::Bound::Lower)
4808                     valueKind = "less than ";
4809                 else if (value.bound == ValueFlow::Value::Bound::Upper)
4810                     valueKind = "greater than ";
4811             }
4812             const std::string info = "Assignment '" + tok->astParent()->expressionString() + "', assigned value is " + valueKind + value.infoString();
4813             value.errorPath.emplace_back(tok, info);
4814         }
4815     }
4816 
4817     if (tokenlist->isCPP() && vars.size() == 1 && Token::Match(vars.front()->typeStartToken(), "bool|_Bool")) {
4818         for (ValueFlow::Value& value : values) {
4819             if (value.isImpossible())
4820                 continue;
4821             if (value.isIntValue())
4822                 value.intvalue = (value.intvalue != 0);
4823             if (value.isTokValue())
4824                 value.intvalue = (value.tokvalue != nullptr);
4825         }
4826     }
4827 
4828     // Static variable initialisation?
4829     if (vars.size() == 1 && vars.front()->isStatic() && init)
4830         lowerToPossible(values);
4831 
4832     // Skip RHS
4833     const Token * nextExpression = tok->astParent() ? nextAfterAstRightmostLeaf(tok->astParent()) : tok->next();
4834 
4835     for (ValueFlow::Value& value : values) {
4836         if (value.isSymbolicValue())
4837             continue;
4838         if (value.isTokValue())
4839             continue;
4840         value.tokvalue = tok;
4841     }
4842     valueFlowForward(const_cast<Token*>(nextExpression), endOfVarScope, expr, values, tokenlist, settings);
4843 }
4844 
valueFlowForwardAssign(Token * const tok,const Variable * const var,const std::list<ValueFlow::Value> & values,const bool,const bool init,TokenList * const tokenlist,ErrorLogger * const errorLogger,const Settings * const settings)4845 static void valueFlowForwardAssign(Token* const tok,
4846                                    const Variable* const var,
4847                                    const std::list<ValueFlow::Value>& values,
4848                                    const bool,
4849                                    const bool init,
4850                                    TokenList* const tokenlist,
4851                                    ErrorLogger* const errorLogger,
4852                                    const Settings* const settings)
4853 {
4854     valueFlowForwardAssign(tok, var->nameToken(), {var}, values, init, tokenlist, errorLogger, settings);
4855 }
4856 
truncateValues(std::list<ValueFlow::Value> values,const ValueType * dst,const ValueType * src,const Settings * settings)4857 static std::list<ValueFlow::Value> truncateValues(std::list<ValueFlow::Value> values,
4858                                                   const ValueType* dst,
4859                                                   const ValueType* src,
4860                                                   const Settings* settings)
4861 {
4862     if (!dst || !dst->isIntegral())
4863         return values;
4864 
4865     const size_t sz = ValueFlow::getSizeOf(*dst, settings);
4866 
4867     if (src) {
4868         const size_t osz = ValueFlow::getSizeOf(*src, settings);
4869         if (osz >= sz && dst->sign == ValueType::Sign::SIGNED && src->sign == ValueType::Sign::UNSIGNED) {
4870             values.remove_if([&](const ValueFlow::Value& value) {
4871                 if (!value.isIntValue())
4872                     return false;
4873                 if (!value.isImpossible())
4874                     return false;
4875                 if (value.bound != ValueFlow::Value::Bound::Upper)
4876                     return false;
4877                 if (osz == sz && value.intvalue < 0)
4878                     return true;
4879                 if (osz > sz)
4880                     return true;
4881                 return false;
4882             });
4883         }
4884     }
4885 
4886     for (ValueFlow::Value &value : values) {
4887         // Don't truncate impossible values since those can be outside of the valid range
4888         if (value.isImpossible())
4889             continue;
4890         if (value.isFloatValue()) {
4891             value.intvalue = value.floatValue;
4892             value.valueType = ValueFlow::Value::ValueType::INT;
4893         }
4894 
4895         if (value.isIntValue() && sz > 0 && sz < 8) {
4896             const MathLib::biguint unsignedMaxValue = (1ULL << (sz * 8)) - 1ULL;
4897             const MathLib::biguint signBit = 1ULL << (sz * 8 - 1);
4898             value.intvalue &= unsignedMaxValue;
4899             if (dst->sign == ValueType::Sign::SIGNED && (value.intvalue & signBit))
4900                 value.intvalue |= ~unsignedMaxValue;
4901         }
4902     }
4903     return values;
4904 }
4905 
isVariableInit(const Token * tok)4906 static bool isVariableInit(const Token *tok)
4907 {
4908     return tok->str() == "(" &&
4909            tok->isBinaryOp() &&
4910            tok->astOperand1()->variable() &&
4911            tok->astOperand1()->variable()->nameToken() == tok->astOperand1() &&
4912            tok->astOperand1()->variable()->valueType() &&
4913            tok->astOperand1()->variable()->valueType()->type >= ValueType::Type::VOID &&
4914            !Token::simpleMatch(tok->astOperand2(), ",");
4915 }
4916 
valueFlowAfterAssign(TokenList * tokenlist,SymbolDatabase * symboldatabase,ErrorLogger * errorLogger,const Settings * settings)4917 static void valueFlowAfterAssign(TokenList *tokenlist, SymbolDatabase* symboldatabase, ErrorLogger *errorLogger, const Settings *settings)
4918 {
4919     for (const Scope * scope : symboldatabase->functionScopes) {
4920         std::set<nonneg int> aliased;
4921         for (Token* tok = const_cast<Token*>(scope->bodyStart); tok != scope->bodyEnd; tok = tok->next()) {
4922             // Alias
4923             if (tok->isUnaryOp("&")) {
4924                 aliased.insert(tok->astOperand1()->exprId());
4925                 continue;
4926             }
4927 
4928             // Assignment
4929             if ((tok->str() != "=" && !isVariableInit(tok)) || (tok->astParent()))
4930                 continue;
4931 
4932             // Lhs should be a variable
4933             if (!tok->astOperand1() || !tok->astOperand1()->exprId())
4934                 continue;
4935             const nonneg int exprid = tok->astOperand1()->exprId();
4936             if (aliased.find(exprid) != aliased.end())
4937                 continue;
4938             std::vector<const Variable*> vars = getLHSVariables(tok);
4939 
4940             // Rhs values..
4941             if (!tok->astOperand2() || tok->astOperand2()->values().empty())
4942                 continue;
4943 
4944             std::list<ValueFlow::Value> values = truncateValues(
4945                 tok->astOperand2()->values(), tok->astOperand1()->valueType(), tok->astOperand2()->valueType(), settings);
4946             // Remove known values
4947             std::set<ValueFlow::Value::ValueType> types;
4948             if (tok->astOperand1()->hasKnownValue()) {
4949                 for (const ValueFlow::Value& value:tok->astOperand1()->values()) {
4950                     if (value.isKnown() && !value.isSymbolicValue())
4951                         types.insert(value.valueType);
4952                 }
4953             }
4954             values.remove_if([&](const ValueFlow::Value& value) {
4955                 return types.count(value.valueType) > 0;
4956             });
4957             // Remove container size if its not a container
4958             if (!astIsContainer(tok->astOperand2()))
4959                 values.remove_if([&](const ValueFlow::Value& value) {
4960                     return value.valueType == ValueFlow::Value::ValueType::CONTAINER_SIZE;
4961                 });
4962             // Remove symbolic values that are the same as the LHS
4963             values.remove_if([&](const ValueFlow::Value& value) {
4964                 if (value.isSymbolicValue() && value.tokvalue)
4965                     return value.tokvalue->exprId() == tok->astOperand1()->exprId();
4966                 return false;
4967             });
4968             // If assignment copy by value, remove Uninit values..
4969             if ((tok->astOperand1()->valueType() && tok->astOperand1()->valueType()->pointer == 0) ||
4970                 (tok->astOperand1()->variable() && tok->astOperand1()->variable()->isReference() && tok->astOperand1()->variable()->nameToken() == tok->astOperand1()))
4971                 values.remove_if([&](const ValueFlow::Value& value) {
4972                     return value.isUninitValue();
4973                 });
4974             if (values.empty())
4975                 continue;
4976             const bool init = vars.size() == 1 && vars.front()->nameToken() == tok->astOperand1();
4977             valueFlowForwardAssign(
4978                 tok->astOperand2(), tok->astOperand1(), vars, values, init, tokenlist, errorLogger, settings);
4979         }
4980     }
4981 }
4982 
valueFlowSetConditionToKnown(const Token * tok,std::list<ValueFlow::Value> & values,bool then)4983 static void valueFlowSetConditionToKnown(const Token* tok, std::list<ValueFlow::Value>& values, bool then)
4984 {
4985     if (values.empty())
4986         return;
4987     if (then && !Token::Match(tok, "==|!|("))
4988         return;
4989     if (!then && !Token::Match(tok, "!=|%var%|("))
4990         return;
4991     if (isConditionKnown(tok, then))
4992         changePossibleToKnown(values);
4993 }
4994 
isBreakScope(const Token * const endToken)4995 static bool isBreakScope(const Token* const endToken)
4996 {
4997     if (!Token::simpleMatch(endToken, "}"))
4998         return false;
4999     if (!Token::simpleMatch(endToken->link(), "{"))
5000         return false;
5001     return Token::findmatch(endToken->link(), "break|goto", endToken);
5002 }
5003 
asImpossible(ValueFlow::Value v)5004 static ValueFlow::Value asImpossible(ValueFlow::Value v)
5005 {
5006     v.invertRange();
5007     v.setImpossible();
5008     return v;
5009 }
5010 
insertImpossible(std::list<ValueFlow::Value> & values,const std::list<ValueFlow::Value> & input)5011 static void insertImpossible(std::list<ValueFlow::Value>& values, const std::list<ValueFlow::Value>& input)
5012 {
5013     std::transform(input.begin(), input.end(), std::back_inserter(values), &asImpossible);
5014 }
5015 
insertNegateKnown(std::list<ValueFlow::Value> & values,const std::list<ValueFlow::Value> & input)5016 static void insertNegateKnown(std::list<ValueFlow::Value>& values, const std::list<ValueFlow::Value>& input)
5017 {
5018     for (ValueFlow::Value value:input) {
5019         if (!value.isIntValue() && !value.isContainerSizeValue())
5020             continue;
5021         value.intvalue = !value.intvalue;
5022         value.setKnown();
5023         values.push_back(value);
5024     }
5025 }
5026 
5027 struct ConditionHandler {
5028     struct Condition {
5029         const Token *vartok;
5030         std::list<ValueFlow::Value> true_values;
5031         std::list<ValueFlow::Value> false_values;
5032         bool inverted = false;
5033         // Whether to insert impossible values for the condition or only use possible values
5034         bool impossible = true;
5035 
ConditionConditionHandler::Condition5036         Condition() : vartok(nullptr), true_values(), false_values(), inverted(false), impossible(true) {}
5037     };
5038 
5039     virtual Analyzer::Result forward(Token* start,
5040                                      const Token* stop,
5041                                      const Token* exprTok,
5042                                      const std::list<ValueFlow::Value>& values,
5043                                      TokenList* tokenlist,
5044                                      const Settings* settings) const = 0;
5045 
5046     virtual Analyzer::Result forward(Token* top,
5047                                      const Token* exprTok,
5048                                      const std::list<ValueFlow::Value>& values,
5049                                      TokenList* tokenlist,
5050                                      const Settings* settings) const = 0;
5051 
5052     virtual void reverse(Token* start,
5053                          const Token* endToken,
5054                          const Token* exprTok,
5055                          const std::list<ValueFlow::Value>& values,
5056                          TokenList* tokenlist,
5057                          const Settings* settings) const = 0;
5058 
5059     virtual std::vector<Condition> parse(const Token* tok, const Settings* settings) const = 0;
5060 
traverseConditionConditionHandler5061     void traverseCondition(TokenList* tokenlist,
5062                            SymbolDatabase* symboldatabase,
5063                            const std::function<void(const Condition& cond, Token* tok, const Scope* scope)>& f) const
5064     {
5065         for (const Scope *scope : symboldatabase->functionScopes) {
5066             for (Token *tok = const_cast<Token *>(scope->bodyStart); tok != scope->bodyEnd; tok = tok->next()) {
5067                 if (Token::Match(tok, "if|while|for ("))
5068                     continue;
5069 
5070                 const Token* top = tok->astTop();
5071                 if (!top)
5072                     continue;
5073 
5074                 if (!Token::Match(top->previous(), "if|while|for (") && !Token::Match(tok->astParent(), "&&|%oror%|?"))
5075                     continue;
5076                 for (const Condition& cond : parse(tok, tokenlist->getSettings())) {
5077                     if (!cond.vartok)
5078                         continue;
5079                     if (cond.vartok->exprId() == 0)
5080                         continue;
5081                     if (cond.vartok->hasKnownIntValue())
5082                         continue;
5083                     if (cond.true_values.empty() || cond.false_values.empty())
5084                         continue;
5085                     if (!isConstExpression(cond.vartok, tokenlist->getSettings()->library, true, tokenlist->isCPP()))
5086                         continue;
5087                     f(cond, tok, scope);
5088                 }
5089             }
5090         }
5091     }
5092 
beforeConditionConditionHandler5093     void beforeCondition(TokenList* tokenlist,
5094                          SymbolDatabase* symboldatabase,
5095                          ErrorLogger* errorLogger,
5096                          const Settings* settings) const {
5097         traverseCondition(tokenlist, symboldatabase, [&](const Condition& cond, Token* tok, const Scope*) {
5098             if (cond.vartok->exprId() == 0)
5099                 return;
5100 
5101             // If condition is known then don't propagate value
5102             if (tok->hasKnownIntValue())
5103                 return;
5104 
5105             const Token* top = tok->astTop();
5106 
5107             if (Token::Match(top, "%assign%"))
5108                 return;
5109             if (Token::Match(cond.vartok->astParent(), "%assign%|++|--"))
5110                 return;
5111 
5112             if (Token::simpleMatch(tok->astParent(), "?") && tok->astParent()->isExpandedMacro()) {
5113                 if (settings->debugwarnings)
5114                     bailout(tokenlist,
5115                             errorLogger,
5116                             tok,
5117                             "variable '" + cond.vartok->expressionString() + "', condition is defined in macro");
5118                 return;
5119             }
5120 
5121             // if,macro => bailout
5122             if (Token::simpleMatch(top->previous(), "if (") && top->previous()->isExpandedMacro()) {
5123                 if (settings->debugwarnings)
5124                     bailout(tokenlist,
5125                             errorLogger,
5126                             tok,
5127                             "variable '" + cond.vartok->expressionString() + "', condition is defined in macro");
5128                 return;
5129             }
5130 
5131             std::list<ValueFlow::Value> values = cond.true_values;
5132             if (cond.true_values != cond.false_values)
5133                 values.insert(values.end(), cond.false_values.begin(), cond.false_values.end());
5134 
5135             // extra logic for unsigned variables 'i>=1' => possible value can also be 0
5136             if (Token::Match(tok, "<|>")) {
5137                 values.remove_if([](const ValueFlow::Value& v) {
5138                     if (v.isIntValue())
5139                         return v.intvalue != 0;
5140                     return false;
5141                 });
5142                 if (cond.vartok->valueType() && cond.vartok->valueType()->sign != ValueType::Sign::UNSIGNED)
5143                     return;
5144             }
5145             if (values.empty())
5146                 return;
5147 
5148             // bailout: for/while-condition, variable is changed in while loop
5149             if (Token::Match(top->previous(), "for|while (") && Token::simpleMatch(top->link(), ") {")) {
5150 
5151                 // Variable changed in 3rd for-expression
5152                 if (Token::simpleMatch(top->previous(), "for (")) {
5153                     if (top->astOperand2() && top->astOperand2()->astOperand2() &&
5154                         isExpressionChanged(
5155                             cond.vartok, top->astOperand2()->astOperand2(), top->link(), settings, tokenlist->isCPP())) {
5156                         if (settings->debugwarnings)
5157                             bailout(tokenlist,
5158                                     errorLogger,
5159                                     tok,
5160                                     "variable '" + cond.vartok->expressionString() + "' used in loop");
5161                         return;
5162                     }
5163                 }
5164 
5165                 // Variable changed in loop code
5166                 const Token* const start = top;
5167                 const Token* const block = top->link()->next();
5168                 const Token* const end = block->link();
5169 
5170                 if (isExpressionChanged(cond.vartok, start, end, settings, tokenlist->isCPP())) {
5171                     // If its reassigned in loop then analyze from the end
5172                     if (!Token::Match(tok, "%assign%|++|--") &&
5173                         findExpression(cond.vartok->exprId(), start, end, [&](const Token* tok2) {
5174                         return Token::Match(tok2->astParent(), "%assign%") && astIsLHS(tok2);
5175                     })) {
5176                         // Start at the end of the loop body
5177                         Token* bodyTok = top->link()->next();
5178                         reverse(bodyTok->link(), bodyTok, cond.vartok, values, tokenlist, settings);
5179                     }
5180                     if (settings->debugwarnings)
5181                         bailout(tokenlist,
5182                                 errorLogger,
5183                                 tok,
5184                                 "variable '" + cond.vartok->expressionString() + "' used in loop");
5185                     return;
5186                 }
5187             }
5188 
5189             Token* startTok = nullptr;
5190             if (astIsRHS(tok))
5191                 startTok = tok->astParent();
5192             else if (astIsLHS(tok))
5193                 startTok = previousBeforeAstLeftmostLeaf(tok->astParent());
5194             if (!startTok)
5195                 startTok = tok->previous();
5196 
5197             reverse(startTok, nullptr, cond.vartok, values, tokenlist, settings);
5198         });
5199     }
5200 
afterConditionConditionHandler5201     void afterCondition(TokenList* tokenlist,
5202                         SymbolDatabase* symboldatabase,
5203                         ErrorLogger* errorLogger,
5204                         const Settings* settings) const {
5205         traverseCondition(tokenlist, symboldatabase, [&](const Condition& cond, Token* tok, const Scope* scope) {
5206             if (Token::simpleMatch(tok->astParent(), "?"))
5207                 return;
5208             const Token* top = tok->astTop();
5209 
5210             std::list<ValueFlow::Value> thenValues;
5211             std::list<ValueFlow::Value> elseValues;
5212 
5213             if (!Token::Match(tok, "!=|=|(|.") && tok != cond.vartok) {
5214                 thenValues.insert(thenValues.end(), cond.true_values.begin(), cond.true_values.end());
5215                 if (cond.impossible && isConditionKnown(tok, false))
5216                     insertImpossible(elseValues, cond.false_values);
5217             }
5218             if (!Token::Match(tok, "==|!")) {
5219                 elseValues.insert(elseValues.end(), cond.false_values.begin(), cond.false_values.end());
5220                 if (cond.impossible && isConditionKnown(tok, true)) {
5221                     insertImpossible(thenValues, cond.true_values);
5222                     if (tok == cond.vartok && astIsBool(tok))
5223                         insertNegateKnown(thenValues, cond.true_values);
5224                 }
5225             }
5226 
5227             if (cond.inverted)
5228                 std::swap(thenValues, elseValues);
5229 
5230             if (Token::Match(tok->astParent(), "%oror%|&&")) {
5231                 Token* parent = tok->astParent();
5232                 if (astIsRHS(tok) && astIsLHS(parent) && parent->astParent() &&
5233                     parent->str() == parent->astParent()->str())
5234                     parent = parent->astParent();
5235                 else if (!astIsLHS(tok)) {
5236                     parent = nullptr;
5237                 }
5238                 if (parent) {
5239                     std::vector<Token*> nextExprs = {parent->astOperand2()};
5240                     if (astIsLHS(parent) && parent->astParent() && parent->astParent()->str() == parent->str()) {
5241                         nextExprs.push_back(parent->astParent()->astOperand2());
5242                     }
5243                     const std::string& op(parent->str());
5244                     std::list<ValueFlow::Value> values;
5245                     if (op == "&&")
5246                         values = thenValues;
5247                     else if (op == "||")
5248                         values = elseValues;
5249                     if (Token::Match(tok, "==|!=") || (tok == cond.vartok && astIsBool(tok)))
5250                         changePossibleToKnown(values);
5251                     if (astIsFloat(cond.vartok, false) ||
5252                         (!cond.vartok->valueType() &&
5253                          std::all_of(values.begin(), values.end(), [](const ValueFlow::Value& v) {
5254                         return v.isIntValue() || v.isFloatValue();
5255                     })))
5256                         values.remove_if([&](const ValueFlow::Value& v) {
5257                             return v.isImpossible();
5258                         });
5259                     for (Token* start:nextExprs) {
5260                         Analyzer::Result r = forward(start, cond.vartok, values, tokenlist, settings);
5261                         if (r.terminate != Analyzer::Terminate::None)
5262                             return;
5263                     }
5264                 }
5265             }
5266 
5267             {
5268                 const Token* tok2 = tok;
5269                 std::string op;
5270                 bool mixedOperators = false;
5271                 while (tok2->astParent()) {
5272                     const Token* parent = tok2->astParent();
5273                     if (Token::Match(parent, "%oror%|&&")) {
5274                         if (op.empty()) {
5275                             op = parent->str();
5276                         } else if (op != parent->str()) {
5277                             mixedOperators = true;
5278                             break;
5279                         }
5280                     }
5281                     if (parent->str() == "!") {
5282                         op = (op == "&&" ? "||" : "&&");
5283                     }
5284                     tok2 = parent;
5285                 }
5286 
5287                 if (mixedOperators) {
5288                     return;
5289                 }
5290             }
5291 
5292             if (top && Token::Match(top->previous(), "if|while (") && !top->previous()->isExpandedMacro()) {
5293                 // if astParent is "!" we need to invert codeblock
5294                 {
5295                     const Token* tok2 = tok;
5296                     while (tok2->astParent()) {
5297                         const Token* parent = tok2->astParent();
5298                         while (parent && parent->str() == "&&")
5299                             parent = parent->astParent();
5300                         if (parent && (parent->str() == "!" || Token::simpleMatch(parent, "== false")))
5301                             std::swap(thenValues, elseValues);
5302                         tok2 = parent;
5303                     }
5304                 }
5305 
5306                 bool deadBranch[] = {false, false};
5307                 // start token of conditional code
5308                 Token* startTokens[] = {nullptr, nullptr};
5309                 // determine startToken(s)
5310                 if (Token::simpleMatch(top->link(), ") {"))
5311                     startTokens[0] = top->link()->next();
5312                 if (Token::simpleMatch(top->link()->linkAt(1), "} else {"))
5313                     startTokens[1] = top->link()->linkAt(1)->tokAt(2);
5314 
5315                 int changeBlock = -1;
5316                 int bailBlock = -1;
5317 
5318                 for (int i = 0; i < 2; i++) {
5319                     const Token* const startToken = startTokens[i];
5320                     if (!startToken)
5321                         continue;
5322                     std::list<ValueFlow::Value>& values = (i == 0 ? thenValues : elseValues);
5323                     valueFlowSetConditionToKnown(tok, values, i == 0);
5324 
5325                     Analyzer::Result r =
5326                         forward(startTokens[i], startTokens[i]->link(), cond.vartok, values, tokenlist, settings);
5327                     deadBranch[i] = r.terminate == Analyzer::Terminate::Escape;
5328                     if (r.action.isModified() && !deadBranch[i])
5329                         changeBlock = i;
5330                     if (r.terminate != Analyzer::Terminate::None && r.terminate != Analyzer::Terminate::Escape &&
5331                         r.terminate != Analyzer::Terminate::Modified)
5332                         bailBlock = i;
5333                     changeKnownToPossible(values);
5334                 }
5335                 if (changeBlock >= 0 && !Token::simpleMatch(top->previous(), "while (")) {
5336                     if (settings->debugwarnings)
5337                         bailout(tokenlist,
5338                                 errorLogger,
5339                                 startTokens[changeBlock]->link(),
5340                                 "valueFlowAfterCondition: " + cond.vartok->expressionString() +
5341                                 " is changed in conditional block");
5342                     return;
5343                 } else if (bailBlock >= 0) {
5344                     if (settings->debugwarnings)
5345                         bailout(tokenlist,
5346                                 errorLogger,
5347                                 startTokens[bailBlock]->link(),
5348                                 "valueFlowAfterCondition: bailing in conditional block");
5349                     return;
5350                 }
5351 
5352                 // After conditional code..
5353                 if (Token::simpleMatch(top->link(), ") {")) {
5354                     Token* after = top->link()->linkAt(1);
5355                     bool dead_if = deadBranch[0];
5356                     bool dead_else = deadBranch[1];
5357                     const Token* unknownFunction = nullptr;
5358                     if (tok->astParent() && Token::simpleMatch(tok->astParent()->previous(), "while ("))
5359                         dead_if = !isBreakScope(after);
5360                     else if (!dead_if)
5361                         dead_if = isReturnScope(after, &settings->library, &unknownFunction);
5362 
5363                     if (!dead_if && unknownFunction) {
5364                         if (settings->debugwarnings)
5365                             bailout(tokenlist, errorLogger, unknownFunction, "possible noreturn scope");
5366                         return;
5367                     }
5368 
5369                     if (Token::simpleMatch(after, "} else {")) {
5370                         after = after->linkAt(2);
5371                         unknownFunction = nullptr;
5372                         if (!dead_else)
5373                             dead_else = isReturnScope(after, &settings->library, &unknownFunction);
5374                         if (!dead_else && unknownFunction) {
5375                             if (settings->debugwarnings)
5376                                 bailout(tokenlist, errorLogger, unknownFunction, "possible noreturn scope");
5377                             return;
5378                         }
5379                     }
5380 
5381                     if (dead_if && dead_else)
5382                         return;
5383 
5384                     std::list<ValueFlow::Value> values;
5385                     if (dead_if) {
5386                         values = elseValues;
5387                     } else if (dead_else) {
5388                         values = thenValues;
5389                     } else {
5390                         std::copy_if(thenValues.begin(),
5391                                      thenValues.end(),
5392                                      std::back_inserter(values),
5393                                      std::mem_fn(&ValueFlow::Value::isPossible));
5394                         std::copy_if(elseValues.begin(),
5395                                      elseValues.end(),
5396                                      std::back_inserter(values),
5397                                      std::mem_fn(&ValueFlow::Value::isPossible));
5398                     }
5399 
5400                     if (values.empty())
5401                         return;
5402 
5403                     if (dead_if || dead_else) {
5404                         const Token* parent = tok->astParent();
5405                         // Skip the not operator
5406                         while (Token::simpleMatch(parent, "!"))
5407                             parent = parent->astParent();
5408                         bool possible = false;
5409                         if (Token::Match(parent, "&&|%oror%")) {
5410                             std::string op = parent->str();
5411                             while (parent && parent->str() == op)
5412                                 parent = parent->astParent();
5413                             if (Token::simpleMatch(parent, "!") || Token::simpleMatch(parent, "== false"))
5414                                 possible = op == "||";
5415                             else
5416                                 possible = op == "&&";
5417                         }
5418                         if (possible) {
5419                             values.remove_if(std::mem_fn(&ValueFlow::Value::isImpossible));
5420                             changeKnownToPossible(values);
5421                         } else {
5422                             valueFlowSetConditionToKnown(tok, values, true);
5423                             valueFlowSetConditionToKnown(tok, values, false);
5424                         }
5425                     }
5426                     if (values.empty())
5427                         return;
5428                     forward(after, scope->bodyEnd, cond.vartok, values, tokenlist, settings);
5429                 }
5430             }
5431         });
5432     }
~ConditionHandlerConditionHandler5433     virtual ~ConditionHandler() {}
5434 };
5435 
valueFlowCondition(const ValuePtr<ConditionHandler> & handler,TokenList * tokenlist,SymbolDatabase * symboldatabase,ErrorLogger * errorLogger,const Settings * settings)5436 static void valueFlowCondition(const ValuePtr<ConditionHandler>& handler,
5437                                TokenList* tokenlist,
5438                                SymbolDatabase* symboldatabase,
5439                                ErrorLogger* errorLogger,
5440                                const Settings* settings)
5441 {
5442     handler->beforeCondition(tokenlist, symboldatabase, errorLogger, settings);
5443     handler->afterCondition(tokenlist, symboldatabase, errorLogger, settings);
5444 }
5445 
5446 struct SimpleConditionHandler : ConditionHandler {
forwardSimpleConditionHandler5447     virtual Analyzer::Result forward(Token* start,
5448                                      const Token* stop,
5449                                      const Token* exprTok,
5450                                      const std::list<ValueFlow::Value>& values,
5451                                      TokenList* tokenlist,
5452                                      const Settings* settings) const OVERRIDE {
5453         return valueFlowForward(start->next(), stop, exprTok, values, tokenlist, settings);
5454     }
5455 
forwardSimpleConditionHandler5456     virtual Analyzer::Result forward(Token* top,
5457                                      const Token* exprTok,
5458                                      const std::list<ValueFlow::Value>& values,
5459                                      TokenList* tokenlist,
5460                                      const Settings* settings) const OVERRIDE {
5461         return valueFlowForward(top, exprTok, values, tokenlist, settings);
5462     }
5463 
reverseSimpleConditionHandler5464     virtual void reverse(Token* start,
5465                          const Token* endToken,
5466                          const Token* exprTok,
5467                          const std::list<ValueFlow::Value>& values,
5468                          TokenList* tokenlist,
5469                          const Settings* settings) const OVERRIDE {
5470         return valueFlowReverse(start, endToken, exprTok, values, tokenlist, settings);
5471     }
5472 
parseSimpleConditionHandler5473     virtual std::vector<Condition> parse(const Token* tok, const Settings*) const OVERRIDE {
5474         Condition cond;
5475         ValueFlow::Value true_value;
5476         ValueFlow::Value false_value;
5477         const Token *vartok = parseCompareInt(tok, true_value, false_value);
5478         if (vartok) {
5479             if (vartok->hasKnownIntValue())
5480                 return {};
5481             if (vartok->str() == "=" && vartok->astOperand1() && vartok->astOperand2())
5482                 vartok = vartok->astOperand1();
5483             cond.true_values.push_back(true_value);
5484             cond.false_values.push_back(false_value);
5485             cond.vartok = vartok;
5486             return {cond};
5487         }
5488 
5489         if (tok->str() == "!") {
5490             vartok = tok->astOperand1();
5491 
5492         } else if (tok->astParent() && (Token::Match(tok->astParent(), "%oror%|&&|?") ||
5493                                         Token::Match(tok->astParent()->previous(), "if|while ("))) {
5494             if (Token::simpleMatch(tok, "="))
5495                 vartok = tok->astOperand1();
5496             else if (!Token::Match(tok, "%comp%|%assign%"))
5497                 vartok = tok;
5498         }
5499 
5500         if (!vartok)
5501             return {};
5502         cond.true_values.emplace_back(tok, 0LL);
5503         cond.false_values.emplace_back(tok, 0LL);
5504         cond.vartok = vartok;
5505 
5506         return {cond};
5507     }
5508 };
5509 
isInBounds(const ValueFlow::Value & value,MathLib::bigint x)5510 static bool isInBounds(const ValueFlow::Value& value, MathLib::bigint x)
5511 {
5512     if (value.intvalue == x)
5513         return true;
5514     if (value.bound == ValueFlow::Value::Bound::Lower && value.intvalue > x)
5515         return false;
5516     if (value.bound == ValueFlow::Value::Bound::Upper && value.intvalue < x)
5517         return false;
5518     // Checking for equality is not necessary since we already know the value is not equal
5519     if (value.bound == ValueFlow::Value::Bound::Point)
5520         return false;
5521     return true;
5522 }
5523 
getCompareIntValue(const std::list<ValueFlow::Value> & values,std::function<bool (MathLib::bigint,MathLib::bigint)> compare)5524 static const ValueFlow::Value* getCompareIntValue(const std::list<ValueFlow::Value>& values, std::function<bool(MathLib::bigint, MathLib::bigint)> compare)
5525 {
5526     const ValueFlow::Value* result = nullptr;
5527     for (const ValueFlow::Value& value : values) {
5528         if (!value.isIntValue())
5529             continue;
5530         if (result)
5531             result = &std::min(value, *result, [compare](const ValueFlow::Value& x, const ValueFlow::Value& y) {
5532                 return compare(x.intvalue, y.intvalue);
5533             });
5534         else
5535             result = &value;
5536     }
5537     return result;
5538 }
5539 
proveLessThan(const std::list<ValueFlow::Value> & values,MathLib::bigint x)5540 static const ValueFlow::Value* proveLessThan(const std::list<ValueFlow::Value>& values, MathLib::bigint x)
5541 {
5542     const ValueFlow::Value* result = nullptr;
5543     const ValueFlow::Value* maxValue = getCompareIntValue(values, std::greater<MathLib::bigint> {});
5544     if (maxValue && maxValue->isImpossible() && maxValue->bound == ValueFlow::Value::Bound::Lower) {
5545         if (maxValue->intvalue <= x)
5546             result = maxValue;
5547     }
5548     return result;
5549 }
5550 
proveGreaterThan(const std::list<ValueFlow::Value> & values,MathLib::bigint x)5551 static const ValueFlow::Value* proveGreaterThan(const std::list<ValueFlow::Value>& values, MathLib::bigint x)
5552 {
5553     const ValueFlow::Value* result = nullptr;
5554     const ValueFlow::Value* minValue = getCompareIntValue(values, std::less<MathLib::bigint> {});
5555     if (minValue && minValue->isImpossible() && minValue->bound == ValueFlow::Value::Bound::Upper) {
5556         if (minValue->intvalue >= x)
5557             result = minValue;
5558     }
5559     return result;
5560 }
5561 
proveNotEqual(const std::list<ValueFlow::Value> & values,MathLib::bigint x)5562 static const ValueFlow::Value* proveNotEqual(const std::list<ValueFlow::Value>& values, MathLib::bigint x)
5563 {
5564     const ValueFlow::Value* result = nullptr;
5565     for (const ValueFlow::Value& value : values) {
5566         if (value.valueType != ValueFlow::Value::ValueType::INT)
5567             continue;
5568         if (result && !isInBounds(value, result->intvalue))
5569             continue;
5570         if (value.isImpossible()) {
5571             if (value.intvalue == x)
5572                 return &value;
5573             if (!isInBounds(value, x))
5574                 continue;
5575             result = &value;
5576         } else {
5577             if (value.intvalue == x)
5578                 return nullptr;
5579             if (!isInBounds(value, x))
5580                 continue;
5581             result = nullptr;
5582         }
5583     }
5584     return result;
5585 }
5586 
inferCondition(const std::string & op,const Token * varTok,MathLib::bigint val)5587 ValueFlow::Value inferCondition(const std::string& op, const Token* varTok, MathLib::bigint val)
5588 {
5589     if (!varTok)
5590         return ValueFlow::Value{};
5591     if (varTok->hasKnownIntValue())
5592         return ValueFlow::Value{};
5593     if (std::none_of(varTok->values().begin(), varTok->values().end(), [](const ValueFlow::Value& v) {
5594         return v.isImpossible() && v.valueType == ValueFlow::Value::ValueType::INT;
5595     })) {
5596         return ValueFlow::Value{};
5597     }
5598     const ValueFlow::Value* result = nullptr;
5599     bool known = false;
5600     if (op == "==" || op == "!=") {
5601         result = proveNotEqual(varTok->values(), val);
5602         known = op == "!=";
5603     } else if (op == "<" || op == ">=") {
5604         result = proveLessThan(varTok->values(), val);
5605         known = op == "<";
5606         if (!result && !isSaturated(val)) {
5607             result = proveGreaterThan(varTok->values(), val - 1);
5608             known = op == ">=";
5609         }
5610     } else if (op == ">" || op == "<=") {
5611         result = proveGreaterThan(varTok->values(), val);
5612         known = op == ">";
5613         if (!result && !isSaturated(val)) {
5614             result = proveLessThan(varTok->values(), val + 1);
5615             known = op == "<=";
5616         }
5617     }
5618     if (!result)
5619         return ValueFlow::Value{};
5620     ValueFlow::Value value = *result;
5621     value.intvalue = known;
5622     value.bound = ValueFlow::Value::Bound::Point;
5623     value.setKnown();
5624     return value;
5625 }
5626 
inferCondition(std::string op,MathLib::bigint val,const Token * varTok)5627 ValueFlow::Value inferCondition(std::string op, MathLib::bigint val, const Token* varTok)
5628 {
5629     // Flip the operator
5630     if (op == ">")
5631         op = "<";
5632     else if (op == "<")
5633         op = ">";
5634     else if (op == ">=")
5635         op = "<=";
5636     else if (op == "<=")
5637         op = ">=";
5638     return inferCondition(op, varTok, val);
5639 }
5640 
valueFlowInferCondition(TokenList * tokenlist,const Settings * settings)5641 static void valueFlowInferCondition(TokenList* tokenlist,
5642                                     const Settings* settings)
5643 {
5644     for (Token* tok = tokenlist->front(); tok; tok = tok->next()) {
5645         if (!tok->astParent())
5646             continue;
5647         if (tok->hasKnownIntValue())
5648             continue;
5649         if (tok->variable() && (Token::Match(tok->astParent(), "?|&&|!|%oror%") ||
5650                                 Token::Match(tok->astParent()->previous(), "if|while ("))) {
5651             const ValueFlow::Value* result = proveNotEqual(tok->values(), 0);
5652             if (!result)
5653                 continue;
5654             ValueFlow::Value value = *result;
5655             value.intvalue = 1;
5656             value.bound = ValueFlow::Value::Bound::Point;
5657             value.setKnown();
5658             setTokenValue(tok, value, settings);
5659         } else if (tok->isComparisonOp()) {
5660             ValueFlow::Value value{};
5661             std::string op = tok->str();
5662             if (tok->astOperand1()->hasKnownIntValue()) {
5663                 MathLib::bigint val = tok->astOperand1()->values().front().intvalue;
5664                 const Token* varTok = tok->astOperand2();
5665                 value = inferCondition(tok->str(), val, varTok);
5666             } else if (tok->astOperand2()->hasKnownIntValue()) {
5667                 MathLib::bigint val = tok->astOperand2()->values().front().intvalue;
5668                 const Token* varTok = tok->astOperand1();
5669                 value = inferCondition(tok->str(), varTok, val);
5670             }
5671 
5672             if (!value.isKnown())
5673                 continue;
5674             setTokenValue(tok, value, settings);
5675         }
5676     }
5677 }
5678 
5679 struct SymbolicConditionHandler : SimpleConditionHandler {
parseSymbolicConditionHandler5680     virtual std::vector<Condition> parse(const Token* tok, const Settings*) const OVERRIDE
5681     {
5682         if (!Token::Match(tok, "%comp%"))
5683             return {};
5684         if (tok->hasKnownIntValue())
5685             return {};
5686         if (!tok->astOperand1() || tok->astOperand1()->hasKnownIntValue() || tok->astOperand1()->isLiteral())
5687             return {};
5688         if (!tok->astOperand2() || tok->astOperand2()->hasKnownIntValue() || tok->astOperand2()->isLiteral())
5689             return {};
5690 
5691         std::vector<Condition> result;
5692         for (int i = 0; i < 2; i++) {
5693             const bool lhs = i == 0;
5694             const Token* vartok = lhs ? tok->astOperand1() : tok->astOperand2();
5695             const Token* valuetok = lhs ? tok->astOperand2() : tok->astOperand1();
5696             if (valuetok->hasKnownSymbolicValue(vartok))
5697                 continue;
5698             if (vartok->hasKnownSymbolicValue(valuetok))
5699                 continue;
5700             ValueFlow::Value true_value;
5701             ValueFlow::Value false_value;
5702             setConditionalValues(tok, !lhs, 0, true_value, false_value);
5703             setSymbolic(true_value, valuetok);
5704             setSymbolic(false_value, valuetok);
5705 
5706             Condition cond;
5707             cond.true_values = {true_value};
5708             cond.false_values = {false_value};
5709             cond.vartok = vartok;
5710             result.push_back(cond);
5711         }
5712         return result;
5713     }
5714 };
5715 
valueFlowForLoop2(const Token * tok,ProgramMemory * memory1,ProgramMemory * memory2,ProgramMemory * memoryAfter)5716 static bool valueFlowForLoop2(const Token *tok,
5717                               ProgramMemory *memory1,
5718                               ProgramMemory *memory2,
5719                               ProgramMemory *memoryAfter)
5720 {
5721     // for ( firstExpression ; secondExpression ; thirdExpression )
5722     const Token *firstExpression  = tok->next()->astOperand2()->astOperand1();
5723     const Token *secondExpression = tok->next()->astOperand2()->astOperand2()->astOperand1();
5724     const Token *thirdExpression = tok->next()->astOperand2()->astOperand2()->astOperand2();
5725 
5726     ProgramMemory programMemory;
5727     MathLib::bigint result(0);
5728     bool error = false;
5729     execute(firstExpression, &programMemory, &result, &error);
5730     if (error)
5731         return false;
5732     execute(secondExpression, &programMemory, &result, &error);
5733     if (result == 0) // 2nd expression is false => no looping
5734         return false;
5735     if (error) {
5736         // If a variable is reassigned in second expression, return false
5737         bool reassign = false;
5738         visitAstNodes(secondExpression,
5739                       [&](const Token *t) {
5740             if (t->str() == "=" && t->astOperand1() && programMemory.hasValue(t->astOperand1()->varId()))
5741                 // TODO: investigate what variable is assigned.
5742                 reassign = true;
5743             return reassign ? ChildrenToVisit::done : ChildrenToVisit::op1_and_op2;
5744         });
5745         if (reassign)
5746             return false;
5747     }
5748 
5749     ProgramMemory startMemory(programMemory);
5750     ProgramMemory endMemory;
5751 
5752     int maxcount = 10000;
5753     while (result != 0 && !error && --maxcount > 0) {
5754         endMemory = programMemory;
5755         execute(thirdExpression, &programMemory, &result, &error);
5756         if (!error)
5757             execute(secondExpression, &programMemory, &result, &error);
5758     }
5759 
5760     if (memory1)
5761         memory1->swap(startMemory);
5762     if (!error) {
5763         if (memory2)
5764             memory2->swap(endMemory);
5765         if (memoryAfter)
5766             memoryAfter->swap(programMemory);
5767     }
5768 
5769     return true;
5770 }
5771 
valueFlowForLoopSimplify(Token * const bodyStart,const nonneg int varid,bool globalvar,const MathLib::bigint value,TokenList * tokenlist,ErrorLogger * errorLogger,const Settings * settings)5772 static void valueFlowForLoopSimplify(Token * const bodyStart, const nonneg int varid, bool globalvar, const MathLib::bigint value, TokenList *tokenlist, ErrorLogger *errorLogger, const Settings *settings)
5773 {
5774     const Token * const bodyEnd = bodyStart->link();
5775 
5776     // Is variable modified inside for loop
5777     if (isVariableChanged(bodyStart, bodyEnd, varid, globalvar, settings, tokenlist->isCPP()))
5778         return;
5779 
5780     for (Token *tok2 = bodyStart->next(); tok2 != bodyEnd; tok2 = tok2->next()) {
5781         if (tok2->varId() == varid) {
5782             const Token * parent = tok2->astParent();
5783             while (parent) {
5784                 const Token * const p = parent;
5785                 parent = parent->astParent();
5786                 if (!parent || parent->str() == ":")
5787                     break;
5788                 if (parent->str() == "?") {
5789                     if (parent->astOperand2() != p)
5790                         parent = nullptr;
5791                     break;
5792                 }
5793             }
5794             if (parent) {
5795                 if (settings->debugwarnings)
5796                     bailout(tokenlist, errorLogger, tok2, "For loop variable " + tok2->str() + " stopping on ?");
5797                 continue;
5798             }
5799 
5800             ValueFlow::Value value1(value);
5801             value1.varId = tok2->varId();
5802             setTokenValue(tok2, value1, settings);
5803         }
5804 
5805         if (Token::Match(tok2, "%oror%|&&")) {
5806             const ProgramMemory programMemory(getProgramMemory(tok2->astTop(), varid, ValueFlow::Value(value), settings));
5807             if ((tok2->str() == "&&" && !conditionIsTrue(tok2->astOperand1(), programMemory)) ||
5808                 (tok2->str() == "||" && !conditionIsFalse(tok2->astOperand1(), programMemory))) {
5809                 // Skip second expression..
5810                 const Token *parent = tok2;
5811                 while (parent && parent->str() == tok2->str())
5812                     parent = parent->astParent();
5813                 // Jump to end of condition
5814                 if (parent && parent->str() == "(") {
5815                     tok2 = parent->link();
5816                     // cast
5817                     if (Token::simpleMatch(tok2, ") ("))
5818                         tok2 = tok2->linkAt(1);
5819                 }
5820             }
5821 
5822         }
5823         if ((tok2->str() == "&&" && conditionIsFalse(tok2->astOperand1(), getProgramMemory(tok2->astTop(), varid, ValueFlow::Value(value), settings))) ||
5824             (tok2->str() == "||" && conditionIsTrue(tok2->astOperand1(), getProgramMemory(tok2->astTop(), varid, ValueFlow::Value(value), settings))))
5825             break;
5826 
5827         else if (Token::simpleMatch(tok2, ") {") && Token::findmatch(tok2->link(), "%varid%", tok2, varid)) {
5828             if (Token::findmatch(tok2, "continue|break|return", tok2->linkAt(1), varid)) {
5829                 if (settings->debugwarnings)
5830                     bailout(tokenlist, errorLogger, tok2, "For loop variable bailout on conditional continue|break|return");
5831                 break;
5832             }
5833             if (settings->debugwarnings)
5834                 bailout(tokenlist, errorLogger, tok2, "For loop variable skipping conditional scope");
5835             tok2 = tok2->next()->link();
5836             if (Token::simpleMatch(tok2, "} else {")) {
5837                 if (Token::findmatch(tok2, "continue|break|return", tok2->linkAt(2), varid)) {
5838                     if (settings->debugwarnings)
5839                         bailout(tokenlist, errorLogger, tok2, "For loop variable bailout on conditional continue|break|return");
5840                     break;
5841                 }
5842 
5843                 tok2 = tok2->linkAt(2);
5844             }
5845         }
5846 
5847         else if (Token::simpleMatch(tok2, ") {")) {
5848             if (settings->debugwarnings)
5849                 bailout(tokenlist, errorLogger, tok2, "For loop skipping {} code");
5850             tok2 = tok2->linkAt(1);
5851             if (Token::simpleMatch(tok2, "} else {"))
5852                 tok2 = tok2->linkAt(2);
5853         }
5854     }
5855 }
5856 
valueFlowForLoopSimplifyAfter(Token * fortok,nonneg int varid,const MathLib::bigint num,TokenList * tokenlist,const Settings * settings)5857 static void valueFlowForLoopSimplifyAfter(Token* fortok,
5858                                           nonneg int varid,
5859                                           const MathLib::bigint num,
5860                                           TokenList* tokenlist,
5861                                           const Settings* settings)
5862 {
5863     const Token *vartok = nullptr;
5864     for (const Token *tok = fortok; tok; tok = tok->next()) {
5865         if (tok->varId() == varid) {
5866             vartok = tok;
5867             break;
5868         }
5869     }
5870     if (!vartok || !vartok->variable())
5871         return;
5872 
5873     const Variable *var = vartok->variable();
5874     const Token *endToken = nullptr;
5875     if (var->isLocal())
5876         endToken = var->scope()->bodyEnd;
5877     else
5878         endToken = fortok->scope()->bodyEnd;
5879 
5880     Token* blockTok = fortok->linkAt(1)->linkAt(1);
5881     std::list<ValueFlow::Value> values;
5882     values.emplace_back(num);
5883     values.back().errorPath.emplace_back(fortok,"After for loop, " + var->name() + " has value " + values.back().infoString());
5884 
5885     if (blockTok != endToken) {
5886         valueFlowForward(blockTok->next(), endToken, vartok, values, tokenlist, settings);
5887     }
5888 }
5889 
valueFlowForLoop(TokenList * tokenlist,SymbolDatabase * symboldatabase,ErrorLogger * errorLogger,const Settings * settings)5890 static void valueFlowForLoop(TokenList *tokenlist, SymbolDatabase* symboldatabase, ErrorLogger *errorLogger, const Settings *settings)
5891 {
5892     for (const Scope &scope : symboldatabase->scopeList) {
5893         if (scope.type != Scope::eFor)
5894             continue;
5895 
5896         Token* tok = const_cast<Token*>(scope.classDef);
5897         Token* const bodyStart = const_cast<Token*>(scope.bodyStart);
5898 
5899         if (!Token::simpleMatch(tok->next()->astOperand2(), ";") ||
5900             !Token::simpleMatch(tok->next()->astOperand2()->astOperand2(), ";"))
5901             continue;
5902 
5903         nonneg int varid;
5904         bool knownInitValue, partialCond;
5905         MathLib::bigint initValue, stepValue, lastValue;
5906 
5907         if (extractForLoopValues(tok, &varid, &knownInitValue, &initValue, &partialCond, &stepValue, &lastValue)) {
5908             const bool executeBody = !knownInitValue || initValue <= lastValue;
5909             const Token* vartok = Token::findmatch(tok, "%varid%", bodyStart, varid);
5910             if (executeBody && vartok) {
5911                 std::list<ValueFlow::Value> initValues;
5912                 initValues.emplace_back(initValue, ValueFlow::Value::Bound::Lower);
5913                 initValues.push_back(asImpossible(initValues.back()));
5914                 Analyzer::Result result =
5915                     valueFlowForward(bodyStart, bodyStart->link(), vartok, initValues, tokenlist, settings);
5916 
5917                 if (!result.action.isModified()) {
5918                     std::list<ValueFlow::Value> lastValues;
5919                     lastValues.emplace_back(lastValue, ValueFlow::Value::Bound::Upper);
5920                     lastValues.back().conditional = true;
5921                     lastValues.push_back(asImpossible(lastValues.back()));
5922                     if (stepValue != 1)
5923                         lastValues.pop_front();
5924                     valueFlowForward(bodyStart, bodyStart->link(), vartok, lastValues, tokenlist, settings);
5925                 }
5926             }
5927             const MathLib::bigint afterValue = executeBody ? lastValue + stepValue : initValue;
5928             valueFlowForLoopSimplifyAfter(tok, varid, afterValue, tokenlist, settings);
5929         } else {
5930             ProgramMemory mem1, mem2, memAfter;
5931             if (valueFlowForLoop2(tok, &mem1, &mem2, &memAfter)) {
5932                 ProgramMemory::Map::const_iterator it;
5933                 for (it = mem1.values.begin(); it != mem1.values.end(); ++it) {
5934                     if (!it->second.isIntValue())
5935                         continue;
5936                     valueFlowForLoopSimplify(bodyStart, it->first, false, it->second.intvalue, tokenlist, errorLogger, settings);
5937                 }
5938                 for (it = mem2.values.begin(); it != mem2.values.end(); ++it) {
5939                     if (!it->second.isIntValue())
5940                         continue;
5941                     valueFlowForLoopSimplify(bodyStart, it->first, false, it->second.intvalue, tokenlist, errorLogger, settings);
5942                 }
5943                 for (it = memAfter.values.begin(); it != memAfter.values.end(); ++it) {
5944                     if (!it->second.isIntValue())
5945                         continue;
5946                     valueFlowForLoopSimplifyAfter(tok, it->first, it->second.intvalue, tokenlist, settings);
5947                 }
5948             }
5949         }
5950     }
5951 }
5952 
5953 struct MultiValueFlowAnalyzer : ValueFlowAnalyzer {
5954     std::unordered_map<nonneg int, ValueFlow::Value> values;
5955     std::unordered_map<nonneg int, const Variable*> vars;
5956     SymbolDatabase* symboldatabase;
5957 
MultiValueFlowAnalyzerMultiValueFlowAnalyzer5958     MultiValueFlowAnalyzer() : ValueFlowAnalyzer(), values(), vars(), symboldatabase(nullptr) {}
5959 
MultiValueFlowAnalyzerMultiValueFlowAnalyzer5960     MultiValueFlowAnalyzer(const std::unordered_map<const Variable*, ValueFlow::Value>& args, const TokenList* t, SymbolDatabase* s)
5961         : ValueFlowAnalyzer(t), values(), vars(), symboldatabase(s) {
5962         for (const auto& p:args) {
5963             values[p.first->declarationId()] = p.second;
5964             vars[p.first->declarationId()] = p.first;
5965         }
5966     }
5967 
getVarsMultiValueFlowAnalyzer5968     virtual const std::unordered_map<nonneg int, const Variable*>& getVars() const {
5969         return vars;
5970     }
5971 
getValueMultiValueFlowAnalyzer5972     virtual const ValueFlow::Value* getValue(const Token* tok) const OVERRIDE {
5973         if (tok->varId() == 0)
5974             return nullptr;
5975         auto it = values.find(tok->varId());
5976         if (it == values.end())
5977             return nullptr;
5978         return &it->second;
5979     }
getValueMultiValueFlowAnalyzer5980     virtual ValueFlow::Value* getValue(const Token* tok) OVERRIDE {
5981         if (tok->varId() == 0)
5982             return nullptr;
5983         auto it = values.find(tok->varId());
5984         if (it == values.end())
5985             return nullptr;
5986         return &it->second;
5987     }
5988 
makeConditionalMultiValueFlowAnalyzer5989     virtual void makeConditional() OVERRIDE {
5990         for (auto&& p:values) {
5991             p.second.conditional = true;
5992         }
5993     }
5994 
addErrorPathMultiValueFlowAnalyzer5995     virtual void addErrorPath(const Token* tok, const std::string& s) OVERRIDE {
5996         for (auto&& p:values) {
5997             p.second.errorPath.emplace_back(tok, "Assuming condition is " + s);
5998         }
5999     }
6000 
isAliasMultiValueFlowAnalyzer6001     virtual bool isAlias(const Token* tok, bool& inconclusive) const OVERRIDE {
6002         const auto range = SelectValueFromVarIdMapRange(&values);
6003 
6004         for (const auto& p:getVars()) {
6005             nonneg int varid = p.first;
6006             const Variable* var = p.second;
6007             if (tok->varId() == varid)
6008                 return true;
6009             if (isAliasOf(var, tok, varid, range, &inconclusive))
6010                 return true;
6011         }
6012         return false;
6013     }
6014 
isGlobalMultiValueFlowAnalyzer6015     virtual bool isGlobal() const OVERRIDE {
6016         return false;
6017     }
6018 
lowerToPossibleMultiValueFlowAnalyzer6019     virtual bool lowerToPossible() OVERRIDE {
6020         for (auto&& p:values) {
6021             if (p.second.isImpossible())
6022                 return false;
6023             p.second.changeKnownToPossible();
6024         }
6025         return true;
6026     }
lowerToInconclusiveMultiValueFlowAnalyzer6027     virtual bool lowerToInconclusive() OVERRIDE {
6028         for (auto&& p:values) {
6029             if (p.second.isImpossible())
6030                 return false;
6031             p.second.setInconclusive();
6032         }
6033         return true;
6034     }
6035 
isConditionalMultiValueFlowAnalyzer6036     virtual bool isConditional() const OVERRIDE {
6037         for (auto&& p:values) {
6038             if (p.second.conditional)
6039                 return true;
6040             if (p.second.condition)
6041                 return !p.second.isImpossible();
6042         }
6043         return false;
6044     }
6045 
stopOnConditionMultiValueFlowAnalyzer6046     virtual bool stopOnCondition(const Token*) const OVERRIDE {
6047         return isConditional();
6048     }
6049 
updateScopeMultiValueFlowAnalyzer6050     virtual bool updateScope(const Token* endBlock, bool) const OVERRIDE {
6051         const Scope* scope = endBlock->scope();
6052         if (!scope)
6053             return false;
6054         if (scope->type == Scope::eLambda) {
6055             for (const auto& p:values) {
6056                 if (!p.second.isLifetimeValue())
6057                     return false;
6058             }
6059             return true;
6060         } else if (scope->type == Scope::eIf || scope->type == Scope::eElse || scope->type == Scope::eWhile ||
6061                    scope->type == Scope::eFor) {
6062             auto pred = [](const ValueFlow::Value& value) {
6063                 if (value.isKnown())
6064                     return true;
6065                 if (value.isImpossible())
6066                     return true;
6067                 if (value.isLifetimeValue())
6068                     return true;
6069                 return false;
6070             };
6071             if (std::all_of(values.begin(), values.end(), std::bind(pred, std::bind(SelectMapValues{}, std::placeholders::_1))))
6072                 return true;
6073             if (isConditional())
6074                 return false;
6075             const Token* condTok = getCondTokFromEnd(endBlock);
6076             std::set<nonneg int> varids;
6077             std::transform(getVars().begin(), getVars().end(), std::inserter(varids, varids.begin()), SelectMapKeys{});
6078             return bifurcate(condTok, varids, getSettings());
6079         }
6080 
6081         return false;
6082     }
6083 
matchMultiValueFlowAnalyzer6084     virtual bool match(const Token* tok) const OVERRIDE {
6085         return values.count(tok->varId()) > 0;
6086     }
6087 
getProgramStateMultiValueFlowAnalyzer6088     virtual ProgramState getProgramState() const OVERRIDE {
6089         ProgramState ps;
6090         for (const auto& p:values)
6091             ps[p.first] = p.second;
6092         return ps;
6093     }
6094 
forkScopeMultiValueFlowAnalyzer6095     virtual void forkScope(const Token* endBlock) OVERRIDE {
6096         ProgramMemory pm = {getProgramState()};
6097         const Scope* scope = endBlock->scope();
6098         const Token* condTok = getCondTokFromEnd(endBlock);
6099         if (scope && condTok)
6100             programMemoryParseCondition(pm, condTok, nullptr, getSettings(), scope->type != Scope::eElse);
6101         if (condTok && Token::simpleMatch(condTok->astParent(), ";")) {
6102             ProgramMemory endMemory;
6103             if (valueFlowForLoop2(condTok->astTop()->previous(), nullptr, &endMemory, nullptr))
6104                 pm.replace(endMemory);
6105         }
6106         // ProgramMemory pm = pms.get(endBlock->link()->next(), getProgramState());
6107         for (const auto& p:pm.values) {
6108             nonneg int varid = p.first;
6109             if (!symboldatabase->isVarId(varid))
6110                 continue;
6111             ValueFlow::Value value = p.second;
6112             if (vars.count(varid) != 0)
6113                 continue;
6114             if (value.isImpossible())
6115                 continue;
6116             value.setPossible();
6117             values[varid] = value;
6118             if (symboldatabase)
6119                 vars[varid] = symboldatabase->getVariableFromVarId(varid);
6120         }
6121     }
6122 };
6123 
6124 template<class Key, class F>
productParams(const std::unordered_map<Key,std::list<ValueFlow::Value>> & vars,F f)6125 bool productParams(const std::unordered_map<Key, std::list<ValueFlow::Value>>& vars, F f)
6126 {
6127     using Args = std::vector<std::unordered_map<Key, ValueFlow::Value>>;
6128     Args args(1);
6129     // Compute cartesian product of all arguments
6130     for (const auto& p:vars) {
6131         if (p.second.empty())
6132             continue;
6133         args.back()[p.first] = p.second.front();
6134     }
6135     for (const auto& p:vars) {
6136         if (args.size() > 256)
6137             return false;
6138         if (p.second.empty())
6139             continue;
6140         std::for_each(std::next(p.second.begin()), p.second.end(), [&](const ValueFlow::Value& value) {
6141             Args new_args;
6142             for (auto arg:args) {
6143                 if (value.path != 0) {
6144                     for (const auto& q:arg) {
6145                         if (q.second.path == 0)
6146                             continue;
6147                         if (q.second.path != value.path)
6148                             return;
6149                     }
6150                 }
6151                 arg[p.first] = value;
6152                 new_args.push_back(arg);
6153             }
6154             std::copy(new_args.begin(), new_args.end(), std::back_inserter(args));
6155         });
6156     }
6157 
6158     for (const auto& arg:args) {
6159         if (arg.empty())
6160             continue;
6161         bool skip = false;
6162         // Make sure all arguments are the same path
6163         MathLib::bigint path = arg.begin()->second.path;
6164         for (const auto& p:arg) {
6165             if (p.second.path != path) {
6166                 skip = true;
6167                 break;
6168             }
6169         }
6170         if (skip)
6171             continue;
6172         f(arg);
6173     }
6174     return true;
6175 }
6176 
valueFlowInjectParameter(TokenList * tokenlist,SymbolDatabase * symboldatabase,ErrorLogger * errorLogger,const Settings * settings,const Scope * functionScope,const std::unordered_map<const Variable *,std::list<ValueFlow::Value>> & vars)6177 static void valueFlowInjectParameter(TokenList* tokenlist,
6178                                      SymbolDatabase* symboldatabase,
6179                                      ErrorLogger* errorLogger,
6180                                      const Settings* settings,
6181                                      const Scope* functionScope,
6182                                      const std::unordered_map<const Variable*, std::list<ValueFlow::Value>>& vars)
6183 {
6184     bool r = productParams(vars, [&](const std::unordered_map<const Variable*, ValueFlow::Value>& arg) {
6185         MultiValueFlowAnalyzer a(arg, tokenlist, symboldatabase);
6186         valueFlowGenericForward(const_cast<Token*>(functionScope->bodyStart), functionScope->bodyEnd, a, settings);
6187     });
6188     if (!r) {
6189         std::string fname = "<unknown>";
6190         Function* f = functionScope->function;
6191         if (f)
6192             fname = f->name();
6193         if (settings->debugwarnings)
6194             bailout(tokenlist, errorLogger, functionScope->bodyStart, "Too many argument passed to " + fname);
6195     }
6196 }
6197 
valueFlowInjectParameter(TokenList * tokenlist,const Settings * settings,const Variable * arg,const Scope * functionScope,const std::list<ValueFlow::Value> & argvalues)6198 static void valueFlowInjectParameter(TokenList* tokenlist,
6199                                      const Settings* settings,
6200                                      const Variable* arg,
6201                                      const Scope* functionScope,
6202                                      const std::list<ValueFlow::Value>& argvalues)
6203 {
6204     // Is argument passed by value or const reference, and is it a known non-class type?
6205     if (arg->isReference() && !arg->isConst() && !arg->isClass())
6206         return;
6207 
6208     // Set value in function scope..
6209     const nonneg int varid2 = arg->declarationId();
6210     if (!varid2)
6211         return;
6212 
6213     valueFlowForward(const_cast<Token*>(functionScope->bodyStart->next()),
6214                      functionScope->bodyEnd,
6215                      arg->nameToken(),
6216                      argvalues,
6217                      tokenlist,
6218                      settings);
6219 }
6220 
valueFlowSwitchVariable(TokenList * tokenlist,SymbolDatabase * symboldatabase,ErrorLogger * errorLogger,const Settings * settings)6221 static void valueFlowSwitchVariable(TokenList *tokenlist, SymbolDatabase* symboldatabase, ErrorLogger *errorLogger, const Settings *settings)
6222 {
6223     for (const Scope &scope : symboldatabase->scopeList) {
6224         if (scope.type != Scope::ScopeType::eSwitch)
6225             continue;
6226         if (!Token::Match(scope.classDef, "switch ( %var% ) {"))
6227             continue;
6228         const Token *vartok = scope.classDef->tokAt(2);
6229         const Variable *var = vartok->variable();
6230         if (!var)
6231             continue;
6232 
6233         // bailout: global non-const variables
6234         if (!(var->isLocal() || var->isArgument()) && !var->isConst()) {
6235             if (settings->debugwarnings)
6236                 bailout(tokenlist, errorLogger, vartok, "switch variable " + var->name() + " is global");
6237             continue;
6238         }
6239 
6240         for (Token *tok = scope.bodyStart->next(); tok != scope.bodyEnd; tok = tok->next()) {
6241             if (tok->str() == "{") {
6242                 tok = tok->link();
6243                 continue;
6244             }
6245             if (Token::Match(tok, "case %num% :")) {
6246                 std::list<ValueFlow::Value> values;
6247                 values.emplace_back(MathLib::toLongNumber(tok->next()->str()));
6248                 values.back().condition = tok;
6249                 const std::string info("case " + tok->next()->str() + ": " + vartok->str() + " is " + tok->next()->str() + " here.");
6250                 values.back().errorPath.emplace_back(tok, info);
6251                 bool known = false;
6252                 if ((Token::simpleMatch(tok->previous(), "{") || Token::simpleMatch(tok->tokAt(-2), "break ;")) && !Token::Match(tok->tokAt(3), ";| case"))
6253                     known = true;
6254                 while (Token::Match(tok->tokAt(3), ";| case %num% :")) {
6255                     known = false;
6256                     tok = tok->tokAt(3);
6257                     if (!tok->isName())
6258                         tok = tok->next();
6259                     values.emplace_back(MathLib::toLongNumber(tok->next()->str()));
6260                     values.back().condition = tok;
6261                     const std::string info2("case " + tok->next()->str() + ": " + vartok->str() + " is " + tok->next()->str() + " here.");
6262                     values.back().errorPath.emplace_back(tok, info2);
6263                 }
6264                 for (std::list<ValueFlow::Value>::const_iterator val = values.begin(); val != values.end(); ++val) {
6265                     valueFlowReverse(tokenlist,
6266                                      const_cast<Token*>(scope.classDef),
6267                                      vartok,
6268                                      *val,
6269                                      ValueFlow::Value(),
6270                                      errorLogger,
6271                                      settings);
6272                 }
6273                 if (vartok->variable()->scope()) {
6274                     if (known)
6275                         values.back().setKnown();
6276 
6277                     // FIXME We must check if there is a return. See #9276
6278                     /*
6279                        valueFlowForwardVariable(tok->tokAt(3),
6280                                              vartok->variable()->scope()->bodyEnd,
6281                                              vartok->variable(),
6282                                              vartok->varId(),
6283                                              values,
6284                                              values.back().isKnown(),
6285                                              false,
6286                                              tokenlist,
6287                                              errorLogger,
6288                                              settings);
6289                      */
6290                 }
6291             }
6292         }
6293     }
6294 }
6295 
setTokenValues(Token * tok,const std::list<ValueFlow::Value> & values,const Settings * settings)6296 static void setTokenValues(Token *tok, const std::list<ValueFlow::Value> &values, const Settings *settings)
6297 {
6298     for (const ValueFlow::Value &value : values) {
6299         if (value.isIntValue())
6300             setTokenValue(tok, value, settings);
6301     }
6302 }
6303 
getFunctionArgumentValues(const Token * argtok)6304 static std::list<ValueFlow::Value> getFunctionArgumentValues(const Token *argtok)
6305 {
6306     std::list<ValueFlow::Value> argvalues(argtok->values());
6307     removeImpossible(argvalues);
6308     if (argvalues.empty() && Token::Match(argtok, "%comp%|%oror%|&&|!")) {
6309         argvalues.emplace_back(0);
6310         argvalues.emplace_back(1);
6311     }
6312     return argvalues;
6313 }
6314 
valueFlowLibraryFunction(Token * tok,const std::string & returnValue,const Settings * settings)6315 static void valueFlowLibraryFunction(Token *tok, const std::string &returnValue, const Settings *settings)
6316 {
6317     std::unordered_map<nonneg int, std::list<ValueFlow::Value>> argValues;
6318     int argn = 1;
6319     for (const Token *argtok : getArguments(tok->previous())) {
6320         argValues[argn] = getFunctionArgumentValues(argtok);
6321         argn++;
6322     }
6323     if (returnValue.find("arg") != std::string::npos && argValues.empty())
6324         return;
6325 
6326     TokenList tokenList(settings);
6327     {
6328         const std::string code = "return " + returnValue + ";";
6329         std::istringstream istr(code);
6330         if (!tokenList.createTokens(istr))
6331             return;
6332     }
6333 
6334     // combine operators, set links, etc..
6335     std::stack<Token *> lpar;
6336     for (Token *tok2 = tokenList.front(); tok2; tok2 = tok2->next()) {
6337         if (Token::Match(tok2, "[!<>=] =")) {
6338             tok2->str(tok2->str() + "=");
6339             tok2->deleteNext();
6340         } else if (tok2->str() == "(")
6341             lpar.push(tok2);
6342         else if (tok2->str() == ")") {
6343             if (lpar.empty())
6344                 return;
6345             Token::createMutualLinks(lpar.top(), tok2);
6346             lpar.pop();
6347         }
6348     }
6349     if (!lpar.empty())
6350         return;
6351 
6352     // set varids
6353     for (Token* tok2 = tokenList.front(); tok2; tok2 = tok2->next()) {
6354         if (tok2->str().compare(0, 3, "arg") != 0)
6355             continue;
6356         nonneg int id = std::atoi(tok2->str().c_str() + 3);
6357         tok2->varId(id);
6358     }
6359 
6360     // Evaluate expression
6361     tokenList.createAst();
6362     Token* expr = tokenList.front()->astOperand1();
6363     ValueFlow::valueFlowConstantFoldAST(expr, settings);
6364 
6365     productParams(argValues, [&](const std::unordered_map<nonneg int, ValueFlow::Value>& arg) {
6366         ProgramMemory pm{arg};
6367         MathLib::bigint result = 0;
6368         bool error = false;
6369         execute(expr, &pm, &result, &error);
6370         if (error)
6371             return;
6372         ValueFlow::Value value(result);
6373         value.setKnown();
6374         for (auto&& p : arg) {
6375             if (p.second.isPossible())
6376                 value.setPossible();
6377             if (p.second.isInconclusive()) {
6378                 value.setInconclusive();
6379                 break;
6380             }
6381         }
6382         setTokenValue(tok, value, settings);
6383     });
6384 }
6385 
valueFlowSubFunction(TokenList * tokenlist,SymbolDatabase * symboldatabase,ErrorLogger * errorLogger,const Settings * settings)6386 static void valueFlowSubFunction(TokenList* tokenlist, SymbolDatabase* symboldatabase,  ErrorLogger* errorLogger, const Settings* settings)
6387 {
6388     int id = 0;
6389     for (const Scope* scope : symboldatabase->functionScopes) {
6390         const Function* function = scope->function;
6391         if (!function)
6392             continue;
6393         for (const Token *tok = scope->bodyStart; tok != scope->bodyEnd; tok = tok->next()) {
6394             if (!Token::Match(tok, "%name% ("))
6395                 continue;
6396 
6397             const Function * const calledFunction = tok->function();
6398             if (!calledFunction) {
6399                 // library function?
6400                 const std::string& returnValue(settings->library.returnValue(tok));
6401                 if (!returnValue.empty())
6402                     valueFlowLibraryFunction(tok->next(), returnValue, settings);
6403                 continue;
6404             }
6405 
6406             const Scope * const calledFunctionScope = calledFunction->functionScope;
6407             if (!calledFunctionScope)
6408                 continue;
6409 
6410             id++;
6411             std::unordered_map<const Variable*, std::list<ValueFlow::Value>> argvars;
6412             // TODO: Rewrite this. It does not work well to inject 1 argument at a time.
6413             const std::vector<const Token *> &callArguments = getArguments(tok);
6414             for (int argnr = 0U; argnr < callArguments.size(); ++argnr) {
6415                 const Token *argtok = callArguments[argnr];
6416                 // Get function argument
6417                 const Variable * const argvar = calledFunction->getArgumentVar(argnr);
6418                 if (!argvar)
6419                     break;
6420 
6421                 // passing value(s) to function
6422                 std::list<ValueFlow::Value> argvalues(getFunctionArgumentValues(argtok));
6423 
6424                 // Remove non-local lifetimes
6425                 argvalues.remove_if([](const ValueFlow::Value& v) {
6426                     if (v.isLifetimeValue())
6427                         return !v.isLocalLifetimeValue() && !v.isSubFunctionLifetimeValue();
6428                     return false;
6429                 });
6430                 // Don't forward container sizes for now since programmemory can't evaluate conditions
6431                 argvalues.remove_if(std::mem_fn(&ValueFlow::Value::isContainerSizeValue));
6432                 // Remove uninit values if argument is passed by value
6433                 if (argtok->variable() && !argtok->variable()->isPointer() && argvalues.size() == 1 && argvalues.front().isUninitValue()) {
6434                     if (CheckUninitVar::isVariableUsage(tokenlist->isCPP(), argtok, settings->library, false, CheckUninitVar::Alloc::NO_ALLOC, 0))
6435                         continue;
6436                 }
6437 
6438                 if (argvalues.empty())
6439                     continue;
6440 
6441                 // Error path..
6442                 for (ValueFlow::Value &v : argvalues) {
6443                     const std::string nr = MathLib::toString(argnr + 1) + getOrdinalText(argnr + 1);
6444 
6445                     v.errorPath.emplace_back(argtok,
6446                                              "Calling function '" +
6447                                              calledFunction->name() +
6448                                              "', " +
6449                                              nr +
6450                                              " argument '" +
6451                                              argtok->expressionString() +
6452                                              "' value is " +
6453                                              v.infoString());
6454                     v.path = 256 * v.path + id % 256;
6455                     // Change scope of lifetime values
6456                     if (v.isLifetimeValue())
6457                         v.lifetimeScope = ValueFlow::Value::LifetimeScope::SubFunction;
6458                 }
6459 
6460                 // passed values are not "known"..
6461                 lowerToPossible(argvalues);
6462 
6463                 argvars[argvar] = argvalues;
6464             }
6465             valueFlowInjectParameter(tokenlist, symboldatabase, errorLogger, settings, calledFunctionScope, argvars);
6466         }
6467     }
6468 }
6469 
valueFlowFunctionDefaultParameter(TokenList * tokenlist,SymbolDatabase * symboldatabase,const Settings * settings)6470 static void valueFlowFunctionDefaultParameter(TokenList* tokenlist, SymbolDatabase* symboldatabase, const Settings* settings)
6471 {
6472     if (!tokenlist->isCPP())
6473         return;
6474 
6475     for (const Scope* scope : symboldatabase->functionScopes) {
6476         const Function* function = scope->function;
6477         if (!function)
6478             continue;
6479         for (std::size_t arg = function->minArgCount(); arg < function->argCount(); arg++) {
6480             const Variable* var = function->getArgumentVar(arg);
6481             if (var && var->hasDefault() && Token::Match(var->nameToken(), "%var% = %num%|%str% [,)]")) {
6482                 const std::list<ValueFlow::Value> &values = var->nameToken()->tokAt(2)->values();
6483                 std::list<ValueFlow::Value> argvalues;
6484                 for (const ValueFlow::Value &value : values) {
6485                     ValueFlow::Value v(value);
6486                     v.defaultArg = true;
6487                     v.changeKnownToPossible();
6488                     if (v.isPossible())
6489                         argvalues.push_back(v);
6490                 }
6491                 if (!argvalues.empty())
6492                     valueFlowInjectParameter(tokenlist, settings, var, scope, argvalues);
6493             }
6494         }
6495     }
6496 }
6497 
isKnown(const Token * tok)6498 static bool isKnown(const Token * tok)
6499 {
6500     return tok && tok->hasKnownIntValue();
6501 }
6502 
valueFlowFunctionReturn(TokenList * tokenlist,ErrorLogger * errorLogger)6503 static void valueFlowFunctionReturn(TokenList *tokenlist, ErrorLogger *errorLogger)
6504 {
6505     for (Token *tok = tokenlist->back(); tok; tok = tok->previous()) {
6506         if (tok->str() != "(" || !tok->astOperand1() || !tok->astOperand1()->function())
6507             continue;
6508 
6509         if (tok->hasKnownValue())
6510             continue;
6511 
6512         // Arguments..
6513         std::vector<MathLib::bigint> parvalues;
6514         if (tok->astOperand2()) {
6515             const Token *partok = tok->astOperand2();
6516             while (partok && partok->str() == "," && isKnown(partok->astOperand2()))
6517                 partok = partok->astOperand1();
6518             if (!isKnown(partok))
6519                 continue;
6520             parvalues.push_back(partok->values().front().intvalue);
6521             partok = partok->astParent();
6522             while (partok && partok->str() == ",") {
6523                 parvalues.push_back(partok->astOperand2()->values().front().intvalue);
6524                 partok = partok->astParent();
6525             }
6526             if (partok != tok)
6527                 continue;
6528         }
6529 
6530         // Get scope and args of function
6531         const Function * const function = tok->astOperand1()->function();
6532         const Scope * const functionScope = function->functionScope;
6533         if (!functionScope || !Token::simpleMatch(functionScope->bodyStart, "{ return")) {
6534             if (functionScope && tokenlist->getSettings()->debugwarnings && Token::findsimplematch(functionScope->bodyStart, "return", functionScope->bodyEnd))
6535                 bailout(tokenlist, errorLogger, tok, "function return; nontrivial function body");
6536             continue;
6537         }
6538 
6539         ProgramMemory programMemory;
6540         for (std::size_t i = 0; i < parvalues.size(); ++i) {
6541             const Variable * const arg = function->getArgumentVar(i);
6542             if (!arg || !Token::Match(arg->typeStartToken(), "%type% %name% ,|)")) {
6543                 if (tokenlist->getSettings()->debugwarnings)
6544                     bailout(tokenlist, errorLogger, tok, "function return; unhandled argument type");
6545                 programMemory.clear();
6546                 break;
6547             }
6548             programMemory.setIntValue(arg->declarationId(), parvalues[i]);
6549         }
6550         if (programMemory.empty() && !parvalues.empty())
6551             continue;
6552 
6553         // Determine return value of subfunction..
6554         MathLib::bigint result = 0;
6555         bool error = false;
6556         execute(functionScope->bodyStart->next()->astOperand1(),
6557                 &programMemory,
6558                 &result,
6559                 &error);
6560         if (!error) {
6561             ValueFlow::Value v(result);
6562             if (function->hasVirtualSpecifier())
6563                 v.setPossible();
6564             else
6565                 v.setKnown();
6566             setTokenValue(tok, v, tokenlist->getSettings());
6567         }
6568     }
6569 }
6570 
valueFlowUninit(TokenList * tokenlist,SymbolDatabase *,const Settings * settings)6571 static void valueFlowUninit(TokenList* tokenlist, SymbolDatabase* /*symbolDatabase*/, const Settings* settings)
6572 {
6573     for (Token *tok = tokenlist->front(); tok; tok = tok->next()) {
6574         if (!Token::Match(tok,"[;{}] %type%"))
6575             continue;
6576         if (!tok->scope()->isExecutable())
6577             continue;
6578         const Token *vardecl = tok->next();
6579         bool stdtype = false;
6580         bool pointer = false;
6581         while (Token::Match(vardecl, "%name%|::|*") && vardecl->varId() == 0) {
6582             stdtype |= vardecl->isStandardType();
6583             pointer |= vardecl->str() == "*";
6584             vardecl = vardecl->next();
6585         }
6586         // if (!stdtype && !pointer)
6587         // continue;
6588         if (!Token::Match(vardecl, "%var% ;"))
6589             continue;
6590         const Variable *var = vardecl->variable();
6591         if (!var || var->nameToken() != vardecl || var->isInit())
6592             continue;
6593         if ((!var->isPointer() && var->type() && var->type()->needInitialization != Type::NeedInitialization::True) ||
6594             !var->isLocal() || var->isStatic() || var->isExtern() || var->isReference() || var->isThrow())
6595             continue;
6596         if (!var->type() && !stdtype && !pointer)
6597             continue;
6598 
6599         ValueFlow::Value uninitValue;
6600         uninitValue.setKnown();
6601         uninitValue.valueType = ValueFlow::Value::ValueType::UNINIT;
6602         uninitValue.tokvalue = vardecl;
6603         std::list<ValueFlow::Value> values;
6604         values.push_back(uninitValue);
6605 
6606         valueFlowForward(vardecl->next(), vardecl->scope()->bodyEnd, var->nameToken(), values, tokenlist, settings);
6607     }
6608 }
6609 
6610 static bool isContainerSizeChanged(const Token* tok, const Settings* settings = nullptr, int depth = 20);
6611 
6612 static bool isContainerSizeChanged(nonneg int varId,
6613                                    const Token* start,
6614                                    const Token* end,
6615                                    const Settings* settings = nullptr,
6616                                    int depth = 20);
6617 
isContainerSizeChangedByFunction(const Token * tok,const Settings * settings=nullptr,int depth=20)6618 static bool isContainerSizeChangedByFunction(const Token* tok, const Settings* settings = nullptr, int depth = 20)
6619 {
6620     if (!tok->valueType() || !tok->valueType()->container)
6621         return false;
6622     // If we are accessing an element then we are not changing the container size
6623     if (Token::Match(tok, "%name% . %name% (")) {
6624         Library::Container::Yield yield = tok->valueType()->container->getYield(tok->strAt(2));
6625         if (yield != Library::Container::Yield::NO_YIELD)
6626             return false;
6627     }
6628     if (Token::simpleMatch(tok->astParent(), "["))
6629         return false;
6630 
6631     // address of variable
6632     const bool addressOf = tok->valueType()->pointer || (tok->astParent() && tok->astParent()->isUnaryOp("&"));
6633 
6634     int narg;
6635     const Token * ftok = getTokenArgumentFunction(tok, narg);
6636     if (!ftok)
6637         return false; // not a function => variable not changed
6638     const Function * fun = ftok->function();
6639     if (fun && !fun->hasVirtualSpecifier()) {
6640         const Variable *arg = fun->getArgumentVar(narg);
6641         if (arg) {
6642             if (!arg->isReference() && !addressOf)
6643                 return false;
6644             if (!addressOf && arg->isConst())
6645                 return false;
6646             if (arg->valueType() && arg->valueType()->constness == 1)
6647                 return false;
6648             const Scope * scope = fun->functionScope;
6649             if (scope) {
6650                 // Argument not used
6651                 if (!arg->nameToken())
6652                     return false;
6653                 if (depth > 0)
6654                     return isContainerSizeChanged(
6655                         arg->declarationId(), scope->bodyStart, scope->bodyEnd, settings, depth - 1);
6656             }
6657             // Don't know => Safe guess
6658             return true;
6659         }
6660     }
6661 
6662     bool inconclusive = false;
6663     const bool isChanged = isVariableChangedByFunctionCall(tok, 0, settings, &inconclusive);
6664     return (isChanged || inconclusive);
6665 }
6666 
6667 struct ContainerExpressionAnalyzer : ExpressionAnalyzer {
ContainerExpressionAnalyzerContainerExpressionAnalyzer6668     ContainerExpressionAnalyzer() : ExpressionAnalyzer() {}
6669 
ContainerExpressionAnalyzerContainerExpressionAnalyzer6670     ContainerExpressionAnalyzer(const Token* expr, const ValueFlow::Value& val, const TokenList* t)
6671         : ExpressionAnalyzer(expr, val, t)
6672     {}
6673 
matchContainerExpressionAnalyzer6674     virtual bool match(const Token* tok) const OVERRIDE {
6675         return tok->exprId() == expr->exprId() || (astIsIterator(tok) && isAliasOf(tok, expr->exprId()));
6676     }
6677 
isWritableContainerExpressionAnalyzer6678     virtual Action isWritable(const Token* tok, Direction d) const OVERRIDE {
6679         if (astIsIterator(tok))
6680             return Action::None;
6681         if (d == Direction::Reverse)
6682             return Action::None;
6683         if (!getValue(tok))
6684             return Action::None;
6685         if (!tok->valueType() || !tok->valueType()->container)
6686             return Action::None;
6687         const Token* parent = tok->astParent();
6688 
6689         if (tok->valueType()->container->stdStringLike && Token::simpleMatch(parent, "+=") && astIsLHS(tok) && parent->astOperand2()) {
6690             const Token* rhs = parent->astOperand2();
6691             if (rhs->tokType() == Token::eString)
6692                 return Action::Read | Action::Write | Action::Incremental;
6693             if (rhs->valueType() && rhs->valueType()->container && rhs->valueType()->container->stdStringLike) {
6694                 if (std::any_of(rhs->values().begin(), rhs->values().end(), [&](const ValueFlow::Value &rhsval) {
6695                     return rhsval.isKnown() && rhsval.isContainerSizeValue();
6696                 }))
6697                     return Action::Read | Action::Write | Action::Incremental;
6698             }
6699         } else if (Token::Match(tok, "%name% . %name% (")) {
6700             Library::Container::Action action = tok->valueType()->container->getAction(tok->strAt(2));
6701             if (action == Library::Container::Action::PUSH || action == Library::Container::Action::POP) {
6702                 std::vector<const Token*> args = getArguments(tok->tokAt(3));
6703                 if (args.size() < 2)
6704                     return Action::Read | Action::Write | Action::Incremental;
6705             }
6706         }
6707         return Action::None;
6708     }
6709 
writeValueContainerExpressionAnalyzer6710     virtual void writeValue(ValueFlow::Value* val, const Token* tok, Direction d) const OVERRIDE {
6711         if (d == Direction::Reverse)
6712             return;
6713         if (!val)
6714             return;
6715         if (!tok->astParent())
6716             return;
6717         const Token* parent = tok->astParent();
6718         if (!tok->valueType() || !tok->valueType()->container)
6719             return;
6720 
6721         if (tok->valueType()->container->stdStringLike && Token::simpleMatch(parent, "+=") && parent->astOperand2()) {
6722             const Token* rhs = parent->astOperand2();
6723             if (rhs->tokType() == Token::eString)
6724                 val->intvalue += Token::getStrLength(rhs);
6725             else if (rhs->valueType() && rhs->valueType()->container && rhs->valueType()->container->stdStringLike) {
6726                 for (const ValueFlow::Value &rhsval : rhs->values()) {
6727                     if (rhsval.isKnown() && rhsval.isContainerSizeValue()) {
6728                         val->intvalue += rhsval.intvalue;
6729                     }
6730                 }
6731             }
6732         } else if (Token::Match(tok, "%name% . %name% (")) {
6733             Library::Container::Action action = tok->valueType()->container->getAction(tok->strAt(2));
6734             if (action == Library::Container::Action::PUSH)
6735                 val->intvalue++;
6736             if (action == Library::Container::Action::POP)
6737                 val->intvalue--;
6738         }
6739     }
6740 
isModifiedContainerExpressionAnalyzer6741     virtual Action isModified(const Token* tok) const OVERRIDE {
6742         Action read = Action::Read;
6743         // An iterator won't change the container size
6744         if (astIsIterator(tok))
6745             return read;
6746         if (Token::Match(tok->astParent(), "%assign%") && astIsLHS(tok))
6747             return Action::Invalid;
6748         if (isLikelyStreamRead(isCPP(), tok->astParent()))
6749             return Action::Invalid;
6750         if (astIsContainer(tok) && isContainerSizeChanged(tok, getSettings()))
6751             return Action::Invalid;
6752         return read;
6753     }
6754 };
6755 
valueFlowContainerForward(Token * startToken,const Token * endToken,const Token * exprTok,const ValueFlow::Value & value,TokenList * tokenlist)6756 static Analyzer::Result valueFlowContainerForward(Token* startToken,
6757                                                   const Token* endToken,
6758                                                   const Token* exprTok,
6759                                                   const ValueFlow::Value& value,
6760                                                   TokenList* tokenlist)
6761 {
6762     ContainerExpressionAnalyzer a(exprTok, value, tokenlist);
6763     return valueFlowGenericForward(startToken, endToken, a, tokenlist->getSettings());
6764 }
6765 
valueFlowContainerForwardRecursive(Token * top,const Token * exprTok,const ValueFlow::Value & value,TokenList * tokenlist)6766 static Analyzer::Result valueFlowContainerForwardRecursive(Token* top,
6767                                                            const Token* exprTok,
6768                                                            const ValueFlow::Value& value,
6769                                                            TokenList* tokenlist)
6770 {
6771     ContainerExpressionAnalyzer a(exprTok, value, tokenlist);
6772     return valueFlowGenericForward(top, a, tokenlist->getSettings());
6773 }
6774 
valueFlowContainerForward(Token * startToken,const Token * exprTok,const ValueFlow::Value & value,TokenList * tokenlist)6775 static Analyzer::Result valueFlowContainerForward(Token* startToken,
6776                                                   const Token* exprTok,
6777                                                   const ValueFlow::Value& value,
6778                                                   TokenList* tokenlist)
6779 {
6780     const Token* endToken = nullptr;
6781     const Function* f = Scope::nestedInFunction(startToken->scope());
6782     if (f && f->functionScope)
6783         endToken = f->functionScope->bodyEnd;
6784     return valueFlowContainerForward(startToken, endToken, exprTok, value, tokenlist);
6785 }
6786 
valueFlowContainerReverse(Token * tok,const Token * const endToken,const Token * const varToken,const std::list<ValueFlow::Value> & values,TokenList * tokenlist,const Settings * settings)6787 static void valueFlowContainerReverse(Token* tok,
6788                                       const Token* const endToken,
6789                                       const Token* const varToken,
6790                                       const std::list<ValueFlow::Value>& values,
6791                                       TokenList* tokenlist,
6792                                       const Settings* settings)
6793 {
6794     for (const ValueFlow::Value& value : values) {
6795         ContainerExpressionAnalyzer a(varToken, value, tokenlist);
6796         valueFlowGenericReverse(tok, endToken, a, settings);
6797     }
6798 }
6799 
isContainerSizeChanged(const Token * tok,const Settings * settings,int depth)6800 static bool isContainerSizeChanged(const Token* tok, const Settings* settings, int depth)
6801 {
6802     if (!tok)
6803         return false;
6804     if (!tok->valueType() || !tok->valueType()->container)
6805         return true;
6806     if (Token::Match(tok, "%name% %assign%|<<"))
6807         return true;
6808     if (Token::Match(tok, "%var% [") && tok->valueType()->container->stdAssociativeLike)
6809         return true;
6810     if (Token::Match(tok, "%name% . %name% (")) {
6811         Library::Container::Action action = tok->valueType()->container->getAction(tok->strAt(2));
6812         Library::Container::Yield yield = tok->valueType()->container->getYield(tok->strAt(2));
6813         switch (action) {
6814         case Library::Container::Action::RESIZE:
6815         case Library::Container::Action::CLEAR:
6816         case Library::Container::Action::PUSH:
6817         case Library::Container::Action::POP:
6818         case Library::Container::Action::CHANGE:
6819         case Library::Container::Action::INSERT:
6820         case Library::Container::Action::ERASE:
6821         case Library::Container::Action::CHANGE_INTERNAL:
6822             return true;
6823         case Library::Container::Action::NO_ACTION: // might be unknown action
6824             return yield == Library::Container::Yield::NO_YIELD;
6825         case Library::Container::Action::FIND:
6826         case Library::Container::Action::CHANGE_CONTENT:
6827             break;
6828         }
6829     }
6830     if (isContainerSizeChangedByFunction(tok, settings, depth))
6831         return true;
6832     return false;
6833 }
6834 
isContainerSizeChanged(nonneg int varId,const Token * start,const Token * end,const Settings * settings,int depth)6835 static bool isContainerSizeChanged(nonneg int varId,
6836                                    const Token* start,
6837                                    const Token* end,
6838                                    const Settings* settings,
6839                                    int depth)
6840 {
6841     for (const Token *tok = start; tok != end; tok = tok->next()) {
6842         if (tok->varId() != varId)
6843             continue;
6844         if (isContainerSizeChanged(tok, settings, depth))
6845             return true;
6846     }
6847     return false;
6848 }
6849 
valueFlowSmartPointer(TokenList * tokenlist,ErrorLogger * errorLogger,const Settings * settings)6850 static void valueFlowSmartPointer(TokenList *tokenlist, ErrorLogger * errorLogger, const Settings *settings)
6851 {
6852     for (Token *tok = tokenlist->front(); tok; tok = tok->next()) {
6853         if (!tok->scope())
6854             continue;
6855         if (!tok->scope()->isExecutable())
6856             continue;
6857         if (tok->variable()) {
6858             const Variable* var = tok->variable();
6859             if (!var->isSmartPointer())
6860                 continue;
6861             if (var->nameToken() == tok) {
6862                 if (Token::Match(tok, "%var% (|{") && tok->next()->astOperand2() &&
6863                     tok->next()->astOperand2()->str() != ",") {
6864                     Token* inTok = tok->next()->astOperand2();
6865                     std::list<ValueFlow::Value> values = inTok->values();
6866                     const bool constValue = inTok->isNumber();
6867                     valueFlowForwardAssign(inTok, var, values, constValue, true, tokenlist, errorLogger, settings);
6868 
6869                 } else if (Token::Match(tok, "%var% ;")) {
6870                     std::list<ValueFlow::Value> values;
6871                     ValueFlow::Value v(0);
6872                     v.setKnown();
6873                     values.push_back(v);
6874                     valueFlowForwardAssign(tok, var, values, false, true, tokenlist, errorLogger, settings);
6875                 }
6876             } else if (Token::Match(tok, "%var% . reset (") && tok->next()->originalName() != "->") {
6877                 if (Token::simpleMatch(tok->tokAt(3), "( )")) {
6878                     std::list<ValueFlow::Value> values;
6879                     ValueFlow::Value v(0);
6880                     v.setKnown();
6881                     values.push_back(v);
6882                     valueFlowForwardAssign(tok->tokAt(3), var, values, false, false, tokenlist, errorLogger, settings);
6883                 } else {
6884                     tok->removeValues(std::mem_fn(&ValueFlow::Value::isIntValue));
6885                     Token* inTok = tok->tokAt(3)->astOperand2();
6886                     if (!inTok)
6887                         continue;
6888                     std::list<ValueFlow::Value> values = inTok->values();
6889                     const bool constValue = inTok->isNumber();
6890                     valueFlowForwardAssign(inTok, var, values, constValue, false, tokenlist, errorLogger, settings);
6891                 }
6892             } else if (Token::Match(tok, "%var% . release ( )") && tok->next()->originalName() != "->") {
6893                 const Token* parent = tok->tokAt(3)->astParent();
6894                 bool hasParentReset = false;
6895                 while (parent) {
6896                     if (Token::Match(parent->tokAt(-3), "%varid% . release|reset (", tok->varId())) {
6897                         hasParentReset = true;
6898                         break;
6899                     }
6900                     parent = parent->astParent();
6901                 }
6902                 if (hasParentReset)
6903                     continue;
6904                 std::list<ValueFlow::Value> values;
6905                 ValueFlow::Value v(0);
6906                 v.setKnown();
6907                 values.push_back(v);
6908                 valueFlowForwardAssign(tok->tokAt(3), var, values, false, false, tokenlist, errorLogger, settings);
6909             }
6910         } else if (Token::Match(tok->previous(), "%name%|> (|{") && astIsSmartPointer(tok) &&
6911                    astIsSmartPointer(tok->astOperand1())) {
6912             std::vector<const Token*> args = getArguments(tok);
6913             if (args.empty())
6914                 continue;
6915             for (const ValueFlow::Value& v : args.front()->values())
6916                 setTokenValue(tok, v, settings);
6917         }
6918     }
6919 }
6920 
valueFlowIterators(TokenList * tokenlist,const Settings * settings)6921 static void valueFlowIterators(TokenList *tokenlist, const Settings *settings)
6922 {
6923     for (Token *tok = tokenlist->front(); tok; tok = tok->next()) {
6924         if (!tok->scope())
6925             continue;
6926         if (!tok->scope()->isExecutable())
6927             continue;
6928         if (!astIsContainer(tok))
6929             continue;
6930         if (Token::Match(tok->astParent(), ". %name% (")) {
6931             Library::Container::Yield yield = tok->valueType()->container->getYield(tok->astParent()->strAt(1));
6932             ValueFlow::Value v(0);
6933             v.setKnown();
6934             if (yield == Library::Container::Yield::START_ITERATOR) {
6935                 v.valueType = ValueFlow::Value::ValueType::ITERATOR_START;
6936                 setTokenValue(tok->astParent()->tokAt(2), v, settings);
6937             } else if (yield == Library::Container::Yield::END_ITERATOR) {
6938                 v.valueType = ValueFlow::Value::ValueType::ITERATOR_END;
6939                 setTokenValue(tok->astParent()->tokAt(2), v, settings);
6940             }
6941         }
6942     }
6943 }
6944 
getIteratorValues(std::list<ValueFlow::Value> values,const ValueFlow::Value::ValueKind * kind=nullptr)6945 static std::list<ValueFlow::Value> getIteratorValues(std::list<ValueFlow::Value> values, const ValueFlow::Value::ValueKind* kind = nullptr)
6946 {
6947     values.remove_if([&](const ValueFlow::Value& v) {
6948         if (kind && v.valueKind != *kind)
6949             return true;
6950         return !v.isIteratorValue();
6951     });
6952     return values;
6953 }
6954 
6955 struct IteratorConditionHandler : SimpleConditionHandler {
parseIteratorConditionHandler6956     virtual std::vector<Condition> parse(const Token* tok, const Settings*) const OVERRIDE {
6957         Condition cond;
6958 
6959         ValueFlow::Value true_value;
6960         ValueFlow::Value false_value;
6961 
6962         if (Token::Match(tok, "==|!=")) {
6963             if (!tok->astOperand1() || !tok->astOperand2())
6964                 return {};
6965 
6966             ValueFlow::Value::ValueKind kind = ValueFlow::Value::ValueKind::Known;
6967             std::list<ValueFlow::Value> values = getIteratorValues(tok->astOperand1()->values(), &kind);
6968             if (!values.empty()) {
6969                 cond.vartok = tok->astOperand2();
6970             } else {
6971                 values = getIteratorValues(tok->astOperand2()->values());
6972                 if (!values.empty())
6973                     cond.vartok = tok->astOperand1();
6974             }
6975             for (ValueFlow::Value& v:values) {
6976                 v.setPossible();
6977                 v.assumeCondition(tok);
6978             }
6979             cond.true_values = values;
6980             cond.false_values = values;
6981         }
6982 
6983         return {cond};
6984     }
6985 };
6986 
valueFlowIteratorInfer(TokenList * tokenlist,const Settings * settings)6987 static void valueFlowIteratorInfer(TokenList *tokenlist, const Settings *settings)
6988 {
6989     for (Token *tok = tokenlist->front(); tok; tok = tok->next()) {
6990         if (!tok->scope())
6991             continue;
6992         if (!tok->scope()->isExecutable())
6993             continue;
6994         std::list<ValueFlow::Value> values = getIteratorValues(tok->values());
6995         values.remove_if([&](const ValueFlow::Value& v) {
6996             if (!v.isImpossible())
6997                 return true;
6998             if (v.isIteratorEndValue() && v.intvalue <= 0)
6999                 return true;
7000             if (v.isIteratorStartValue() && v.intvalue >= 0)
7001                 return true;
7002             return false;
7003         });
7004         for (ValueFlow::Value& v:values) {
7005             v.setPossible();
7006             if (v.isIteratorStartValue())
7007                 v.intvalue++;
7008             if (v.isIteratorEndValue())
7009                 v.intvalue--;
7010             setTokenValue(tok, v, settings);
7011         }
7012     }
7013 }
7014 
getContainerValues(const Token * tok)7015 static std::vector<ValueFlow::Value> getContainerValues(const Token* tok)
7016 {
7017     std::vector<ValueFlow::Value> values;
7018     if (tok) {
7019         std::copy_if(tok->values().begin(),
7020                      tok->values().end(),
7021                      std::back_inserter(values),
7022                      std::mem_fn(&ValueFlow::Value::isContainerSizeValue));
7023     }
7024     return values;
7025 }
7026 
makeContainerSizeValue(std::size_t s,bool known=true)7027 static ValueFlow::Value makeContainerSizeValue(std::size_t s, bool known = true)
7028 {
7029     ValueFlow::Value value(s);
7030     value.valueType = ValueFlow::Value::ValueType::CONTAINER_SIZE;
7031     if (known)
7032         value.setKnown();
7033     return value;
7034 }
7035 
makeContainerSizeValue(const Token * tok,bool known=true)7036 static std::vector<ValueFlow::Value> makeContainerSizeValue(const Token* tok, bool known = true)
7037 {
7038     if (tok->hasKnownIntValue())
7039         return {makeContainerSizeValue(tok->values().front().intvalue, known)};
7040     return {};
7041 }
7042 
getInitListSize(const Token * tok,const Library::Container * container,bool known=true)7043 static std::vector<ValueFlow::Value> getInitListSize(const Token* tok,
7044                                                      const Library::Container* container,
7045                                                      bool known = true)
7046 {
7047     std::vector<const Token*> args = getArguments(tok);
7048     // Strings don't use an init list
7049     if (!args.empty() && container->stdStringLike) {
7050         if (astIsIntegral(args[0], false)) {
7051             if (args.size() > 1)
7052                 return {makeContainerSizeValue(args[0], known)};
7053         } else if (astIsPointer(args[0])) {
7054             // TODO: Try to read size of string literal
7055             if (args.size() == 2 && astIsIntegral(args[1], false))
7056                 return {makeContainerSizeValue(args[1], known)};
7057         } else if (astIsContainer(args[0])) {
7058             if (args.size() == 1)
7059                 return getContainerValues(args[0]);
7060             if (args.size() == 3)
7061                 return {makeContainerSizeValue(args[2], known)};
7062         }
7063         return {};
7064     } else if ((args.size() == 1 && astIsContainer(args[0]) && args[0]->valueType()->container == container) ||
7065                (args.size() == 2 && astIsIterator(args[0]) && astIsIterator(args[1]))) {
7066         return getContainerValues(args[0]);
7067     }
7068     return {makeContainerSizeValue(args.size(), known)};
7069 }
7070 
valueFlowContainerSize(TokenList * tokenlist,SymbolDatabase * symboldatabase,ErrorLogger *,const Settings * settings)7071 static void valueFlowContainerSize(TokenList *tokenlist, SymbolDatabase* symboldatabase, ErrorLogger * /*errorLogger*/, const Settings *settings)
7072 {
7073     std::map<int, std::size_t> static_sizes;
7074     // declaration
7075     for (const Variable *var : symboldatabase->variableList()) {
7076         bool known = true;
7077         if (!var || !var->isLocal() || var->isPointer() || var->isReference() || var->isStatic())
7078             continue;
7079         if (!var->valueType() || !var->valueType()->container)
7080             continue;
7081         if (!astIsContainer(var->nameToken()))
7082             continue;
7083         if (var->nameToken()->hasKnownValue(ValueFlow::Value::ValueType::CONTAINER_SIZE))
7084             continue;
7085         if (!Token::Match(var->nameToken(), "%name% ;") &&
7086             !(Token::Match(var->nameToken(), "%name% {") && Token::simpleMatch(var->nameToken()->next()->link(), "} ;")))
7087             continue;
7088         if (var->nameToken()->astTop() && Token::Match(var->nameToken()->astTop()->previous(), "for|while"))
7089             known = !isVariableChanged(var, settings, true);
7090         if (var->valueType()->container->size_templateArgNo >= 0) {
7091             if (var->dimensions().size() == 1 && var->dimensions().front().known)
7092                 static_sizes[var->declarationId()] = var->dimensions().front().num;
7093             continue;
7094         }
7095         std::vector<ValueFlow::Value> values{ValueFlow::Value{0}};
7096         values.back().valueType = ValueFlow::Value::ValueType::CONTAINER_SIZE;
7097         if (known)
7098             values.back().setKnown();
7099         if (Token::simpleMatch(var->nameToken()->next(), "{")) {
7100             const Token* initList = var->nameToken()->next();
7101             values = getInitListSize(initList, var->valueType()->container, known);
7102         }
7103         for (const ValueFlow::Value& value : values)
7104             valueFlowContainerForward(var->nameToken()->next(), var->nameToken(), value, tokenlist);
7105     }
7106 
7107     // after assignment
7108     for (const Scope *functionScope : symboldatabase->functionScopes) {
7109         for (const Token *tok = functionScope->bodyStart; tok != functionScope->bodyEnd; tok = tok->next()) {
7110             if (static_sizes.count(tok->varId()) > 0) {
7111                 ValueFlow::Value value(static_sizes.at(tok->varId()));
7112                 value.valueType = ValueFlow::Value::ValueType::CONTAINER_SIZE;
7113                 value.setKnown();
7114                 setTokenValue(const_cast<Token*>(tok), value, settings);
7115             } else if (Token::Match(tok, "%name%|;|{|} %var% = %str% ;")) {
7116                 const Token *containerTok = tok->next();
7117                 if (containerTok->exprId() == 0)
7118                     continue;
7119                 if (containerTok->valueType() && containerTok->valueType()->container && containerTok->valueType()->container->stdStringLike) {
7120                     ValueFlow::Value value(Token::getStrLength(containerTok->tokAt(2)));
7121                     value.valueType = ValueFlow::Value::ValueType::CONTAINER_SIZE;
7122                     value.setKnown();
7123                     valueFlowContainerForward(containerTok->next(), containerTok, value, tokenlist);
7124                 }
7125             } else if (Token::Match(tok, "%name%|;|{|}|> %var% = {") && Token::simpleMatch(tok->linkAt(3), "} ;")) {
7126                 const Token* containerTok = tok->next();
7127                 if (containerTok->exprId() == 0)
7128                     continue;
7129                 if (astIsContainer(containerTok) && containerTok->valueType()->container->size_templateArgNo < 0) {
7130                     std::vector<ValueFlow::Value> values = getInitListSize(tok->tokAt(3), containerTok->valueType()->container);
7131                     for (const ValueFlow::Value& value : values)
7132                         valueFlowContainerForward(containerTok->next(), containerTok, value, tokenlist);
7133                 }
7134             } else if (Token::Match(tok, ". %name% (") && tok->astOperand1() && tok->astOperand1()->valueType() && tok->astOperand1()->valueType()->container) {
7135                 const Token* containerTok = tok->astOperand1();
7136                 if (containerTok->exprId() == 0)
7137                     continue;
7138                 Library::Container::Action action = containerTok->valueType()->container->getAction(tok->strAt(1));
7139                 if (action == Library::Container::Action::CLEAR) {
7140                     ValueFlow::Value value(0);
7141                     value.valueType = ValueFlow::Value::ValueType::CONTAINER_SIZE;
7142                     value.setKnown();
7143                     valueFlowContainerForward(tok->next(), containerTok, value, tokenlist);
7144                 } else if (action == Library::Container::Action::RESIZE && tok->tokAt(2)->astOperand2() &&
7145                            tok->tokAt(2)->astOperand2()->hasKnownIntValue()) {
7146                     ValueFlow::Value value(tok->tokAt(2)->astOperand2()->values().front());
7147                     value.valueType = ValueFlow::Value::ValueType::CONTAINER_SIZE;
7148                     value.setKnown();
7149                     valueFlowContainerForward(tok->next(), containerTok, value, tokenlist);
7150                 }
7151             }
7152         }
7153     }
7154 }
7155 
7156 struct ContainerConditionHandler : ConditionHandler {
forwardContainerConditionHandler7157     virtual Analyzer::Result forward(Token* start,
7158                                      const Token* stop,
7159                                      const Token* exprTok,
7160                                      const std::list<ValueFlow::Value>& values,
7161                                      TokenList* tokenlist,
7162                                      const Settings*) const OVERRIDE {
7163         Analyzer::Result result{};
7164         for (const ValueFlow::Value& value : values)
7165             result.update(valueFlowContainerForward(start->next(), stop, exprTok, value, tokenlist));
7166         return result;
7167     }
7168 
forwardContainerConditionHandler7169     virtual Analyzer::Result forward(Token* top,
7170                                      const Token* exprTok,
7171                                      const std::list<ValueFlow::Value>& values,
7172                                      TokenList* tokenlist,
7173                                      const Settings*) const OVERRIDE {
7174         Analyzer::Result result{};
7175         for (const ValueFlow::Value& value : values)
7176             result.update(valueFlowContainerForwardRecursive(top, exprTok, value, tokenlist));
7177         return result;
7178     }
7179 
reverseContainerConditionHandler7180     virtual void reverse(Token* start,
7181                          const Token* endTok,
7182                          const Token* exprTok,
7183                          const std::list<ValueFlow::Value>& values,
7184                          TokenList* tokenlist,
7185                          const Settings* settings) const OVERRIDE {
7186         return valueFlowContainerReverse(start, endTok, exprTok, values, tokenlist, settings);
7187     }
7188 
parseContainerConditionHandler7189     virtual std::vector<Condition> parse(const Token* tok, const Settings* settings) const OVERRIDE
7190     {
7191         Condition cond;
7192         ValueFlow::Value true_value;
7193         ValueFlow::Value false_value;
7194         const Token *vartok = parseCompareInt(tok, true_value, false_value);
7195         if (vartok) {
7196             vartok = settings->library.getContainerFromYield(vartok, Library::Container::Yield::SIZE);
7197             if (!vartok)
7198                 return {};
7199             true_value.valueType = ValueFlow::Value::ValueType::CONTAINER_SIZE;
7200             false_value.valueType = ValueFlow::Value::ValueType::CONTAINER_SIZE;
7201             cond.true_values.push_back(true_value);
7202             cond.false_values.push_back(false_value);
7203             cond.vartok = vartok;
7204             return {cond};
7205         }
7206 
7207         // Empty check
7208         if (tok->str() == "(") {
7209             vartok = settings->library.getContainerFromYield(tok, Library::Container::Yield::EMPTY);
7210             // TODO: Handle .size()
7211             if (!vartok)
7212                 return {};
7213             const Token *parent = tok->astParent();
7214             while (parent) {
7215                 if (Token::Match(parent, "%comp%"))
7216                     return {};
7217                 parent = parent->astParent();
7218             }
7219             ValueFlow::Value value(tok, 0LL);
7220             value.valueType = ValueFlow::Value::ValueType::CONTAINER_SIZE;
7221             cond.true_values.emplace_back(value);
7222             cond.false_values.emplace_back(std::move(value));
7223             cond.vartok = vartok;
7224             cond.inverted = true;
7225             return {cond};
7226         }
7227         // String compare
7228         if (Token::Match(tok, "==|!=")) {
7229             const Token *strtok = nullptr;
7230             if (Token::Match(tok->astOperand1(), "%str%")) {
7231                 strtok = tok->astOperand1();
7232                 vartok = tok->astOperand2();
7233             } else if (Token::Match(tok->astOperand2(), "%str%")) {
7234                 strtok = tok->astOperand2();
7235                 vartok = tok->astOperand1();
7236             }
7237             if (!strtok)
7238                 return {};
7239             if (!astIsContainer(vartok))
7240                 return {};
7241             ValueFlow::Value value(tok, Token::getStrLength(strtok));
7242             value.valueType = ValueFlow::Value::ValueType::CONTAINER_SIZE;
7243             cond.false_values.emplace_back(value);
7244             cond.true_values.emplace_back(std::move(value));
7245             cond.vartok = vartok;
7246             cond.impossible = false;
7247             return {cond};
7248         }
7249         return {};
7250     }
7251 };
7252 
valueFlowDynamicBufferSize(TokenList * tokenlist,SymbolDatabase * symboldatabase,const Settings * settings)7253 static void valueFlowDynamicBufferSize(TokenList* tokenlist, SymbolDatabase* symboldatabase, const Settings* settings)
7254 {
7255     for (const Scope *functionScope : symboldatabase->functionScopes) {
7256         for (const Token *tok = functionScope->bodyStart; tok != functionScope->bodyEnd; tok = tok->next()) {
7257             if (!Token::Match(tok, "[;{}] %var% ="))
7258                 continue;
7259 
7260             if (!tok->next()->variable())
7261                 continue;
7262 
7263             const Token *rhs = tok->tokAt(2)->astOperand2();
7264             while (rhs && rhs->isCast())
7265                 rhs = rhs->astOperand2() ? rhs->astOperand2() : rhs->astOperand1();
7266             if (!rhs)
7267                 continue;
7268 
7269             if (!Token::Match(rhs->previous(), "%name% ("))
7270                 continue;
7271 
7272             const Library::AllocFunc *allocFunc = settings->library.getAllocFuncInfo(rhs->previous());
7273             if (!allocFunc)
7274                 allocFunc = settings->library.getReallocFuncInfo(rhs->previous());
7275             if (!allocFunc || allocFunc->bufferSize == Library::AllocFunc::BufferSize::none)
7276                 continue;
7277 
7278             const std::vector<const Token *> args = getArguments(rhs->previous());
7279 
7280             const Token * const arg1 = (args.size() >= allocFunc->bufferSizeArg1) ? args[allocFunc->bufferSizeArg1 - 1] : nullptr;
7281             const Token * const arg2 = (args.size() >= allocFunc->bufferSizeArg2) ? args[allocFunc->bufferSizeArg2 - 1] : nullptr;
7282 
7283             MathLib::bigint sizeValue = -1;
7284             switch (allocFunc->bufferSize) {
7285             case Library::AllocFunc::BufferSize::none:
7286                 break;
7287             case Library::AllocFunc::BufferSize::malloc:
7288                 if (arg1 && arg1->hasKnownIntValue())
7289                     sizeValue = arg1->getKnownIntValue();
7290                 break;
7291             case Library::AllocFunc::BufferSize::calloc:
7292                 if (arg1 && arg2 && arg1->hasKnownIntValue() && arg2->hasKnownIntValue())
7293                     sizeValue = arg1->getKnownIntValue() * arg2->getKnownIntValue();
7294                 break;
7295             case Library::AllocFunc::BufferSize::strdup:
7296                 if (arg1 && arg1->hasKnownValue()) {
7297                     const ValueFlow::Value &value = arg1->values().back();
7298                     if (value.isTokValue() && value.tokvalue->tokType() == Token::eString)
7299                         sizeValue = Token::getStrLength(value.tokvalue) + 1; // Add one for the null terminator
7300                 }
7301                 break;
7302             }
7303             if (sizeValue < 0)
7304                 continue;
7305 
7306             ValueFlow::Value value(sizeValue);
7307             value.errorPath.emplace_back(tok->tokAt(2), "Assign " + tok->strAt(1) + ", buffer with size " + MathLib::toString(sizeValue));
7308             value.valueType = ValueFlow::Value::ValueType::BUFFER_SIZE;
7309             value.setKnown();
7310             const std::list<ValueFlow::Value> values{value};
7311             valueFlowForward(const_cast<Token*>(rhs), functionScope->bodyEnd, tok->next(), values, tokenlist, settings);
7312         }
7313     }
7314 }
7315 
getMinMaxValues(const ValueType * vt,const cppcheck::Platform & platform,MathLib::bigint * minValue,MathLib::bigint * maxValue)7316 static bool getMinMaxValues(const ValueType *vt, const cppcheck::Platform &platform, MathLib::bigint *minValue, MathLib::bigint *maxValue)
7317 {
7318     if (!vt || !vt->isIntegral() || vt->pointer)
7319         return false;
7320 
7321     int bits;
7322     switch (vt->type) {
7323     case ValueType::Type::BOOL:
7324         bits = 1;
7325         break;
7326     case ValueType::Type::CHAR:
7327         bits = platform.char_bit;
7328         break;
7329     case ValueType::Type::SHORT:
7330         bits = platform.short_bit;
7331         break;
7332     case ValueType::Type::INT:
7333         bits = platform.int_bit;
7334         break;
7335     case ValueType::Type::LONG:
7336         bits = platform.long_bit;
7337         break;
7338     case ValueType::Type::LONGLONG:
7339         bits = platform.long_long_bit;
7340         break;
7341     default:
7342         return false;
7343     }
7344 
7345     if (bits == 1) {
7346         *minValue = 0;
7347         *maxValue = 1;
7348     } else if (bits < 62) {
7349         if (vt->sign == ValueType::Sign::UNSIGNED) {
7350             *minValue = 0;
7351             *maxValue = (1LL << bits) - 1;
7352         } else {
7353             *minValue = -(1LL << (bits - 1));
7354             *maxValue = (1LL << (bits - 1)) - 1;
7355         }
7356     } else if (bits == 64) {
7357         if (vt->sign == ValueType::Sign::UNSIGNED) {
7358             *minValue = 0;
7359             *maxValue = LLONG_MAX; // todo max unsigned value
7360         } else {
7361             *minValue = LLONG_MIN;
7362             *maxValue = LLONG_MAX;
7363         }
7364     } else {
7365         return false;
7366     }
7367 
7368     return true;
7369 }
7370 
getMinMaxValues(const std::string & typestr,const Settings * settings,MathLib::bigint * minvalue,MathLib::bigint * maxvalue)7371 static bool getMinMaxValues(const std::string &typestr, const Settings *settings, MathLib::bigint *minvalue, MathLib::bigint *maxvalue)
7372 {
7373     TokenList typeTokens(settings);
7374     std::istringstream istr(typestr+";");
7375     if (!typeTokens.createTokens(istr))
7376         return false;
7377     typeTokens.simplifyPlatformTypes();
7378     typeTokens.simplifyStdType();
7379     const ValueType &vt = ValueType::parseDecl(typeTokens.front(), settings);
7380     return getMinMaxValues(&vt, *settings, minvalue, maxvalue);
7381 }
7382 
valueFlowSafeFunctions(TokenList * tokenlist,SymbolDatabase * symboldatabase,const Settings * settings)7383 static void valueFlowSafeFunctions(TokenList* tokenlist, SymbolDatabase* symboldatabase, const Settings* settings)
7384 {
7385     for (const Scope *functionScope : symboldatabase->functionScopes) {
7386         if (!functionScope->bodyStart)
7387             continue;
7388         const Function *function = functionScope->function;
7389         if (!function)
7390             continue;
7391 
7392         const bool safe = function->isSafe(settings);
7393         const bool all = safe && settings->platformType != cppcheck::Platform::PlatformType::Unspecified;
7394 
7395         for (const Variable &arg : function->argumentList) {
7396             if (!arg.nameToken() || !arg.valueType())
7397                 continue;
7398 
7399             if (arg.valueType()->type == ValueType::Type::CONTAINER) {
7400                 if (!safe)
7401                     continue;
7402                 std::list<ValueFlow::Value> argValues;
7403                 argValues.emplace_back(0);
7404                 argValues.back().valueType = ValueFlow::Value::ValueType::CONTAINER_SIZE;
7405                 argValues.back().errorPath.emplace_back(arg.nameToken(), "Assuming " + arg.name() + " is empty");
7406                 argValues.back().safe = true;
7407                 argValues.emplace_back(1000000);
7408                 argValues.back().valueType = ValueFlow::Value::ValueType::CONTAINER_SIZE;
7409                 argValues.back().errorPath.emplace_back(arg.nameToken(), "Assuming " + arg.name() + " size is 1000000");
7410                 argValues.back().safe = true;
7411                 for (const ValueFlow::Value &value : argValues)
7412                     valueFlowContainerForward(
7413                         const_cast<Token*>(functionScope->bodyStart), arg.nameToken(), value, tokenlist);
7414                 continue;
7415             }
7416 
7417             MathLib::bigint low, high;
7418             bool isLow = arg.nameToken()->getCppcheckAttribute(TokenImpl::CppcheckAttributes::Type::LOW, &low);
7419             bool isHigh = arg.nameToken()->getCppcheckAttribute(TokenImpl::CppcheckAttributes::Type::HIGH, &high);
7420 
7421             if (!isLow && !isHigh && !all)
7422                 continue;
7423 
7424             const bool safeLow = !isLow;
7425             const bool safeHigh = !isHigh;
7426 
7427             if ((!isLow || !isHigh) && all) {
7428                 MathLib::bigint minValue, maxValue;
7429                 if (getMinMaxValues(arg.valueType(), *settings, &minValue, &maxValue)) {
7430                     if (!isLow)
7431                         low = minValue;
7432                     if (!isHigh)
7433                         high = maxValue;
7434                     isLow = isHigh = true;
7435                 } else if (arg.valueType()->type == ValueType::Type::FLOAT || arg.valueType()->type == ValueType::Type::DOUBLE || arg.valueType()->type == ValueType::Type::LONGDOUBLE) {
7436                     std::list<ValueFlow::Value> argValues;
7437                     argValues.emplace_back(0);
7438                     argValues.back().valueType = ValueFlow::Value::ValueType::FLOAT;
7439                     argValues.back().floatValue = isLow ? low : -1E25f;
7440                     argValues.back().errorPath.emplace_back(arg.nameToken(), "Safe checks: Assuming argument has value " + MathLib::toString(argValues.back().floatValue));
7441                     argValues.back().safe = true;
7442                     argValues.emplace_back(0);
7443                     argValues.back().valueType = ValueFlow::Value::ValueType::FLOAT;
7444                     argValues.back().floatValue = isHigh ? high : 1E25f;
7445                     argValues.back().errorPath.emplace_back(arg.nameToken(), "Safe checks: Assuming argument has value " + MathLib::toString(argValues.back().floatValue));
7446                     argValues.back().safe = true;
7447                     valueFlowForward(const_cast<Token*>(functionScope->bodyStart->next()),
7448                                      functionScope->bodyEnd,
7449                                      arg.nameToken(),
7450                                      argValues,
7451                                      tokenlist,
7452                                      settings);
7453                     continue;
7454                 }
7455             }
7456 
7457             std::list<ValueFlow::Value> argValues;
7458             if (isLow) {
7459                 argValues.emplace_back(low);
7460                 argValues.back().errorPath.emplace_back(arg.nameToken(), std::string(safeLow ? "Safe checks: " : "") + "Assuming argument has value " + MathLib::toString(low));
7461                 argValues.back().safe = safeLow;
7462             }
7463             if (isHigh) {
7464                 argValues.emplace_back(high);
7465                 argValues.back().errorPath.emplace_back(arg.nameToken(), std::string(safeHigh ? "Safe checks: " : "") + "Assuming argument has value " + MathLib::toString(high));
7466                 argValues.back().safe = safeHigh;
7467             }
7468 
7469             if (!argValues.empty())
7470                 valueFlowForward(const_cast<Token*>(functionScope->bodyStart->next()),
7471                                  functionScope->bodyEnd,
7472                                  arg.nameToken(),
7473                                  argValues,
7474                                  tokenlist,
7475                                  settings);
7476         }
7477     }
7478 }
7479 
valueFlowUnknownFunctionReturn(TokenList * tokenlist,const Settings * settings)7480 static void valueFlowUnknownFunctionReturn(TokenList *tokenlist, const Settings *settings)
7481 {
7482     if (settings->checkUnknownFunctionReturn.empty())
7483         return;
7484     for (Token *tok = tokenlist->front(); tok; tok = tok->next()) {
7485         if (!tok->astParent() || tok->str() != "(" || !tok->previous()->isName())
7486             continue;
7487         if (settings->checkUnknownFunctionReturn.find(tok->previous()->str()) == settings->checkUnknownFunctionReturn.end())
7488             continue;
7489         std::vector<MathLib::bigint> unknownValues = settings->library.unknownReturnValues(tok->astOperand1());
7490         if (unknownValues.empty())
7491             continue;
7492 
7493         // Get min/max values for return type
7494         const std::string &typestr = settings->library.returnValueType(tok->previous());
7495         MathLib::bigint minvalue, maxvalue;
7496         if (!getMinMaxValues(typestr, settings, &minvalue, &maxvalue))
7497             continue;
7498 
7499         for (MathLib::bigint value : unknownValues) {
7500             if (value < minvalue)
7501                 value = minvalue;
7502             else if (value > maxvalue)
7503                 value = maxvalue;
7504             setTokenValue(const_cast<Token *>(tok), ValueFlow::Value(value), settings);
7505         }
7506     }
7507 }
7508 
Value(const Token * c,long long val,Bound b)7509 ValueFlow::Value::Value(const Token* c, long long val, Bound b)
7510     : valueType(ValueType::INT),
7511     bound(b),
7512     intvalue(val),
7513     tokvalue(nullptr),
7514     floatValue(0.0),
7515     moveKind(MoveKind::NonMovedVariable),
7516     varvalue(val),
7517     condition(c),
7518     varId(0),
7519     safe(false),
7520     conditional(false),
7521     defaultArg(false),
7522     indirect(0),
7523     path(0),
7524     wideintvalue(0),
7525     lifetimeKind(LifetimeKind::Object),
7526     lifetimeScope(LifetimeScope::Local),
7527     valueKind(ValueKind::Possible)
7528 {
7529     errorPath.emplace_back(c, "Assuming that condition '" + c->expressionString() + "' is not redundant");
7530 }
7531 
assumeCondition(const Token * tok)7532 void ValueFlow::Value::assumeCondition(const Token* tok)
7533 {
7534     condition = tok;
7535     errorPath.emplace_back(tok, "Assuming that condition '" + tok->expressionString() + "' is not redundant");
7536 }
7537 
infoString() const7538 std::string ValueFlow::Value::infoString() const
7539 {
7540     switch (valueType) {
7541     case ValueType::INT:
7542         return MathLib::toString(intvalue);
7543     case ValueType::TOK:
7544         return tokvalue->str();
7545     case ValueType::FLOAT:
7546         return MathLib::toString(floatValue);
7547     case ValueType::MOVED:
7548         return "<Moved>";
7549     case ValueType::UNINIT:
7550         return "<Uninit>";
7551     case ValueType::BUFFER_SIZE:
7552     case ValueType::CONTAINER_SIZE:
7553         return "size=" + MathLib::toString(intvalue);
7554     case ValueType::ITERATOR_START:
7555         return "start=" + MathLib::toString(intvalue);
7556     case ValueType::ITERATOR_END:
7557         return "end=" + MathLib::toString(intvalue);
7558     case ValueType::LIFETIME:
7559         return "lifetime=" + tokvalue->str();
7560     case ValueType::SYMBOLIC:
7561         std::string result = "symbolic=" + tokvalue->expressionString();
7562         if (intvalue > 0)
7563             result += "+" + MathLib::toString(intvalue);
7564         else if (intvalue < 0)
7565             result += "-" + MathLib::toString(-intvalue);
7566         return result;
7567     }
7568     throw InternalError(nullptr, "Invalid ValueFlow Value type");
7569 }
7570 
toString(MoveKind moveKind)7571 const char* ValueFlow::Value::toString(MoveKind moveKind)
7572 {
7573     switch (moveKind) {
7574     case MoveKind::NonMovedVariable:
7575         return "NonMovedVariable";
7576     case MoveKind::MovedVariable:
7577         return "MovedVariable";
7578     case MoveKind::ForwardedVariable:
7579         return "ForwardedVariable";
7580     }
7581     return "";
7582 }
7583 
toString(LifetimeKind lifetimeKind)7584 const char* ValueFlow::Value::toString(LifetimeKind lifetimeKind)
7585 {
7586     switch (lifetimeKind) {
7587     case LifetimeKind::Object:
7588         return "Object";
7589     case LifetimeKind::SubObject:
7590         return "SubObject";
7591     case LifetimeKind::Lambda:
7592         return "Lambda";
7593     case LifetimeKind::Iterator:
7594         return "Iterator";
7595     case LifetimeKind::Address:
7596         return "Address";
7597     }
7598     return "";
7599 }
7600 
sameToken(const Token * tok1,const Token * tok2)7601 bool ValueFlow::Value::sameToken(const Token* tok1, const Token* tok2)
7602 {
7603     if (tok1 == tok2)
7604         return true;
7605     if (!tok1)
7606         return false;
7607     if (tok1->exprId() == 0 || tok2->exprId() == 0)
7608         return false;
7609     return tok1->exprId() == tok2->exprId();
7610 }
toString(LifetimeScope lifetimeScope)7611 const char* ValueFlow::Value::toString(LifetimeScope lifetimeScope)
7612 {
7613     switch (lifetimeScope) {
7614     case ValueFlow::Value::LifetimeScope::Local:
7615         return "Local";
7616     case ValueFlow::Value::LifetimeScope::Argument:
7617         return "Argument";
7618     case ValueFlow::Value::LifetimeScope::SubFunction:
7619         return "SubFunction";
7620     }
7621     return "";
7622 }
toString(Bound bound)7623 const char* ValueFlow::Value::toString(Bound bound)
7624 {
7625     switch (bound) {
7626     case ValueFlow::Value::Bound::Point:
7627         return "Point";
7628     case ValueFlow::Value::Bound::Upper:
7629         return "Upper";
7630     case ValueFlow::Value::Bound::Lower:
7631         return "Lower";
7632     }
7633     return "";
7634 }
7635 
valueFlowConstantFoldAST(Token * expr,const Settings * settings)7636 const ValueFlow::Value *ValueFlow::valueFlowConstantFoldAST(Token *expr, const Settings *settings)
7637 {
7638     if (expr && expr->values().empty()) {
7639         valueFlowConstantFoldAST(expr->astOperand1(), settings);
7640         valueFlowConstantFoldAST(expr->astOperand2(), settings);
7641         valueFlowSetConstantValue(expr, settings, true /* TODO: this is a guess */);
7642     }
7643     return expr && expr->hasKnownValue() ? &expr->values().front() : nullptr;
7644 }
7645 
getTotalValues(TokenList * tokenlist)7646 static std::size_t getTotalValues(TokenList *tokenlist)
7647 {
7648     std::size_t n = 1;
7649     for (Token *tok = tokenlist->front(); tok; tok = tok->next())
7650         n += tok->values().size();
7651     return n;
7652 }
7653 
setValues(TokenList * tokenlist,SymbolDatabase * symboldatabase,ErrorLogger * errorLogger,const Settings * settings)7654 void ValueFlow::setValues(TokenList *tokenlist, SymbolDatabase* symboldatabase, ErrorLogger *errorLogger, const Settings *settings)
7655 {
7656     for (Token *tok = tokenlist->front(); tok; tok = tok->next())
7657         tok->clearValueFlow();
7658 
7659     valueFlowEnumValue(symboldatabase, settings);
7660     valueFlowNumber(tokenlist);
7661     valueFlowString(tokenlist);
7662     valueFlowArray(tokenlist);
7663     valueFlowUnknownFunctionReturn(tokenlist, settings);
7664     valueFlowGlobalConstVar(tokenlist, settings);
7665     valueFlowEnumValue(symboldatabase, settings);
7666     valueFlowNumber(tokenlist);
7667     valueFlowGlobalStaticVar(tokenlist, settings);
7668     valueFlowPointerAlias(tokenlist);
7669     valueFlowLifetime(tokenlist, symboldatabase, errorLogger, settings);
7670     valueFlowSymbolic(tokenlist, symboldatabase);
7671     valueFlowBitAnd(tokenlist);
7672     valueFlowSameExpressions(tokenlist);
7673     valueFlowConditionExpressions(tokenlist, symboldatabase, errorLogger, settings);
7674 
7675     std::size_t values = 0;
7676     std::size_t n = 4;
7677     while (n > 0 && values < getTotalValues(tokenlist)) {
7678         values = getTotalValues(tokenlist);
7679         valueFlowImpossibleValues(tokenlist, settings);
7680         valueFlowSymbolicAbs(tokenlist, symboldatabase);
7681         valueFlowCondition(SymbolicConditionHandler{}, tokenlist, symboldatabase, errorLogger, settings);
7682         valueFlowSymbolicInfer(tokenlist, symboldatabase);
7683         valueFlowArrayBool(tokenlist);
7684         valueFlowRightShift(tokenlist, settings);
7685         valueFlowAfterAssign(tokenlist, symboldatabase, errorLogger, settings);
7686         valueFlowCondition(SimpleConditionHandler{}, tokenlist, symboldatabase, errorLogger, settings);
7687         valueFlowInferCondition(tokenlist, settings);
7688         valueFlowSwitchVariable(tokenlist, symboldatabase, errorLogger, settings);
7689         valueFlowForLoop(tokenlist, symboldatabase, errorLogger, settings);
7690         valueFlowSubFunction(tokenlist, symboldatabase, errorLogger, settings);
7691         valueFlowFunctionReturn(tokenlist, errorLogger);
7692         valueFlowLifetime(tokenlist, symboldatabase, errorLogger, settings);
7693         valueFlowFunctionDefaultParameter(tokenlist, symboldatabase, settings);
7694         valueFlowUninit(tokenlist, symboldatabase, settings);
7695         valueFlowUninitPointerAliasDeref(tokenlist);
7696         if (tokenlist->isCPP()) {
7697             valueFlowAfterMove(tokenlist, symboldatabase, settings);
7698             valueFlowSmartPointer(tokenlist, errorLogger, settings);
7699             valueFlowIterators(tokenlist, settings);
7700             valueFlowCondition(IteratorConditionHandler{}, tokenlist, symboldatabase, errorLogger, settings);
7701             valueFlowIteratorInfer(tokenlist, settings);
7702             valueFlowContainerSize(tokenlist, symboldatabase, errorLogger, settings);
7703             valueFlowCondition(ContainerConditionHandler{}, tokenlist, symboldatabase, errorLogger, settings);
7704         }
7705         valueFlowSafeFunctions(tokenlist, symboldatabase, settings);
7706         n--;
7707     }
7708 
7709     valueFlowDynamicBufferSize(tokenlist, symboldatabase, settings);
7710 }
7711 
unknown()7712 ValueFlow::Value ValueFlow::Value::unknown()
7713 {
7714     Value v;
7715     v.valueType = Value::ValueType::UNINIT;
7716     return v;
7717 }
7718 
eitherTheConditionIsRedundant(const Token * condition)7719 std::string ValueFlow::eitherTheConditionIsRedundant(const Token *condition)
7720 {
7721     if (!condition)
7722         return "Either the condition is redundant";
7723     if (condition->str() == "case") {
7724         std::string expr;
7725         for (const Token *tok = condition; tok && tok->str() != ":"; tok = tok->next()) {
7726             expr += tok->str();
7727             if (Token::Match(tok, "%name%|%num% %name%|%num%"))
7728                 expr += ' ';
7729         }
7730         return "Either the switch case '" + expr + "' is redundant";
7731     }
7732     return "Either the condition '" + condition->expressionString() + "' is redundant";
7733 }
7734 
findValue(const std::list<ValueFlow::Value> & values,const Settings * settings,std::function<bool (const ValueFlow::Value &)> pred)7735 const ValueFlow::Value* ValueFlow::findValue(const std::list<ValueFlow::Value>& values,
7736                                              const Settings* settings,
7737                                              std::function<bool(const ValueFlow::Value&)> pred)
7738 {
7739     const ValueFlow::Value* ret = nullptr;
7740     for (const ValueFlow::Value& v : values) {
7741         if (pred(v)) {
7742             if (!ret || ret->isInconclusive() || (ret->condition && !v.isInconclusive()))
7743                 ret = &v;
7744             if (!ret->isInconclusive() && !ret->condition)
7745                 break;
7746         }
7747     }
7748     if (settings && ret) {
7749         if (ret->isInconclusive() && !settings->certainty.isEnabled(Certainty::inconclusive))
7750             return nullptr;
7751         if (ret->condition && !settings->severity.isEnabled(Severity::warning))
7752             return nullptr;
7753     }
7754     return ret;
7755 }
7756 
isOutOfBoundsImpl(const ValueFlow::Value & size,const Token * indexTok,bool condition)7757 static std::vector<ValueFlow::Value> isOutOfBoundsImpl(const ValueFlow::Value& size,
7758                                                        const Token* indexTok,
7759                                                        bool condition)
7760 {
7761     if (!indexTok)
7762         return {};
7763     const ValueFlow::Value* indexValue = indexTok->getMaxValue(condition, size.path);
7764     if (!indexValue)
7765         return {};
7766     if (indexValue->intvalue >= size.intvalue)
7767         return {*indexValue};
7768     if (!condition)
7769         return {};
7770     // TODO: Use a better way to decide if the variable in unconstrained
7771     if (!indexTok->variable() || !indexTok->variable()->isArgument())
7772         return {};
7773     if (std::any_of(indexTok->values().begin(), indexTok->values().end(), [&](const ValueFlow::Value& v) {
7774         return v.isSymbolicValue() && v.isPossible() && v.bound == ValueFlow::Value::Bound::Upper;
7775     }))
7776         return {};
7777     if (indexValue->bound != ValueFlow::Value::Bound::Lower)
7778         return {};
7779     if (size.bound == ValueFlow::Value::Bound::Lower)
7780         return {};
7781     ValueFlow::Value inBoundsValue = inferCondition("<", indexTok, size.intvalue);
7782     if (inBoundsValue.isKnown() && inBoundsValue.intvalue != 0)
7783         return {};
7784     ValueFlow::Value value = inferCondition(">=", indexTok, indexValue->intvalue);
7785     if (!value.isKnown())
7786         return {};
7787     if (value.intvalue == 0)
7788         return {};
7789     value.intvalue = size.intvalue;
7790     value.bound = ValueFlow::Value::Bound::Lower;
7791     return {value};
7792 }
7793 
isOutOfBounds(const Value & size,const Token * indexTok,bool possible)7794 std::vector<ValueFlow::Value> ValueFlow::isOutOfBounds(const Value& size, const Token* indexTok, bool possible)
7795 {
7796     std::vector<ValueFlow::Value> result = isOutOfBoundsImpl(size, indexTok, false);
7797     if (!result.empty())
7798         return result;
7799     if (!possible)
7800         return result;
7801     return isOutOfBoundsImpl(size, indexTok, true);
7802 }
7803