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