ValueFlow: getExpressionRange, valueFlowRightShift

This commit is contained in:
Daniel Marjamäki 2018-11-03 23:25:46 +01:00
parent 8a05be34f8
commit 6878de2c5e
2 changed files with 105 additions and 0 deletions

View File

@ -1089,6 +1089,93 @@ static void valueFlowBitAnd(TokenList *tokenlist)
}
}
static bool getExpressionRange(const Token *expr, MathLib::bigint *minvalue, MathLib::bigint *maxvalue)
{
if (expr->hasKnownIntValue()) {
if (minvalue)
*minvalue = expr->values().front().intvalue;
if (maxvalue)
*maxvalue = expr->values().front().intvalue;
return true;
}
if (expr->str() == "&" && expr->astOperand1() && expr->astOperand2()) {
MathLib::bigint vals[4];
bool lhsHasKnownRange = getExpressionRange(expr->astOperand1(), &vals[0], &vals[1]);
bool rhsHasKnownRange = getExpressionRange(expr->astOperand2(), &vals[2], &vals[3]);
if (!lhsHasKnownRange && !rhsHasKnownRange)
return false;
if (!lhsHasKnownRange || !rhsHasKnownRange) {
if (minvalue)
*minvalue = lhsHasKnownRange ? vals[0] : vals[2];
if (maxvalue)
*maxvalue = lhsHasKnownRange ? vals[1] : vals[3];
} else {
if (minvalue)
*minvalue = vals[0] & vals[2];
if (maxvalue)
*maxvalue = vals[1] & vals[3];
}
return true;
}
if (expr->str() == "%" && expr->astOperand1() && expr->astOperand2()) {
MathLib::bigint vals[4];
if (!getExpressionRange(expr->astOperand2(), &vals[2], &vals[3]))
return false;
if (vals[2] <= 0)
return false;
bool lhsHasKnownRange = getExpressionRange(expr->astOperand1(), &vals[0], &vals[1]);
if (lhsHasKnownRange && vals[0] < 0)
return false;
// If lhs has unknown value, it must be unsigned
if (!lhsHasKnownRange && (!expr->astOperand1()->valueType() || expr->astOperand1()->valueType()->sign != ValueType::Sign::UNSIGNED))
return false;
if (minvalue)
*minvalue = 0;
if (maxvalue)
*maxvalue = vals[3] - 1;
return true;
}
return false;
}
static void valueFlowRightShift(TokenList *tokenList)
{
for (Token *tok = tokenList->front(); tok; tok = tok->next()) {
if (tok->str() != ">>")
continue;
if (tok->hasKnownValue())
continue;
if (!tok->astOperand1() || !tok->astOperand2())
continue;
if (!tok->astOperand2()->hasKnownValue())
continue;
if (!tok->astOperand1()->valueType() || !tok->astOperand1()->valueType()->isIntegral())
continue;
if (!tok->astOperand2()->valueType() || !tok->astOperand2()->valueType()->isIntegral())
continue;
MathLib::bigint lhsmax=0;
if (!getExpressionRange(tok->astOperand1(), nullptr, &lhsmax))
continue;
if (lhsmax < 0)
continue;
if ((1 << tok->astOperand2()->values().front().intvalue) <= lhsmax)
continue;
ValueFlow::Value val(0);
val.setKnown();
setTokenValue(tok, val, tokenList->getSettings());
}
}
static void valueFlowOppositeCondition(SymbolDatabase *symboldatabase, const Settings *settings)
{
for (const Scope &scope : symboldatabase->scopeList) {
@ -3793,6 +3880,7 @@ void ValueFlow::setValues(TokenList *tokenlist, SymbolDatabase* symboldatabase,
std::size_t values = 0;
while (std::time(0) < timeout && values < getTotalValues(tokenlist)) {
values = getTotalValues(tokenlist);
valueFlowRightShift(tokenlist);
valueFlowOppositeCondition(symboldatabase, settings);
valueFlowBeforeCondition(tokenlist, symboldatabase, errorLogger, settings);
valueFlowAfterMove(tokenlist, symboldatabase, errorLogger, settings);

View File

@ -57,6 +57,7 @@ private:
TEST_CASE(valueFlowMove);
TEST_CASE(valueFlowBitAnd);
TEST_CASE(valueFlowRightShift);
TEST_CASE(valueFlowCalculations);
TEST_CASE(valueFlowSizeof);
@ -2258,6 +2259,22 @@ private:
ASSERT_EQUALS(false, testValueOfX(code,3U,16));
}
void valueFlowRightShift() {
const char *code;
code = "int f(int a) {\n"
" int x = (a & 0xff) >> 16;\n"
" return x;\n"
"}";
ASSERT_EQUALS(true, testValueOfX(code,3U,0));
code = "int f(unsigned int a) {\n"
" int x = (a % 123) >> 16;\n"
" return x;\n"
"}";
ASSERT_EQUALS(true, testValueOfX(code,3U,0));
}
void valueFlowSwitchVariable() {
const char *code;
code = "void f(int x) {\n"