Fix FP in solveExpr when using symbolic values (#3391)
This commit is contained in:
parent
e6cf4cad87
commit
0f897acecd
|
@ -2322,7 +2322,7 @@ struct ValueFlowAnalyzer : Analyzer {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
ValuePtr<Analyzer> makeAnalyzer(const Token* exprTok, const ValueFlow::Value& value, const TokenList* tokenlist);
|
ValuePtr<Analyzer> makeAnalyzer(const Token* exprTok, ValueFlow::Value value, const TokenList* tokenlist);
|
||||||
|
|
||||||
struct SingleValueFlowAnalyzer : ValueFlowAnalyzer {
|
struct SingleValueFlowAnalyzer : ValueFlowAnalyzer {
|
||||||
std::unordered_map<nonneg int, const Variable*> varids;
|
std::unordered_map<nonneg int, const Variable*> varids;
|
||||||
|
@ -2580,52 +2580,43 @@ static const Token* parseBinaryIntOp(const Token* expr, MathLib::bigint& known)
|
||||||
return varTok;
|
return varTok;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class F>
|
static const Token* solveExprValue(const Token* expr, ValueFlow::Value& value)
|
||||||
void transformIntValues(std::list<ValueFlow::Value>& values, F f)
|
|
||||||
{
|
|
||||||
std::transform(values.begin(), values.end(), values.begin(), [&](ValueFlow::Value x) {
|
|
||||||
if (x.isIntValue() || x.isIteratorValue())
|
|
||||||
x.intvalue = f(x.intvalue);
|
|
||||||
return x;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
static const Token* solveExprValues(const Token* expr, std::list<ValueFlow::Value>& values)
|
|
||||||
{
|
{
|
||||||
|
if (!value.isIntValue() && !value.isIteratorValue() && !value.isSymbolicValue())
|
||||||
|
return expr;
|
||||||
|
if (value.isSymbolicValue() && !Token::Match(expr, "+|-"))
|
||||||
|
return expr;
|
||||||
MathLib::bigint intval;
|
MathLib::bigint intval;
|
||||||
const Token* binaryTok = parseBinaryIntOp(expr, intval);
|
const Token* binaryTok = parseBinaryIntOp(expr, intval);
|
||||||
if (binaryTok && expr->str().size() == 1) {
|
if (binaryTok && expr->str().size() == 1) {
|
||||||
switch (expr->str()[0]) {
|
switch (expr->str()[0]) {
|
||||||
case '+': {
|
case '+': {
|
||||||
transformIntValues(values, [&](MathLib::bigint x) {
|
value.intvalue -= intval;
|
||||||
return x - intval;
|
return solveExprValue(binaryTok, value);
|
||||||
});
|
}
|
||||||
return solveExprValues(binaryTok, values);
|
case '-': {
|
||||||
|
value.intvalue += intval;
|
||||||
|
return solveExprValue(binaryTok, value);
|
||||||
}
|
}
|
||||||
case '*': {
|
case '*': {
|
||||||
if (intval == 0)
|
if (intval == 0)
|
||||||
break;
|
break;
|
||||||
transformIntValues(values, [&](MathLib::bigint x) {
|
value.intvalue /= intval;
|
||||||
return x / intval;
|
return solveExprValue(binaryTok, value);
|
||||||
});
|
|
||||||
return solveExprValues(binaryTok, values);
|
|
||||||
}
|
}
|
||||||
case '^': {
|
case '^': {
|
||||||
transformIntValues(values, [&](MathLib::bigint x) {
|
value.intvalue ^= intval;
|
||||||
return x ^ intval;
|
return solveExprValue(binaryTok, value);
|
||||||
});
|
|
||||||
return solveExprValues(binaryTok, values);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return expr;
|
return expr;
|
||||||
}
|
}
|
||||||
|
|
||||||
ValuePtr<Analyzer> makeAnalyzer(const Token* exprTok, const ValueFlow::Value& value, const TokenList* tokenlist)
|
ValuePtr<Analyzer> makeAnalyzer(const Token* exprTok, ValueFlow::Value value, const TokenList* tokenlist)
|
||||||
{
|
{
|
||||||
std::list<ValueFlow::Value> values = {value};
|
const Token* expr = solveExprValue(exprTok, value);
|
||||||
const Token* expr = solveExprValues(exprTok, values);
|
return ExpressionAnalyzer(expr, value, tokenlist);
|
||||||
return ExpressionAnalyzer(expr, values.front(), tokenlist);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static Analyzer::Result valueFlowForward(Token* startToken,
|
static Analyzer::Result valueFlowForward(Token* startToken,
|
||||||
|
@ -2635,8 +2626,11 @@ static Analyzer::Result valueFlowForward(Token* startToken,
|
||||||
TokenList* const tokenlist,
|
TokenList* const tokenlist,
|
||||||
const Settings* settings)
|
const Settings* settings)
|
||||||
{
|
{
|
||||||
const Token* expr = solveExprValues(exprTok, values);
|
Analyzer::Result result{};
|
||||||
return valueFlowForwardExpression(startToken, endToken, expr, values, tokenlist, settings);
|
for (const ValueFlow::Value& v : values) {
|
||||||
|
result.update(valueFlowGenericForward(startToken, endToken, makeAnalyzer(exprTok, v, tokenlist), settings));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Analyzer::Result valueFlowForward(Token* top,
|
static Analyzer::Result valueFlowForward(Token* top,
|
||||||
|
|
|
@ -6028,6 +6028,19 @@ private:
|
||||||
ASSERT_EQUALS(false, testValueOfXKnown(code, 4U, "i", 0));
|
ASSERT_EQUALS(false, testValueOfXKnown(code, 4U, "i", 0));
|
||||||
ASSERT_EQUALS(false, testValueOfXKnown(code, 4U, "i", 1));
|
ASSERT_EQUALS(false, testValueOfXKnown(code, 4U, "i", 1));
|
||||||
ASSERT_EQUALS(true, testValueOfXKnown(code, 4U, "j", 0));
|
ASSERT_EQUALS(true, testValueOfXKnown(code, 4U, "j", 0));
|
||||||
|
|
||||||
|
code = "void f(int x) {\n"
|
||||||
|
" int y = x + 1;\n"
|
||||||
|
" return x;\n"
|
||||||
|
"}\n";
|
||||||
|
ASSERT_EQUALS(false, testValueOfXKnown(code, 3U, "y", 0));
|
||||||
|
ASSERT_EQUALS(true, testValueOfXKnown(code, 3U, "y", -1));
|
||||||
|
|
||||||
|
code = "void f(int x) {\n"
|
||||||
|
" int y = x * 2;\n"
|
||||||
|
" return x;\n"
|
||||||
|
"}\n";
|
||||||
|
ASSERT_EQUALS(false, testValueOfXKnown(code, 3U, "y", 0));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue