Extend nullPointerArithmetic to check for addition as well
This commit is contained in:
parent
97b17d50aa
commit
d240a36a60
|
@ -523,13 +523,27 @@ void CheckNullPointer::arithmetic()
|
||||||
for (std::size_t i = 0; i < functions; ++i) {
|
for (std::size_t i = 0; i < functions; ++i) {
|
||||||
const Scope * scope = symbolDatabase->functionScopes[i];
|
const Scope * scope = symbolDatabase->functionScopes[i];
|
||||||
for (const Token* tok = scope->classStart->next(); tok != scope->classEnd; tok = tok->next()) {
|
for (const Token* tok = scope->classStart->next(); tok != scope->classEnd; tok = tok->next()) {
|
||||||
if (!tok->astOperand2() || tok->str() != "-")
|
if (!Token::Match(tok, "-|+|+=|-=|++|--"))
|
||||||
continue;
|
continue;
|
||||||
// pointer subtraction
|
const Token *pointerOperand;
|
||||||
if (!tok->valueType() || !tok->valueType()->pointer)
|
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;
|
continue;
|
||||||
// Can LHS be NULL?
|
MathLib::bigint checkValue = 0;
|
||||||
const ValueFlow::Value *value = tok->astOperand1()->getValue(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)
|
if (!value)
|
||||||
continue;
|
continue;
|
||||||
if (!_settings->inconclusive && value->isInconclusive())
|
if (!_settings->inconclusive && value->isInconclusive())
|
||||||
|
@ -544,10 +558,17 @@ void CheckNullPointer::arithmetic()
|
||||||
void CheckNullPointer::arithmeticError(const Token *tok, const ValueFlow::Value *value)
|
void CheckNullPointer::arithmeticError(const Token *tok, const ValueFlow::Value *value)
|
||||||
{
|
{
|
||||||
std::string errmsg;
|
std::string errmsg;
|
||||||
if (value && value->condition)
|
if (tok && tok->str().front() == '-') {
|
||||||
errmsg = ValueFlow::eitherTheConditionIsRedundant(value->condition) + " or there is overflow in pointer subtraction.";
|
if (value && value->condition)
|
||||||
else
|
errmsg = ValueFlow::eitherTheConditionIsRedundant(value->condition) + " or there is overflow in pointer subtraction.";
|
||||||
errmsg = "Overflow in pointer arithmetic, NULL pointer is subtracted.";
|
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;
|
std::list<const Token*> callstack;
|
||||||
callstack.push_back(tok);
|
callstack.push_back(tok);
|
||||||
|
|
|
@ -105,6 +105,7 @@ private:
|
||||||
TEST_CASE(nullpointer_internal_error); // #5080
|
TEST_CASE(nullpointer_internal_error); // #5080
|
||||||
TEST_CASE(ticket6505);
|
TEST_CASE(ticket6505);
|
||||||
TEST_CASE(subtract);
|
TEST_CASE(subtract);
|
||||||
|
TEST_CASE(addNull);
|
||||||
}
|
}
|
||||||
|
|
||||||
void check(const char code[], bool inconclusive = false, const char filename[] = "test.cpp") {
|
void check(const char code[], bool inconclusive = false, const char filename[] = "test.cpp") {
|
||||||
|
@ -2571,6 +2572,68 @@ private:
|
||||||
" p = s - 20;\n"
|
" p = s - 20;\n"
|
||||||
"}\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());
|
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());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue