Cppcheck
exprengine.cpp
Go to the documentation of this file.
1 /*
2  * Cppcheck - A tool for static C/C++ code analysis
3  * Copyright (C) 2007-2022 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 ExprEngine component in Cppcheck. Its job is to
21  * convert the C/C++ code into expressions that the Z3 prover understands.
22  * We can then ask Z3 prover for instance if variable "x" can be 123 and
23  * the Z3 prover can tell us that.
24  *
25  * Overview
26  * ========
27  *
28  * The ExprEngine performs a "abstract execution" of each function.
29  * - ExprEngine performs "forward" analysis only. It starts at the top
30  * of the functions.
31  * - There is a abstract program state `Data::memory`.
32  * - The constraints are stored in the vector `Data::constraints`.
33  *
34  * Abstract program state
35  * ======================
36  *
37  * The map `Data::memory` contains the abstract values of all variables
38  * that are used in the current function scope.
39  *
40  * Use `--debug-bug-hunting --verbose` to dump out `Data::memory`.
41  * Example output:
42  * 2:5: { x=$1 y=$2}
43  * Explanation:
44  * At line 2, column 5: The memory has two variables. Variable x has the
45  * value $1. Variable y has the value $2.
46  *
47  * Different value names:
48  * - Typical abstract value has name that starts with "$". The number is
49  * just a incremented value.
50  * - If a variable has a known value then the concrete value is written.
51  * Example: `{ x=1 }`.
52  * - For an uninitialized value the output says "?". For example: `{ a=? }`
53  * - For buffers the output is something like `{ buf=($3,size=10,[:]=?,[$1]=$2) }`
54  * The first item "$3" is the name of the buffer value.
55  * The second item says that the size of this buffer is 10.
56  * After that comes `[index]=value` items that show what values buffer items have:
57  * `[:]=?` means that all items are uninitialized.
58  * `[$1]=$2` means that the buffer item at index "$1" has value "$2".
59  *
60  * Abstract execution
61  * ==================
62  *
63  * The function:
64  * static std::string execute(const Token *start, const Token *end, Data &data)
65  *
66  * Perform abstract execution of the code from `start` to `end`. The
67  * `data` is modified during the abstract execution.
68  *
69  * Each astTop token is executed. From that, operands are executed
70  * recursively in the "execute.." functions. The result of an operand is
71  * a abstract value.
72  *
73  * Branches
74  * --------
75  *
76  * Imagine:
77  * code1
78  * if (x > 0)
79  * code2
80  * else
81  * code3
82  * code4
83  *
84  * When "if" is reached.. the current `data` is branched into `thenData`
85  * and `elseData`.
86  * For "thenData" a constraint is added: x>0
87  * For "elseData" a constraint is added: !(x>0)
88  *
89  * Then analysis of `thenData` and `elseData` will continue separately,
90  * by recursive execution. The "code4" block will be analysed both with
91  * `thenData` and `elseData`.
92  *
93  * Z3
94  * ==
95  *
96  * The ExprEngine will not execute Z3 unless a check wants it to.
97  *
98  * The abstract values and all their constraints is added to a Z3 solver
99  * object and after that Z3 can tell us if some condition can be true.
100  *
101  * Z3 is a SMT solver:
102  * https://en.wikipedia.org/wiki/Satisfiability_modulo_theories
103  *
104  * In SMT:
105  * - all variables are "constant". A variable can not be changed or assigned.
106  * - There is no "execution". The solver considers all equations simultaneously.
107  *
108  * Simple example (TestExpr::expr6):
109  *
110  * void f(unsigned char x)
111  * {
112  * unsigned char y = 8 - x;\n"
113  * y > 1000;
114  * }
115  *
116  * If a check wants to know if "y > 1000" can be true, ExprEngine will
117  * generate this Z3 input:
118  *
119  * (declare-fun $1 () Int)
120  * (assert (and (>= $1 0) (<= $1 255)))
121  * (assert (> (- 8 $1) 1000))
122  *
123  * A symbol "$1" is created.
124  * assert that "$1" is a value 0-255.
125  * assert that "8-$1" is greater than 1000.
126  *
127  * Z3 can now determine if these assertions are possible or not. In this
128  * case these assertions are not possible, there is no value for $1 between
129  * 0-255 that means that "8-$1" is greater than 1000.
130  */
131 
132 #include "exprengine.h"
133 
134 #include "astutils.h"
135 #include "bughuntingchecks.h"
136 #include "errorlogger.h"
137 #include "library.h"
138 #include "mathlib.h"
139 #include "platform.h"
140 #include "settings.h"
141 #include "symboldatabase.h"
142 #include "token.h"
143 #include "tokenize.h"
144 #include "tokenlist.h"
145 
146 #include <cctype>
147 #include <climits>
148 #include <cstdint>
149 #include <ctime>
150 #include <exception>
151 #include <iostream>
152 #include <limits>
153 #include <list>
154 #include <memory>
155 #include <set>
156 #include <tuple>
157 
158 #ifdef USE_Z3
159 #include <z3++.h>
160 #include <z3_version.h>
161 #define GET_VERSION_INT(A,B,C) ((A) * 10000 + (B) * 100 + (C))
162 #define Z3_VERSION_INT GET_VERSION_INT(Z3_MAJOR_VERSION, Z3_MINOR_VERSION, Z3_BUILD_NUMBER)
163 #endif
164 
165 const uint32_t MAX_BUFFER_SIZE = ~0U >> 1;
166 #define CONTRACT 1
167 
168 namespace {
169  struct ExprEngineException {
170  ExprEngineException(const Token *tok, const std::string &what) : tok(tok), what(what) {}
171  const Token *tok;
172  const std::string what;
173  };
174  struct TerminateExpression {};
175 }
176 
177 static std::string str(ExprEngine::ValuePtr val)
178 {
179  const char *typestr = "???UnknownValueType???";
180  switch (val->type) {
182  typestr = "AddressOfValue";
183  break;
185  typestr = "ArrayValue";
186  break;
188  typestr = "UninitValue";
189  break;
191  typestr = "IntRange";
192  break;
194  typestr = "FloatRange";
195  break;
197  typestr = "ConditionalValue";
198  break;
200  typestr = "StringLiteralValue";
201  break;
203  typestr = "StructValue";
204  break;
206  typestr = "BinOpResult";
207  break;
209  typestr = "IntegerTruncation";
210  break;
212  typestr = "FunctionCallArgumentValues";
213  break;
215  typestr = "BailoutValue";
216  break;
217  }
218 
219  return val->name + "=" + std::string(typestr) + "(" + val->getRange() + ")";
220 }
221 
222 static size_t extfind(const std::string &str, const std::string &what, size_t pos)
223 {
224  int indent = 0;
225  for (; pos < str.size(); ++pos) {
226  if (indent <= 0 && str[pos] == what[0])
227  return pos;
228  else if (str[pos] == '\"') {
229  ++pos;
230  while (pos < str.size()) {
231  if (str[pos] == '\"')
232  break;
233  if (pos == '\\')
234  ++pos;
235  ++pos;
236  }
237  } else if (str[pos] == '(')
238  ++indent;
239  else if (str[pos] == ')')
240  --indent;
241  }
242  return std::string::npos;
243 }
244 
245 std::string ExprEngine::str(int128_t value)
246 {
247  std::ostringstream ostr;
248 #ifdef __GNUC__
249  if (value == (int)value) {
250  ostr << (int) value;
251  return ostr.str();
252  }
253  if (value < 0) {
254  ostr << "-";
255  value = -value;
256  }
257 
258  uint64_t high = value >> 64;
259  uint64_t low = value;
260  if (high > 0)
261  ostr << "h" << std::hex << high << "l";
262  ostr << std::hex << low;
263 #else
264  ostr << value;
265 #endif
266  return ostr.str();
267 }
268 
269 static ExprEngine::ValuePtr getValueRangeFromValueType(const std::string &name, const ValueType *vt, const cppcheck::Platform &platform);
270 
271 namespace {
272  class TrackExecution {
273  public:
274  TrackExecution() : mDataIndexCounter(0), mAbortLine(-1) {}
275 
276  int getNewDataIndex() {
277  return mDataIndexCounter++;
278  }
279 
280  void symbolRange(const Token *tok, ExprEngine::ValuePtr value) {
281  if (!tok || !value)
282  return;
283  if (tok->index() == 0)
284  return;
285  const std::string &symbolicExpression = value->getSymbolicExpression();
286  if (std::isdigit(symbolicExpression[0]) || value->type == ExprEngine::ValueType::BinOpResult || value->type == ExprEngine::ValueType::UninitValue)
287  return;
288  if (mSymbols.find(symbolicExpression) != mSymbols.end())
289  return;
290  mSymbols.insert(symbolicExpression);
291  mMap[tok].push_back(str(value));
292  }
293 
294  void state(const Token *tok, const std::string &s) {
295  mMap[tok].push_back(s);
296  }
297 
298  void print(std::ostream &out) {
299  std::set<std::pair<int,int>> locations;
300  for (const auto& it : mMap) {
301  locations.insert(std::pair<int,int>(it.first->linenr(), it.first->column()));
302  }
303  for (const std::pair<int,int> &loc : locations) {
304  int lineNumber = loc.first;
305  int column = loc.second;
306  for (auto &it : mMap) {
307  const Token *tok = it.first;
308  if (lineNumber != tok->linenr())
309  continue;
310  if (column != tok->column())
311  continue;
312  const std::vector<std::string> &dumps = it.second;
313  for (const std::string &dump : dumps)
314  out << lineNumber << ":" << column << ": " << dump << "\n";
315  }
316  }
317  }
318 
319  void report(std::ostream &out, const Scope *functionScope) const {
320  int linenr = -1;
321  std::string code;
322  for (const Token *tok = functionScope->bodyStart->next(); tok != functionScope->bodyEnd; tok = tok->next()) {
323  if (tok->linenr() > linenr) {
324  if (!code.empty())
325  out << getStatus(linenr) << " " << code << std::endl;
326  linenr = tok->linenr();
327  code.clear();
328  }
329  code += " " + tok->str();
330  }
331 
332  out << getStatus(linenr) << " " << code << std::endl;
333  }
334 
335  void setAbortLine(int linenr) {
336  if (linenr > 0 && (mAbortLine == -1 || linenr < mAbortLine))
337  mAbortLine = linenr;
338  }
339 
340  void addError(int linenr) {
341  mErrors.insert(linenr);
342  }
343 
344  bool isAllOk() const {
345  return mErrors.empty();
346  }
347 
348  void addMissingContract(const std::string &f) {
349  mMissingContracts.insert(f);
350  }
351 
352  const std::set<std::string> getMissingContracts() const {
353  return mMissingContracts;
354  }
355 
356  void ifSplit(const Token *tok, unsigned int thenIndex, unsigned int elseIndex) {
357  mMap[tok].push_back("D" + std::to_string(thenIndex) + ": Split. Then:D" + std::to_string(thenIndex) + " Else:D" + std::to_string(elseIndex));
358  }
359 
360  private:
361  const char *getStatus(int linenr) const {
362  if (mErrors.find(linenr) != mErrors.end())
363  return "ERROR";
364  if (mAbortLine > 0 && linenr >= mAbortLine)
365  return "--";
366  return "ok";
367  }
368 
369  std::map<const Token *, std::vector<std::string>> mMap;
370 
371  int mDataIndexCounter;
372  int mAbortLine;
373  std::set<std::string> mSymbols;
374  std::set<int> mErrors;
375  std::set<std::string> mMissingContracts;
376  };
377 
378  class Data : public ExprEngine::DataBase {
379  public:
380  Data(int *symbolValueIndex, ErrorLogger *errorLogger, const Tokenizer *tokenizer, const Settings *settings, const std::string &currentFunction, const std::vector<ExprEngine::Callback> &callbacks, TrackExecution *trackExecution)
381  : DataBase(currentFunction, settings)
382  , symbolValueIndex(symbolValueIndex)
383  , errorLogger(errorLogger)
384  , tokenizer(tokenizer)
385  , callbacks(callbacks)
386  , recursion(0)
387  , startTime(std::time(nullptr))
388  , mTrackExecution(trackExecution)
389  , mDataIndex(trackExecution->getNewDataIndex()) {}
390 
391  Data(const Data &old)
392  : DataBase(old.currentFunction, old.settings)
393  , memory(old.memory)
394  , symbolValueIndex(old.symbolValueIndex)
395  , errorLogger(old.errorLogger)
396  , tokenizer(old.tokenizer)
397  , callbacks(old.callbacks)
398  , constraints(old.constraints)
399  , recursion(old.recursion)
400  , startTime(old.startTime)
401  , mTrackExecution(old.mTrackExecution)
402  , mDataIndex(mTrackExecution->getNewDataIndex()) {
403  for (auto &it: memory) {
404  if (!it.second)
405  continue;
406  if (auto oldValue = std::dynamic_pointer_cast<ExprEngine::ArrayValue>(it.second))
407  it.second = std::make_shared<ExprEngine::ArrayValue>(getNewSymbolName(), *oldValue);
408  }
409  }
410 
411  using Memory = std::map<nonneg int, ExprEngine::ValuePtr>;
412  Memory memory;
413  int * const symbolValueIndex;
414  ErrorLogger *errorLogger;
415  const Tokenizer * const tokenizer;
416  const std::vector<ExprEngine::Callback> &callbacks;
417  std::vector<ExprEngine::ValuePtr> constraints;
418  int recursion;
419  std::time_t startTime;
420 
421  bool isC() const override {
422  return tokenizer->isC();
423  }
424  bool isCPP() const override {
425  return tokenizer->isCPP();
426  }
427 
428 #ifdef CONTRACT
429  ExprEngine::ValuePtr executeContract(const Function *function, ExprEngine::ValuePtr (*executeExpression)(const Token*, Data&)) {
430  const auto it = settings->functionContracts.find(function->fullName());
431  if (it == settings->functionContracts.end())
432  return ExprEngine::ValuePtr();
433  const std::string &expects = it->second;
434  TokenList tokenList(settings);
435  std::istringstream istr(expects);
436  tokenList.createTokens(istr);
437  tokenList.createAst();
438  SymbolDatabase *symbolDatabase = const_cast<SymbolDatabase*>(tokenizer->getSymbolDatabase());
439  for (Token *tok = tokenList.front(); tok; tok = tok->next()) {
440  for (const Variable &arg: function->argumentList) {
441  if (arg.name() == tok->str()) {
442  tok->variable(&arg);
443  tok->varId(arg.declarationId());
444  }
445  }
446  }
447  symbolDatabase->setValueTypeInTokenList(false, tokenList.front());
448  return executeExpression(tokenList.front()->astTop(), *this);
449  }
450 
451  void contractConstraints(const Function *function, ExprEngine::ValuePtr (*executeExpression)(const Token*, Data&)) {
452  auto value = executeContract(function, executeExpression);
453  if (value)
454  constraints.push_back(value);
455  }
456 #endif
457 
458  void assignValue(const Token *tok, unsigned int varId, ExprEngine::ValuePtr value) {
459  if (varId == 0)
460  return;
461  mTrackExecution->symbolRange(tok, value);
462  if (value) {
463  if (auto arr = std::dynamic_pointer_cast<ExprEngine::ArrayValue>(value)) {
464  for (const auto &dim: arr->size)
465  mTrackExecution->symbolRange(tok, dim);
466  for (const auto &indexAndValue: arr->data)
467  mTrackExecution->symbolRange(tok, indexAndValue.value);
468  } else if (auto s = std::dynamic_pointer_cast<ExprEngine::StructValue>(value)) {
469  for (const auto &m: s->member)
470  mTrackExecution->symbolRange(tok, m.second);
471  }
472  }
473  memory[varId] = value;
474  }
475 
476  void assignStructMember(const Token *tok, ExprEngine::StructValue *structVal, const std::string &memberName, ExprEngine::ValuePtr value) {
477  mTrackExecution->symbolRange(tok, value);
478  structVal->member[memberName] = value;
479  }
480 
481  void functionCall() {
482  // Remove values for global variables
483  const SymbolDatabase *symbolDatabase = tokenizer->getSymbolDatabase();
484  for (std::map<nonneg int, ExprEngine::ValuePtr>::iterator it = memory.begin(); it != memory.end();) {
485  unsigned int varid = it->first;
486  const Variable *var = symbolDatabase->getVariableFromVarId(varid);
487  if (var && var->isGlobal())
488  it = memory.erase(it);
489  else
490  ++it;
491  }
492  }
493 
494  std::string getNewSymbolName() final {
495  return "$" + std::to_string(++(*symbolValueIndex));
496  }
497 
498  std::shared_ptr<ExprEngine::ArrayValue> getArrayValue(const Token *tok) {
499  const Memory::iterator it = memory.find(tok->varId());
500  if (it != memory.end())
501  return std::dynamic_pointer_cast<ExprEngine::ArrayValue>(it->second);
502  if (tok->varId() == 0 || !tok->variable())
503  return std::shared_ptr<ExprEngine::ArrayValue>();
504  auto val = std::make_shared<ExprEngine::ArrayValue>(this, tok->variable());
505  assignValue(tok, tok->varId(), val);
506  return val;
507  }
508 
509  ExprEngine::ValuePtr getValue(unsigned int varId, const ValueType *valueType, const Token *tok) {
510  const Memory::const_iterator it = memory.find(varId);
511  if (it != memory.end())
512  return it->second;
513  if (!valueType)
514  return ExprEngine::ValuePtr();
515 
516  // constant value..
517  const Variable *var = tokenizer->getSymbolDatabase()->getVariableFromVarId(varId);
518  if (var && valueType->constness == 1 && Token::Match(var->nameToken(), "%var% =")) {
519  const Token *initExpr = var->nameToken()->next()->astOperand2();
520  if (initExpr && initExpr->hasKnownIntValue()) {
521  auto intval = initExpr->getKnownIntValue();
522  return std::make_shared<ExprEngine::IntRange>(std::to_string(intval), intval, intval);
523  }
524  }
525 
526  ExprEngine::ValuePtr value = getValueRangeFromValueType(getNewSymbolName(), valueType, *settings);
527  if (value) {
528  if (tok->variable() && tok->variable()->nameToken())
529  addConstraints(value, tok->variable()->nameToken());
530  assignValue(tok, varId, value);
531  }
532  return value;
533  }
534 
535  void trackCheckContract(const Token *tok, const std::string &solverOutput) {
536  std::ostringstream os;
537  os << "checkContract:{\n";
538 
539  std::string line;
540  std::istringstream istr(solverOutput);
541  while (std::getline(istr, line))
542  os << " " << line << "\n";
543 
544  os << "}";
545 
546  mTrackExecution->state(tok, os.str());
547  }
548 
549  void trackProgramState(const Token *tok) {
550  if (memory.empty())
551  return;
552  const SymbolDatabase * const symbolDatabase = tokenizer->getSymbolDatabase();
553  std::ostringstream s;
554  s << "D" << mDataIndex << ":" << "memory:{";
555  bool first = true;
556  for (const auto &mem : memory) {
557  ExprEngine::ValuePtr value = mem.second;
558  const Variable *var = symbolDatabase->getVariableFromVarId(mem.first);
559  if (!var)
560  continue;
561  if (!first)
562  s << " ";
563  first = false;
564  s << var->name() << "=";
565  if (!value)
566  s << "(null)";
567  else if (value->name[0] == '$' && value->getSymbolicExpression() != value->name)
568  s << "(" << value->name << "," << value->getSymbolicExpression() << ")";
569  else
570  s << value->name;
571  }
572  s << "}";
573 
574  if (!constraints.empty()) {
575  s << " constraints:{";
576  first = true;
577  for (const auto &constraint: constraints) {
578  if (!first)
579  s << " ";
580  first = false;
581  s << constraint->getSymbolicExpression();
582  }
583  s << "}";
584  }
585  mTrackExecution->state(tok, s.str());
586  }
587 
588  void addMissingContract(const std::string &f) {
589  mTrackExecution->addMissingContract(f);
590  }
591 
593  auto b = std::dynamic_pointer_cast<ExprEngine::BinOpResult>(v);
594  if (b) {
595  std::string binop;
596  if (b->binop == "==")
597  binop = "!=";
598  else if (b->binop == "!=")
599  binop = "==";
600  else if (b->binop == ">=")
601  binop = "<";
602  else if (b->binop == "<=")
603  binop = ">";
604  else if (b->binop == ">")
605  binop = "<=";
606  else if (b->binop == "<")
607  binop = ">=";
608  if (!binop.empty())
609  return std::make_shared<ExprEngine::BinOpResult>(binop, b->op1, b->op2);
610  }
611  if (std::dynamic_pointer_cast<ExprEngine::FloatRange>(v)) {
612  auto zero = std::make_shared<ExprEngine::FloatRange>("0.0", 0.0, 0.0);
613  return std::make_shared<ExprEngine::BinOpResult>("==", v, zero);
614  }
615  auto zero = std::make_shared<ExprEngine::IntRange>("0", 0, 0);
616  return std::make_shared<ExprEngine::BinOpResult>("==", v, zero);
617  }
618 
619  void addConstraint(ExprEngine::ValuePtr condValue, bool trueCond) {
620  if (!condValue)
621  return;
622  if (trueCond)
623  constraints.push_back(condValue);
624  else
625  constraints.push_back(notValue(condValue));
626  }
627 
628  void addConstraint(ExprEngine::ValuePtr lhsValue, ExprEngine::ValuePtr rhsValue, bool equals) {
629  if (!lhsValue || !rhsValue)
630  return;
631  constraints.push_back(std::make_shared<ExprEngine::BinOpResult>(equals?"==":"!=", lhsValue, rhsValue));
632  }
633 
634  void addConstraints(ExprEngine::ValuePtr value, const Token *tok) {
635 #ifdef CONTRACT
636  MathLib::bigint low;
637  if (tok->getCppcheckAttribute(TokenImpl::CppcheckAttributes::Type::LOW, &low))
638  addConstraint(std::make_shared<ExprEngine::BinOpResult>(">=", value, std::make_shared<ExprEngine::IntRange>(std::to_string(low), low, low)), true);
639 
640  MathLib::bigint high;
641  if (tok->getCppcheckAttribute(TokenImpl::CppcheckAttributes::Type::HIGH, &high))
642  addConstraint(std::make_shared<ExprEngine::BinOpResult>("<=", value, std::make_shared<ExprEngine::IntRange>(std::to_string(high), high, high)), true);
643 #endif
644  }
645 
646  void reportError(const Token *tok,
647  Severity::SeverityType severity,
648  const char id[],
649  const std::string &text,
650  CWE cwe,
651  bool inconclusive,
652  bool incomplete,
653  const std::string &functionName) override {
654  if (errorPath.empty())
655  mTrackExecution->addError(tok->linenr());
656 
657  ErrorPath e = errorPath;
658  e.push_back(ErrorPathItem(tok, text));
659  ErrorMessage errmsg(e, &tokenizer->list, severity, id, text, cwe, inconclusive ? Certainty::inconclusive : Certainty::normal, true);
660  errmsg.incomplete = incomplete;
661  errmsg.function = functionName.empty() ? currentFunction : functionName;
662  errorLogger->reportErr(errmsg);
663  }
664 
665  std::string str() const {
666  std::ostringstream ret;
667  std::map<std::string, ExprEngine::ValuePtr> vars;
668  for (const auto &mem: memory) {
669  if (!mem.second)
670  continue;
671  const Variable *var = tokenizer->getSymbolDatabase()->getVariableFromVarId(mem.first);
672  if (var && var->isLocal())
673  continue;
674  ret << " @" << mem.first << ":" << mem.second->name;
675  getSymbols(vars, mem.second);
676  }
677  for (const auto &var: vars) {
678  if (var.second->name[0] == '$')
679  ret << " " << ::str(var.second);
680  }
681  for (const auto &c: constraints)
682  ret << " (" << c->getSymbolicExpression() << ")";
683  ret << std::endl;
684  return ret.str();
685  }
686 
687  void load(const std::string &s) {
688  std::vector<ImportData> importData;
689  parsestr(s, &importData);
690  //simplify(importData);
691 
692  if (importData.empty())
693  return;
694 
695  std::map<std::string, ExprEngine::ValuePtr> symbols;
696  for (const auto &mem: memory) {
697  getSymbols(symbols, mem.second);
698  }
699 
700  // TODO: combined symbolvalue
701  std::map<int, std::string> combinedMemory;
702  for (const ImportData &d: importData) {
703  for (const auto &mem: d.mem) {
704  auto c = combinedMemory.find(mem.first);
705  if (c == combinedMemory.end()) {
706  combinedMemory[mem.first] = mem.second;
707  continue;
708  }
709  if (c->second == mem.second)
710  continue;
711  if (c->second == "?" || mem.second == "?")
712  c->second = "?";
713  else
714  c->second.clear();
715  }
716  }
717 
718  for (const auto &mem: combinedMemory) {
719  int varid = mem.first;
720  const std::string &name = mem.second;
721  auto it = memory.find(varid);
722  if (it != memory.end() && it->second && it->second->name == name)
723  continue;
724  if (name.empty()) {
725  if (it != memory.end())
726  memory.erase(it);
727  continue;
728  }
729  auto it2 = symbols.find(name);
730  if (it2 != symbols.end()) {
731  memory[varid] = it2->second;
732  continue;
733  }
734  if (name == "?") {
735  auto uninitValue = std::make_shared<ExprEngine::UninitValue>();
736  symbols[name] = uninitValue;
737  memory[varid] = uninitValue;
738  continue;
739  }
740  if (std::isdigit(name[0])) {
741  long long v = std::stoi(name);
742  auto intRange = std::make_shared<ExprEngine::IntRange>(name, v, v);
743  symbols[name] = intRange;
744  memory[varid] = intRange;
745  continue;
746  }
747  // TODO: handle this value..
748  if (it != memory.end())
749  memory.erase(it);
750  }
751  }
752 
753  static void ifSplit(const Token *tok, const Data& thenData, const Data& elseData) {
754  thenData.mTrackExecution->ifSplit(tok, thenData.mDataIndex, elseData.mDataIndex);
755  }
756 
757  private:
758  TrackExecution * const mTrackExecution;
759  const int mDataIndex;
760 
761  struct ImportData {
762  std::map<int, std::string> mem;
763  std::map<std::string, std::string> sym;
764  std::vector<std::string> constraints;
765  };
766 
767  static void parsestr(const std::string &s, std::vector<ImportData> *importData) {
768  std::string line;
769  std::istringstream istr(s);
770  while (std::getline(istr, line)) {
771  if (line.empty())
772  continue;
773  line += " ";
774  ImportData d;
775  for (std::string::size_type pos = 0; pos < line.size();) {
776  pos = line.find_first_not_of(" ", pos);
777  if (pos == std::string::npos)
778  break;
779  if (line[pos] == '@') {
780  ++pos;
781  std::string::size_type colon = line.find(":", pos);
782  std::string::size_type end = line.find(" ", colon);
783  const std::string lhs = line.substr(pos, colon-pos);
784  pos = colon + 1;
785  const std::string rhs = line.substr(pos, end-pos);
786  d.mem[std::stoi(lhs)] = rhs;
787  pos = end;
788  } else if (line[pos] == '$') {
789  const std::string::size_type eq = line.find("=", pos);
790  const std::string lhs = line.substr(pos, eq-pos);
791  pos = eq + 1;
792  const std::string::size_type end = extfind(line, " ", pos);
793  const std::string rhs = line.substr(pos, end-pos);
794  pos = end;
795  d.sym[lhs] = rhs;
796  } else if (line[pos] == '(') {
797  const std::string::size_type end = extfind(line, " ", pos);
798  const std::string c = line.substr(pos, end-pos);
799  pos = end;
800  d.constraints.push_back(c);
801  } else {
802  throw ExprEngineException(nullptr, "Internal Error: Data::parsestr(), line:" + line);
803  }
804  }
805  importData->push_back(d);
806  }
807  }
808 
809  void getSymbols(std::map<std::string, ExprEngine::ValuePtr> &symbols, ExprEngine::ValuePtr val) const {
810  if (!val)
811  return;
812  symbols[val->name] = val;
813  if (auto arrayValue = std::dynamic_pointer_cast<ExprEngine::ArrayValue>(val)) {
814  for (const auto &sizeValue: arrayValue->size)
815  getSymbols(symbols, sizeValue);
816  for (const auto &indexValue: arrayValue->data) {
817  getSymbols(symbols, indexValue.index);
818  getSymbols(symbols, indexValue.value);
819  }
820  }
821  if (auto structValue = std::dynamic_pointer_cast<ExprEngine::StructValue>(val)) {
822  for (const auto &memberNameValue: structValue->member)
823  getSymbols(symbols, memberNameValue.second);
824  }
825  }
826  };
827 }
828 
829 #ifdef __clang__
830 // work around "undefined reference to `__muloti4'" linker error - see https://bugs.llvm.org/show_bug.cgi?id=16404
831 __attribute__((no_sanitize("undefined")))
832 #endif
834 {
835  auto b = std::dynamic_pointer_cast<ExprEngine::BinOpResult>(origValue);
836  if (!b)
837  return origValue;
838  if (!b->op1 || !b->op2)
839  return origValue;
840  auto intRange1 = std::dynamic_pointer_cast<ExprEngine::IntRange>(b->op1);
841  auto intRange2 = std::dynamic_pointer_cast<ExprEngine::IntRange>(b->op2);
842  if (intRange1 && intRange2 && intRange1->minValue == intRange1->maxValue && intRange2->minValue == intRange2->maxValue) {
843  const std::string &binop = b->binop;
844  int128_t v;
845  if (binop == "+")
846  v = intRange1->minValue + intRange2->minValue;
847  else if (binop == "-")
848  v = intRange1->minValue - intRange2->minValue;
849  else if (binop == "*")
850  v = intRange1->minValue * intRange2->minValue;
851  else if (binop == "/" && intRange2->minValue != 0)
852  v = intRange1->minValue / intRange2->minValue;
853  else if (binop == "%" && intRange2->minValue != 0)
854  v = intRange1->minValue % intRange2->minValue;
855  else
856  return origValue;
857  return std::make_shared<ExprEngine::IntRange>(ExprEngine::str(v), v, v);
858  }
859  return origValue;
860 }
861 
863 {
864  if (!value)
865  return value;
866  if (value->type == ExprEngine::ValueType::UninitValue) {
867  auto rangeValue = getValueRangeFromValueType(data.getNewSymbolName(), valueType, *data.settings);
868  if (rangeValue)
869  return rangeValue;
870  }
871  if (auto conditionalValue = std::dynamic_pointer_cast<ExprEngine::ConditionalValue>(value)) {
872  if (conditionalValue->values.size() == 1 && conditionalValue->values[0].second && conditionalValue->values[0].second->type == ExprEngine::ValueType::UninitValue) {
873  auto rangeValue = getValueRangeFromValueType(data.getNewSymbolName(), valueType, *data.settings);
874  if (rangeValue)
875  return rangeValue;
876  }
877  }
878  return value;
879 }
880 
881 static int128_t truncateInt(int128_t value, int bits, char sign)
882 {
883  value = value & (((int128_t)1 << bits) - 1);
884  // Sign extension
885  if (sign == 's' && value & (1ULL << (bits - 1)))
886  value |= ~(((int128_t)1 << bits) - 1);
887  return value;
888 }
889 
890 ExprEngine::ArrayValue::ArrayValue(const std::string &name, ExprEngine::ValuePtr size, ExprEngine::ValuePtr value, bool pointer, bool nullPointer, bool uninitPointer)
892  , pointer(pointer), nullPointer(nullPointer), uninitPointer(uninitPointer)
893 {
894  this->size.push_back(size);
895  assign(ExprEngine::ValuePtr(), value);
896 }
897 
899  : Value(data->getNewSymbolName(), ExprEngine::ValueType::ArrayValue)
900  , pointer(var && var->isPointer()), nullPointer(var && var->isPointer()), uninitPointer(var && var->isPointer())
901 {
902  if (var) {
903  for (const auto &dim : var->dimensions()) {
904  if (dim.known)
905  size.push_back(std::make_shared<ExprEngine::IntRange>(std::to_string(dim.num), dim.num, dim.num));
906  else
907  size.push_back(std::make_shared<ExprEngine::IntRange>(data->getNewSymbolName(), 1, ExprEngine::ArrayValue::MAXSIZE));
908  }
909  } else {
910  size.push_back(std::make_shared<ExprEngine::IntRange>(data->getNewSymbolName(), 1, ExprEngine::ArrayValue::MAXSIZE));
911  }
912 
913  const Token *initToken = var ? var->nameToken() : nullptr;
914  while (initToken && initToken->str() != "=")
915  initToken = initToken->astParent();
916 
917  ValuePtr val;
918  if (var && !var->isGlobal() && !var->isStatic() && !(var->isArgument() && var->isConst()) && !initToken)
919  val = std::make_shared<ExprEngine::UninitValue>();
920  else if (var && var->valueType()) {
921  ::ValueType vt(*var->valueType());
922  vt.pointer = 0;
923  val = getValueRangeFromValueType(data->getNewSymbolName(), &vt, *data->settings);
924  }
926 }
927 
928 ExprEngine::ArrayValue::ArrayValue(const std::string &name, const ExprEngine::ArrayValue &arrayValue)
930  , pointer(arrayValue.pointer), nullPointer(arrayValue.nullPointer), uninitPointer(arrayValue.uninitPointer)
931  , data(arrayValue.data), size(arrayValue.size)
932 {}
933 
934 
936 {
937  std::string r = getSymbolicExpression();
938  if (nullPointer)
939  r += std::string(r.empty() ? "" : ",") + "null";
940  if (uninitPointer)
941  r += std::string(r.empty() ? "" : ",") + "->?";
942  return r;
943 }
944 
946 {
947  if (!index)
948  data.clear();
949  if (value) {
950  if (index) {
951  // Remove old item that will be "overwritten"
952  for (size_t i = 0; i < data.size(); ++i) {
953  if (data[i].index && data[i].index->name == index->name) {
954  data.erase(data.begin() + i);
955  break;
956  }
957  }
958  }
959 
960  ExprEngine::ArrayValue::IndexAndValue indexAndValue = {index, value};
961  data.push_back(indexAndValue);
962  }
963 }
964 
966 {
967  data.clear();
968  ExprEngine::ArrayValue::IndexAndValue indexAndValue = {
969  ExprEngine::ValuePtr(), std::make_shared<ExprEngine::IntRange>("0", 0, 0)
970  };
971  data.push_back(indexAndValue);
972 }
973 
975 {
976  if (!v1 || !v2)
977  return !v1 && !v2;
978  return v1->name == v2->name;
979 }
980 
982 {
983  if (!v1 || !v2)
984  return false; // Don't know!
985  auto intRange1 = std::dynamic_pointer_cast<ExprEngine::IntRange>(v1);
986  auto intRange2 = std::dynamic_pointer_cast<ExprEngine::IntRange>(v2);
987  if (intRange1 && intRange2 && (intRange1->minValue > intRange2->maxValue || intRange1->maxValue < intRange2->maxValue))
988  return true;
989  return false;
990 }
991 
993 {
995  if (!index)
996  return ret;
997  for (const auto &indexAndValue : data) {
998  if (::isEqual(index, indexAndValue.index))
999  ret.clear();
1000  if (isNonOverlapping(index, indexAndValue.index))
1001  continue;
1002  // Array contains string literal data...
1003  if (!indexAndValue.index && indexAndValue.value->type == ExprEngine::ValueType::StringLiteralValue) {
1004  auto stringLiteral = std::dynamic_pointer_cast<ExprEngine::StringLiteralValue>(indexAndValue.value);
1005  if (!stringLiteral) {
1006  ret.push_back(std::pair<ValuePtr,ValuePtr>(indexAndValue.index, std::make_shared<ExprEngine::IntRange>("", -128, 128)));
1007  continue;
1008  }
1009  if (auto i = std::dynamic_pointer_cast<ExprEngine::IntRange>(index)) {
1010  if (i->minValue >= 0 && i->minValue == i->maxValue) {
1011  int c = 0;
1012  if (i->minValue < stringLiteral->size())
1013  c = stringLiteral->string[i->minValue];
1014  ret.push_back(std::pair<ValuePtr,ValuePtr>(indexAndValue.index, std::make_shared<ExprEngine::IntRange>(std::to_string(c), c, c)));
1015  continue;
1016  }
1017  }
1018  int cmin = 0, cmax = 0;
1019  for (char c : stringLiteral->string) {
1020  if (c < cmin)
1021  cmin = c;
1022  else if (c > cmax)
1023  cmax = c;
1024  }
1025  ret.push_back(std::pair<ValuePtr,ValuePtr>(indexAndValue.index, std::make_shared<ExprEngine::IntRange>("", cmin, cmax)));
1026  continue;
1027  }
1028 
1029  // Rename IntRange
1030  if (auto i = std::dynamic_pointer_cast<ExprEngine::IntRange>(indexAndValue.value)) {
1031  ret.push_back(std::pair<ValuePtr,ValuePtr>(indexAndValue.index, std::make_shared<ExprEngine::IntRange>(indexAndValue.value->name + ":" + index->name, i->minValue, i->maxValue)));
1032  continue;
1033  }
1034 
1035  ret.push_back(std::pair<ValuePtr,ValuePtr>(indexAndValue.index, indexAndValue.value));
1036  }
1037 
1038  if (ret.size() == 1)
1039  ret[0].first = ExprEngine::ValuePtr();
1040  else if (ret.size() == 2 && !ret[0].first) {
1041  ret[0].first = std::make_shared<ExprEngine::BinOpResult>("!=", index, ret[1].first);
1042  ret[1].first = std::make_shared<ExprEngine::BinOpResult>("==", index, ret[1].first);
1043  } else {
1044  // FIXME!!
1045  ret.clear();
1046  }
1047 
1048  return ret;
1049 }
1050 
1052 {
1053  std::ostringstream ostr;
1054  ostr << "{";
1055  bool first = true;
1056  for (const auto& condvalue : values) {
1057  ValuePtr cond = condvalue.first;
1058  ValuePtr value = condvalue.second;
1059 
1060  if (!first)
1061  ostr << ",";
1062  first = false;
1063  ostr << "{"
1064  << (cond ? cond->getSymbolicExpression() : std::string("(null)"))
1065  << ","
1066  << value->getSymbolicExpression()
1067  << "}";
1068  }
1069  ostr << "}";
1070  return ostr.str();
1071 }
1072 
1074 {
1075  std::ostringstream ostr;
1076  if (size.empty())
1077  ostr << "(null)";
1078  else {
1079  for (const auto &dim: size)
1080  ostr << "[" << (dim ? dim->name : std::string("(null)")) << "]";
1081  }
1082  for (const auto &indexAndValue : data) {
1083  ostr << ",["
1084  << (!indexAndValue.index ? std::string(":") : indexAndValue.index->name)
1085  << "]=";
1086  if (indexAndValue.value->type == ExprEngine::ValueType::StructValue)
1087  ostr << "("
1088  << indexAndValue.value->name
1089  << ","
1090  << indexAndValue.value->getSymbolicExpression()
1091  << ")";
1092  else
1093  ostr << indexAndValue.value->name;
1094  }
1095  return ostr.str();
1096 }
1097 
1099 {
1100  std::ostringstream ostr;
1101  ostr << "{";
1102  bool first = true;
1103  for (const auto& m: member) {
1104  const std::string &memberName = m.first;
1105  auto memberValue = m.second;
1106  if (!first)
1107  ostr << ",";
1108  first = false;
1109  ostr << memberName << "=" << (memberValue ? memberValue->getSymbolicExpression() : std::string("(null)"));
1110  }
1111  ostr << "}";
1112  return ostr.str();
1113 }
1114 
1116 {
1117  return sign + std::to_string(bits) + "(" + inputValue->getSymbolicExpression() + ")";
1118 }
1119 
1120 #ifdef USE_Z3
1121 
1122 class ExprData {
1123 public:
1124  using ValueExpr = std::map<std::string, z3::expr>;
1125  using AssertionList = std::vector<z3::expr>;
1126 
1127  class BailoutValueException : public ExprEngineException {
1128  public:
1129  BailoutValueException() : ExprEngineException(nullptr, "Incomplete analysis") {}
1130  };
1131 
1132  z3::context context;
1133  ValueExpr valueExpr;
1134  AssertionList assertionList;
1135 
1136  void addAssertions(z3::solver &solver) const {
1137  for (const auto &assertExpr : assertionList)
1138  solver.add(assertExpr);
1139  }
1140 
1141  void addConstraints(z3::solver &solver, const Data* data) {
1142  for (const auto &constraint : data->constraints) {
1143  try {
1144  solver.add(getConstraintExpr(constraint));
1145  } catch (const BailoutValueException &) {}
1146  }
1147  }
1148 
1149  z3::expr addInt(const std::string &name, int128_t minValue, int128_t maxValue) {
1150  z3::expr e = context.int_const(name.c_str());
1151  valueExpr.emplace(name, e);
1152  if (minValue >= INT_MIN && maxValue <= INT_MAX)
1153  assertionList.push_back(e >= int(minValue) && e <= int(maxValue));
1154  else if (maxValue <= INT_MAX)
1155  assertionList.push_back(e <= int(maxValue));
1156  else if (minValue >= INT_MIN)
1157  assertionList.push_back(e >= int(minValue));
1158  return e;
1159  }
1160 
1161  z3::expr addFloat(const std::string &name) {
1162  z3::expr e = z3_fp_const(name);
1163  valueExpr.emplace(name, e);
1164  return e;
1165  }
1166 
1167  z3::expr getExpr(const ExprEngine::BinOpResult *b) {
1168  auto op1 = getExpr(b->op1);
1169  auto op2 = getExpr(b->op2);
1170 
1171  // floating point promotion
1172  if (b->binop != "&&" && b->binop != "||" && b->binop != "<<" && b->binop != ">>") {
1173  if (z3_is_fp(op1) || z3_is_fp(op2)) {
1174  z3_to_fp(op1);
1175  z3_to_fp(op2);
1176  }
1177  }
1178 
1179  if (b->binop == "+")
1180  return op1 + op2;
1181  if (b->binop == "-")
1182  return op1 - op2;
1183  if (b->binop == "*")
1184  return op1 * op2;
1185  if (b->binop == "/")
1186  return op1 / op2;
1187  if (b->binop == "%")
1188 #if Z3_VERSION_INT >= GET_VERSION_INT(4,8,5)
1189  return op1 % op2;
1190 #else
1191  return op1 - (op1 / op2) * op2;
1192 #endif
1193  if (b->binop == "==")
1194  return int_expr(op1) == int_expr(op2);
1195  if (b->binop == "!=")
1196  return op1 != op2;
1197  if (b->binop == ">=")
1198  return op1 >= op2;
1199  if (b->binop == "<=")
1200  return op1 <= op2;
1201  if (b->binop == ">")
1202  return op1 > op2;
1203  if (b->binop == "<")
1204  return op1 < op2;
1205  if (b->binop == "&&")
1206  return bool_expr(op1) && bool_expr(op2);
1207  if (b->binop == "||")
1208  return bool_expr(op1) || bool_expr(op2);
1209  if (b->binop == "<<")
1210  return op1 * z3::pw(context.int_val(2), op2);
1211  if (b->binop == ">>")
1212  return op1 / z3::pw(context.int_val(2), op2);
1213  throw ExprEngineException(nullptr, "Internal error: Unhandled operator " + b->binop);
1214  }
1215 
1216  z3::expr getExpr(ExprEngine::ValuePtr v) {
1217  if (!v)
1218  throw ExprEngineException(nullptr, "Can not solve expressions, operand value is null");
1219  if (v->type == ExprEngine::ValueType::BailoutValue)
1220  throw BailoutValueException();
1221  if (auto intRange = std::dynamic_pointer_cast<ExprEngine::IntRange>(v)) {
1222  if (intRange->name[0] != '$')
1223  return z3_int_val(intRange->minValue);
1224  auto it = valueExpr.find(v->name);
1225  if (it != valueExpr.end())
1226  return it->second;
1227  return addInt(v->name, intRange->minValue, intRange->maxValue);
1228  }
1229 
1230  if (auto floatRange = std::dynamic_pointer_cast<ExprEngine::FloatRange>(v)) {
1231  if (floatRange->name[0] != '$')
1232  return z3_fp_val(floatRange->minValue, floatRange->name);
1233 
1234  auto it = valueExpr.find(v->name);
1235  if (it != valueExpr.end())
1236  return it->second;
1237  return addFloat(v->name);
1238  }
1239 
1240  if (auto b = std::dynamic_pointer_cast<ExprEngine::BinOpResult>(v)) {
1241  return getExpr(b.get());
1242  }
1243 
1244  if (auto c = std::dynamic_pointer_cast<ExprEngine::ConditionalValue>(v)) {
1245  if (c->values.empty())
1246  throw ExprEngineException(nullptr, "ConditionalValue is empty");
1247 
1248  if (c->values.size() == 1)
1249  return getExpr(c->values[0].second);
1250 
1251  return z3::ite(getExpr(c->values[1].first),
1252  getExpr(c->values[1].second),
1253  getExpr(c->values[0].second));
1254  }
1255 
1256  if (auto integerTruncation = std::dynamic_pointer_cast<ExprEngine::IntegerTruncation>(v)) {
1257  return getExpr(integerTruncation->inputValue);
1258  //return getExpr(integerTruncation->inputValue) & ((1 << integerTruncation->bits) - 1);
1259  }
1260 
1261  if (v->type == ExprEngine::ValueType::UninitValue)
1262  return context.int_val(0);
1263 
1264  throw ExprEngineException(nullptr, "Internal error: Unhandled value type");
1265  }
1266 
1267  z3::expr getConstraintExpr(ExprEngine::ValuePtr v) {
1268  if (v->type == ExprEngine::ValueType::IntRange)
1269  return (getExpr(v) != 0);
1270  return bool_expr(getExpr(v));
1271  }
1272 
1273  z3::expr bool_expr(z3::expr e) {
1274  if (e.is_bool())
1275  return e;
1276 
1277  // Workaround for z3 bug: https://github.com/Z3Prover/z3/issues/4905
1278  if (z3_is_fp(e))
1279  return e != z3_fp_val(0.0, "0.0");
1280 
1281  return e != 0;
1282  }
1283 
1284  z3::expr int_expr(z3::expr e) {
1285  if (e.is_bool())
1286  return z3::ite(e, context.int_val(1), context.int_val(0));
1287  return e;
1288  }
1289 
1290  // Wrapper functions for Z3 interface. Instead of having ifdefs embedded
1291  // in the code we have wrapper functions with ifdefs. The code that use
1292  // these will be cleaner and hopefully more robust.
1293 
1294  z3::expr z3_fp_const(const std::string &name) {
1295  return context.real_const(name.c_str());
1296  }
1297 
1298  z3::expr z3_fp_val(long double value, std::string name) {
1299  (void)value;
1300  while (name.size() > 1 && (name.back() == 'f' || name.back() == 'F' || name.back() == 'l' || name.back() == 'L'))
1301  name.erase(name.size() - 1);
1302  return context.real_val(name.c_str());
1303  }
1304 
1305  bool z3_is_fp(z3::expr e) const {
1306  return e.is_real();
1307  }
1308 
1309  void z3_to_fp(z3::expr &e) {
1310  if (e.is_int())
1311  e = z3::to_real(e);
1312  }
1313 
1314 
1315  z3::expr z3_int_val(int128_t value) {
1316 #if Z3_VERSION_INT >= GET_VERSION_INT(4,7,1)
1317  return context.int_val(int64_t(value));
1318 #else
1319  return context.int_val((long long)(value));
1320 #endif
1321  }
1322 };
1323 #endif
1324 
1325 bool ExprEngine::UninitValue::isUninit(const DataBase *dataBase) const {
1326  const Data *data = dynamic_cast<const Data *>(dataBase);
1327  if (data->constraints.empty())
1328  return true;
1329 #ifdef USE_Z3
1330  // Check the value against the constraints
1331  ExprData exprData;
1332  z3::solver solver(exprData.context);
1333  try {
1334  exprData.addConstraints(solver, data);
1335  exprData.addAssertions(solver);
1336  return solver.check() == z3::sat;
1337  } catch (const z3::exception &exception) {
1338  std::cerr << "z3: " << exception << std::endl;
1339  return true; // Safe option is to return true
1340  } catch (const ExprData::BailoutValueException &) {
1341  return true; // Safe option is to return true
1342  } catch (const ExprEngineException &) {
1343  return true; // Safe option is to return true
1344  }
1345 #else
1346  // The value may or may not be uninitialized
1347  return false;
1348 #endif
1349 }
1350 
1351 bool ExprEngine::IntRange::isEqual(const DataBase *dataBase, int value) const
1352 {
1353  if (value < minValue || value > maxValue)
1354  return false;
1355 
1356  const Data *data = dynamic_cast<const Data *>(dataBase);
1357  if (data->constraints.empty())
1358  return true;
1359 #ifdef USE_Z3
1360  // Check the value against the constraints
1361  ExprData exprData;
1362  z3::solver solver(exprData.context);
1363  try {
1364  z3::expr e = exprData.addInt(name, minValue, maxValue);
1365  exprData.addConstraints(solver, data);
1366  exprData.addAssertions(solver);
1367  solver.add(e == value);
1368  return solver.check() == z3::sat;
1369  } catch (const z3::exception &exception) {
1370  std::cerr << "z3: " << exception << std::endl;
1371  return true; // Safe option is to return true
1372  } catch (const ExprData::BailoutValueException &) {
1373  return true; // Safe option is to return true
1374  } catch (const ExprEngineException &) {
1375  return true; // Safe option is to return true
1376  }
1377 #else
1378  // The value may or may not be in range
1379  return false;
1380 #endif
1381 }
1382 
1383 bool ExprEngine::IntRange::isGreaterThan(const DataBase *dataBase, int value) const
1384 {
1385  if (maxValue <= value)
1386  return false;
1387 
1388  const Data *data = dynamic_cast<const Data *>(dataBase);
1389  if (data->constraints.empty())
1390  return true;
1391 #ifdef USE_Z3
1392  // Check the value against the constraints
1393  ExprData exprData;
1394  z3::solver solver(exprData.context);
1395  try {
1396  z3::expr e = exprData.addInt(name, minValue, maxValue);
1397  exprData.addConstraints(solver, data);
1398  exprData.addAssertions(solver);
1399  solver.add(e > value);
1400  return solver.check() == z3::sat;
1401  } catch (const z3::exception &exception) {
1402  std::cerr << "z3: " << exception << std::endl;
1403  return true; // Safe option is to return true
1404  } catch (const ExprData::BailoutValueException &) {
1405  return true; // Safe option is to return true
1406  } catch (const ExprEngineException &) {
1407  return true; // Safe option is to return true
1408  }
1409 #else
1410  // The value may or may not be in range
1411  return false;
1412 #endif
1413 }
1414 
1415 bool ExprEngine::IntRange::isLessThan(const DataBase *dataBase, int value) const
1416 {
1417  if (minValue >= value)
1418  return false;
1419 
1420  const Data *data = dynamic_cast<const Data *>(dataBase);
1421  if (data->constraints.empty())
1422  return true;
1423 #ifdef USE_Z3
1424  // Check the value against the constraints
1425  ExprData exprData;
1426  z3::solver solver(exprData.context);
1427  try {
1428  z3::expr e = exprData.addInt(name, minValue, maxValue);
1429  exprData.addConstraints(solver, data);
1430  exprData.addAssertions(solver);
1431  solver.add(e < value);
1432  return solver.check() == z3::sat;
1433  } catch (const z3::exception &exception) {
1434  std::cerr << "z3: " << exception << std::endl;
1435  return true; // Safe option is to return true
1436  } catch (const ExprData::BailoutValueException &) {
1437  return true; // Safe option is to return true
1438  } catch (const ExprEngineException &) {
1439  return true; // Safe option is to return true
1440  }
1441 #else
1442  // The value may or may not be in range
1443  return false;
1444 #endif
1445 }
1446 
1447 bool ExprEngine::FloatRange::isEqual(const DataBase *dataBase, int value) const
1448 {
1449  if (MathLib::isFloat(name)) {
1450  float f = MathLib::toDoubleNumber(name);
1451  return value >= f - 0.00001 && value <= f + 0.00001;
1452  }
1453  const Data *data = dynamic_cast<const Data *>(dataBase);
1454  if (data->constraints.empty())
1455  return true;
1456 #ifdef USE_Z3
1457  // Check the value against the constraints
1458  ExprData exprData;
1459  z3::solver solver(exprData.context);
1460  try {
1461  z3::expr e = exprData.addFloat(name);
1462  exprData.addConstraints(solver, data);
1463  exprData.addAssertions(solver);
1464  // Workaround for z3 bug: https://github.com/Z3Prover/z3/issues/4905
1465 #if Z3_VERSION_INT >= GET_VERSION_INT(4,8,0)
1466  z3::expr val_e = exprData.context.fpa_val(static_cast<double>(value));
1467 #else
1468  z3::expr val_e = exprData.context.real_val(value);
1469 #endif // Z3_VERSION_INT
1470  solver.add(e == val_e);
1471  return solver.check() != z3::unsat;
1472  } catch (const z3::exception &exception) {
1473  std::cerr << "z3: " << exception << std::endl;
1474  return true; // Safe option is to return true
1475  } catch (const ExprData::BailoutValueException &) {
1476  return true; // Safe option is to return true
1477  } catch (const ExprEngineException &) {
1478  return true; // Safe option is to return true
1479  }
1480 #else
1481  // The value may or may not be in range
1482  return false;
1483 #endif
1484 }
1485 
1486 bool ExprEngine::FloatRange::isGreaterThan(const DataBase *dataBase, int value) const
1487 {
1488  if (value < minValue || value > maxValue)
1489  return false;
1490 
1491  const Data *data = dynamic_cast<const Data *>(dataBase);
1492  if (data->constraints.empty())
1493  return true;
1494  if (MathLib::isFloat(name))
1495  return value > MathLib::toDoubleNumber(name);
1496 #ifdef USE_Z3
1497  // Check the value against the constraints
1498  ExprData exprData;
1499  z3::solver solver(exprData.context);
1500  try {
1501  z3::expr e = exprData.addFloat(name);
1502  exprData.addConstraints(solver, data);
1503  exprData.addAssertions(solver);
1504  solver.add(e > value);
1505  return solver.check() == z3::sat;
1506  } catch (const z3::exception &exception) {
1507  std::cerr << "z3: " << exception << std::endl;
1508  return true; // Safe option is to return true
1509  } catch (const ExprData::BailoutValueException &) {
1510  return true; // Safe option is to return true
1511  } catch (const ExprEngineException &) {
1512  return true; // Safe option is to return true
1513  }
1514 #else
1515  // The value may or may not be in range
1516  return false;
1517 #endif
1518 }
1519 
1520 bool ExprEngine::FloatRange::isLessThan(const DataBase *dataBase, int value) const
1521 {
1522  if (value < minValue || value > maxValue)
1523  return false;
1524 
1525  const Data *data = dynamic_cast<const Data *>(dataBase);
1526  if (data->constraints.empty())
1527  return true;
1528  if (MathLib::isFloat(name))
1529  return value < MathLib::toDoubleNumber(name);
1530 #ifdef USE_Z3
1531  // Check the value against the constraints
1532  ExprData exprData;
1533  z3::solver solver(exprData.context);
1534  try {
1535  z3::expr e = exprData.addFloat(name);
1536  exprData.addConstraints(solver, data);
1537  exprData.addAssertions(solver);
1538  solver.add(e < value);
1539  return solver.check() == z3::sat;
1540  } catch (const z3::exception &exception) {
1541  std::cerr << "z3: " << exception << std::endl;
1542  return true; // Safe option is to return true
1543  } catch (const ExprData::BailoutValueException &) {
1544  return true; // Safe option is to return true
1545  } catch (const ExprEngineException &) {
1546  return true; // Safe option is to return true
1547  }
1548 #else
1549  // The value may or may not be in range
1550  return false;
1551 #endif
1552 }
1553 
1554 
1555 bool ExprEngine::BinOpResult::isEqual(const ExprEngine::DataBase *dataBase, int value) const
1556 {
1557 #ifdef USE_Z3
1558  try {
1559  ExprData exprData;
1560  z3::solver solver(exprData.context);
1561  z3::expr e = exprData.getExpr(this);
1562  exprData.addConstraints(solver, dynamic_cast<const Data *>(dataBase));
1563  exprData.addAssertions(solver);
1564  solver.add(exprData.int_expr(e) == value);
1565  return solver.check() == z3::sat;
1566  } catch (const z3::exception &exception) {
1567  std::cerr << "z3:" << exception << std::endl;
1568  return true; // Safe option is to return true
1569  } catch (const ExprData::BailoutValueException &) {
1570  return true; // Safe option is to return true
1571  } catch (const ExprEngineException &) {
1572  return true; // Safe option is to return true
1573  }
1574 #else
1575  (void)dataBase;
1576  (void)value;
1577  return false;
1578 #endif
1579 }
1580 
1581 bool ExprEngine::BinOpResult::isGreaterThan(const ExprEngine::DataBase *dataBase, int value) const
1582 {
1583 #ifdef USE_Z3
1584  try {
1585  ExprData exprData;
1586  z3::solver solver(exprData.context);
1587  z3::expr e = exprData.getExpr(this);
1588  exprData.addConstraints(solver, dynamic_cast<const Data *>(dataBase));
1589  exprData.addAssertions(solver);
1590  solver.add(e > value);
1591  return solver.check() == z3::sat;
1592  } catch (const z3::exception &exception) {
1593  std::cerr << "z3:" << exception << std::endl;
1594  return true; // Safe option is to return true
1595  } catch (const ExprData::BailoutValueException &) {
1596  return true; // Safe option is to return true
1597  } catch (const ExprEngineException &) {
1598  return true; // Safe option is to return true
1599  }
1600 #else
1601  (void)dataBase;
1602  (void)value;
1603  return false;
1604 #endif
1605 }
1606 
1607 bool ExprEngine::BinOpResult::isLessThan(const ExprEngine::DataBase *dataBase, int value) const
1608 {
1609 #ifdef USE_Z3
1610  try {
1611  ExprData exprData;
1612  z3::solver solver(exprData.context);
1613  z3::expr e = exprData.getExpr(this);
1614  exprData.addConstraints(solver, dynamic_cast<const Data *>(dataBase));
1615  exprData.addAssertions(solver);
1616  solver.add(e < value);
1617  return solver.check() == z3::sat;
1618  } catch (const z3::exception &exception) {
1619  std::cerr << "z3:" << exception << std::endl;
1620  return true; // Safe option is to return true
1621  } catch (const ExprData::BailoutValueException &) {
1622  return true; // Safe option is to return true
1623  } catch (const ExprEngineException &) {
1624  return true; // Safe option is to return true
1625  }
1626 #else
1627  (void)dataBase;
1628  (void)value;
1629  return false;
1630 #endif
1631 }
1632 
1634 {
1635 #ifdef USE_Z3
1636  try {
1637  ExprData exprData;
1638  z3::solver solver(exprData.context);
1639  z3::expr e = exprData.getExpr(this);
1640  exprData.addConstraints(solver, dynamic_cast<const Data *>(dataBase));
1641  exprData.addAssertions(solver);
1642  solver.add(exprData.int_expr(e) != 0);
1643  return solver.check() == z3::sat;
1644  } catch (const z3::exception &exception) {
1645  std::cerr << "z3:" << exception << std::endl;
1646  return true; // Safe option is to return true
1647  } catch (const ExprData::BailoutValueException &) {
1648  return true; // Safe option is to return true
1649  } catch (const ExprEngineException &) {
1650  return true; // Safe option is to return true
1651  }
1652 #else
1653  (void)dataBase;
1654  return false;
1655 #endif
1656 }
1657 
1659 {
1660 #ifdef USE_Z3
1661  try {
1662  ExprData exprData;
1663  z3::solver solver(exprData.context);
1664  z3::expr e = exprData.getExpr(this);
1665  exprData.addConstraints(solver, dynamic_cast<const Data *>(dataBase));
1666  exprData.addAssertions(solver);
1667  solver.add(e);
1668  std::ostringstream os;
1669  os << solver;
1670  switch (solver.check()) {
1671  case z3::sat:
1672  os << "\nz3::sat\n";
1673  break;
1674  case z3::unsat:
1675  os << "\nz3::unsat\n";
1676  break;
1677  case z3::unknown:
1678  os << "\nz3::unknown\n";
1679  break;
1680  }
1681  return os.str();
1682  } catch (const z3::exception &exception) {
1683  std::ostringstream os;
1684  os << "\nz3:" << exception << "\n";
1685  return os.str();
1686  }
1687 #else
1688  (void)dataBase;
1689  return "";
1690 #endif
1691 }
1692 
1693 
1694 // Todo: This is taken from ValueFlow and modified.. we should reuse it
1695 static int getIntBitsFromValueType(const ValueType *vt, const cppcheck::Platform &platform)
1696 {
1697  if (!vt)
1698  return 0;
1699 
1700  switch (vt->type) {
1701  case ValueType::Type::BOOL:
1702  return 1;
1703  case ValueType::Type::CHAR:
1704  return platform.char_bit;
1705  case ValueType::Type::SHORT:
1706  return platform.short_bit;
1707  case ValueType::Type::INT:
1708  return platform.int_bit;
1709  case ValueType::Type::LONG:
1710  return platform.long_bit;
1711  case ValueType::Type::LONGLONG:
1712  return platform.long_long_bit;
1713  default:
1714  return 0;
1715  }
1716 }
1717 
1718 static ExprEngine::ValuePtr getValueRangeFromValueType(const std::string &name, const ValueType *vt, const cppcheck::Platform &platform)
1719 {
1720  if (!vt || !(vt->isIntegral() || vt->isFloat()) || vt->pointer)
1721  return ExprEngine::ValuePtr();
1722 
1723  int bits = getIntBitsFromValueType(vt, platform);
1724  if (bits == 1) {
1725  return std::make_shared<ExprEngine::IntRange>(name, 0, 1);
1726  } else if (bits > 1) {
1727  if (vt->sign == ValueType::Sign::UNSIGNED) {
1728  return std::make_shared<ExprEngine::IntRange>(name, 0, ((int128_t)1 << bits) - 1);
1729  } else {
1730  return std::make_shared<ExprEngine::IntRange>(name, -((int128_t)1 << (bits - 1)), ((int128_t)1 << (bits - 1)) - 1);
1731  }
1732  }
1733 
1734  if (vt->isFloat())
1735  return std::make_shared<ExprEngine::FloatRange>(name, -std::numeric_limits<float>::infinity(), std::numeric_limits<float>::infinity());
1736 
1737  return ExprEngine::ValuePtr();
1738 }
1739 
1740 static ExprEngine::ValuePtr getValueRangeFromValueType(const ValueType *valueType, Data &data)
1741 {
1742  if (valueType && valueType->pointer) {
1743  ExprEngine::ValuePtr val = std::make_shared<ExprEngine::BailoutValue>();
1744  auto bufferSize = std::make_shared<ExprEngine::IntRange>(data.getNewSymbolName(), 1, ExprEngine::ArrayValue::MAXSIZE);
1745  return std::make_shared<ExprEngine::ArrayValue>(data.getNewSymbolName(), bufferSize, val, true, true, false);
1746  }
1747 
1748  if (!valueType || valueType->pointer)
1749  return ExprEngine::ValuePtr();
1750  if (valueType->container) {
1751  ExprEngine::ValuePtr value;
1752  if (valueType->container->stdStringLike)
1753  value = std::make_shared<ExprEngine::IntRange>(data.getNewSymbolName(), -128, 127);
1754  else if (valueType->containerTypeToken) {
1755  ValueType vt = ValueType::parseDecl(valueType->containerTypeToken, data.settings);
1756  value = getValueRangeFromValueType(&vt, data);
1757  } else
1758  return ExprEngine::ValuePtr();
1759  auto bufferSize = std::make_shared<ExprEngine::IntRange>(data.getNewSymbolName(), 0, ExprEngine::ArrayValue::MAXSIZE);
1760  return std::make_shared<ExprEngine::ArrayValue>(data.getNewSymbolName(), bufferSize, value, false, false, false);
1761  }
1762  return getValueRangeFromValueType(data.getNewSymbolName(), valueType, *data.settings);
1763 }
1764 
1765 static void call(const std::vector<ExprEngine::Callback> &callbacks, const Token *tok, ExprEngine::ValuePtr value, Data *dataBase)
1766 {
1767  if (value) {
1768  for (const ExprEngine::Callback& f : callbacks) {
1769  try {
1770  f(tok, *value, dataBase);
1771  } catch (const ExprEngineException &e) {
1772  throw ExprEngineException(tok, e.what);
1773  }
1774  }
1775  }
1776 }
1777 
1778 static ExprEngine::ValuePtr executeExpression(const Token *tok, Data &data);
1779 static ExprEngine::ValuePtr executeExpression1(const Token *tok, Data &data);
1780 static std::string execute(const Token *start, const Token *end, Data &data);
1781 
1782 static ExprEngine::ValuePtr calculateArrayIndex(const Token *tok, Data &data, const ExprEngine::ArrayValue &arrayValue)
1783 {
1784  int nr = 1;
1785  const Token *tok2 = tok;
1786  while (Token::simpleMatch(tok2->astOperand1(), "[")) {
1787  tok2 = tok2->astOperand1();
1788  nr++;
1789  }
1790 
1791  ExprEngine::ValuePtr totalIndex;
1793  while (Token::simpleMatch(tok, "[")) {
1794  auto rawIndex = executeExpression(tok->astOperand2(), data);
1795 
1796  ExprEngine::ValuePtr index;
1797  if (dim)
1798  index = simplifyValue(std::make_shared<ExprEngine::BinOpResult>("*", dim, rawIndex));
1799  else
1800  index = rawIndex;
1801 
1802  if (!totalIndex)
1803  totalIndex = index;
1804  else
1805  totalIndex = simplifyValue(std::make_shared<ExprEngine::BinOpResult>("+", index, totalIndex));
1806 
1807  if (arrayValue.size.size() >= nr) {
1808  if (arrayValue.size[nr-1]) {
1809  if (!dim)
1810  dim = arrayValue.size[nr-1];
1811  else
1812  dim = simplifyValue(std::make_shared<ExprEngine::BinOpResult>("*", dim, arrayValue.size[nr-1]));
1813  }
1814  }
1815 
1816  nr--;
1817  tok = tok->astOperand1();
1818  }
1819 
1820  return totalIndex;
1821 }
1822 
1823 static ExprEngine::ValuePtr executeReturn(const Token *tok, Data &data)
1824 {
1825  ExprEngine::ValuePtr retval = executeExpression(tok->astOperand1(), data);
1826  call(data.callbacks, tok, retval, &data);
1827  return retval;
1828 }
1829 
1830 static ExprEngine::ValuePtr truncateValue(ExprEngine::ValuePtr val, const ValueType *valueType, Data &data)
1831 {
1832  if (!valueType)
1833  return val;
1834  if (valueType->pointer != 0)
1835  return val;
1836  if (!valueType->isIntegral())
1837  return val; // TODO
1838 
1839  int bits = getIntBitsFromValueType(valueType, *data.settings);
1840  if (bits == 0)
1841  // TODO
1842  return val;
1843 
1844  if (auto range = std::dynamic_pointer_cast<ExprEngine::IntRange>(val)) {
1845  if (range->minValue == range->maxValue) {
1846  int128_t newValue = truncateInt(range->minValue, bits, valueType->sign == ValueType::Sign::SIGNED ? 's' : 'u');
1847  if (newValue == range->minValue)
1848  return val;
1849  return std::make_shared<ExprEngine::IntRange>(ExprEngine::str(newValue), newValue, newValue);
1850  }
1851  if (auto typeRange = getValueRangeFromValueType("", valueType, *data.settings)) {
1852  auto typeIntRange = std::dynamic_pointer_cast<ExprEngine::IntRange>(typeRange);
1853  if (typeIntRange) {
1854  if (range->minValue >= typeIntRange->minValue && range->maxValue <= typeIntRange->maxValue)
1855  return val;
1856  }
1857  }
1858 
1859  return std::make_shared<ExprEngine::IntegerTruncation>(data.getNewSymbolName(), val, bits, valueType->sign == ValueType::Sign::SIGNED ? 's' : 'u');
1860  }
1861  // TODO
1862  return val;
1863 }
1864 
1865 static void assignExprValue(const Token *expr, ExprEngine::ValuePtr value, Data &data)
1866 {
1867  if (!expr)
1868  return;
1869  if (expr->varId() > 0) {
1870  data.assignValue(expr, expr->varId(), value);
1871  } else if (expr->str() == "[") {
1872  // Find array token
1873  const Token *arrayToken = expr;
1874  while (Token::simpleMatch(arrayToken, "["))
1875  arrayToken = arrayToken->astOperand1();
1876  if (!arrayToken)
1877  return;
1878  if (auto arrayValue = data.getArrayValue(arrayToken)) {
1879  // Is it array initialization?
1880  if (arrayToken->variable() && arrayToken->variable()->nameToken() == arrayToken) {
1881  if (value->type == ExprEngine::ValueType::StringLiteralValue)
1882  arrayValue->assign(ExprEngine::ValuePtr(), value);
1883  } else {
1884  auto indexValue = calculateArrayIndex(expr, data, *arrayValue);
1885  bool loopAssign = false;
1886  if (auto loopValue = std::dynamic_pointer_cast<ExprEngine::IntRange>(indexValue)) {
1887  if (loopValue->loopScope == expr->scope()) {
1888  loopAssign = true;
1889  for (auto i = loopValue->minValue; i <= loopValue->maxValue; ++i)
1890  arrayValue->assign(std::make_shared<ExprEngine::IntRange>(ExprEngine::str(i), i, i), value);
1891  }
1892  }
1893  if (!loopAssign)
1894  arrayValue->assign(indexValue, value);
1895  }
1896  } else {
1897  const Token * const indexToken = expr->astOperand2();
1898  auto indexValue = executeExpression(indexToken, data);
1899  call(data.callbacks, indexToken, indexValue, &data);
1900  }
1901  } else if (expr->isUnaryOp("*")) {
1902  auto pval = executeExpression(expr->astOperand1(), data);
1903  if (pval && pval->type == ExprEngine::ValueType::AddressOfValue) {
1904  auto val = std::dynamic_pointer_cast<ExprEngine::AddressOfValue>(pval);
1905  if (val)
1906  data.assignValue(expr, val->varId, value);
1907  } else if (pval && pval->type == ExprEngine::ValueType::ArrayValue) {
1908  auto arrayValue = std::dynamic_pointer_cast<ExprEngine::ArrayValue>(pval);
1909  auto indexValue = std::make_shared<ExprEngine::IntRange>("0", 0, 0);
1910  arrayValue->assign(indexValue, value);
1911  } else if (pval && pval->type == ExprEngine::ValueType::BinOpResult) {
1912  auto b = std::dynamic_pointer_cast<ExprEngine::BinOpResult>(pval);
1913  if (b && b->binop == "+") {
1914  std::shared_ptr<ExprEngine::ArrayValue> arr;
1915  ExprEngine::ValuePtr offset;
1916  if (b->op1->type == ExprEngine::ValueType::ArrayValue) {
1917  arr = std::dynamic_pointer_cast<ExprEngine::ArrayValue>(b->op1);
1918  offset = b->op2;
1919  } else {
1920  arr = std::dynamic_pointer_cast<ExprEngine::ArrayValue>(b->op2);
1921  offset = b->op1;
1922  }
1923  if (arr && offset) {
1924  arr->assign(offset, value);
1925  }
1926  }
1927  }
1928  } else if (Token::Match(expr, ". %name%")) {
1929  auto structVal = executeExpression(expr->astOperand1(), data);
1930  if (structVal && structVal->type == ExprEngine::ValueType::StructValue)
1931  data.assignStructMember(expr, &*std::static_pointer_cast<ExprEngine::StructValue>(structVal), expr->next()->str(), value);
1932  }
1933 }
1934 
1935 
1936 static ExprEngine::ValuePtr executeAssign(const Token *tok, Data &data)
1937 {
1938  ExprEngine::ValuePtr rhsValue = executeExpression(tok->astOperand2(), data);
1939 
1940  if (!rhsValue) {
1941  const ValueType * const vt1 = tok->astOperand1() ? tok->astOperand1()->valueType() : nullptr;
1942  const ValueType * const vt2 = tok->astOperand2() ? tok->astOperand2()->valueType() : nullptr;
1943 
1944  rhsValue = getValueRangeFromValueType(vt1, data);
1945  if (!rhsValue && vt2 && vt2->pointer == 0) {
1946  rhsValue = getValueRangeFromValueType(vt2, data);
1947  if (rhsValue)
1948  call(data.callbacks, tok->astOperand2(), rhsValue, &data);
1949  }
1950  if (!rhsValue)
1951  rhsValue = std::make_shared<ExprEngine::BailoutValue>();
1952  }
1953 
1954  ExprEngine::ValuePtr assignValue;
1955  if (tok->str() == "=")
1956  assignValue = rhsValue;
1957  else {
1958  // "+=" => "+"
1959  std::string binop(tok->str());
1960  binop = binop.substr(0, binop.size() - 1);
1961  ExprEngine::ValuePtr lhsValue = executeExpression(tok->astOperand1(), data);
1962  assignValue = simplifyValue(std::make_shared<ExprEngine::BinOpResult>(binop, lhsValue, rhsValue));
1963  }
1964 
1965  const Token *lhsToken = tok->astOperand1();
1966  if (lhsToken)
1967  assignValue = truncateValue(assignValue, lhsToken->valueType(), data);
1968  call(data.callbacks, tok, assignValue, &data);
1969 
1970  assignExprValue(lhsToken, assignValue, data);
1971 
1972  return assignValue;
1973 }
1974 
1975 static ExprEngine::ValuePtr executeIncDec(const Token *tok, Data &data)
1976 {
1977  ExprEngine::ValuePtr beforeValue = executeExpression(tok->astOperand1(), data);
1978  ExprEngine::ValuePtr assignValue = simplifyValue(std::make_shared<ExprEngine::BinOpResult>(tok->str().substr(0,1), beforeValue, std::make_shared<ExprEngine::IntRange>("1", 1, 1)));
1979  assignExprValue(tok->astOperand1(), assignValue, data);
1980  auto retVal = (precedes(tok, tok->astOperand1())) ? assignValue : beforeValue;
1981  auto binOp = std::dynamic_pointer_cast<ExprEngine::BinOpResult>(retVal);
1982  if (binOp && !binOp->op1)
1983  retVal.reset();
1984  call(data.callbacks, tok, retVal, &data);
1985  return retVal;
1986 }
1987 
1988 #ifdef USE_Z3
1989 static void checkContract(Data &data, const Token *tok, const Function *function, const std::vector<ExprEngine::ValuePtr> &argValues)
1990 {
1991 #ifdef CONTRACT
1992  ExprData exprData;
1993  z3::solver solver(exprData.context);
1994  try {
1995  // Invert contract, we want to know if the contract might not be met
1996  try {
1997  solver.add(z3::ite(exprData.getConstraintExpr(data.executeContract(function, executeExpression1)), exprData.context.bool_val(false), exprData.context.bool_val(true)));
1998  } catch (const ExprData::BailoutValueException &) {
1999  throw ExprEngineException(tok, "Internal error: Bailout value used");
2000  }
2001 
2002  bool bailoutValue = false;
2003  for (nonneg int i = 0; i < argValues.size(); ++i) {
2004  const Variable *argvar = function->getArgumentVar(i);
2005  if (!argvar || !argvar->nameToken())
2006  continue;
2007 
2008  ExprEngine::ValuePtr argValue = argValues[i];
2009  if (!argValue || argValue->type == ExprEngine::ValueType::BailoutValue) {
2010  bailoutValue = true;
2011  break;
2012  }
2013 
2014  if (argValue && argValue->type == ExprEngine::ValueType::IntRange) {
2015  solver.add(exprData.getExpr(data.getValue(argvar->declarationId(), nullptr, nullptr)) == exprData.getExpr(argValue));
2016  }
2017  }
2018 
2019  if (!bailoutValue) {
2020  for (const auto &constraint : data.constraints)
2021  solver.add(exprData.getConstraintExpr(constraint));
2022 
2023  exprData.addAssertions(solver);
2024 
2025  // Log solver expressions for debugging/testing purposes
2026  std::ostringstream os;
2027  os << solver;
2028  data.trackCheckContract(tok, os.str());
2029  }
2030 
2031  if (bailoutValue || solver.check() == z3::sat) {
2032  const char id[] = "bughuntingFunctionCall";
2033  const auto contractIt = data.settings->functionContracts.find(function->fullName());
2034  const std::string functionName = contractIt->first;
2035  const std::string functionExpects = contractIt->second;
2036  data.reportError(tok,
2037  Severity::SeverityType::error,
2038  id,
2039  "Function '" + function->name() + "' is called, can not determine that its contract '" + functionExpects + "' is always met.",
2040  CWE(0),
2041  false,
2042  bailoutValue,
2043  functionName);
2044  }
2045  } catch (const z3::exception &exception) {
2046  std::cerr << "z3: " << exception << std::endl;
2047  } catch (const ExprEngineException &) {
2048  const char id[] = "internalErrorInExprEngine";
2049  const auto contractIt = data.settings->functionContracts.find(function->fullName());
2050  const std::string functionName = contractIt->first;
2051  const std::string functionExpects = contractIt->second;
2052  data.reportError(tok,
2053  Severity::SeverityType::error,
2054  id,
2055  "Function '" + function->name() + "' is called, can not determine that its contract '" + functionExpects + "' is always met.",
2056  CWE(0),
2057  false,
2058  true,
2059  functionName);
2060  }
2061 #endif
2062 }
2063 #endif
2064 
2065 static ExprEngine::ValuePtr executeFunctionCall(const Token *tok, Data &data)
2066 {
2067  if (Token::simpleMatch(tok->previous(), "sizeof (")) {
2068  ExprEngine::ValuePtr retVal;
2069  if (tok->hasKnownIntValue()) {
2070  const MathLib::bigint value = tok->getKnownIntValue();
2071  retVal = std::make_shared<ExprEngine::IntRange>(std::to_string(value), value, value);
2072  } else {
2073  retVal = std::make_shared<ExprEngine::IntRange>(data.getNewSymbolName(), 1, 0x7fffffff);
2074  }
2075  call(data.callbacks, tok, retVal, &data);
2076  return retVal;
2077  }
2078 
2079  bool hasBody = tok->astOperand1()->function() && tok->astOperand1()->function()->hasBody();
2080  if (hasBody) {
2081  const Scope *functionScope = tok->scope();
2082  while (functionScope->isExecutable() && functionScope->type != Scope::ScopeType::eFunction)
2083  functionScope = functionScope->nestedIn;
2084  if (functionScope == tok->astOperand1()->function()->functionScope)
2085  hasBody = false;
2086  for (const auto &errorPathItem: data.errorPath) {
2087  if (errorPathItem.first == tok) {
2088  hasBody = false;
2089  break;
2090  }
2091  }
2092  }
2093 
2094  const std::vector<const Token *> &argTokens = getArguments(tok);
2095  std::vector<ExprEngine::ValuePtr> argValues;
2096  for (const Token *argtok : argTokens) {
2097  auto val = hasBody ? executeExpression1(argtok, data) : executeExpression(argtok, data);
2098  argValues.push_back(val);
2099  if (hasBody)
2100  continue;
2101  if (!argtok->valueType() || (argtok->valueType()->constness & 1) == 1)
2102  continue;
2103  if (auto arrayValue = std::dynamic_pointer_cast<ExprEngine::ArrayValue>(val)) {
2104  ValueType vt(*argtok->valueType());
2105  vt.pointer = 0;
2106  auto anyVal = getValueRangeFromValueType(&vt, data);
2107  arrayValue->assign(ExprEngine::ValuePtr(), anyVal);
2108  } else if (auto addressOf = std::dynamic_pointer_cast<ExprEngine::AddressOfValue>(val)) {
2109  ValueType vt(*argtok->valueType());
2110  vt.pointer = 0;
2111  if (vt.isIntegral() && argtok->valueType()->pointer == 1)
2112  data.assignValue(argtok, addressOf->varId, getValueRangeFromValueType(&vt, data));
2113  }
2114  }
2115 
2116  call(data.callbacks, tok, std::make_shared<ExprEngine::FunctionCallArgumentValues>(argValues), &data);
2117 
2118  if (tok->astOperand1()->function()) {
2119  const Function *function = tok->astOperand1()->function();
2120  const std::string &functionName = function->fullName();
2121 #ifdef CONTRACT
2122  const auto contractIt = data.settings->functionContracts.find(functionName);
2123  if (contractIt != data.settings->functionContracts.end()) {
2124 #ifdef USE_Z3
2125  checkContract(data, tok, function, argValues);
2126 #endif
2127  } else if (!argValues.empty()) {
2128  bool bailout = false;
2129  for (const auto &v: argValues)
2130  bailout |= (v && v->type == ExprEngine::ValueType::BailoutValue);
2131  if (!bailout)
2132  data.addMissingContract(functionName);
2133  }
2134 #endif
2135 
2136  // Execute subfunction..
2137  if (hasBody) {
2138  const Scope * const functionScope = function->functionScope;
2139  int argnr = 0;
2140  std::map<const Token *, nonneg int> refs;
2141  for (const Variable &arg: function->argumentList) {
2142  if (argnr < argValues.size() && arg.declarationId() > 0) {
2143  if (arg.isReference())
2144  refs[argTokens[argnr]] = arg.declarationId();
2145  else
2146  argValues[argnr] = translateUninitValueToRange(argValues[argnr], arg.valueType(), data);
2147  data.assignValue(function->functionScope->bodyStart, arg.declarationId(), argValues[argnr]);
2148  }
2149  // TODO default values!
2150  argnr++;
2151  }
2152  data.contractConstraints(function, executeExpression1);
2153  data.errorPath.push_back(ErrorPathItem(tok, "Calling " + function->name()));
2154  try {
2155  data.load(execute(functionScope->bodyStart, functionScope->bodyEnd, data));
2156  for (auto ref: refs) {
2157  auto v = data.getValue(ref.second, nullptr, nullptr);
2158  assignExprValue(ref.first, v, data);
2159  }
2160  } catch (ExprEngineException &e) {
2161  data.errorPath.pop_back();
2162  e.tok = tok;
2163  throw e;
2164  }
2165  data.errorPath.pop_back();
2166  }
2167  }
2168 
2169  else if (const auto *f = data.settings->library.getAllocFuncInfo(tok->astOperand1())) {
2170  if (!f->initData) {
2171  const std::string name = data.getNewSymbolName();
2172  auto size = std::make_shared<ExprEngine::IntRange>(data.getNewSymbolName(), 1, MAX_BUFFER_SIZE);
2173  auto val = std::make_shared<ExprEngine::UninitValue>();
2174  auto result = std::make_shared<ExprEngine::ArrayValue>(name, size, val, false, false, false);
2175  call(data.callbacks, tok, result, &data);
2176  data.functionCall();
2177  return result;
2178  }
2179  }
2180 
2181  auto result = getValueRangeFromValueType(tok->valueType(), data);
2182  call(data.callbacks, tok, result, &data);
2183  data.functionCall();
2184  return result;
2185 }
2186 
2187 static ExprEngine::ValuePtr executeArrayIndex(const Token *tok, Data &data)
2188 {
2189  if (tok->tokType() == Token::eLambda)
2190  throw ExprEngineException(tok, "FIXME: lambda");
2191  const Token *tok2 = tok;
2192  while (Token::simpleMatch(tok2->astOperand1(), "["))
2193  tok2 = tok2->astOperand1();
2194  auto arrayValue = data.getArrayValue(tok2->astOperand1());
2195  if (arrayValue) {
2196  auto indexValue = calculateArrayIndex(tok, data, *arrayValue);
2197  auto conditionalValues = arrayValue->read(indexValue);
2198  for (const auto& value: conditionalValues)
2199  call(data.callbacks, tok, value.second, &data);
2200  if (conditionalValues.size() == 1 && !conditionalValues[0].first)
2201  return conditionalValues[0].second;
2202  return std::make_shared<ExprEngine::ConditionalValue>(data.getNewSymbolName(), conditionalValues);
2203  }
2204 
2205  // TODO: Pointer value..
2206  executeExpression(tok->astOperand1(), data);
2207  executeExpression(tok->astOperand2(), data);
2208 
2209  return ExprEngine::ValuePtr();
2210 }
2211 
2212 static ExprEngine::ValuePtr executeCast(const Token *tok, Data &data)
2213 {
2214  const Token *expr = tok->astOperand2() ? tok->astOperand2() : tok->astOperand1();
2215 
2216  auto val = executeExpression(expr, data);
2217 
2218  if (expr->valueType() && expr->valueType()->type == ::ValueType::Type::VOID && expr->valueType()->pointer > 0) {
2219  if (!tok->valueType() || expr->valueType()->pointer < tok->valueType()->pointer)
2220  return std::make_shared<ExprEngine::UninitValue>();
2221 
2222  auto range = std::make_shared<ExprEngine::UninitValue>();
2223 
2224  if (tok->valueType()->pointer == 0)
2225  return range;
2226 
2227  bool uninitPointer = false, nullPointer = false;
2228  if (val && val->type == ExprEngine::ValueType::ArrayValue) {
2229  nullPointer = std::static_pointer_cast<ExprEngine::ArrayValue>(val)->nullPointer;
2230  uninitPointer = std::static_pointer_cast<ExprEngine::ArrayValue>(val)->uninitPointer;
2231  }
2232 
2233  auto bufferSize = std::make_shared<ExprEngine::IntRange>(data.getNewSymbolName(), 1, MAX_BUFFER_SIZE);
2234  return std::make_shared<ExprEngine::ArrayValue>(data.getNewSymbolName(), bufferSize, range, true, nullPointer, uninitPointer);
2235  }
2236 
2237  if (val) {
2238  // TODO: Cast this..
2239  call(data.callbacks, tok, val, &data);
2240  return val;
2241  }
2242 
2243  val = getValueRangeFromValueType(tok->valueType(), data);
2244  call(data.callbacks, tok, val, &data);
2245  return val;
2246 }
2247 
2248 static ExprEngine::ValuePtr executeDot(const Token *tok, Data &data)
2249 {
2250  if (!tok->astOperand1()) {
2251  auto v = std::make_shared<ExprEngine::BailoutValue>();
2252  call(data.callbacks, tok, v, &data);
2253  return v;
2254  }
2255  std::shared_ptr<ExprEngine::StructValue> structValue = std::dynamic_pointer_cast<ExprEngine::StructValue>(executeExpression(tok->astOperand1(), data));
2256  if (!structValue) {
2257  if (tok->originalName() == "->") {
2258  std::shared_ptr<ExprEngine::ArrayValue> pointerValue = std::dynamic_pointer_cast<ExprEngine::ArrayValue>(data.getValue(tok->astOperand1()->varId(), nullptr, nullptr));
2259  if (pointerValue && pointerValue->pointer && !pointerValue->data.empty()) {
2260  call(data.callbacks, tok->astOperand1(), pointerValue, &data);
2261  auto indexValue = std::make_shared<ExprEngine::IntRange>("0", 0, 0);
2263  for (const auto& val: pointerValue->read(indexValue)) {
2264  structValue = std::dynamic_pointer_cast<ExprEngine::StructValue>(val.second);
2265  if (structValue) {
2266  auto memberValue = structValue->getValueOfMember(tok->astOperand2()->str());
2267  call(data.callbacks, tok, memberValue, &data);
2268  if (!ret)
2269  ret = memberValue;
2270  }
2271  }
2272  return ret;
2273  } else {
2274  call(data.callbacks, tok->astOperand1(), data.getValue(tok->astOperand1()->varId(), nullptr, nullptr), &data);
2275  }
2276  }
2277 
2278  auto v = getValueRangeFromValueType(tok->valueType(), data);
2279  if (!v)
2280  v = std::make_shared<ExprEngine::BailoutValue>();
2281  call(data.callbacks, tok, v, &data);
2282  return v;
2283  }
2284  call(data.callbacks, tok->astOperand1(), structValue, &data);
2285  ExprEngine::ValuePtr memberValue = structValue->getValueOfMember(tok->astOperand2()->str());
2286  call(data.callbacks, tok, memberValue, &data);
2287  return memberValue;
2288 }
2289 
2290 static void streamReadSetValue(const Token *tok, Data &data)
2291 {
2292  if (!tok || !tok->valueType())
2293  return;
2294  if (tok->varId() > 0 && tok->valueType()->pointer) {
2295  const auto oldValue = data.getValue(tok->varId(), tok->valueType(), tok);
2296  if (oldValue && (oldValue->isUninit(&data)))
2297  call(data.callbacks, tok, oldValue, &data);
2298  }
2299  auto rangeValue = getValueRangeFromValueType(tok->valueType(), data);
2300  if (rangeValue)
2301  assignExprValue(tok, rangeValue, data);
2302 }
2303 
2304 static ExprEngine::ValuePtr executeStreamRead(const Token *tok, Data &data)
2305 {
2306  tok = tok->astOperand2();
2307  while (Token::simpleMatch(tok, ">>")) {
2308  streamReadSetValue(tok->astOperand1(), data);
2309  tok = tok->astOperand2();
2310  }
2311  streamReadSetValue(tok, data);
2312  return ExprEngine::ValuePtr();
2313 }
2314 
2315 static ExprEngine::ValuePtr executeBinaryOp(const Token *tok, Data &data)
2316 {
2319 
2320  if (tok->str() == "?") {
2321  if (tok->astOperand1()->hasKnownIntValue()) {
2322  if (tok->astOperand1()->getKnownIntValue())
2323  v2 = executeExpression(tok->astOperand2()->astOperand1(), data);
2324  else
2325  v2 = executeExpression(tok->astOperand2()->astOperand2(), data);
2326  call(data.callbacks, tok, v2, &data);
2327  return v2;
2328  }
2329 
2330  Data trueData(data);
2331  trueData.addConstraint(v1, true);
2332  auto trueValue = simplifyValue(executeExpression(tok->astOperand2()->astOperand1(), trueData));
2333 
2334  Data falseData(data);
2335  falseData.addConstraint(v1, false);
2336  auto falseValue = simplifyValue(executeExpression(tok->astOperand2()->astOperand2(), falseData));
2337 
2338  auto result = simplifyValue(std::make_shared<ExprEngine::BinOpResult>("?", v1, std::make_shared<ExprEngine::BinOpResult>(":", trueValue, falseValue)));
2339  call(data.callbacks, tok, result, &data);
2340  return result;
2341 
2342  } else if (tok->str() == "&&" || tok->str() == "||") {
2343  Data data2(data);
2344  data2.addConstraint(v1, tok->str() == "&&");
2345  v2 = executeExpression(tok->astOperand2(), data2);
2346  } else {
2347  v2 = executeExpression(tok->astOperand2(), data);
2348  }
2349 
2350  if (v1 && v2) {
2351  auto result = simplifyValue(std::make_shared<ExprEngine::BinOpResult>(tok->str(), v1, v2));
2352  call(data.callbacks, tok, result, &data);
2353  return result;
2354  }
2355  if (tok->str() == "&&" && (v1 || v2)) {
2356  auto result = v1 ? v1 : v2;
2357  call(data.callbacks, tok, result, &data);
2358  return result;
2359  }
2360  return ExprEngine::ValuePtr();
2361 }
2362 
2363 static ExprEngine::ValuePtr executeAddressOf(const Token *tok, Data &data)
2364 {
2365  auto addr = std::make_shared<ExprEngine::AddressOfValue>(data.getNewSymbolName(), tok->astOperand1()->varId());
2366  call(data.callbacks, tok, addr, &data);
2367  return addr;
2368 }
2369 
2370 static ExprEngine::ValuePtr executeDeref(const Token *tok, Data &data)
2371 {
2372  ExprEngine::ValuePtr pval = executeExpression(tok->astOperand1(), data);
2373  if (!pval) {
2374  auto v = getValueRangeFromValueType(tok->valueType(), data);
2375  if (tok->astOperand1()->varId()) {
2376  pval = std::make_shared<ExprEngine::ArrayValue>(data.getNewSymbolName(), ExprEngine::ValuePtr(), v, true, false, false);
2377  data.assignValue(tok->astOperand1(), tok->astOperand1()->varId(), pval);
2378  }
2379  call(data.callbacks, tok, v, &data);
2380  return v;
2381  }
2382  auto addressOf = std::dynamic_pointer_cast<ExprEngine::AddressOfValue>(pval);
2383  if (addressOf) {
2384  auto val = data.getValue(addressOf->varId, tok->valueType(), tok);
2385  call(data.callbacks, tok, val, &data);
2386  return val;
2387  }
2388  auto pointer = std::dynamic_pointer_cast<ExprEngine::ArrayValue>(pval);
2389  if (pointer) {
2390  auto indexValue = std::make_shared<ExprEngine::IntRange>("0", 0, 0);
2391  auto conditionalValues = pointer->read(indexValue);
2392  for (const auto& value: conditionalValues)
2393  call(data.callbacks, tok, value.second, &data);
2394  if (conditionalValues.size() == 1 && !conditionalValues[0].first)
2395  return conditionalValues[0].second;
2396  return std::make_shared<ExprEngine::ConditionalValue>(data.getNewSymbolName(), conditionalValues);
2397  }
2398  return ExprEngine::ValuePtr();
2399 }
2400 
2401 static ExprEngine::ValuePtr executeNot(const Token *tok, Data &data)
2402 {
2404  if (!v)
2405  return v;
2406  ExprEngine::ValuePtr zero = std::make_shared<ExprEngine::IntRange>("0", 0, 0);
2407  auto result = simplifyValue(std::make_shared<ExprEngine::BinOpResult>("==", v, zero));
2408  call(data.callbacks, tok, result, &data);
2409  return result;
2410 }
2411 
2412 static ExprEngine::ValuePtr executeVariable(const Token *tok, Data &data)
2413 {
2414  auto val = data.getValue(tok->varId(), tok->valueType(), tok);
2415  call(data.callbacks, tok, val, &data);
2416  return val;
2417 }
2418 
2419 static ExprEngine::ValuePtr executeKnownMacro(const Token *tok, Data &data)
2420 {
2421  const auto intval = tok->getKnownIntValue();
2422  auto val = std::make_shared<ExprEngine::IntRange>(std::to_string(intval), intval, intval);
2423  call(data.callbacks, tok, val, &data);
2424  return val;
2425 }
2426 
2427 static ExprEngine::ValuePtr executeNumber(const Token *tok, Data &data)
2428 {
2429  if (tok->valueType()->isFloat()) {
2430  long double value = MathLib::toDoubleNumber(tok->str());
2431  auto v = std::make_shared<ExprEngine::FloatRange>(tok->str(), value, value);
2432  call(data.callbacks, tok, v, &data);
2433  return v;
2434  }
2435  int128_t value = MathLib::toLongNumber(tok->str());
2436  auto v = std::make_shared<ExprEngine::IntRange>(tok->str(), value, value);
2437  call(data.callbacks, tok, v, &data);
2438  return v;
2439 }
2440 
2441 static ExprEngine::ValuePtr executeStringLiteral(const Token *tok, Data &data)
2442 {
2443  const std::string& s = tok->str();
2444  return std::make_shared<ExprEngine::StringLiteralValue>(data.getNewSymbolName(), s.substr(1, s.size()-2));
2445 }
2446 
2447 static ExprEngine::ValuePtr executeExpression1(const Token *tok, Data &data)
2448 {
2449  if (Settings::terminated())
2450  throw TerminateExpression();
2451 
2452  if (tok->str() == "return")
2453  return executeReturn(tok, data);
2454 
2455  if (tok->isAssignmentOp())
2456  // TODO: Handle more operators
2457  return executeAssign(tok, data);
2458 
2459  if (tok->tokType() == Token::Type::eIncDecOp)
2460  return executeIncDec(tok, data);
2461 
2462  if (tok->astOperand1() && tok->astOperand2() && tok->str() == "[")
2463  return executeArrayIndex(tok, data);
2464 
2465  if (tok->str() == "(") {
2466  if (!tok->isCast())
2467  return executeFunctionCall(tok, data);
2468  return executeCast(tok, data);
2469  }
2470 
2471  if (tok->str() == ".")
2472  return executeDot(tok, data);
2473 
2474  if (tok->str() == "::" && tok->hasKnownIntValue()) { // TODO handle :: better
2475  auto v = tok->getKnownIntValue();
2476  return std::make_shared<ExprEngine::IntRange>(std::to_string(v), v, v);
2477  }
2478 
2479  if (data.tokenizer->isCPP() && tok->str() == ">>" && !tok->astParent() && tok->isBinaryOp() && Token::Match(tok->astOperand1(), "%name%|::"))
2480  return executeStreamRead(tok, data);
2481 
2482  if (tok->astOperand1() && tok->astOperand2())
2483  return executeBinaryOp(tok, data);
2484 
2485  if (tok->isUnaryOp("&") && Token::Match(tok->astOperand1(), "%var%"))
2486  return executeAddressOf(tok, data);
2487 
2488  if (tok->isUnaryOp("*"))
2489  return executeDeref(tok, data);
2490 
2491  if (tok->isUnaryOp("!"))
2492  return executeNot(tok, data);
2493 
2494  if (tok->varId())
2495  return executeVariable(tok, data);
2496 
2497  if (tok->isName() && tok->hasKnownIntValue())
2498  return executeKnownMacro(tok, data);
2499 
2500  if (tok->isNumber() || tok->tokType() == Token::Type::eChar)
2501  return executeNumber(tok, data);
2502 
2503  if (tok->tokType() == Token::Type::eString)
2504  return executeStringLiteral(tok, data);
2505 
2506  return ExprEngine::ValuePtr();
2507 }
2508 
2509 static ExprEngine::ValuePtr executeExpression(const Token *tok, Data &data)
2510 {
2511  return translateUninitValueToRange(executeExpression1(tok, data), tok->valueType(), data);
2512 }
2513 
2514 static ExprEngine::ValuePtr createVariableValue(const Variable &var, Data &data);
2515 
2516 static std::tuple<bool, bool> checkConditionBranches(const ExprEngine::ValuePtr &condValue, const Data &data)
2517 {
2518  bool canBeFalse = true;
2519  bool canBeTrue = true;
2520  if (auto b = std::dynamic_pointer_cast<ExprEngine::BinOpResult>(condValue)) {
2521  canBeFalse = b->isEqual(&data, 0);
2522  canBeTrue = b->isTrue(&data);
2523  } else if (auto i = std::dynamic_pointer_cast<ExprEngine::IntRange>(condValue)) {
2524  canBeFalse = i->isEqual(&data, 0);
2525  canBeTrue = ExprEngine::BinOpResult("!=", i, std::make_shared<ExprEngine::IntRange>("0", 0, 0)).isTrue(&data);
2526  } else if (std::dynamic_pointer_cast<ExprEngine::StringLiteralValue>(condValue)) {
2527  canBeFalse = false;
2528  canBeTrue = true;
2529  } else if (auto f = std::dynamic_pointer_cast<ExprEngine::FloatRange>(condValue)) {
2530  canBeFalse = f->isEqual(&data, 0);
2531  canBeTrue = ExprEngine::BinOpResult("!=", f, std::make_shared<ExprEngine::FloatRange>("0.0", 0.0, 0.0)).isTrue(&data);
2532  }
2533  return std::make_tuple(canBeFalse, canBeTrue);
2534 }
2535 
2536 static std::string execute(const Token *start, const Token *end, Data &data)
2537 {
2538  if (data.recursion > 20)
2539  // FIXME
2540  return data.str();
2541 
2542  // Update data.recursion
2543  struct Recursion {
2544  Recursion(int *var, int value) : var(var), value(value) {
2545  *var = value + 1;
2546  }
2547  ~Recursion() {
2548  if (*var >= value) *var = value;
2549  }
2550  int *var;
2551  int value;
2552  };
2553  Recursion updateRecursion(&data.recursion, data.recursion);
2554 
2555  const std::time_t stopTime = data.startTime + data.settings->bugHuntingCheckFunctionMaxTime;
2556 
2557  for (const Token *tok = start; tok != end; tok = tok->next()) {
2558  if (Token::Match(tok, "[;{}]")) {
2559  data.trackProgramState(tok);
2560  if (tok->str() == ";") {
2561  const Token *prev = tok->previous();
2562  while (prev && !Token::Match(prev, "[;{}]"))
2563  prev = prev->previous();
2564  if (Token::Match(prev, "[;{}] return|throw"))
2565  return data.str();
2566  }
2567  while (Token::simpleMatch(tok, "} catch (") && Token::simpleMatch(tok->linkAt(2), ") {")) {
2568  tok = tok->linkAt(2)->next()->link();
2569  }
2570  if (std::time(nullptr) > stopTime)
2571  return "";
2572  }
2573 
2574  if (Token::simpleMatch(tok, "__CPPCHECK_BAILOUT__ ;"))
2575  // This is intended for testing
2576  throw ExprEngineException(tok, "__CPPCHECK_BAILOUT__");
2577 
2578  if (Token::simpleMatch(tok, "while (") && Token::simpleMatch(tok->linkAt(1), ") ;") && tok->next()->astOperand1()->hasKnownIntValue() && tok->next()->astOperand1()->getKnownIntValue() == 0) {
2579  tok = tok->tokAt(4);
2580  continue;
2581  }
2582 
2583  if (tok->str() == "break") {
2584  const Scope *scope = tok->scope();
2585  while (scope->type == Scope::eIf || scope->type == Scope::eElse)
2586  scope = scope->nestedIn;
2587  tok = scope->bodyEnd;
2588  if (!precedes(tok,end))
2589  return data.str();
2590  }
2591 
2592  if (Token::simpleMatch(tok, "try {") && Token::simpleMatch(tok->linkAt(1), "} catch (")) {
2593  const Token *catchTok = tok->linkAt(1);
2594  while (Token::simpleMatch(catchTok, "} catch (")) {
2595  Data catchData(data);
2596  catchTok = catchTok->linkAt(2)->next();
2597  execute(catchTok, end, catchData);
2598  catchTok = catchTok->link();
2599  }
2600  }
2601 
2602  // Variable declaration..
2603  if (tok->variable() && tok->variable()->nameToken() == tok) {
2604  if (Token::Match(tok, "%varid% ; %varid% =", tok->varId())) {
2605  // if variable is not used in assignment rhs then we do not need to create a "confusing" variable value..
2606  bool foundInRhs = false;
2607  visitAstNodes(tok->tokAt(3)->astOperand2(), [&](const Token *rhs) {
2608  if (rhs->varId()==tok->varId()) {
2609  foundInRhs = true;
2610  return ChildrenToVisit::done;
2611  }
2613  });
2614  if (!foundInRhs) {
2615  tok = tok->tokAt(2);
2616  continue;
2617  }
2618  data.assignValue(tok, tok->varId(), createVariableValue(*tok->variable(), data));
2619  } else if (tok->variable()->isArray()) {
2620  data.assignValue(tok, tok->varId(), std::make_shared<ExprEngine::ArrayValue>(&data, tok->variable()));
2621  if (Token::Match(tok, "%name% ["))
2622  tok = tok->linkAt(1);
2623  } else if (Token::Match(tok, "%var% ;"))
2624  data.assignValue(tok, tok->varId(), createVariableValue(*tok->variable(), data));
2625  } else if (!tok->astParent() && (tok->astOperand1() || tok->astOperand2())) {
2626  executeExpression(tok, data);
2627  if (Token::Match(tok, "throw|return"))
2628  return data.str();
2629  }
2630 
2631  else if (Token::simpleMatch(tok, "if (")) {
2632  const Token *cond = tok->next()->astOperand2(); // TODO: C++17 condition
2633  const ExprEngine::ValuePtr condValue = executeExpression(cond, data);
2634 
2635  bool canBeFalse, canBeTrue;
2636  std::tie(canBeFalse, canBeTrue) = checkConditionBranches(condValue, data);
2637 
2638  Data &thenData(data);
2639  Data elseData(data);
2640  if (canBeFalse && canBeTrue) { // Avoid that constraints are overspecified
2641  thenData.addConstraint(condValue, true);
2642  elseData.addConstraint(condValue, false);
2643  }
2644 
2645  Data::ifSplit(tok, thenData, elseData);
2646 
2647  const Token *thenStart = tok->linkAt(1)->next();
2648  const Token *thenEnd = thenStart->link();
2649 
2650  const Token *exceptionToken = nullptr;
2651  std::string exceptionMessage;
2652  auto exec = [&](const Token *tok1, const Token *tok2, Data& data) {
2653  try {
2654  execute(tok1, tok2, data);
2655  } catch (ExprEngineException &e) {
2656  if (!exceptionToken || (e.tok && precedes(e.tok, exceptionToken))) {
2657  exceptionToken = e.tok;
2658  exceptionMessage = e.what;
2659  }
2660  }
2661  };
2662 
2663  if (canBeTrue)
2664  exec(thenStart->next(), end, thenData);
2665 
2666  if (canBeFalse) {
2667  if (Token::simpleMatch(thenEnd, "} else {")) {
2668  const Token *elseStart = thenEnd->tokAt(2);
2669  exec(elseStart->next(), end, elseData);
2670  } else {
2671  exec(thenEnd, end, elseData);
2672  }
2673  }
2674 
2675  if (exceptionToken)
2676  throw ExprEngineException(exceptionToken, exceptionMessage);
2677 
2678  return (canBeTrue ? thenData.str() : std::string()) +
2679  (canBeFalse ? elseData.str() : std::string());
2680  }
2681 
2682  else if (Token::simpleMatch(tok, "switch (")) {
2683  auto condValue = executeExpression(tok->next()->astOperand2(), data); // TODO: C++17 condition
2684  const Token *bodyStart = tok->linkAt(1)->next();
2685  const Token *bodyEnd = bodyStart->link();
2686  const Token *defaultStart = nullptr;
2687  Data defaultData(data);
2688  const Token *exceptionToken = nullptr;
2689  std::string exceptionMessage;
2690  std::ostringstream ret;
2691  auto exec = [&](const Token *tok1, const Token *tok2, Data& data) {
2692  try {
2693  execute(tok1, tok2, data);
2694  ret << data.str();
2695  } catch (ExprEngineException &e) {
2696  if (!exceptionToken || (e.tok && precedes(e.tok, exceptionToken))) {
2697  exceptionToken = e.tok;
2698  exceptionMessage = e.what;
2699  }
2700  }
2701  };
2702  for (const Token *tok2 = bodyStart->next(); tok2 != bodyEnd; tok2 = tok2->next()) {
2703  if (tok2->str() == "{")
2704  tok2 = tok2->link();
2705  else if (Token::Match(tok2, "case %char%|%num% :")) {
2706  const MathLib::bigint caseValue1 = tok2->next()->getKnownIntValue();
2707  auto caseValue = std::make_shared<ExprEngine::IntRange>(MathLib::toString(caseValue1), caseValue1, caseValue1);
2708  Data caseData(data);
2709  caseData.addConstraint(condValue, caseValue, true);
2710  defaultData.addConstraint(condValue, caseValue, false);
2711  exec(tok2->tokAt(2), end, caseData);
2712  } else if (Token::Match(tok2, "case %name% :") && !Token::Match(tok2->tokAt(3), ";| case")) {
2713  Data caseData(data);
2714  exec(tok2->tokAt(2), end, caseData);
2715  } else if (Token::simpleMatch(tok2, "default :"))
2716  defaultStart = tok2;
2717  }
2718  exec(defaultStart ? defaultStart : bodyEnd, end, defaultData);
2719  if (exceptionToken)
2720  throw ExprEngineException(exceptionToken, exceptionMessage);
2721  return ret.str();
2722  }
2723 
2724  if (Token::simpleMatch(tok, "for (")) {
2725  nonneg int varid;
2726  bool hasKnownInitValue, partialCond;
2727  MathLib::bigint initValue, stepValue, lastValue;
2728  if (extractForLoopValues(tok, &varid, &hasKnownInitValue, &initValue, &partialCond, &stepValue, &lastValue) && hasKnownInitValue && !partialCond) {
2729  auto loopValues = std::make_shared<ExprEngine::IntRange>(data.getNewSymbolName(), initValue, lastValue);
2730  data.assignValue(tok, varid, loopValues);
2731  tok = tok->linkAt(1);
2732  if (tok->next()) {
2733  loopValues->loopScope = tok->next()->scope();
2734  // Check whether the condition expression is always false
2735  if (initValue > lastValue) {
2736  tok = tok->next()->link();
2737  }
2738  }
2739  continue;
2740  }
2741  }
2742 
2743  if (Token::Match(tok, "for|while (") && Token::simpleMatch(tok->linkAt(1), ") {")) {
2744  const Token *cond = tok->next()->astOperand2();
2745  const ExprEngine::ValuePtr condValue = executeExpression(cond, data);
2746 
2747  bool canBeFalse = false, canBeTrue = true;
2748  if (tok->str() == "while")
2749  std::tie(canBeFalse, canBeTrue) = checkConditionBranches(condValue, data);
2750 
2751  Data &bodyData(data);
2752  Data noexecData(data);
2753  if (canBeFalse && canBeTrue) { // Avoid that constraints are overspecified
2754  bodyData.addConstraint(condValue, true);
2755  }
2756 
2757  Data::ifSplit(tok, bodyData, noexecData);
2758 
2759  const Token *bodyStart = tok->linkAt(1)->next();
2760  const Token *bodyEnd = bodyStart->link();
2761 
2762  // TODO this is very rough code
2763  if (canBeTrue) {
2764  std::set<int> changedVariables;
2765  for (const Token *tok2 = tok; tok2 != bodyEnd; tok2 = tok2->next()) {
2766  if (Token::Match(tok2, "%assign%")) {
2767  const Token *lhs = tok2->astOperand1();
2768  while (Token::simpleMatch(lhs, "["))
2769  lhs = lhs->astOperand1();
2770  if (!lhs)
2771  throw ExprEngineException(tok2, "Unhandled assignment in loop");
2772  if (Token::Match(lhs, ". %name% =|[") && Token::simpleMatch(lhs->astOperand1(), ".")) {
2773  const Token *structToken = lhs;
2774  while (Token::Match(structToken, ".|["))
2775  structToken = structToken->astOperand1();
2776  if (Token::Match(structToken, "%var%")) {
2777  bodyData.assignValue(structToken, structToken->varId(), std::make_shared<ExprEngine::BailoutValue>());
2778  changedVariables.insert(structToken->varId());
2779  continue;
2780  }
2781  }
2782  if (Token::Match(lhs, ". %name% =|[") && lhs->astOperand1() && lhs->astOperand1()->valueType()) {
2783  const Token *structToken = lhs->astOperand1();
2784  if (!structToken->valueType() || !structToken->varId())
2785  throw ExprEngineException(tok2, "Unhandled assignment in loop");
2786  const Scope *structScope = structToken->valueType()->typeScope;
2787  if (!structScope)
2788  throw ExprEngineException(tok2, "Unhandled assignment in loop");
2789  const std::string &memberName = tok2->previous()->str();
2790  ExprEngine::ValuePtr memberValue;
2791  for (const Variable &member : structScope->varlist) {
2792  if (memberName == member.name() && member.valueType()) {
2793  memberValue = createVariableValue(member, bodyData);
2794  break;
2795  }
2796  }
2797  if (!memberValue)
2798  throw ExprEngineException(tok2, "Unhandled assignment in loop");
2799 
2800  ExprEngine::ValuePtr structVal1 = bodyData.getValue(structToken->varId(), structToken->valueType(), structToken);
2801  if (!structVal1)
2802  structVal1 = createVariableValue(*structToken->variable(), bodyData);
2803  auto structVal = std::dynamic_pointer_cast<ExprEngine::StructValue>(structVal1);
2804  if (!structVal) {
2805  // Handle pointer to a struct
2806  if (auto structPtr = std::dynamic_pointer_cast<ExprEngine::ArrayValue>(structVal1)) {
2807  if (structPtr->pointer && !structPtr->data.empty()) {
2808  auto indexValue = std::make_shared<ExprEngine::IntRange>("0", 0, 0);
2809  for (const auto &val: structPtr->read(indexValue)) {
2810  structVal = std::dynamic_pointer_cast<ExprEngine::StructValue>(val.second);
2811  }
2812  }
2813  }
2814  if (!structVal)
2815  throw ExprEngineException(tok2, "Unhandled assignment in loop");
2816  }
2817 
2818  bodyData.assignStructMember(tok2, &*structVal, memberName, memberValue);
2819  continue;
2820  }
2821  if (lhs->isUnaryOp("*") && lhs->astOperand1()->varId()) {
2822  const Token *varToken = tok2->astOperand1()->astOperand1();
2823  ExprEngine::ValuePtr val = bodyData.getValue(varToken->varId(), varToken->valueType(), varToken);
2824  if (val && val->type == ExprEngine::ValueType::ArrayValue) {
2825  // Try to assign "any" value
2826  auto arrayValue = std::dynamic_pointer_cast<ExprEngine::ArrayValue>(val);
2827  arrayValue->assign(std::make_shared<ExprEngine::IntRange>("0", 0, 0), std::make_shared<ExprEngine::BailoutValue>());
2828  continue;
2829  }
2830  }
2831  if (!lhs->variable())
2832  throw ExprEngineException(tok2, "Unhandled assignment in loop");
2833  // give variable "any" value
2834  int varid = lhs->varId();
2835  if (changedVariables.find(varid) != changedVariables.end())
2836  continue;
2837  changedVariables.insert(varid);
2838  auto oldValue = bodyData.getValue(varid, nullptr, nullptr);
2839  if (oldValue && oldValue->isUninit(&bodyData))
2840  call(bodyData.callbacks, lhs, oldValue, &bodyData);
2841  if (oldValue && oldValue->type == ExprEngine::ValueType::ArrayValue) {
2842  // Try to assign "any" value
2843  auto arrayValue = std::dynamic_pointer_cast<ExprEngine::ArrayValue>(oldValue);
2844  arrayValue->assign(std::make_shared<ExprEngine::IntRange>(bodyData.getNewSymbolName(), 0, MAX_BUFFER_SIZE), std::make_shared<ExprEngine::BailoutValue>());
2845  continue;
2846  }
2847  bodyData.assignValue(tok2, varid, getValueRangeFromValueType(lhs->valueType(), bodyData));
2848  continue;
2849  } else if (Token::Match(tok2, "++|--") && tok2->astOperand1() && tok2->astOperand1()->variable()) {
2850  // give variable "any" value
2851  const Token *vartok = tok2->astOperand1();
2852  int varid = vartok->varId();
2853  if (changedVariables.find(varid) != changedVariables.end())
2854  continue;
2855  changedVariables.insert(varid);
2856  auto oldValue = bodyData.getValue(varid, nullptr, nullptr);
2857  if (oldValue && oldValue->type == ExprEngine::ValueType::UninitValue)
2858  call(bodyData.callbacks, tok2, oldValue, &bodyData);
2859  bodyData.assignValue(tok2, varid, getValueRangeFromValueType(vartok->valueType(), bodyData));
2860  }
2861  }
2862  }
2863 
2864  const Token *exceptionToken = nullptr;
2865  std::string exceptionMessage;
2866  auto exec = [&](const Token *tok1, const Token *tok2, Data& data) {
2867  try {
2868  execute(tok1, tok2, data);
2869  } catch (ExprEngineException &e) {
2870  if (!exceptionToken || (e.tok && precedes(e.tok, exceptionToken))) {
2871  exceptionToken = e.tok;
2872  exceptionMessage = e.what;
2873  }
2874  }
2875  };
2876 
2877  if (canBeTrue)
2878  exec(bodyStart->next(), end, bodyData);
2879  if (canBeFalse)
2880  exec(bodyEnd, end, noexecData);
2881 
2882  if (exceptionToken)
2883  throw ExprEngineException(exceptionToken, exceptionMessage);
2884 
2885  return (canBeTrue ? bodyData.str() : std::string()) +
2886  (canBeFalse ? noexecData.str() : std::string());
2887  }
2888 
2889  if (Token::simpleMatch(tok, "} else {"))
2890  tok = tok->linkAt(2);
2891  }
2892 
2893  return data.str();
2894 }
2895 
2896 void ExprEngine::executeAllFunctions(ErrorLogger *errorLogger, const Tokenizer *tokenizer, const Settings *settings, const std::vector<ExprEngine::Callback> &callbacks, std::ostream &report)
2897 {
2898  const SymbolDatabase *symbolDatabase = tokenizer->getSymbolDatabase();
2899  for (const Scope *functionScope : symbolDatabase->functionScopes) {
2900  try {
2901  executeFunction(functionScope, errorLogger, tokenizer, settings, callbacks, report);
2902  } catch (const ExprEngineException &e) {
2903  // FIXME.. there should not be exceptions
2904  std::string functionName = functionScope->function->name();
2905  std::cout << "Verify: Aborted analysis of function '" << functionName << "':" << e.tok->linenr() << ": " << e.what << std::endl;
2906  } catch (const std::exception &e) {
2907  // FIXME.. there should not be exceptions
2908  std::string functionName = functionScope->function->name();
2909  std::cout << "Verify: Aborted analysis of function '" << functionName << "': " << e.what() << std::endl;
2910  } catch (const TerminateExpression &) {
2911  break;
2912  }
2913  }
2914 }
2915 
2916 static ExprEngine::ValuePtr createStructVal(const Token *tok, const Scope *structScope, bool uninitData, Data &data)
2917 {
2918  if (!structScope)
2919  return ExprEngine::ValuePtr();
2920  std::shared_ptr<ExprEngine::StructValue> structValue = std::make_shared<ExprEngine::StructValue>(data.getNewSymbolName());
2921  auto uninitValue = std::make_shared<ExprEngine::UninitValue>();
2922  for (const Variable &member : structScope->varlist) {
2923  if (uninitData && !member.isInit()) {
2924  if (member.isPointer()) {
2925  structValue->member[member.name()] = uninitValue;
2926  continue;
2927  }
2928  if (member.valueType() && member.valueType()->type >= ::ValueType::Type::CHAR) {
2929  structValue->member[member.name()] = uninitValue;
2930  continue;
2931  }
2932  }
2933  if (member.valueType() && member.valueType()->isIntegral()) {
2934  ExprEngine::ValuePtr memberValue = createVariableValue(member, data);
2935  if (memberValue)
2936  data.assignStructMember(tok, structValue.get(), member.name(), memberValue);
2937  }
2938  }
2939  return structValue;
2940 }
2941 
2942 static ExprEngine::ValuePtr createVariableValue(const Variable &var, Data &data)
2943 {
2944  if (!var.nameToken())
2945  return ExprEngine::ValuePtr();
2946  const ValueType *valueType = var.valueType();
2947  if (!valueType || valueType->type == ValueType::Type::UNKNOWN_TYPE)
2948  valueType = var.nameToken()->valueType();
2949  if (!valueType || valueType->type == ValueType::Type::UNKNOWN_TYPE) {
2950  // variable with unknown type
2951  if (var.isLocal() && var.isPointer() && !var.isArray())
2952  return std::make_shared<ExprEngine::UninitValue>();
2953  return ExprEngine::ValuePtr();
2954  }
2955 
2956  if (valueType->pointer > 0) {
2957  if (var.isLocal())
2958  return std::make_shared<ExprEngine::UninitValue>();
2959  auto bufferSize = std::make_shared<ExprEngine::IntRange>(data.getNewSymbolName(), 1, MAX_BUFFER_SIZE);
2960  ExprEngine::ValuePtr pointerValue;
2961  if (valueType->type == ValueType::Type::RECORD)
2962  pointerValue = createStructVal(var.nameToken(), valueType->typeScope, var.isLocal() && !var.isStatic(), data);
2963  else {
2964  ValueType vt(*valueType);
2965  vt.pointer = 0;
2966  if (vt.constness & 1)
2967  pointerValue = getValueRangeFromValueType(&vt, data);
2968  else
2969  pointerValue = std::make_shared<ExprEngine::UninitValue>();
2970  }
2971  return std::make_shared<ExprEngine::ArrayValue>(data.getNewSymbolName(), bufferSize, pointerValue, true, true, var.isLocal() && !var.isStatic());
2972  }
2973  if (var.isArray())
2974  return std::make_shared<ExprEngine::ArrayValue>(&data, &var);
2975  if (valueType->isIntegral() || valueType->isFloat()) {
2976  ExprEngine::ValuePtr value;
2977  if (var.isLocal() && !var.isStatic())
2978  value = std::make_shared<ExprEngine::UninitValue>();
2979  else
2980  value = getValueRangeFromValueType(valueType, data);
2981  data.addConstraints(value, var.nameToken());
2982  return value;
2983  }
2984  if (valueType->type == ValueType::Type::RECORD) {
2985  bool uninitData = true;
2986  if (var.isLocal() && !var.isStatic()) {
2987  uninitData = !valueType->typeScope ||
2988  !valueType->typeScope->definedType ||
2990  }
2991  if (var.isArgument() && var.isConst())
2992  uninitData = false;
2993  return createStructVal(var.nameToken(), valueType->typeScope, uninitData, data);
2994  }
2995  if (valueType->smartPointerType) {
2996  auto structValue = createStructVal(var.nameToken(), valueType->smartPointerType->classScope, var.isLocal() && !var.isStatic(), data);
2997  auto size = std::make_shared<ExprEngine::IntRange>(data.getNewSymbolName(), 1, MAX_BUFFER_SIZE);
2998  return std::make_shared<ExprEngine::ArrayValue>(data.getNewSymbolName(), size, structValue, true, true, false);
2999  }
3000  return getValueRangeFromValueType(valueType, data);
3001 }
3002 
3003 void ExprEngine::executeFunction(const Scope *functionScope, ErrorLogger *errorLogger, const Tokenizer *tokenizer, const Settings *settings, const std::vector<ExprEngine::Callback> &callbacks, std::ostream &report)
3004 {
3005  if (!functionScope->bodyStart)
3006  return;
3007  const Function *function = functionScope->function;
3008  if (!function)
3009  return;
3010  if (functionScope->bodyStart->fileIndex() > 0)
3011  // TODO.. what about functions in headers?
3012  return;
3013 
3014  const std::string currentFunction = function->fullName();
3015 
3016  int symbolValueIndex = 0;
3017  TrackExecution trackExecution;
3018  Data data(&symbolValueIndex, errorLogger, tokenizer, settings, currentFunction, callbacks, &trackExecution);
3019 
3020  for (const Variable &arg : function->argumentList)
3021  data.assignValue(functionScope->bodyStart, arg.declarationId(), createVariableValue(arg, data));
3022 
3023 #ifdef CONTRACT
3024  data.contractConstraints(function, executeExpression1);
3025 #endif
3026 
3027  const std::time_t stopTime = data.startTime + data.settings->bugHuntingCheckFunctionMaxTime;
3028 
3029  try {
3030  execute(functionScope->bodyStart, functionScope->bodyEnd, data);
3031  } catch (const ExprEngineException &e) {
3032  if (settings->debugBugHunting)
3033  report << "ExprEngineException " << e.tok->linenr() << ":" << e.tok->column() << ": " << e.what << "\n";
3034  trackExecution.setAbortLine(e.tok->linenr());
3035  auto bailoutValue = std::make_shared<BailoutValue>();
3036  for (const Token *tok = e.tok; tok != functionScope->bodyEnd; tok = tok->next()) {
3037  if (std::time(nullptr) >= stopTime)
3038  break;
3039  if (Token::Match(tok, "return|throw|while|if|for (")) {
3040  tok = tok->next();
3041  continue;
3042  }
3043  call(callbacks, tok, bailoutValue, &data);
3044  }
3045  }
3046 
3047  const bool bugHuntingReport = !settings->bugHuntingReport.empty();
3048 
3049  if (settings->debugBugHunting && (settings->verbose || callbacks.empty() || !trackExecution.isAllOk())) {
3050  if (bugHuntingReport)
3051  report << "[debug]" << std::endl;
3052  trackExecution.print(report);
3053  if (!callbacks.empty()) {
3054  if (bugHuntingReport)
3055  report << "[details]" << std::endl;
3056  trackExecution.report(report, functionScope);
3057  }
3058  }
3059 
3060  // Write a report
3061  if (bugHuntingReport) {
3062  std::set<std::string> intvars;
3063  for (const Scope &scope: tokenizer->getSymbolDatabase()->scopeList) {
3064  if (scope.isExecutable())
3065  continue;
3066  std::string path;
3067  bool valid = true;
3068  for (const Scope *s = &scope; s->type != Scope::ScopeType::eGlobal; s = s->nestedIn) {
3069  if (s->isExecutable()) {
3070  valid = false;
3071  break;
3072  }
3073  path = s->className + "::" + path;
3074  }
3075  if (!valid)
3076  continue;
3077  for (const Variable &var: scope.varlist) {
3078  if (var.nameToken() && !var.nameToken()->hasCppcheckAttributes() && var.valueType() && var.valueType()->pointer == 0 && var.valueType()->constness == 0 && var.valueType()->isIntegral())
3079  intvars.insert(path + var.name());
3080  }
3081  }
3082  for (const std::string &v: intvars)
3083  report << "[intvar] " << v << std::endl;
3084  for (const std::string &f: trackExecution.getMissingContracts())
3085  report << "[missing contract] " << f << std::endl;
3086  }
3087 }
3088 
3089 void ExprEngine::runChecks(ErrorLogger *errorLogger, const Tokenizer *tokenizer, const Settings *settings)
3090 {
3091 
3092  std::vector<ExprEngine::Callback> callbacks;
3093  addBughuntingChecks(&callbacks);
3094 
3095  std::ostringstream report;
3096  ExprEngine::executeAllFunctions(errorLogger, tokenizer, settings, callbacks, report);
3097  if (settings->bugHuntingReport.empty())
3098  std::cout << report.str();
3099  else if (errorLogger)
3100  errorLogger->bughuntingReport(report.str());
3101 }
3102 
3104 {
3105  if (!val) {
3106  std::cout << "NULL";
3107  return;
3108  }
3109  switch (val->type) {
3111  std::cout << "AddressOfValue(" << std::dynamic_pointer_cast<ExprEngine::AddressOfValue>(val)->varId << ")";
3112  break;
3114  std::cout << "ArrayValue";
3115  break;
3117  std::cout << "BailoutValue";
3118  break;
3120  auto b = std::dynamic_pointer_cast<ExprEngine::BinOpResult>(val);
3121  std::cout << "(";
3122  dumpRecursive(b->op1);
3123  std::cout << " " << b->binop << " ";
3124  dumpRecursive(b->op2);
3125  std::cout << ")";
3126  }
3127  break;
3129  std::cout << "ConditionalValue";
3130  break;
3132  std::cout << "FloatRange";
3133  break;
3135  std::cout << "FunctionCallArgumentValues(";
3136  const char *sep = "";
3137  for (const auto &arg: std::dynamic_pointer_cast<ExprEngine::FunctionCallArgumentValues>(val)->argValues) {
3138  std::cout << sep;
3139  sep = ",";
3140  if (!arg)
3141  std::cout << "NULL";
3142  else
3143  dumpRecursive(arg);
3144  }
3145  std::cout << ")";
3146  }
3147  break;
3149  std::cout << "IntRange";
3150  break;
3152  std::cout << "IntegerTruncation(";
3153  dumpRecursive(std::dynamic_pointer_cast<ExprEngine::IntegerTruncation>(val)->inputValue);
3154  std::cout << ")";
3155  break;
3157  std::cout << "StringLiteralValue";
3158  break;
3160  std::cout << "StructValue";
3161  break;
3163  std::cout << "UninitValue";
3164  break;
3165  }
3166 }
3167 
3169 {
3170  dumpRecursive(val);
3171  std::cout << "\n";
3172 }
3173 
3174 
bool extractForLoopValues(const Token *forToken, nonneg int *const varid, bool *const knownInitValue, MathLib::bigint *const initValue, bool *const partialCond, MathLib::bigint *const stepValue, MathLib::bigint *const lastValue)
Extract for loop values: loopvar varid, init value, step value, last value (inclusive)
Definition: astutils.cpp:732
bool precedes(const Token *tok1, const Token *tok2)
If tok2 comes after tok1.
Definition: astutils.cpp:792
std::vector< const Token * > getArguments(const Token *ftok)
Get arguments (AST)
Definition: astutils.cpp:2581
void visitAstNodes(T *ast, const TFunc &visitor)
Visit AST nodes recursively.
Definition: astutils.h:53
void addBughuntingChecks(std::vector< ExprEngine::Callback > *callbacks)
@ inconclusive
Definition: errortypes.h:47
This is an interface, which the class responsible of error logging should implement.
Definition: errorlogger.h:238
virtual void bughuntingReport(const std::string &str)=0
virtual void reportErr(const ErrorMessage &msg)=0
Information about found errors and warnings is directed here.
Wrapper for error messages, provided by reportErr()
Definition: errorlogger.h:60
std::string getSymbolicExpression() const override
std::vector< IndexAndValue > data
Definition: exprengine.h:217
std::vector< ValuePtr > size
Definition: exprengine.h:218
ArrayValue(const std::string &name, ValuePtr size, ValuePtr value, bool pointer, bool nullPointer, bool uninitPointer)
Definition: exprengine.cpp:890
void assign(ValuePtr index, ValuePtr value)
Definition: exprengine.cpp:945
ConditionalValue::Vector read(ValuePtr index) const
Definition: exprengine.cpp:992
std::string getRange() const override
Definition: exprengine.cpp:935
bool isTrue(const DataBase *dataBase) const
virtual bool isLessThan(const DataBase *dataBase, int value) const override
bool isGreaterThan(const DataBase *dataBase, int value) const override
bool isEqual(const DataBase *dataBase, int value) const override
std::string getExpr(DataBase *dataBase) const
std::string getSymbolicExpression() const override
std::vector< std::pair< ValuePtr, ValuePtr > > Vector
Definition: exprengine.h:184
bool isEqual(const DataBase *dataBase, int value) const override
bool isGreaterThan(const DataBase *dataBase, int value) const override
bool isLessThan(const DataBase *dataBase, int value) const override
bool isLessThan(const DataBase *dataBase, int value) const override
bool isGreaterThan(const DataBase *dataBase, int value) const override
bool isEqual(const DataBase *dataBase, int value) const override
std::string getSymbolicExpression() const override
std::map< std::string, ValuePtr > member
Definition: exprengine.h:258
std::string getSymbolicExpression() const override
bool isUninit(const DataBase *dataBase) const override
ValueType type
Definition: exprengine.h:128
const std::string & name() const
std::string fullName() const
static bool isFloat(const std::string &str)
Definition: mathlib.cpp:512
static bigint toLongNumber(const std::string &str)
Definition: mathlib.cpp:361
static double toDoubleNumber(const std::string &str)
Definition: mathlib.cpp:471
static std::string toString(T value)
Definition: mathlib.h:76
long long bigint
Definition: mathlib.h:69
std::list< Variable > varlist
ScopeType type
Type * definedType
Function * function
function info for this function
const Scope * nestedIn
const Token * bodyStart
'{' token
const Token * bodyEnd
'}' token
bool isExecutable() const
This is just a container for general settings so that we don't need to pass individual values to func...
Definition: settings.h:91
std::string bugHuntingReport
Filename for bug hunting report.
Definition: settings.h:119
bool debugBugHunting
Debug bug hunting.
Definition: settings.h:166
static bool terminated()
termination requested?
Definition: settings.h:418
bool verbose
Is –verbose given?
Definition: settings.h:372
SeverityType
Message severities.
Definition: errortypes.h:64
std::vector< const Scope * > functionScopes
Fast access to function scopes.
const Variable * getVariableFromVarId(nonneg int varId) const
void setValueTypeInTokenList(bool reportDebugWarnings, Token *tokens=nullptr)
Set valuetype in provided tokenlist.
std::list< Scope > scopeList
Information about all namespaces/classes/structrues.
The token list that the TokenList generates is a linked-list of this class.
Definition: token.h:172
void str(T &&s)
Definition: token.h:198
nonneg int index() const
Definition: token.h:1199
static bool Match(const Token *tok, const char pattern[], nonneg int varid=0)
Match given token (or list of tokens) to a pattern list.
Definition: token.cpp:639
const std::string & originalName() const
Definition: token.h:1144
bool isName() const
Definition: token.h:394
bool hasKnownIntValue() const
Definition: token.cpp:2369
MathLib::bigint getKnownIntValue() const
Definition: token.h:1169
Token * next() const
Definition: token.h:808
const ValueType * valueType() const
Definition: token.h:364
void astOperand1(Token *tok)
Definition: token.cpp:1375
bool isNumber() const
Definition: token.h:404
nonneg int varId() const
Definition: token.h:842
bool isCast() const
Definition: token.h:490
bool isUnaryOp(const std::string &s) const
Definition: token.h:443
Token * previous() const
Definition: token.h:837
const Token * tokAt(int index) const
Definition: token.cpp:361
bool hasCppcheckAttributes() const
Definition: token.h:568
Token::Type tokType() const
Definition: token.h:376
void astOperand2(Token *tok)
Definition: token.cpp:1387
void scope(const Scope *s)
Associate this token with given scope.
Definition: token.h:998
void link(Token *linkToToken)
Create link to given token.
Definition: token.h:975
const Token * linkAt(int index) const
Definition: token.cpp:375
@ eLambda
Definition: token.h:186
bool isBinaryOp() const
Definition: token.h:440
bool isAssignmentOp() const
Definition: token.h:431
bool getCppcheckAttribute(TokenImpl::CppcheckAttributes::Type type, MathLib::bigint *value) const
Definition: token.h:565
nonneg int linenr() const
Definition: token.h:794
void variable(const Variable *v)
Associate this token with given variable.
Definition: token.h:1026
static bool simpleMatch(const Token *tok, const char(&pattern)[count])
Match given token (or list of tokens) to a pattern list.
Definition: token.h:275
nonneg int fileIndex() const
Definition: token.h:787
nonneg int column() const
Definition: token.h:801
void astParent(Token *tok)
Definition: token.cpp:1356
The main purpose is to tokenize the source code.
Definition: tokenize.h:52
TokenList list
Token list: stores all tokens.
Definition: tokenize.h:899
bool isC() const
Is the code C.
Definition: tokenize.h:99
const SymbolDatabase * getSymbolDatabase() const
Definition: tokenize.h:871
bool isCPP() const
Is the code CPP.
Definition: tokenize.h:104
enum Type::NeedInitialization needInitialization
const Scope * classScope
Value type.
bool isFloat() const
enum ValueType::Type type
const Library::Container * container
If the type is a container defined in a cfg file, this is the used.
nonneg int constness
bit 0=data, bit 1=*, bit 2=**
bool isIntegral() const
nonneg int pointer
0=>not pointer, 1=>*, 2=>**, 3=>***, etc
const Token * containerTypeToken
The container type token.
const Scope * typeScope
if the type definition is seen this point out the type scope
enum ValueType::Sign sign
static ValueType parseDecl(const Token *type, const Settings *settings)
const ::Type * smartPointerType
Smart pointer type.
Information about a member variable.
bool isArgument() const
Is variable a function argument.
bool isReference() const
Is reference variable.
bool isLocal() const
Is variable local.
bool isGlobal() const
Is variable global.
const std::string & name() const
Get name string.
bool isConst() const
Is variable const.
bool isArray() const
Is variable an array.
const Token * nameToken() const
Get name token.
nonneg int declarationId() const
Get declaration ID (varId used for variable in its declaration).
bool isInit() const
Is variable initialized in its declaration.
const std::vector< Dimension > & dimensions() const
Get array dimensions.
bool isPointer() const
Is pointer variable.
bool isStatic() const
Is variable static.
const ValueType * valueType() const
Platform settings.
Definition: platform.h:41
nonneg int long_long_bit
bits in long
Definition: platform.h:85
nonneg int short_bit
bits in char
Definition: platform.h:82
nonneg int int_bit
bits in short
Definition: platform.h:83
nonneg int char_bit
Definition: platform.h:81
nonneg int long_bit
bits in int
Definition: platform.h:84
#define nonneg
Definition: config.h:81
static ExprEngine::ValuePtr executeKnownMacro(const Token *tok, Data &data)
static bool isEqual(ExprEngine::ValuePtr v1, ExprEngine::ValuePtr v2)
Definition: exprengine.cpp:974
static ExprEngine::ValuePtr createStructVal(const Token *tok, const Scope *structScope, bool uninitData, Data &data)
static ExprEngine::ValuePtr calculateArrayIndex(const Token *tok, Data &data, const ExprEngine::ArrayValue &arrayValue)
static ExprEngine::ValuePtr executeArrayIndex(const Token *tok, Data &data)
static std::string str(ExprEngine::ValuePtr val)
Definition: exprengine.cpp:177
static ExprEngine::ValuePtr executeBinaryOp(const Token *tok, Data &data)
static bool isNonOverlapping(ExprEngine::ValuePtr v1, ExprEngine::ValuePtr v2)
Definition: exprengine.cpp:981
static int getIntBitsFromValueType(const ValueType *vt, const cppcheck::Platform &platform)
static ExprEngine::ValuePtr executeStringLiteral(const Token *tok, Data &data)
static ExprEngine::ValuePtr createVariableValue(const Variable &var, Data &data)
static ExprEngine::ValuePtr executeDot(const Token *tok, Data &data)
static ExprEngine::ValuePtr executeStreamRead(const Token *tok, Data &data)
static ExprEngine::ValuePtr translateUninitValueToRange(ExprEngine::ValuePtr value, const ::ValueType *valueType, Data &data)
Definition: exprengine.cpp:862
static ExprEngine::ValuePtr executeReturn(const Token *tok, Data &data)
static ExprEngine::ValuePtr executeNumber(const Token *tok, Data &data)
static ExprEngine::ValuePtr executeVariable(const Token *tok, Data &data)
static void assignExprValue(const Token *expr, ExprEngine::ValuePtr value, Data &data)
static ExprEngine::ValuePtr executeFunctionCall(const Token *tok, Data &data)
static int128_t truncateInt(int128_t value, int bits, char sign)
Definition: exprengine.cpp:881
static void streamReadSetValue(const Token *tok, Data &data)
static std::tuple< bool, bool > checkConditionBranches(const ExprEngine::ValuePtr &condValue, const Data &data)
static std::string execute(const Token *start, const Token *end, Data &data)
static ExprEngine::ValuePtr executeNot(const Token *tok, Data &data)
static ExprEngine::ValuePtr executeCast(const Token *tok, Data &data)
static ExprEngine::ValuePtr executeIncDec(const Token *tok, Data &data)
static ExprEngine::ValuePtr executeExpression1(const Token *tok, Data &data)
static void dumpRecursive(ExprEngine::ValuePtr val)
static ExprEngine::ValuePtr getValueRangeFromValueType(const std::string &name, const ValueType *vt, const cppcheck::Platform &platform)
static ExprEngine::ValuePtr executeDeref(const Token *tok, Data &data)
static ExprEngine::ValuePtr simplifyValue(ExprEngine::ValuePtr origValue)
Definition: exprengine.cpp:833
static ExprEngine::ValuePtr truncateValue(ExprEngine::ValuePtr val, const ValueType *valueType, Data &data)
static ExprEngine::ValuePtr executeExpression(const Token *tok, Data &data)
static ExprEngine::ValuePtr executeAssign(const Token *tok, Data &data)
static ExprEngine::ValuePtr executeAddressOf(const Token *tok, Data &data)
static void call(const std::vector< ExprEngine::Callback > &callbacks, const Token *tok, ExprEngine::ValuePtr value, Data *dataBase)
const uint32_t MAX_BUFFER_SIZE
This is the ExprEngine component in Cppcheck.
Definition: exprengine.cpp:165
static size_t extfind(const std::string &str, const std::string &what, size_t pos)
Definition: exprengine.cpp:222
long long int128_t
Definition: exprengine.h:41
std::pair< const Token *, std::string > ErrorPathItem
Definition: errortypes.h:125
std::list< ErrorPathItem > ErrorPath
Definition: errortypes.h:126
void executeFunction(const Scope *functionScope, ErrorLogger *errorLogger, const Tokenizer *tokenizer, const Settings *settings, const std::vector< Callback > &callbacks, std::ostream &report)
void runChecks(ErrorLogger *errorLogger, const Tokenizer *tokenizer, const Settings *settings)
std::shared_ptr< Value > ValuePtr
Definition: exprengine.h:73
void CPPCHECKLIB executeAllFunctions(ErrorLogger *errorLogger, const Tokenizer *tokenizer, const Settings *settings, const std::vector< Callback > &callbacks, std::ostream &report)
Execute all functions.
void dump(ExprEngine::ValuePtr val)
std::function< void(const Token *, const ExprEngine::Value &, ExprEngine::DataBase *)> Callback
Definition: exprengine.h:338
std::string str(int128_t)
Definition: exprengine.cpp:245
static void indent(std::string &str, const nonneg int indent1, const nonneg int indent2)
Definition: token.cpp:1621
#define bailout(tokenlist, errorLogger, tok, what)
Definition: valueflow.cpp:143