diff --git a/lib/checkbool.cpp b/lib/checkbool.cpp index 48167187d..3ecaf21e2 100644 --- a/lib/checkbool.cpp +++ b/lib/checkbool.cpp @@ -509,3 +509,47 @@ void CheckBool::comparisonOfBoolExpressionWithIntError(const Token *tok, bool n0 reportError(tok, Severity::warning, "compareBoolExpressionWithInt", "Comparison of a boolean expression with an integer."); } + + +void CheckBool::pointerArithBool() +{ + 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 (Token::Match(tok, "if|while (")) { + pointerArithBoolCond(tok->next()->astOperand2()); + } + } + } +} + +void CheckBool::pointerArithBoolCond(const Token *tok) +{ + if (!tok) + return; + if (Token::Match(tok, "&&|%oror%")) { + pointerArithBoolCond(tok->astOperand1()); + pointerArithBoolCond(tok->astOperand2()); + return; + } + if (tok->str() != "+") + return; + + if (tok->astOperand1() && + tok->astOperand1()->isName() && + tok->astOperand1()->variable() && + tok->astOperand1()->variable()->isPointer() && + tok->astOperand2()->isNumber()) + pointerArithBoolError(tok); +} + +void CheckBool::pointerArithBoolError(const Token *tok) +{ + reportError(tok, + Severity::error, + "pointerArithBool", + "Converting pointer arithmetic result to bool. Either a dereference is forgot, or pointer overflow is required to get a false value"); +} diff --git a/lib/checkbool.h b/lib/checkbool.h index 8e6d9eb5e..72205e02d 100644 --- a/lib/checkbool.h +++ b/lib/checkbool.h @@ -54,6 +54,7 @@ public: // Checks checkBool.checkComparisonOfBoolExpressionWithInt(); checkBool.checkComparisonOfBoolWithInt(); + checkBool.pointerArithBool(); } /** @brief Run checks against the simplified token list */ @@ -89,6 +90,10 @@ public: /** @brief %Check for comparing a bool expression with an integer other than 0 or 1 */ void checkComparisonOfBoolExpressionWithInt(); + /** @brief %Check for 'if (p+1)' etc. either somebody forgot to dereference, or else somebody uses pointer overflow */ + void pointerArithBool(); + void pointerArithBoolCond(const Token *tok); + private: // Error messages.. void comparisonOfFuncReturningBoolError(const Token *tok, const std::string &expression); @@ -100,6 +105,7 @@ private: void assignBoolToPointerError(const Token *tok); void bitwiseOnBooleanError(const Token *tok, const std::string &varname, const std::string &op); void comparisonOfBoolExpressionWithIntError(const Token *tok, bool n0o1); + void pointerArithBoolError(const Token *tok); void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const { CheckBool c(0, settings, errorLogger); @@ -112,6 +118,7 @@ private: c.comparisonOfBoolWithIntError(0, "varname", true); c.bitwiseOnBooleanError(0, "varname", "&&"); c.comparisonOfBoolExpressionWithIntError(0, true); + c.pointerArithBoolError(0); } static std::string myName() { @@ -126,7 +133,8 @@ private: "* comparison of a boolean expression with an integer other than 0 or 1\n" "* comparison of a function returning boolean value using relational operator\n" "* comparison of a boolean value with boolean value using relational operator\n" - "* using bool in bitwise expression\n"; + "* using bool in bitwise expression\n" + "* pointer addition in condition (either dereference is forgot or pointer overflow is required to make the condition false)\n"; } }; /// @} diff --git a/test/testbool.cpp b/test/testbool.cpp index b3808fb45..eca537fb6 100644 --- a/test/testbool.cpp +++ b/test/testbool.cpp @@ -56,6 +56,9 @@ private: TEST_CASE(checkComparisonOfFuncReturningBool4); TEST_CASE(checkComparisonOfFuncReturningBool5); TEST_CASE(checkComparisonOfFuncReturningBool6); + + // Converting pointer addition result to bool + TEST_CASE(pointerArithBool1); } void check(const char code[], bool experimental = false, const char filename[] = "test.cpp") { @@ -869,6 +872,18 @@ private: "}"); ASSERT_EQUALS("", errout.str()); } + + void pointerArithBool1() { // #5126 + check("void f(char *p) {\n" + " if (p+1){}\n" + "}"); + ASSERT_EQUALS("[test.cpp:2]: (error) Converting pointer arithmetic result to bool. Either a dereference is forgot, or pointer overflow is required to get a false value\n", errout.str()); + + check("void f(char *p) {\n" + " if (p && p+1){}\n" + "}"); + ASSERT_EQUALS("[test.cpp:2]: (error) Converting pointer arithmetic result to bool. Either a dereference is forgot, or pointer overflow is required to get a false value\n", errout.str()); + } }; REGISTER_TEST(TestBool)