ValueFlow: getExpressionRange, valueFlowRightShift
This commit is contained in:
parent
8a05be34f8
commit
6878de2c5e
|
@ -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)
|
static void valueFlowOppositeCondition(SymbolDatabase *symboldatabase, const Settings *settings)
|
||||||
{
|
{
|
||||||
for (const Scope &scope : symboldatabase->scopeList) {
|
for (const Scope &scope : symboldatabase->scopeList) {
|
||||||
|
@ -3793,6 +3880,7 @@ void ValueFlow::setValues(TokenList *tokenlist, SymbolDatabase* symboldatabase,
|
||||||
std::size_t values = 0;
|
std::size_t values = 0;
|
||||||
while (std::time(0) < timeout && values < getTotalValues(tokenlist)) {
|
while (std::time(0) < timeout && values < getTotalValues(tokenlist)) {
|
||||||
values = getTotalValues(tokenlist);
|
values = getTotalValues(tokenlist);
|
||||||
|
valueFlowRightShift(tokenlist);
|
||||||
valueFlowOppositeCondition(symboldatabase, settings);
|
valueFlowOppositeCondition(symboldatabase, settings);
|
||||||
valueFlowBeforeCondition(tokenlist, symboldatabase, errorLogger, settings);
|
valueFlowBeforeCondition(tokenlist, symboldatabase, errorLogger, settings);
|
||||||
valueFlowAfterMove(tokenlist, symboldatabase, errorLogger, settings);
|
valueFlowAfterMove(tokenlist, symboldatabase, errorLogger, settings);
|
||||||
|
|
|
@ -57,6 +57,7 @@ private:
|
||||||
TEST_CASE(valueFlowMove);
|
TEST_CASE(valueFlowMove);
|
||||||
|
|
||||||
TEST_CASE(valueFlowBitAnd);
|
TEST_CASE(valueFlowBitAnd);
|
||||||
|
TEST_CASE(valueFlowRightShift);
|
||||||
|
|
||||||
TEST_CASE(valueFlowCalculations);
|
TEST_CASE(valueFlowCalculations);
|
||||||
TEST_CASE(valueFlowSizeof);
|
TEST_CASE(valueFlowSizeof);
|
||||||
|
@ -2258,6 +2259,22 @@ private:
|
||||||
ASSERT_EQUALS(false, testValueOfX(code,3U,16));
|
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() {
|
void valueFlowSwitchVariable() {
|
||||||
const char *code;
|
const char *code;
|
||||||
code = "void f(int x) {\n"
|
code = "void f(int x) {\n"
|
||||||
|
|
Loading…
Reference in New Issue