Fix FP in solveExpr when using symbolic values (#3391)

This commit is contained in:
Paul Fultz II 2021-08-09 13:41:10 -05:00 committed by GitHub
parent e6cf4cad87
commit 0f897acecd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 37 additions and 30 deletions

View File

@ -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,

View File

@ -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));
} }
}; };