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)
169 struct ExprEngineException {
170 ExprEngineException(
const Token *tok,
const std::string &what) : tok(tok), what(what) {}
172 const std::string what;
174 struct TerminateExpression {};
179 const char *typestr =
"???UnknownValueType???";
182 typestr =
"AddressOfValue";
185 typestr =
"ArrayValue";
188 typestr =
"UninitValue";
191 typestr =
"IntRange";
194 typestr =
"FloatRange";
197 typestr =
"ConditionalValue";
200 typestr =
"StringLiteralValue";
203 typestr =
"StructValue";
206 typestr =
"BinOpResult";
209 typestr =
"IntegerTruncation";
212 typestr =
"FunctionCallArgumentValues";
215 typestr =
"BailoutValue";
219 return val->name +
"=" + std::string(typestr) +
"(" + val->getRange() +
")";
222 static size_t extfind(
const std::string &
str,
const std::string &what,
size_t pos)
225 for (; pos <
str.size(); ++pos) {
228 else if (
str[pos] ==
'\"') {
230 while (pos <
str.size()) {
231 if (
str[pos] ==
'\"')
237 }
else if (
str[pos] ==
'(')
239 else if (
str[pos] ==
')')
242 return std::string::npos;
247 std::ostringstream ostr;
249 if (value == (
int)value) {
258 uint64_t high = value >> 64;
259 uint64_t low = value;
261 ostr <<
"h" << std::hex << high <<
"l";
262 ostr << std::hex << low;
272 class TrackExecution {
274 TrackExecution() : mDataIndexCounter(0), mAbortLine(-1) {}
276 int getNewDataIndex() {
277 return mDataIndexCounter++;
283 if (tok->
index() == 0)
285 const std::string &symbolicExpression = value->getSymbolicExpression();
288 if (mSymbols.find(symbolicExpression) != mSymbols.end())
290 mSymbols.insert(symbolicExpression);
291 mMap[tok].push_back(
str(value));
294 void state(
const Token *tok,
const std::string &s) {
295 mMap[tok].push_back(s);
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()));
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())
310 if (column != tok->
column())
312 const std::vector<std::string> &dumps = it.second;
313 for (
const std::string &
dump : dumps)
314 out << lineNumber <<
":" << column <<
": " <<
dump <<
"\n";
319 void report(std::ostream &out,
const Scope *functionScope)
const {
323 if (tok->
linenr() > linenr) {
325 out << getStatus(linenr) <<
" " << code << std::endl;
329 code +=
" " + tok->
str();
332 out << getStatus(linenr) <<
" " << code << std::endl;
335 void setAbortLine(
int linenr) {
336 if (linenr > 0 && (mAbortLine == -1 || linenr < mAbortLine))
340 void addError(
int linenr) {
341 mErrors.insert(linenr);
344 bool isAllOk()
const {
345 return mErrors.empty();
348 void addMissingContract(
const std::string &f) {
349 mMissingContracts.insert(f);
352 const std::set<std::string> getMissingContracts()
const {
353 return mMissingContracts;
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));
361 const char *getStatus(
int linenr)
const {
362 if (mErrors.find(linenr) != mErrors.end())
364 if (mAbortLine > 0 && linenr >= mAbortLine)
369 std::map<const Token *, std::vector<std::string>> mMap;
371 int mDataIndexCounter;
373 std::set<std::string> mSymbols;
374 std::set<int> mErrors;
375 std::set<std::string> mMissingContracts;
380 Data(
int *symbolValueIndex,
ErrorLogger *errorLogger,
const Tokenizer *tokenizer,
const Settings *settings,
const std::string ¤tFunction,
const std::vector<ExprEngine::Callback> &callbacks, TrackExecution *trackExecution)
381 : DataBase(currentFunction, settings)
382 , symbolValueIndex(symbolValueIndex)
383 , errorLogger(errorLogger)
384 , tokenizer(tokenizer)
385 , callbacks(callbacks)
387 , startTime(std::time(nullptr))
388 , mTrackExecution(trackExecution)
389 , mDataIndex(trackExecution->getNewDataIndex()) {}
391 Data(
const Data &old)
392 : DataBase(old.currentFunction, old.settings)
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) {
406 if (
auto oldValue = std::dynamic_pointer_cast<ExprEngine::ArrayValue>(it.second))
407 it.second = std::make_shared<ExprEngine::ArrayValue>(getNewSymbolName(), *oldValue);
411 using Memory = std::map<nonneg int, ExprEngine::ValuePtr>;
413 int *
const symbolValueIndex;
416 const std::vector<ExprEngine::Callback> &callbacks;
417 std::vector<ExprEngine::ValuePtr> constraints;
419 std::time_t startTime;
421 bool isC()
const override {
422 return tokenizer->
isC();
424 bool isCPP()
const override {
425 return tokenizer->
isCPP();
430 const auto it = settings->functionContracts.find(function->fullName());
431 if (it == settings->functionContracts.end())
433 const std::string &expects = it->second;
435 std::istringstream istr(expects);
436 tokenList.createTokens(istr);
437 tokenList.createAst();
439 for (
Token *tok = tokenList.front(); tok; tok = tok->
next()) {
440 for (
const Variable &arg: function->argumentList) {
441 if (arg.
name() == tok->
str()) {
454 constraints.push_back(value);
461 mTrackExecution->symbolRange(tok, 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);
473 memory[varId] = value;
477 mTrackExecution->symbolRange(tok, value);
478 structVal->
member[memberName] = value;
481 void functionCall() {
484 for (std::map<nonneg int, ExprEngine::ValuePtr>::iterator it = memory.begin(); it != memory.end();) {
485 unsigned int varid = it->first;
488 it = memory.erase(it);
494 std::string getNewSymbolName() final {
495 return "$" + std::to_string(++(*symbolValueIndex));
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);
503 return std::shared_ptr<ExprEngine::ArrayValue>();
504 auto val = std::make_shared<ExprEngine::ArrayValue>(
this, tok->
variable());
505 assignValue(tok, tok->
varId(), val);
510 const Memory::const_iterator it = memory.find(varId);
511 if (it != memory.end())
522 return std::make_shared<ExprEngine::IntRange>(std::to_string(intval), intval, intval);
529 addConstraints(value, tok->
variable()->nameToken());
530 assignValue(tok, varId, value);
535 void trackCheckContract(
const Token *tok,
const std::string &solverOutput) {
536 std::ostringstream os;
537 os <<
"checkContract:{\n";
540 std::istringstream istr(solverOutput);
541 while (std::getline(istr, line))
542 os <<
" " << line <<
"\n";
546 mTrackExecution->state(tok, os.str());
549 void trackProgramState(
const Token *tok) {
553 std::ostringstream s;
554 s <<
"D" << mDataIndex <<
":" <<
"memory:{";
556 for (
const auto &mem : memory) {
564 s << var->
name() <<
"=";
567 else if (value->name[0] ==
'$' && value->getSymbolicExpression() != value->name)
568 s <<
"(" << value->name <<
"," << value->getSymbolicExpression() <<
")";
574 if (!constraints.empty()) {
575 s <<
" constraints:{";
577 for (
const auto &constraint: constraints) {
581 s << constraint->getSymbolicExpression();
585 mTrackExecution->state(tok, s.str());
588 void addMissingContract(
const std::string &f) {
589 mTrackExecution->addMissingContract(f);
593 auto b = std::dynamic_pointer_cast<ExprEngine::BinOpResult>(v);
596 if (b->binop ==
"==")
598 else if (b->binop ==
"!=")
600 else if (b->binop ==
">=")
602 else if (b->binop ==
"<=")
604 else if (b->binop ==
">")
606 else if (b->binop ==
"<")
609 return std::make_shared<ExprEngine::BinOpResult>(binop, b->op1, b->op2);
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);
615 auto zero = std::make_shared<ExprEngine::IntRange>(
"0", 0, 0);
616 return std::make_shared<ExprEngine::BinOpResult>(
"==", v, zero);
623 constraints.push_back(condValue);
625 constraints.push_back(notValue(condValue));
629 if (!lhsValue || !rhsValue)
631 constraints.push_back(std::make_shared<ExprEngine::BinOpResult>(equals?
"==":
"!=", lhsValue, rhsValue));
638 addConstraint(std::make_shared<ExprEngine::BinOpResult>(
">=", value, std::make_shared<ExprEngine::IntRange>(std::to_string(low), low, low)),
true);
642 addConstraint(std::make_shared<ExprEngine::BinOpResult>(
"<=", value, std::make_shared<ExprEngine::IntRange>(std::to_string(high), high, high)),
true);
646 void reportError(
const Token *tok,
649 const std::string &text,
653 const std::string &functionName)
override {
654 if (errorPath.empty())
655 mTrackExecution->addError(tok->
linenr());
660 errmsg.incomplete = incomplete;
661 errmsg.function = functionName.empty() ? currentFunction : functionName;
665 std::string
str()
const {
666 std::ostringstream ret;
667 std::map<std::string, ExprEngine::ValuePtr> vars;
668 for (
const auto &mem: memory) {
674 ret <<
" @" << mem.first <<
":" << mem.second->
name;
675 getSymbols(vars, mem.second);
677 for (
const auto &var: vars) {
678 if (var.second->
name[0] ==
'$')
679 ret <<
" " <<
::str(var.second);
681 for (
const auto &c: constraints)
682 ret <<
" (" << c->getSymbolicExpression() <<
")";
687 void load(
const std::string &s) {
688 std::vector<ImportData> importData;
689 parsestr(s, &importData);
692 if (importData.empty())
695 std::map<std::string, ExprEngine::ValuePtr> symbols;
696 for (
const auto &mem: memory) {
697 getSymbols(symbols, mem.second);
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;
709 if (c->second == mem.second)
711 if (c->second ==
"?" || mem.second ==
"?")
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)
725 if (it != memory.end())
729 auto it2 = symbols.find(name);
730 if (it2 != symbols.end()) {
731 memory[varid] = it2->second;
735 auto uninitValue = std::make_shared<ExprEngine::UninitValue>();
736 symbols[name] = uninitValue;
737 memory[varid] = uninitValue;
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;
748 if (it != memory.end())
753 static void ifSplit(
const Token *tok,
const Data& thenData,
const Data& elseData) {
754 thenData.mTrackExecution->ifSplit(tok, thenData.mDataIndex, elseData.mDataIndex);
758 TrackExecution *
const mTrackExecution;
759 const int mDataIndex;
762 std::map<int, std::string> mem;
763 std::map<std::string, std::string> sym;
764 std::vector<std::string> constraints;
767 static void parsestr(
const std::string &s, std::vector<ImportData> *importData) {
769 std::istringstream istr(s);
770 while (std::getline(istr, line)) {
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)
779 if (line[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);
785 const std::string rhs = line.substr(pos, end-pos);
786 d.mem[std::stoi(lhs)] = rhs;
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);
792 const std::string::size_type end =
extfind(line,
" ", pos);
793 const std::string rhs = line.substr(pos, end-pos);
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);
800 d.constraints.push_back(c);
802 throw ExprEngineException(
nullptr,
"Internal Error: Data::parsestr(), line:" + line);
805 importData->push_back(d);
809 void getSymbols(std::map<std::string, ExprEngine::ValuePtr> &symbols,
ExprEngine::ValuePtr val)
const {
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);
821 if (
auto structValue = std::dynamic_pointer_cast<ExprEngine::StructValue>(val)) {
822 for (
const auto &memberNameValue: structValue->member)
823 getSymbols(symbols, memberNameValue.second);
831 __attribute__((no_sanitize(
"undefined")))
835 auto b = std::dynamic_pointer_cast<ExprEngine::BinOpResult>(origValue);
838 if (!b->op1 || !b->op2)
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;
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;
857 return std::make_shared<ExprEngine::IntRange>(
ExprEngine::str(v), v, v);
871 if (
auto conditionalValue = std::dynamic_pointer_cast<ExprEngine::ConditionalValue>(value)) {
883 value = value & (((
int128_t)1 << bits) - 1);
885 if (sign ==
's' && value & (1ULL << (bits - 1)))
886 value |= ~(((
int128_t)1 << bits) - 1);
892 , pointer(pointer), nullPointer(nullPointer), uninitPointer(uninitPointer)
894 this->size.push_back(
size);
900 , pointer(var && var->isPointer()), nullPointer(var && var->isPointer()), uninitPointer(var && var->isPointer())
905 size.push_back(std::make_shared<ExprEngine::IntRange>(std::to_string(dim.num), dim.num, dim.num));
914 while (initToken && initToken->
str() !=
"=")
919 val = std::make_shared<ExprEngine::UninitValue>();
930 , pointer(arrayValue.pointer), nullPointer(arrayValue.nullPointer), uninitPointer(arrayValue.uninitPointer)
931 , data(arrayValue.data), size(arrayValue.size)
937 std::string r = getSymbolicExpression();
939 r += std::string(r.empty() ?
"" :
",") +
"null";
941 r += std::string(r.empty() ?
"" :
",") +
"->?";
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);
961 data.push_back(indexAndValue);
971 data.push_back(indexAndValue);
978 return v1->name == v2->name;
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))
997 for (
const auto &indexAndValue : data) {
998 if (::
isEqual(index, indexAndValue.index))
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)));
1009 if (
auto i = std::dynamic_pointer_cast<ExprEngine::IntRange>(index)) {
1010 if (i->minValue >= 0 && i->minValue == i->maxValue) {
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)));
1018 int cmin = 0, cmax = 0;
1019 for (
char c : stringLiteral->string) {
1025 ret.push_back(std::pair<ValuePtr,ValuePtr>(indexAndValue.index, std::make_shared<ExprEngine::IntRange>(
"", cmin, cmax)));
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)));
1035 ret.push_back(std::pair<ValuePtr,ValuePtr>(indexAndValue.index, indexAndValue.value));
1038 if (ret.size() == 1)
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);
1053 std::ostringstream ostr;
1056 for (
const auto& condvalue : values) {
1064 << (cond ? cond->getSymbolicExpression() : std::string(
"(null)"))
1066 << value->getSymbolicExpression()
1075 std::ostringstream ostr;
1079 for (
const auto &dim: size)
1080 ostr <<
"[" << (dim ? dim->name : std::string(
"(null)")) <<
"]";
1082 for (
const auto &indexAndValue : data) {
1084 << (!indexAndValue.index ? std::string(
":") : indexAndValue.index->name)
1088 << indexAndValue.value->name
1090 << indexAndValue.value->getSymbolicExpression()
1093 ostr << indexAndValue.value->name;
1100 std::ostringstream ostr;
1103 for (
const auto& m: member) {
1104 const std::string &memberName = m.first;
1105 auto memberValue = m.second;
1109 ostr << memberName <<
"=" << (memberValue ? memberValue->getSymbolicExpression() : std::string(
"(null)"));
1117 return sign + std::to_string(bits) +
"(" + inputValue->getSymbolicExpression() +
")";
1124 using ValueExpr = std::map<std::string, z3::expr>;
1125 using AssertionList = std::vector<z3::expr>;
1127 class BailoutValueException :
public ExprEngineException {
1129 BailoutValueException() : ExprEngineException(nullptr,
"Incomplete analysis") {}
1132 z3::context context;
1133 ValueExpr valueExpr;
1134 AssertionList assertionList;
1136 void addAssertions(z3::solver &solver)
const {
1137 for (
const auto &assertExpr : assertionList)
1138 solver.add(assertExpr);
1141 void addConstraints(z3::solver &solver,
const Data* data) {
1142 for (
const auto &constraint : data->constraints) {
1144 solver.add(getConstraintExpr(constraint));
1145 }
catch (
const BailoutValueException &) {}
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));
1161 z3::expr addFloat(
const std::string &name) {
1162 z3::expr e = z3_fp_const(name);
1163 valueExpr.emplace(name, e);
1168 auto op1 = getExpr(b->
op1);
1169 auto op2 = getExpr(b->
op2);
1173 if (z3_is_fp(op1) || z3_is_fp(op2)) {
1179 if (b->
binop ==
"+")
1181 if (b->
binop ==
"-")
1183 if (b->
binop ==
"*")
1185 if (b->
binop ==
"/")
1187 if (b->
binop ==
"%")
1188 #if Z3_VERSION_INT >= GET_VERSION_INT(4,8,5)
1193 if (b->
binop ==
"==")
1194 return int_expr(op1) == int_expr(op2);
1195 if (b->
binop ==
"!=")
1197 if (b->
binop ==
">=")
1199 if (b->
binop ==
"<=")
1201 if (b->
binop ==
">")
1203 if (b->
binop ==
"<")
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);
1218 throw ExprEngineException(
nullptr,
"Can not solve expressions, operand value is null");
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())
1227 return addInt(v->name, intRange->minValue, intRange->maxValue);
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);
1234 auto it = valueExpr.find(v->name);
1235 if (it != valueExpr.end())
1237 return addFloat(v->name);
1240 if (
auto b = std::dynamic_pointer_cast<ExprEngine::BinOpResult>(v)) {
1241 return getExpr(b.get());
1244 if (
auto c = std::dynamic_pointer_cast<ExprEngine::ConditionalValue>(v)) {
1245 if (c->values.empty())
1246 throw ExprEngineException(
nullptr,
"ConditionalValue is empty");
1248 if (c->values.size() == 1)
1249 return getExpr(c->values[0].second);
1251 return z3::ite(getExpr(c->values[1].first),
1252 getExpr(c->values[1].second),
1253 getExpr(c->values[0].second));
1256 if (
auto integerTruncation = std::dynamic_pointer_cast<ExprEngine::IntegerTruncation>(v)) {
1257 return getExpr(integerTruncation->inputValue);
1262 return context.int_val(0);
1264 throw ExprEngineException(
nullptr,
"Internal error: Unhandled value type");
1269 return (getExpr(v) != 0);
1270 return bool_expr(getExpr(v));
1273 z3::expr bool_expr(z3::expr e) {
1279 return e != z3_fp_val(0.0,
"0.0");
1284 z3::expr int_expr(z3::expr e) {
1286 return z3::ite(e, context.int_val(1), context.int_val(0));
1294 z3::expr z3_fp_const(
const std::string &name) {
1295 return context.real_const(name.c_str());
1298 z3::expr z3_fp_val(
long double value, std::string name) {
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());
1305 bool z3_is_fp(z3::expr e)
const {
1309 void z3_to_fp(z3::expr &e) {
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));
1319 return context.int_val((
long long)(value));
1326 const Data *data =
dynamic_cast<const Data *
>(dataBase);
1327 if (data->constraints.empty())
1332 z3::solver solver(exprData.context);
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;
1340 }
catch (
const ExprData::BailoutValueException &) {
1342 }
catch (
const ExprEngineException &) {
1353 if (value < minValue || value > maxValue)
1356 const Data *data =
dynamic_cast<const Data *
>(dataBase);
1357 if (data->constraints.empty())
1362 z3::solver solver(exprData.context);
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;
1372 }
catch (
const ExprData::BailoutValueException &) {
1374 }
catch (
const ExprEngineException &) {
1385 if (maxValue <= value)
1388 const Data *data =
dynamic_cast<const Data *
>(dataBase);
1389 if (data->constraints.empty())
1394 z3::solver solver(exprData.context);
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;
1404 }
catch (
const ExprData::BailoutValueException &) {
1406 }
catch (
const ExprEngineException &) {
1417 if (minValue >= value)
1420 const Data *data =
dynamic_cast<const Data *
>(dataBase);
1421 if (data->constraints.empty())
1426 z3::solver solver(exprData.context);
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;
1436 }
catch (
const ExprData::BailoutValueException &) {
1438 }
catch (
const ExprEngineException &) {
1451 return value >= f - 0.00001 && value <= f + 0.00001;
1453 const Data *data =
dynamic_cast<const Data *
>(dataBase);
1454 if (data->constraints.empty())
1459 z3::solver solver(exprData.context);
1461 z3::expr e = exprData.addFloat(name);
1462 exprData.addConstraints(solver, data);
1463 exprData.addAssertions(solver);
1465 #if Z3_VERSION_INT >= GET_VERSION_INT(4,8,0)
1466 z3::expr val_e = exprData.context.fpa_val(
static_cast<double>(value));
1468 z3::expr val_e = exprData.context.real_val(value);
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;
1475 }
catch (
const ExprData::BailoutValueException &) {
1477 }
catch (
const ExprEngineException &) {
1488 if (value < minValue || value > maxValue)
1491 const Data *data =
dynamic_cast<const Data *
>(dataBase);
1492 if (data->constraints.empty())
1499 z3::solver solver(exprData.context);
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;
1509 }
catch (
const ExprData::BailoutValueException &) {
1511 }
catch (
const ExprEngineException &) {
1522 if (value < minValue || value > maxValue)
1525 const Data *data =
dynamic_cast<const Data *
>(dataBase);
1526 if (data->constraints.empty())
1533 z3::solver solver(exprData.context);
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;
1543 }
catch (
const ExprData::BailoutValueException &) {
1545 }
catch (
const ExprEngineException &) {
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;
1569 }
catch (
const ExprData::BailoutValueException &) {
1571 }
catch (
const ExprEngineException &) {
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;
1595 }
catch (
const ExprData::BailoutValueException &) {
1597 }
catch (
const ExprEngineException &) {
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;
1621 }
catch (
const ExprData::BailoutValueException &) {
1623 }
catch (
const ExprEngineException &) {
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;
1647 }
catch (
const ExprData::BailoutValueException &) {
1649 }
catch (
const ExprEngineException &) {
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);
1668 std::ostringstream os;
1670 switch (solver.check()) {
1672 os <<
"\nz3::sat\n";
1675 os <<
"\nz3::unsat\n";
1678 os <<
"\nz3::unknown\n";
1682 }
catch (
const z3::exception &exception) {
1683 std::ostringstream os;
1684 os <<
"\nz3:" << exception <<
"\n";
1701 case ValueType::Type::BOOL:
1703 case ValueType::Type::CHAR:
1705 case ValueType::Type::SHORT:
1707 case ValueType::Type::INT:
1709 case ValueType::Type::LONG:
1711 case ValueType::Type::LONGLONG:
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);
1730 return std::make_shared<ExprEngine::IntRange>(name, -((
int128_t)1 << (bits - 1)), ((
int128_t)1 << (bits - 1)) - 1);
1735 return std::make_shared<ExprEngine::FloatRange>(name, -std::numeric_limits<float>::infinity(), std::numeric_limits<float>::infinity());
1742 if (valueType && valueType->
pointer) {
1745 return std::make_shared<ExprEngine::ArrayValue>(data.getNewSymbolName(), bufferSize, val,
true,
true,
false);
1748 if (!valueType || valueType->
pointer)
1753 value = std::make_shared<ExprEngine::IntRange>(data.getNewSymbolName(), -128, 127);
1760 return std::make_shared<ExprEngine::ArrayValue>(data.getNewSymbolName(), bufferSize, value,
false,
false,
false);
1770 f(tok, *value, dataBase);
1771 }
catch (
const ExprEngineException &e) {
1772 throw ExprEngineException(tok, e.what);
1785 const Token *tok2 = tok;
1798 index =
simplifyValue(std::make_shared<ExprEngine::BinOpResult>(
"*", dim, rawIndex));
1805 totalIndex =
simplifyValue(std::make_shared<ExprEngine::BinOpResult>(
"+", index, totalIndex));
1807 if (arrayValue.
size.size() >= nr) {
1808 if (arrayValue.
size[nr-1]) {
1810 dim = arrayValue.
size[nr-1];
1812 dim =
simplifyValue(std::make_shared<ExprEngine::BinOpResult>(
"*", dim, arrayValue.
size[nr-1]));
1826 call(data.callbacks, tok, retval, &data);
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)
1849 return std::make_shared<ExprEngine::IntRange>(
ExprEngine::str(newValue), newValue, newValue);
1852 auto typeIntRange = std::dynamic_pointer_cast<ExprEngine::IntRange>(typeRange);
1854 if (range->minValue >= typeIntRange->minValue && range->maxValue <= typeIntRange->maxValue)
1859 return std::make_shared<ExprEngine::IntegerTruncation>(data.getNewSymbolName(), val, bits, valueType->
sign == ValueType::Sign::SIGNED ?
's' :
'u');
1869 if (expr->
varId() > 0) {
1870 data.assignValue(expr, expr->
varId(), value);
1871 }
else if (expr->
str() ==
"[") {
1873 const Token *arrayToken = expr;
1878 if (
auto arrayValue = data.getArrayValue(arrayToken)) {
1880 if (arrayToken->
variable() && arrayToken->
variable()->nameToken() == arrayToken) {
1885 bool loopAssign =
false;
1886 if (
auto loopValue = std::dynamic_pointer_cast<ExprEngine::IntRange>(indexValue)) {
1887 if (loopValue->loopScope == expr->
scope()) {
1889 for (
auto i = loopValue->minValue; i <= loopValue->maxValue; ++i)
1890 arrayValue->assign(std::make_shared<ExprEngine::IntRange>(
ExprEngine::str(i), i, i), value);
1894 arrayValue->assign(indexValue, value);
1899 call(data.callbacks, indexToken, indexValue, &data);
1904 auto val = std::dynamic_pointer_cast<ExprEngine::AddressOfValue>(pval);
1906 data.assignValue(expr, val->
varId, value);
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);
1912 auto b = std::dynamic_pointer_cast<ExprEngine::BinOpResult>(pval);
1913 if (b && b->
binop ==
"+") {
1914 std::shared_ptr<ExprEngine::ArrayValue> arr;
1917 arr = std::dynamic_pointer_cast<ExprEngine::ArrayValue>(b->
op1);
1920 arr = std::dynamic_pointer_cast<ExprEngine::ArrayValue>(b->
op2);
1923 if (arr && offset) {
1924 arr->assign(offset, value);
1931 data.assignStructMember(expr, &*std::static_pointer_cast<ExprEngine::StructValue>(structVal), expr->
next()->
str(), value);
1945 if (!rhsValue && vt2 && vt2->
pointer == 0) {
1951 rhsValue = std::make_shared<ExprEngine::BailoutValue>();
1955 if (tok->
str() ==
"=")
1956 assignValue = rhsValue;
1959 std::string binop(tok->
str());
1960 binop = binop.substr(0, binop.size() - 1);
1962 assignValue =
simplifyValue(std::make_shared<ExprEngine::BinOpResult>(binop, lhsValue, rhsValue));
1968 call(data.callbacks, tok, assignValue, &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)));
1981 auto binOp = std::dynamic_pointer_cast<ExprEngine::BinOpResult>(retVal);
1982 if (binOp && !binOp->op1)
1984 call(data.callbacks, tok, retVal, &data);
1989 static void checkContract(Data &data,
const Token *tok,
const Function *
function,
const std::vector<ExprEngine::ValuePtr> &argValues)
1993 z3::solver solver(exprData.context);
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");
2002 bool bailoutValue =
false;
2003 for (
nonneg int i = 0; i < argValues.size(); ++i) {
2004 const Variable *argvar =
function->getArgumentVar(i);
2010 bailoutValue =
true;
2015 solver.add(exprData.getExpr(data.getValue(argvar->
declarationId(),
nullptr,
nullptr)) == exprData.getExpr(argValue));
2019 if (!bailoutValue) {
2020 for (
const auto &constraint : data.constraints)
2021 solver.add(exprData.getConstraintExpr(constraint));
2023 exprData.addAssertions(solver);
2026 std::ostringstream os;
2028 data.trackCheckContract(tok, os.str());
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,
2039 "Function '" + function->name() +
"' is called, can not determine that its contract '" + functionExpects +
"' is always met.",
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,
2055 "Function '" + function->name() +
"' is called, can not determine that its contract '" + functionExpects +
"' is always met.",
2071 retVal = std::make_shared<ExprEngine::IntRange>(std::to_string(value), value, value);
2073 retVal = std::make_shared<ExprEngine::IntRange>(data.getNewSymbolName(), 1, 0x7fffffff);
2075 call(data.callbacks, tok, retVal, &data);
2082 while (functionScope->
isExecutable() && functionScope->
type != Scope::ScopeType::eFunction)
2083 functionScope = functionScope->
nestedIn;
2084 if (functionScope == tok->
astOperand1()->function()->functionScope)
2086 for (
const auto &errorPathItem: data.errorPath) {
2087 if (errorPathItem.first == tok) {
2094 const std::vector<const Token *> &argTokens =
getArguments(tok);
2095 std::vector<ExprEngine::ValuePtr> argValues;
2096 for (
const Token *argtok : argTokens) {
2098 argValues.push_back(val);
2101 if (!argtok->valueType() || (argtok->valueType()->constness & 1) == 1)
2103 if (
auto arrayValue = std::dynamic_pointer_cast<ExprEngine::ArrayValue>(val)) {
2108 }
else if (
auto addressOf = std::dynamic_pointer_cast<ExprEngine::AddressOfValue>(val)) {
2111 if (vt.
isIntegral() && argtok->valueType()->pointer == 1)
2116 call(data.callbacks, tok, std::make_shared<ExprEngine::FunctionCallArgumentValues>(argValues), &data);
2120 const std::string &functionName =
function->fullName();
2122 const auto contractIt = data.settings->functionContracts.find(functionName);
2123 if (contractIt != data.settings->functionContracts.end()) {
2125 checkContract(data, tok,
function, argValues);
2127 }
else if (!argValues.empty()) {
2129 for (
const auto &v: argValues)
2132 data.addMissingContract(functionName);
2138 const Scope *
const functionScope =
function->functionScope;
2140 std::map<const Token *, nonneg int> refs;
2141 for (
const Variable &arg: function->argumentList) {
2147 data.assignValue(function->functionScope->bodyStart, arg.
declarationId(), argValues[argnr]);
2153 data.errorPath.push_back(
ErrorPathItem(tok,
"Calling " + function->name()));
2156 for (
auto ref: refs) {
2157 auto v = data.getValue(ref.second,
nullptr,
nullptr);
2160 }
catch (ExprEngineException &e) {
2161 data.errorPath.pop_back();
2165 data.errorPath.pop_back();
2169 else if (
const auto *f = data.settings->library.getAllocFuncInfo(tok->
astOperand1())) {
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();
2182 call(data.callbacks, tok, result, &data);
2183 data.functionCall();
2190 throw ExprEngineException(tok,
"FIXME: lambda");
2191 const Token *tok2 = tok;
2194 auto arrayValue = data.getArrayValue(tok2->
astOperand1());
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);
2220 return std::make_shared<ExprEngine::UninitValue>();
2222 auto range = std::make_shared<ExprEngine::UninitValue>();
2227 bool uninitPointer =
false, nullPointer =
false;
2229 nullPointer = std::static_pointer_cast<ExprEngine::ArrayValue>(val)->nullPointer;
2230 uninitPointer = std::static_pointer_cast<ExprEngine::ArrayValue>(val)->uninitPointer;
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);
2239 call(data.callbacks, tok, val, &data);
2244 call(data.callbacks, tok, val, &data);
2251 auto v = std::make_shared<ExprEngine::BailoutValue>();
2252 call(data.callbacks, tok, v, &data);
2255 std::shared_ptr<ExprEngine::StructValue> structValue = std::dynamic_pointer_cast<ExprEngine::StructValue>(
executeExpression(tok->
astOperand1(), data));
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()) {
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);
2266 auto memberValue = structValue->getValueOfMember(tok->
astOperand2()->str());
2267 call(data.callbacks, tok, memberValue, &data);
2280 v = std::make_shared<ExprEngine::BailoutValue>();
2281 call(data.callbacks, tok, v, &data);
2286 call(data.callbacks, tok, memberValue, &data);
2295 const auto oldValue = data.getValue(tok->
varId(), tok->
valueType(), tok);
2296 if (oldValue && (oldValue->isUninit(&data)))
2297 call(data.callbacks, tok, oldValue, &data);
2320 if (tok->
str() ==
"?") {
2326 call(data.callbacks, tok, v2, &data);
2330 Data trueData(data);
2331 trueData.addConstraint(v1,
true);
2334 Data falseData(data);
2335 falseData.addConstraint(v1,
false);
2338 auto result =
simplifyValue(std::make_shared<ExprEngine::BinOpResult>(
"?", v1, std::make_shared<ExprEngine::BinOpResult>(
":", trueValue, falseValue)));
2339 call(data.callbacks, tok, result, &data);
2342 }
else if (tok->
str() ==
"&&" || tok->
str() ==
"||") {
2344 data2.addConstraint(v1, tok->
str() ==
"&&");
2351 auto result =
simplifyValue(std::make_shared<ExprEngine::BinOpResult>(tok->
str(), v1, v2));
2352 call(data.callbacks, tok, result, &data);
2355 if (tok->
str() ==
"&&" && (v1 || v2)) {
2356 auto result = v1 ? v1 : v2;
2357 call(data.callbacks, tok, result, &data);
2365 auto addr = std::make_shared<ExprEngine::AddressOfValue>(data.getNewSymbolName(), tok->
astOperand1()->varId());
2366 call(data.callbacks, tok, addr, &data);
2376 pval = std::make_shared<ExprEngine::ArrayValue>(data.getNewSymbolName(),
ExprEngine::ValuePtr(), v,
true,
false,
false);
2379 call(data.callbacks, tok, v, &data);
2382 auto addressOf = std::dynamic_pointer_cast<ExprEngine::AddressOfValue>(pval);
2384 auto val = data.getValue(addressOf->varId, tok->
valueType(), tok);
2385 call(data.callbacks, tok, val, &data);
2388 auto pointer = std::dynamic_pointer_cast<ExprEngine::ArrayValue>(pval);
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);
2407 auto result =
simplifyValue(std::make_shared<ExprEngine::BinOpResult>(
"==", v, zero));
2408 call(data.callbacks, tok, result, &data);
2415 call(data.callbacks, tok, val, &data);
2422 auto val = std::make_shared<ExprEngine::IntRange>(std::to_string(intval), intval, intval);
2423 call(data.callbacks, tok, val, &data);
2431 auto v = std::make_shared<ExprEngine::FloatRange>(tok->
str(), value, value);
2432 call(data.callbacks, tok, v, &data);
2436 auto v = std::make_shared<ExprEngine::IntRange>(tok->
str(), value, value);
2437 call(data.callbacks, tok, v, &data);
2443 const std::string& s = tok->
str();
2444 return std::make_shared<ExprEngine::StringLiteralValue>(data.getNewSymbolName(), s.substr(1, s.size()-2));
2450 throw TerminateExpression();
2452 if (tok->
str() ==
"return")
2459 if (tok->
tokType() == Token::Type::eIncDecOp)
2465 if (tok->
str() ==
"(") {
2471 if (tok->
str() ==
".")
2476 return std::make_shared<ExprEngine::IntRange>(std::to_string(v), v, v);
2503 if (tok->
tokType() == Token::Type::eString)
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);
2526 }
else if (std::dynamic_pointer_cast<ExprEngine::StringLiteralValue>(condValue)) {
2529 }
else if (
auto f = std::dynamic_pointer_cast<ExprEngine::FloatRange>(condValue)) {
2530 canBeFalse = f->isEqual(&data, 0);
2533 return std::make_tuple(canBeFalse, canBeTrue);
2538 if (data.recursion > 20)
2544 Recursion(
int *var,
int value) : var(var), value(value) {
2548 if (*var >= value) *var = value;
2553 Recursion updateRecursion(&data.recursion, data.recursion);
2555 const std::time_t stopTime = data.startTime + data.settings->bugHuntingCheckFunctionMaxTime;
2557 for (
const Token *tok = start; tok != end; tok = tok->
next()) {
2559 data.trackProgramState(tok);
2560 if (tok->
str() ==
";") {
2570 if (std::time(
nullptr) > stopTime)
2576 throw ExprEngineException(tok,
"__CPPCHECK_BAILOUT__");
2579 tok = tok->
tokAt(4);
2583 if (tok->
str() ==
"break") {
2595 Data catchData(data);
2597 execute(catchTok, end, catchData);
2598 catchTok = catchTok->
link();
2606 bool foundInRhs =
false;
2608 if (rhs->varId()==tok->varId()) {
2610 return ChildrenToVisit::done;
2615 tok = tok->
tokAt(2);
2619 }
else if (tok->
variable()->isArray()) {
2620 data.assignValue(tok, tok->
varId(), std::make_shared<ExprEngine::ArrayValue>(&data, tok->
variable()));
2635 bool canBeFalse, canBeTrue;
2638 Data &thenData(data);
2639 Data elseData(data);
2640 if (canBeFalse && canBeTrue) {
2641 thenData.addConstraint(condValue,
true);
2642 elseData.addConstraint(condValue,
false);
2645 Data::ifSplit(tok, thenData, elseData);
2648 const Token *thenEnd = thenStart->
link();
2650 const Token *exceptionToken =
nullptr;
2651 std::string exceptionMessage;
2652 auto exec = [&](
const Token *tok1,
const Token *tok2, Data& data) {
2655 }
catch (ExprEngineException &e) {
2656 if (!exceptionToken || (e.tok &&
precedes(e.tok, exceptionToken))) {
2657 exceptionToken = e.tok;
2658 exceptionMessage = e.what;
2664 exec(thenStart->
next(), end, thenData);
2669 exec(elseStart->
next(), end, elseData);
2671 exec(thenEnd, end, elseData);
2676 throw ExprEngineException(exceptionToken, exceptionMessage);
2678 return (canBeTrue ? thenData.str() : std::string()) +
2679 (canBeFalse ? elseData.str() : std::string());
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) {
2695 }
catch (ExprEngineException &e) {
2696 if (!exceptionToken || (e.tok &&
precedes(e.tok, exceptionToken))) {
2697 exceptionToken = e.tok;
2698 exceptionMessage = e.what;
2702 for (
const Token *tok2 = bodyStart->
next(); tok2 != bodyEnd; tok2 = tok2->
next()) {
2703 if (tok2->str() ==
"{")
2704 tok2 = tok2->
link();
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);
2713 Data caseData(data);
2714 exec(tok2->tokAt(2), end, caseData);
2716 defaultStart = tok2;
2718 exec(defaultStart ? defaultStart : bodyEnd, end, defaultData);
2720 throw ExprEngineException(exceptionToken, exceptionMessage);
2726 bool hasKnownInitValue, partialCond;
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);
2733 loopValues->loopScope = tok->
next()->
scope();
2735 if (initValue > lastValue) {
2747 bool canBeFalse =
false, canBeTrue =
true;
2748 if (tok->
str() ==
"while")
2751 Data &bodyData(data);
2752 Data noexecData(data);
2753 if (canBeFalse && canBeTrue) {
2754 bodyData.addConstraint(condValue,
true);
2757 Data::ifSplit(tok, bodyData, noexecData);
2760 const Token *bodyEnd = bodyStart->
link();
2764 std::set<int> changedVariables;
2765 for (
const Token *tok2 = tok; tok2 != bodyEnd; tok2 = tok2->
next()) {
2771 throw ExprEngineException(tok2,
"Unhandled assignment in loop");
2773 const Token *structToken = lhs;
2777 bodyData.assignValue(structToken, structToken->
varId(), std::make_shared<ExprEngine::BailoutValue>());
2778 changedVariables.insert(structToken->
varId());
2785 throw ExprEngineException(tok2,
"Unhandled assignment in loop");
2788 throw ExprEngineException(tok2,
"Unhandled assignment in loop");
2789 const std::string &memberName = tok2->previous()->str();
2798 throw ExprEngineException(tok2,
"Unhandled assignment in loop");
2803 auto structVal = std::dynamic_pointer_cast<ExprEngine::StructValue>(structVal1);
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);
2815 throw ExprEngineException(tok2,
"Unhandled assignment in loop");
2818 bodyData.assignStructMember(tok2, &*structVal, memberName, memberValue);
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>());
2832 throw ExprEngineException(tok2,
"Unhandled assignment in loop");
2834 int varid = lhs->
varId();
2835 if (changedVariables.find(varid) != changedVariables.end())
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);
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>());
2849 }
else if (
Token::Match(tok2,
"++|--") && tok2->astOperand1() && tok2->astOperand1()->variable()) {
2852 int varid = vartok->
varId();
2853 if (changedVariables.find(varid) != changedVariables.end())
2855 changedVariables.insert(varid);
2856 auto oldValue = bodyData.getValue(varid,
nullptr,
nullptr);
2858 call(bodyData.callbacks, tok2, oldValue, &bodyData);
2864 const Token *exceptionToken =
nullptr;
2865 std::string exceptionMessage;
2866 auto exec = [&](
const Token *tok1,
const Token *tok2, Data& data) {
2869 }
catch (ExprEngineException &e) {
2870 if (!exceptionToken || (e.tok &&
precedes(e.tok, exceptionToken))) {
2871 exceptionToken = e.tok;
2872 exceptionMessage = e.what;
2878 exec(bodyStart->
next(), end, bodyData);
2880 exec(bodyEnd, end, noexecData);
2883 throw ExprEngineException(exceptionToken, exceptionMessage);
2885 return (canBeTrue ? bodyData.str() : std::string()) +
2886 (canBeFalse ? noexecData.str() : std::string());
2901 executeFunction(functionScope, errorLogger, tokenizer, settings, callbacks, report);
2902 }
catch (
const ExprEngineException &e) {
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) {
2908 std::string functionName = functionScope->
function->
name();
2909 std::cout <<
"Verify: Aborted analysis of function '" << functionName <<
"': " << e.what() << std::endl;
2910 }
catch (
const TerminateExpression &) {
2920 std::shared_ptr<ExprEngine::StructValue> structValue = std::make_shared<ExprEngine::StructValue>(data.getNewSymbolName());
2921 auto uninitValue = std::make_shared<ExprEngine::UninitValue>();
2923 if (uninitData && !member.
isInit()) {
2925 structValue->member[member.
name()] = uninitValue;
2929 structValue->member[member.
name()] = uninitValue;
2936 data.assignStructMember(tok, structValue.get(), member.
name(), memberValue);
2947 if (!valueType || valueType->
type == ValueType::Type::UNKNOWN_TYPE)
2949 if (!valueType || valueType->
type == ValueType::Type::UNKNOWN_TYPE) {
2952 return std::make_shared<ExprEngine::UninitValue>();
2958 return std::make_shared<ExprEngine::UninitValue>();
2959 auto bufferSize = std::make_shared<ExprEngine::IntRange>(data.getNewSymbolName(), 1,
MAX_BUFFER_SIZE);
2961 if (valueType->
type == ValueType::Type::RECORD)
2969 pointerValue = std::make_shared<ExprEngine::UninitValue>();
2971 return std::make_shared<ExprEngine::ArrayValue>(data.getNewSymbolName(), bufferSize, pointerValue,
true,
true, var.
isLocal() && !var.
isStatic());
2974 return std::make_shared<ExprEngine::ArrayValue>(&data, &var);
2978 value = std::make_shared<ExprEngine::UninitValue>();
2981 data.addConstraints(value, var.
nameToken());
2984 if (valueType->
type == ValueType::Type::RECORD) {
2985 bool uninitData =
true;
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);
3014 const std::string currentFunction =
function->
fullName();
3016 int symbolValueIndex = 0;
3017 TrackExecution trackExecution;
3018 Data data(&symbolValueIndex, errorLogger, tokenizer, settings, currentFunction, callbacks, &trackExecution);
3020 for (
const Variable &arg : function->argumentList)
3027 const std::time_t stopTime = data.startTime + data.settings->bugHuntingCheckFunctionMaxTime;
3031 }
catch (
const ExprEngineException &e) {
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)
3039 if (
Token::Match(tok,
"return|throw|while|if|for (")) {
3043 call(callbacks, tok, bailoutValue, &data);
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);
3061 if (bugHuntingReport) {
3062 std::set<std::string> intvars;
3064 if (scope.isExecutable())
3068 for (
const Scope *s = &scope; s->
type != Scope::ScopeType::eGlobal; s = s->nestedIn) {
3069 if (s->isExecutable()) {
3073 path = s->className +
"::" + path;
3077 for (
const Variable &var: scope.varlist) {
3079 intvars.insert(path + var.
name());
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;
3092 std::vector<ExprEngine::Callback> callbacks;
3095 std::ostringstream report;
3098 std::cout << report.str();
3099 else if (errorLogger)
3106 std::cout <<
"NULL";
3109 switch (val->type) {
3111 std::cout <<
"AddressOfValue(" << std::dynamic_pointer_cast<ExprEngine::AddressOfValue>(val)->varId <<
")";
3114 std::cout <<
"ArrayValue";
3117 std::cout <<
"BailoutValue";
3120 auto b = std::dynamic_pointer_cast<ExprEngine::BinOpResult>(val);
3123 std::cout <<
" " << b->
binop <<
" ";
3129 std::cout <<
"ConditionalValue";
3132 std::cout <<
"FloatRange";
3135 std::cout <<
"FunctionCallArgumentValues(";
3136 const char *sep =
"";
3137 for (
const auto &arg: std::dynamic_pointer_cast<ExprEngine::FunctionCallArgumentValues>(val)->argValues) {
3141 std::cout <<
"NULL";
3149 std::cout <<
"IntRange";
3152 std::cout <<
"IntegerTruncation(";
3153 dumpRecursive(std::dynamic_pointer_cast<ExprEngine::IntegerTruncation>(val)->inputValue);
3157 std::cout <<
"StringLiteralValue";
3160 std::cout <<
"StructValue";
3163 std::cout <<
"UninitValue";
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)
bool precedes(const Token *tok1, const Token *tok2)
If tok2 comes after tok1.
std::vector< const Token * > getArguments(const Token *ftok)
Get arguments (AST)
void visitAstNodes(T *ast, const TFunc &visitor)
Visit AST nodes recursively.
void addBughuntingChecks(std::vector< ExprEngine::Callback > *callbacks)
This is an interface, which the class responsible of error logging should implement.
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()
std::string getSymbolicExpression() const override
std::vector< IndexAndValue > data
std::vector< ValuePtr > size
ArrayValue(const std::string &name, ValuePtr size, ValuePtr value, bool pointer, bool nullPointer, bool uninitPointer)
void assign(ValuePtr index, ValuePtr value)
ConditionalValue::Vector read(ValuePtr index) const
std::string getRange() const override
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
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
std::string getSymbolicExpression() const override
bool isUninit(const DataBase *dataBase) const override
const std::string & name() const
std::string fullName() const
static bool isFloat(const std::string &str)
static bigint toLongNumber(const std::string &str)
static double toDoubleNumber(const std::string &str)
static std::string toString(T value)
std::list< Variable > varlist
Function * function
function info for this function
const Token * bodyStart
'{' token
const Token * bodyEnd
'}' token
bool isExecutable() const
This is just a container for general settings so that we don't need to pass individual values to func...
std::string bugHuntingReport
Filename for bug hunting report.
bool debugBugHunting
Debug bug hunting.
static bool terminated()
termination requested?
bool verbose
Is –verbose given?
SeverityType
Message severities.
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.
static bool Match(const Token *tok, const char pattern[], nonneg int varid=0)
Match given token (or list of tokens) to a pattern list.
const std::string & originalName() const
bool hasKnownIntValue() const
MathLib::bigint getKnownIntValue() const
const ValueType * valueType() const
void astOperand1(Token *tok)
bool isUnaryOp(const std::string &s) const
const Token * tokAt(int index) const
bool hasCppcheckAttributes() const
Token::Type tokType() const
void astOperand2(Token *tok)
void scope(const Scope *s)
Associate this token with given scope.
void link(Token *linkToToken)
Create link to given token.
const Token * linkAt(int index) const
bool isAssignmentOp() const
bool getCppcheckAttribute(TokenImpl::CppcheckAttributes::Type type, MathLib::bigint *value) const
nonneg int linenr() const
void variable(const Variable *v)
Associate this token with given variable.
static bool simpleMatch(const Token *tok, const char(&pattern)[count])
Match given token (or list of tokens) to a pattern list.
nonneg int fileIndex() const
nonneg int column() const
void astParent(Token *tok)
The main purpose is to tokenize the source code.
TokenList list
Token list: stores all tokens.
bool isC() const
Is the code C.
const SymbolDatabase * getSymbolDatabase() const
bool isCPP() const
Is the code CPP.
enum Type::NeedInitialization needInitialization
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=**
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
static ExprEngine::ValuePtr executeKnownMacro(const Token *tok, Data &data)
static bool isEqual(ExprEngine::ValuePtr v1, ExprEngine::ValuePtr v2)
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)
static ExprEngine::ValuePtr executeBinaryOp(const Token *tok, Data &data)
static bool isNonOverlapping(ExprEngine::ValuePtr v1, ExprEngine::ValuePtr v2)
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)
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)
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)
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.
static size_t extfind(const std::string &str, const std::string &what, size_t pos)
std::pair< const Token *, std::string > ErrorPathItem
std::list< ErrorPathItem > ErrorPath
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
@ FunctionCallArgumentValues
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
std::string str(int128_t)
static void indent(std::string &str, const nonneg int indent1, const nonneg int indent2)
#define bailout(tokenlist, errorLogger, tok, what)