Extend nullPointerArithmetic to check for addition as well

This commit is contained in:
Paul 2018-04-03 21:32:37 +02:00 committed by Daniel Marjamäki
parent 97b17d50aa
commit d240a36a60
2 changed files with 93 additions and 9 deletions

View File

@ -523,13 +523,27 @@ void CheckNullPointer::arithmetic()
for (std::size_t i = 0; i < functions; ++i) {
const Scope * scope = symbolDatabase->functionScopes[i];
for (const Token* tok = scope->classStart->next(); tok != scope->classEnd; tok = tok->next()) {
if (!tok->astOperand2() || tok->str() != "-")
if (!Token::Match(tok, "-|+|+=|-=|++|--"))
continue;
// pointer subtraction
if (!tok->valueType() || !tok->valueType()->pointer)
const Token *pointerOperand;
if (tok->astOperand1() && tok->astOperand1()->valueType() && tok->astOperand1()->valueType()->pointer != 0)
pointerOperand = tok->astOperand1();
else if (tok->astOperand2() && tok->astOperand2()->valueType() && tok->astOperand2()->valueType()->pointer != 0)
pointerOperand = tok->astOperand2();
else
continue;
// Can LHS be NULL?
const ValueFlow::Value *value = tok->astOperand1()->getValue(0);
MathLib::bigint checkValue = 0;
// When using an assign op, the value read from
// valueflow has already been updated, so instead of
// checking for zero we check that the value is equal
// to RHS
if (tok->astOperand2() && tok->astOperand2()->hasKnownIntValue()) {
if (tok->str() == "-=")
checkValue -= tok->astOperand2()->values().front().intvalue;
else if (tok->str() == "+=")
checkValue = tok->astOperand2()->values().front().intvalue;
}
const ValueFlow::Value *value = pointerOperand->getValue(checkValue);
if (!value)
continue;
if (!_settings->inconclusive && value->isInconclusive())
@ -544,10 +558,17 @@ void CheckNullPointer::arithmetic()
void CheckNullPointer::arithmeticError(const Token *tok, const ValueFlow::Value *value)
{
std::string errmsg;
if (value && value->condition)
errmsg = ValueFlow::eitherTheConditionIsRedundant(value->condition) + " or there is overflow in pointer subtraction.";
else
errmsg = "Overflow in pointer arithmetic, NULL pointer is subtracted.";
if (tok && tok->str().front() == '-') {
if (value && value->condition)
errmsg = ValueFlow::eitherTheConditionIsRedundant(value->condition) + " or there is overflow in pointer subtraction.";
else
errmsg = "Overflow in pointer arithmetic, NULL pointer is subtracted.";
} else {
if (value && value->condition)
errmsg = ValueFlow::eitherTheConditionIsRedundant(value->condition) + " or there is pointer arithmetic with NULL pointer.";
else
errmsg = "Pointer arithmetic with NULL pointer.";
}
std::list<const Token*> callstack;
callstack.push_back(tok);

View File

@ -105,6 +105,7 @@ private:
TEST_CASE(nullpointer_internal_error); // #5080
TEST_CASE(ticket6505);
TEST_CASE(subtract);
TEST_CASE(addNull);
}
void check(const char code[], bool inconclusive = false, const char filename[] = "test.cpp") {
@ -2571,6 +2572,68 @@ private:
" p = s - 20;\n"
"}\n");
ASSERT_EQUALS("[test.cpp:3] -> [test.cpp:2]: (warning) Either the condition '!s' is redundant or there is overflow in pointer subtraction.\n", errout.str());
check("void foo(char *s) {\n"
" s -= 20;\n"
"}\n"
"void bar() { foo(0); }\n");
ASSERT_EQUALS("[test.cpp:2]: (error) Overflow in pointer arithmetic, NULL pointer is subtracted.\n", errout.str());
check("void foo(char *s) {\n"
" if (!s) {}\n"
" s -= 20;\n"
"}\n");
ASSERT_EQUALS("[test.cpp:3] -> [test.cpp:2]: (warning) Either the condition '!s' is redundant or there is overflow in pointer subtraction.\n", errout.str());
check("int* f8() { int *x = NULL; return --x; }");
ASSERT_EQUALS("[test.cpp:1]: (error) Overflow in pointer arithmetic, NULL pointer is subtracted.\n", errout.str());
check("int* f9() { int *x = NULL; return x--; }");
ASSERT_EQUALS("[test.cpp:1]: (error) Overflow in pointer arithmetic, NULL pointer is subtracted.\n", errout.str());
}
void addNull() {
check("void foo(char *s) {\n"
" char * p = s + 20;\n"
"}\n"
"void bar() { foo(0); }\n");
ASSERT_EQUALS("[test.cpp:2]: (error) Pointer arithmetic with NULL pointer.\n", errout.str());
check("void foo(char *s) {\n"
" if (!s) {}\n"
" char * p = s + 20;\n"
"}\n");
ASSERT_EQUALS("[test.cpp:3] -> [test.cpp:2]: (warning) Either the condition '!s' is redundant or there is pointer arithmetic with NULL pointer.\n", errout.str());
check("void foo(char *s) {\n"
" char * p = 20 + s;\n"
"}\n"
"void bar() { foo(0); }\n");
ASSERT_EQUALS("[test.cpp:2]: (error) Pointer arithmetic with NULL pointer.\n", errout.str());
check("void foo(char *s) {\n"
" if (!s) {}\n"
" char * p = 20 + s;\n"
"}\n");
ASSERT_EQUALS("[test.cpp:3] -> [test.cpp:2]: (warning) Either the condition '!s' is redundant or there is pointer arithmetic with NULL pointer.\n", errout.str());
check("void foo(char *s) {\n"
" s += 20;\n"
"}\n"
"void bar() { foo(0); }\n");
ASSERT_EQUALS("[test.cpp:2]: (error) Pointer arithmetic with NULL pointer.\n", errout.str());
check("void foo(char *s) {\n"
" if (!s) {}\n"
" s += 20;\n"
"}\n");
ASSERT_EQUALS("[test.cpp:3] -> [test.cpp:2]: (warning) Either the condition '!s' is redundant or there is pointer arithmetic with NULL pointer.\n", errout.str());
check("int* f7() { int *x = NULL; return ++x; }");
ASSERT_EQUALS("[test.cpp:1]: (error) Pointer arithmetic with NULL pointer.\n", errout.str());
check("int* f10() { int *x = NULL; return x++; } ");
ASSERT_EQUALS("[test.cpp:1]: (error) Pointer arithmetic with NULL pointer.\n", errout.str());
}
};