ExprEngine: Add a temporary overflow check
This commit is contained in:
parent
8ccbdfe725
commit
69016e38bc
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in New Issue