ExprEngine: Add a temporary overflow check

This commit is contained in:
Daniel Marjamäki 2019-09-27 14:20:17 +02:00
parent 8ccbdfe725
commit 69016e38bc
2 changed files with 43 additions and 1 deletions

View File

@ -598,6 +598,9 @@ ExprEngine::BinOpResult::IntOrFloatValue ExprEngine::BinOpResult::evaluate(int t
ExprEngine::BinOpResult::IntOrFloatValue ExprEngine::BinOpResult::evaluateOperand(int test, const std::map<ExprEngine::ValuePtr, int> &valueBit, ExprEngine::ValuePtr value) const ExprEngine::BinOpResult::IntOrFloatValue ExprEngine::BinOpResult::evaluateOperand(int test, const std::map<ExprEngine::ValuePtr, int> &valueBit, ExprEngine::ValuePtr value) const
{ {
if (!value)
throw std::runtime_error("Internal error: null value");
auto binOpResult = std::dynamic_pointer_cast<ExprEngine::BinOpResult>(value); auto binOpResult = std::dynamic_pointer_cast<ExprEngine::BinOpResult>(value);
if (binOpResult) if (binOpResult)
return binOpResult->evaluate(test, valueBit); return binOpResult->evaluate(test, valueBit);
@ -1097,7 +1100,41 @@ void ExprEngine::runChecks(ErrorLogger *errorLogger, const Tokenizer *tokenizer,
} }
}; };
std::function<void(const Token *, const ExprEngine::Value &)> 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<const ExprEngine::BinOpResult *>(&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<const Token*> 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<ExprEngine::Callback> callbacks; std::vector<ExprEngine::Callback> callbacks;
callbacks.push_back(divByZero); callbacks.push_back(divByZero);
callbacks.push_back(integerOverflow);
ExprEngine::executeAllFunctions(tokenizer, settings, callbacks); ExprEngine::executeAllFunctions(tokenizer, settings, callbacks);
} }

View File

@ -219,7 +219,7 @@ namespace ExprEngine {
class BinOpResult : public Value { class BinOpResult : public Value {
public: public:
BinOpResult(const std::string &binop, ValuePtr op1, ValuePtr op2) 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) , binop(binop)
, op1(op1) , op1(op1)
, op2(op2) { , op2(op2) {
@ -264,6 +264,11 @@ namespace ExprEngine {
ValuePtr op1; ValuePtr op1;
ValuePtr op2; ValuePtr op2;
private: 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<ValuePtr, int> &valueBit) const; IntOrFloatValue evaluate(int test, const std::map<ValuePtr, int> &valueBit) const;
IntOrFloatValue evaluateOperand(int test, const std::map<ValuePtr, int> &valueBit, ValuePtr value) const; IntOrFloatValue evaluateOperand(int test, const std::map<ValuePtr, int> &valueBit, ValuePtr value) const;