New check: Pointer overflow (null pointer subtracted)
This commit is contained in:
parent
58eb644003
commit
af5dd2c29e
|
@ -493,3 +493,50 @@ void CheckNullPointer::nullPointerError(const Token *tok, const std::string &var
|
||||||
const std::string errmsg(ValueFlow::eitherTheConditionIsRedundant(nullCheck) + " or there is possible null pointer dereference: " + varname + ".");
|
const std::string errmsg(ValueFlow::eitherTheConditionIsRedundant(nullCheck) + " or there is possible null pointer dereference: " + varname + ".");
|
||||||
reportError(callstack, Severity::warning, "nullPointerRedundantCheck", errmsg, CWE476, inconclusive);
|
reportError(callstack, Severity::warning, "nullPointerRedundantCheck", errmsg, CWE476, inconclusive);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CheckNullPointer::arithmetic()
|
||||||
|
{
|
||||||
|
const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase();
|
||||||
|
const std::size_t functions = symbolDatabase->functionScopes.size();
|
||||||
|
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() != "-")
|
||||||
|
continue;
|
||||||
|
// pointer subtraction
|
||||||
|
if (!tok->valueType() || !tok->valueType()->pointer)
|
||||||
|
continue;
|
||||||
|
// Can LHS be NULL?
|
||||||
|
const ValueFlow::Value *value = tok->astOperand1()->getValue(0);
|
||||||
|
if (!value)
|
||||||
|
continue;
|
||||||
|
if (!_settings->inconclusive && value->inconclusive)
|
||||||
|
continue;
|
||||||
|
if (value->condition && !_settings->isEnabled("warning"))
|
||||||
|
continue;
|
||||||
|
arithmeticError(tok,value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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.";
|
||||||
|
|
||||||
|
std::list<const Token*> callstack;
|
||||||
|
callstack.push_back(tok);
|
||||||
|
if (value && value->condition)
|
||||||
|
callstack.push_back(value->condition);
|
||||||
|
|
||||||
|
reportError(callstack,
|
||||||
|
(value && value->condition) ? Severity::warning : Severity::error,
|
||||||
|
(value && value->condition) ? "nullPointerArithmeticRedundantCheck" : "nullPointerArithmetic",
|
||||||
|
errmsg,
|
||||||
|
CWE(0), // unknown - pointer overflow
|
||||||
|
value && value->inconclusive);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -47,6 +47,7 @@ public:
|
||||||
void runChecks(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) {
|
void runChecks(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) {
|
||||||
CheckNullPointer checkNullPointer(tokenizer, settings, errorLogger);
|
CheckNullPointer checkNullPointer(tokenizer, settings, errorLogger);
|
||||||
checkNullPointer.nullPointer();
|
checkNullPointer.nullPointer();
|
||||||
|
checkNullPointer.arithmetic();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @brief Run checks against the simplified token list */
|
/** @brief Run checks against the simplified token list */
|
||||||
|
@ -96,6 +97,7 @@ private:
|
||||||
c.nullPointerError(nullptr);
|
c.nullPointerError(nullptr);
|
||||||
c.nullPointerError(nullptr, "pointer", false, true, true);
|
c.nullPointerError(nullptr, "pointer", false, true, true);
|
||||||
c.nullPointerError(nullptr, "pointer", nullptr, false);
|
c.nullPointerError(nullptr, "pointer", nullptr, false);
|
||||||
|
c.arithmeticError(nullptr, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Name of check */
|
/** Name of check */
|
||||||
|
@ -106,7 +108,8 @@ private:
|
||||||
/** class info in WIKI format. Used by --doc */
|
/** class info in WIKI format. Used by --doc */
|
||||||
std::string classInfo() const {
|
std::string classInfo() const {
|
||||||
return "Null pointers\n"
|
return "Null pointers\n"
|
||||||
"- null pointer dereferencing\n";
|
"- null pointer dereferencing\n"
|
||||||
|
"- undefined null pointer arithmetic\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -120,6 +123,10 @@ private:
|
||||||
* Dereferencing a pointer and then checking if it's NULL..
|
* Dereferencing a pointer and then checking if it's NULL..
|
||||||
*/
|
*/
|
||||||
void nullPointerByDeRefAndChec();
|
void nullPointerByDeRefAndChec();
|
||||||
|
|
||||||
|
/** undefined null pointer arithmetic */
|
||||||
|
void arithmetic();
|
||||||
|
void arithmeticError(const Token *tok, const ValueFlow::Value *value);
|
||||||
};
|
};
|
||||||
/// @}
|
/// @}
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
|
@ -96,6 +96,7 @@ private:
|
||||||
TEST_CASE(functioncallDefaultArguments);
|
TEST_CASE(functioncallDefaultArguments);
|
||||||
TEST_CASE(nullpointer_internal_error); // #5080
|
TEST_CASE(nullpointer_internal_error); // #5080
|
||||||
TEST_CASE(ticket6505);
|
TEST_CASE(ticket6505);
|
||||||
|
TEST_CASE(subtract);
|
||||||
}
|
}
|
||||||
|
|
||||||
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") {
|
||||||
|
@ -111,12 +112,12 @@ private:
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Check for redundant code..
|
// Check for redundant code..
|
||||||
CheckNullPointer checkNullPointer(&tokenizer, &settings, this);
|
CheckNullPointer checkNullPointer;
|
||||||
checkNullPointer.nullPointer();
|
checkNullPointer.runChecks(&tokenizer, &settings, this);
|
||||||
|
|
||||||
tokenizer.simplifyTokenList2();
|
tokenizer.simplifyTokenList2();
|
||||||
|
|
||||||
checkNullPointer.nullConstantDereference();
|
checkNullPointer.runSimplifiedChecks(&tokenizer, &settings, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -2515,6 +2516,20 @@ private:
|
||||||
"}\n", true, "test.c");
|
"}\n", true, "test.c");
|
||||||
ASSERT_EQUALS("", errout.str());
|
ASSERT_EQUALS("", errout.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void subtract() {
|
||||||
|
check("void foo(char *s) {\n"
|
||||||
|
" p = 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"
|
||||||
|
" 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());
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
REGISTER_TEST(TestNullPointer)
|
REGISTER_TEST(TestNullPointer)
|
||||||
|
|
Loading…
Reference in New Issue