diff --git a/lib/exprengine.cpp b/lib/exprengine.cpp index 84297671e..484d59188 100644 --- a/lib/exprengine.cpp +++ b/lib/exprengine.cpp @@ -598,6 +598,9 @@ ExprEngine::BinOpResult::IntOrFloatValue ExprEngine::BinOpResult::evaluate(int t ExprEngine::BinOpResult::IntOrFloatValue ExprEngine::BinOpResult::evaluateOperand(int test, const std::map &valueBit, ExprEngine::ValuePtr value) const { + if (!value) + throw std::runtime_error("Internal error: null value"); + auto binOpResult = std::dynamic_pointer_cast(value); if (binOpResult) return binOpResult->evaluate(test, valueBit); @@ -1097,7 +1100,41 @@ void ExprEngine::runChecks(ErrorLogger *errorLogger, const Tokenizer *tokenizer, } }; + std::function integerOverflow = [&](const Token *tok, const ExprEngine::Value &value) { + if (!tok->isArithmeticalOp() || !tok->valueType() || !tok->valueType()->isIntegral() || tok->valueType()->pointer > 0) + return; + + const ExprEngine::BinOpResult *b = dynamic_cast(&value); + if (!b) + return; + + ExprEngine::BinOpResult::IntOrFloatValue minValue,maxValue; + b->getRange(&minValue, &maxValue); + if (minValue.isFloat() || maxValue.isFloat()) + return; + + int bits = getIntBitsFromValueType(tok->valueType(), *settings); + if (tok->valueType()->sign == ::ValueType::Sign::SIGNED) { + int128_t v = (int128_t)1 << (bits - 1); + if (minValue.intValue >= -v && maxValue.intValue < v) + return; + } else { + int128_t v = (int128_t)1 << bits; + if (minValue.intValue >= 0 && maxValue.intValue < v) + return; + } + + std::string note; + if (tok->valueType()->sign == ::ValueType::Sign::UNSIGNED) + note = " Note that unsigned integer overflow is defined and will wrap around."; + + std::list callstack{tok}; + ErrorLogger::ErrorMessage errmsg(callstack, &tokenizer->list, Severity::SeverityType::error, "verificationIntegerOverflow", "Integer overflow, " + tok->valueType()->str() + " result." + note, false); + errorLogger->reportErr(errmsg); + }; + std::vector callbacks; callbacks.push_back(divByZero); + callbacks.push_back(integerOverflow); ExprEngine::executeAllFunctions(tokenizer, settings, callbacks); } diff --git a/lib/exprengine.h b/lib/exprengine.h index 5d081a198..ed4cb76df 100644 --- a/lib/exprengine.h +++ b/lib/exprengine.h @@ -219,7 +219,7 @@ namespace ExprEngine { class BinOpResult : public Value { public: BinOpResult(const std::string &binop, ValuePtr op1, ValuePtr op2) - : Value("(" + op1->name + ")" + binop + "(" + op2->name + ")", ValueType::BinOpResult) + : Value(getName(binop, op1, op2), ValueType::BinOpResult) , binop(binop) , op1(op1) , op2(op2) { @@ -264,6 +264,11 @@ namespace ExprEngine { ValuePtr op1; ValuePtr op2; private: + std::string getName(const std::string &binop, ValuePtr op1, ValuePtr op2) const { + std::string name1 = op1 ? op1->name : std::string("null"); + std::string name2 = op2 ? op2->name : std::string("null"); + return "(" + name1 + ")" + binop + "(" + name2 + ")"; + } IntOrFloatValue evaluate(int test, const std::map &valueBit) const; IntOrFloatValue evaluateOperand(int test, const std::map &valueBit, ValuePtr value) const;