Fix some more false positives on zerodiv: error should be issued if type of epxression is known to be integral

This commit is contained in:
Alexander Mai 2015-08-01 18:42:17 +02:00
parent a4e0a8bf54
commit 965a034afd
2 changed files with 75 additions and 5 deletions

View File

@ -32,6 +32,46 @@ namespace {
CheckOther instance;
}
bool astIsIntegral(const Token *tok, bool unknown)
{
// TODO: handle arrays
if (tok->isNumber())
return MathLib::isInt(tok->str());
if (tok->isName()) {
if (tok->variable())
return tok->variable()->isIntegralType();
return unknown;
}
if (tok->str() == "(") {
// cast
if (Token::Match(tok, "( const| float|double )"))
return false;
// Function call
if (tok->previous()->function()) {
if (Token::Match(tok->previous()->function()->retDef, "float|double"))
return false;
else if (Token::Match(tok->previous()->function()->retDef, "bool|char|short|int|long"))
return true;
}
if (tok->strAt(-1) == "sizeof")
return true;
return unknown;
}
if (tok->astOperand2() && (tok->str() == "." || tok->str() == "::"))
return astIsIntegral(tok->astOperand2(), unknown);
if (tok->astOperand1() && tok->str() != "?")
return astIsIntegral(tok->astOperand1(), unknown);
return unknown;
}
bool astIsFloat(const Token *tok, bool unknown)
{
// TODO: handle arrays
@ -1799,7 +1839,7 @@ void CheckOther::checkZeroDivision()
for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) {
if (!Token::Match(tok, "[/%]") || !tok->astOperand1() || !tok->astOperand2())
continue;
if (astIsFloat(tok,false))
if (!astIsIntegral(tok,false))
continue;
if (tok->astOperand1()->isNumber()) {
if (MathLib::isFloat(tok->astOperand1()->str()))
@ -1807,10 +1847,9 @@ void CheckOther::checkZeroDivision()
} else if (tok->astOperand1()->isName()) {
if (tok->astOperand1()->variable() && !tok->astOperand1()->variable()->isIntegralType())
continue;
} else {
} else if (!tok->astOperand1()->isArithmeticalOp()) {
continue;
}
// Value flow..
const ValueFlow::Value *value = tok->astOperand2()->getValue(0LL);
if (!value)

View File

@ -299,18 +299,33 @@ private:
"{\n"
" long a = b / 0x0;\n"
"}");
ASSERT_EQUALS("", errout.str());
check("void f(long b)\n"
"{\n"
" long a = b / 0x0;\n"
"}");
ASSERT_EQUALS("[test.cpp:3]: (error) Division by zero.\n", errout.str());
check("void f()\n"
"{\n"
" long a = b / 0L;\n"
"}");
ASSERT_EQUALS("", errout.str());
check("void f(long b)\n"
"{\n"
" long a = b / 0L;\n"
"}");
ASSERT_EQUALS("[test.cpp:3]: (error) Division by zero.\n", errout.str());
check("void f()\n"
"{\n"
" long a = b / 0ul;\n"
"}");
ASSERT_EQUALS("", errout.str());
check("void f(long b)\n"
"{\n"
" long a = b / 0ul;\n"
"}");
ASSERT_EQUALS("[test.cpp:3]: (error) Division by zero.\n", errout.str());
// Don't warn about floating points (gcc doesn't warn either)
@ -333,6 +348,11 @@ private:
"{ { {\n"
" long a = b / 0;\n"
"} } }");
ASSERT_EQUALS("", errout.str());
check("void f(long b)\n"
"{ { {\n"
" long a = b / 0;\n"
"} } }");
ASSERT_EQUALS("[test.cpp:3]: (error) Division by zero.\n", errout.str());
}
@ -341,14 +361,25 @@ private:
"{ { {\n"
" int a = b % 0;\n"
"} } }");
ASSERT_EQUALS("", errout.str());
check("void f(int b)\n"
"{ { {\n"
" int a = b % 0;\n"
"} } }");
ASSERT_EQUALS("[test.cpp:3]: (error) Division by zero.\n", errout.str());
}
void zeroDiv7() {
// unknown types for x and y --> do not warn
check("void f() {\n"
" int a = x/2*3/0;\n"
" int b = y/2*3%0;\n"
"}");
ASSERT_EQUALS("", errout.str());
check("void f(int x, int y) {\n"
" int a = x/2*3/0;\n"
" int b = y/2*3%0;\n"
"}");
ASSERT_EQUALS("[test.cpp:2]: (error) Division by zero.\n"
"[test.cpp:3]: (error) Division by zero.\n", errout.str());
}
@ -482,12 +513,12 @@ private:
"}");
ASSERT_EQUALS("", errout.str());
// ?:
// Unknown types for b and c --> do not warn
check("int f(int d) {\n"
" int r = (a?b:c) / d;\n"
" if (d == 0) {}\n"
"}");
ASSERT_EQUALS("[test.cpp:3] -> [test.cpp:2]: (warning) Either the condition 'd==0' is redundant or there is division by zero at line 2.\n", errout.str());
ASSERT_EQUALS("", errout.str());
check("int f(int a) {\n"
" int r = a ? 1 / a : 0;\n"