diff --git a/lib/checkother.cpp b/lib/checkother.cpp index c567c9d64..edb626226 100644 --- a/lib/checkother.cpp +++ b/lib/checkother.cpp @@ -3105,3 +3105,25 @@ void CheckOther::comparePointersError(const Token *tok, const ValueFlow::Value * reportError( errorPath, Severity::error, "comparePointers", verb + " pointers that point to different objects", CWE570, false); } + +void CheckOther::checkModuloOfOne() +{ + for (const Token *tok = mTokenizer->tokens(); tok; tok = tok->next()) { + if (!tok->astOperand2() || !tok->astOperand1()) + continue; + if (tok->str() != "%") + continue; + if (!tok->valueType() || !tok->valueType()->isIntegral()) + continue; + + // Value flow.. + const ValueFlow::Value *value = tok->astOperand2()->getValue(1LL); + if (value && value->isKnown()) + checkModuloOfOneError(tok); + } +} + +void CheckOther::checkModuloOfOneError(const Token *tok) +{ + reportError(tok, Severity::style, "moduloofone", "Modulo of one is always equal to zero"); +} diff --git a/lib/checkother.h b/lib/checkother.h index e4053f243..5fc43af31 100644 --- a/lib/checkother.h +++ b/lib/checkother.h @@ -100,6 +100,7 @@ public: checkOther.checkCastIntToCharAndBack(); checkOther.checkMisusedScopedObject(); checkOther.checkAccessOfMovedVariable(); + checkOther.checkModuloOfOne(); } /** @brief Clarify calculation for ".. a * b ? .." */ @@ -215,6 +216,8 @@ public: void checkComparePointers(); + void checkModuloOfOne(); + private: // Error messages.. void checkComparisonFunctionIsAlwaysTrueOrFalseError(const Token* tok, const std::string &functionName, const std::string &varName, const bool result); @@ -271,6 +274,7 @@ private: void shadowError(const Token *var, const Token *shadowed, std::string type); void knownArgumentError(const Token *tok, const Token *ftok, const ValueFlow::Value *value); void comparePointersError(const Token *tok, const ValueFlow::Value *v1, const ValueFlow::Value *v2); + void checkModuloOfOneError(const Token *tok); void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const OVERRIDE { CheckOther c(nullptr, settings, errorLogger); @@ -342,6 +346,7 @@ private: const std::vector nullvec; c.funcArgOrderDifferent("function", nullptr, nullptr, nullvec, nullvec); + c.checkModuloOfOneError(nullptr); } static std::string myName() { @@ -402,7 +407,8 @@ private: "- function declaration and definition argument names different.\n" "- function declaration and definition argument order different.\n" "- shadow variable.\n" - "- variable can be declared const.\n"; + "- variable can be declared const.\n" + "- calculating modulo of one.\n"; } }; /// @} diff --git a/test/testother.cpp b/test/testother.cpp index 33c952dd5..224df2585 100644 --- a/test/testother.cpp +++ b/test/testother.cpp @@ -239,6 +239,8 @@ private: TEST_CASE(checkComparePointers); TEST_CASE(unusedVariableValueTemplate); // #8994 + + TEST_CASE(moduloOfOne); } void check(const char code[], const char *filename = nullptr, bool experimental = false, bool inconclusive = true, bool runSimpleChecks=true, bool verbose=false, Settings* settings = nullptr) { @@ -8565,6 +8567,20 @@ private: ASSERT_EQUALS("", errout.str()); } + void moduloOfOne() { + check("void f(unsigned int x) {\n" + " int y = x % 1;\n" + "}"); + ASSERT_EQUALS("[test.cpp:2]: (style) Modulo of one is always equal to zero\n", errout.str()); + + check("void f() {\n" + " for (int x = 1; x < 10; x++) {\n" + " int y = 100 % x;\n" + " }\n" + "}"); + ASSERT_EQUALS("", errout.str()); + } + }; REGISTER_TEST(TestOther)