diff --git a/cfg/std.cfg b/cfg/std.cfg index 99196138f..6c4affa0b 100644 --- a/cfg/std.cfg +++ b/cfg/std.cfg @@ -1,40 +1,42 @@ true - false - false + false + false - false - - + + false + + - false - false - false + false + false + false false - false - false - false - false - false - false + false + false + false + false + false + false false false - false - false + false + false + false - false + false false @@ -43,18 +45,20 @@ true - false - false + false + false false + false + false @@ -79,9 +83,10 @@ - false - false + false + false + false @@ -201,6 +206,7 @@ + false @@ -251,32 +257,34 @@ - false + false false + false - false 0:255 - false 0:255 - false 0:255 - false 0:255 - false 0:255 - false 0:255 - false 0:255 - false 0:255 - false 0:255 - false 0:255 - false 0:255 - false 0:255 - false - false + false 0:255 + false 0:255 + false 0:255 + false 0:255 + false 0:255 + false 0:255 + false 0:255 + false 0:255 + false 0:255 + false 0:255 + false 0:255 + false 0:255 + false + false + false @@ -284,6 +292,7 @@ + false @@ -311,17 +320,18 @@ - false - false + false + false false - false - false + false + false + false @@ -330,6 +340,7 @@ 0: + false @@ -364,6 +375,7 @@ + false @@ -375,6 +387,7 @@ + false @@ -400,6 +413,7 @@ + false @@ -459,7 +473,7 @@ - false + false false @@ -513,18 +527,21 @@ + false + false + false @@ -532,6 +549,7 @@ + false @@ -559,11 +577,13 @@ + false + false @@ -590,6 +610,7 @@ 0: + false @@ -597,6 +618,7 @@ 0: + false @@ -604,18 +626,21 @@ 0: + false + false + false @@ -636,28 +661,33 @@ + false + false + false + false + false @@ -671,24 +701,28 @@ + false + false + false 0:255 + false @@ -696,11 +730,13 @@ + false + false @@ -713,87 +749,101 @@ + false 0,2:36 + false + false + false + false 0,2:36 + false 0,2:36 + false 0,2:36 - false + false false - false - false 0:255 - false 0:255 + false + false 0:255 + false 0:255 false false false false + false + false + false + false - + 0,2:36 + false 0,2:36 + false 0,2:36 + false diff --git a/lib/checkother.cpp b/lib/checkother.cpp index 3a7ab9b37..79eefaedb 100644 --- a/lib/checkother.cpp +++ b/lib/checkother.cpp @@ -2740,3 +2740,31 @@ void CheckOther::varFuncNullUBError(const Token *tok) " return 0;\n" "}"); } + +//--------------------------------------------------------------------------- +// Check for ignored return values. +//--------------------------------------------------------------------------- +void CheckOther::checkReturnIgnoredReturnValue() +{ + if (!_settings->isEnabled("warning")) + return; + + 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; tok != scope->classEnd; tok = tok->next()) { + if (!Token::Match(tok, "%var% (")) + continue; + + if (!tok->next()->astParent() && _settings->library.useretval.find(tok->str()) != _settings->library.useretval.end()) + ignoredReturnValueError(tok, tok->str()); + } + } +} + +void CheckOther::ignoredReturnValueError(const Token* tok, const std::string& function) +{ + reportError(tok, Severity::warning, "ignoredReturnValue", + "Return value of function " + function + "() is not used.", false); +} diff --git a/lib/checkother.h b/lib/checkother.h index f45d08425..111fa9919 100644 --- a/lib/checkother.h +++ b/lib/checkother.h @@ -73,6 +73,7 @@ public: checkOther.checkVarFuncNullUB(); checkOther.checkNanInArithmeticExpression(); checkOther.checkCommaSeparatedReturn(); + checkOther.checkReturnIgnoredReturnValue(); } /** @brief Run checks against the simplified token list */ @@ -229,6 +230,9 @@ public: /** @brief %Check for using of comparison functions evaluating always to true or false. */ void checkComparisonFunctionIsAlwaysTrueOrFalse(); + /** @brief %Check for ignored return values. */ + void checkReturnIgnoredReturnValue(); + private: // Error messages.. void checkComparisonFunctionIsAlwaysTrueOrFalseError(const Token* tok, const std::string &strFunctionName, const std::string &varName, const bool result); @@ -282,6 +286,7 @@ private: void incompleteArrayFillError(const Token* tok, const std::string& buffer, const std::string& function, bool boolean); void varFuncNullUBError(const Token *tok); void commaSeparatedReturnError(const Token *tok); + void ignoredReturnValueError(const Token* tok, const std::string& function); void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const { CheckOther c(0, settings, errorLogger); @@ -337,6 +342,7 @@ private: c.varFuncNullUBError(0); c.nanInArithmeticExpressionError(0); c.commaSeparatedReturnError(0); + c.ignoredReturnValueError(0, "malloc"); } static std::string myName() { @@ -361,6 +367,7 @@ private: // warning "* either division by zero or useless condition\n" "* memset() with a value out of range as the 2nd parameter\n" + "* return value of certain functions not used\n" // performance "* redundant data copying for const variable\n" diff --git a/lib/library.cpp b/lib/library.cpp index 6eb78b5de..27dde7a9d 100644 --- a/lib/library.cpp +++ b/lib/library.cpp @@ -163,6 +163,8 @@ Library::Error Library::load(const tinyxml2::XMLDocument &doc) functionpure.insert(name); // a constant function is pure } else if (functionnodename == "leak-ignore") leakignore.insert(name); + else if (functionnodename == "use-retval") + useretval.insert(name); else if (functionnodename == "arg" && functionnode->Attribute("nr") != nullptr) { const bool bAnyArg = strcmp(functionnode->Attribute("nr"),"any")==0; const int nr = (bAnyArg) ? -1 : atoi(functionnode->Attribute("nr")); diff --git a/lib/library.h b/lib/library.h index f050df0c4..d02c2d005 100644 --- a/lib/library.h +++ b/lib/library.h @@ -123,6 +123,7 @@ public: std::set leakignore; std::set functionconst; std::set functionpure; + std::set useretval; bool isnoreturn(const std::string &name) const { std::map::const_iterator it = _noreturn.find(name); diff --git a/test/testother.cpp b/test/testother.cpp index e66ad08b1..afeff0035 100644 --- a/test/testother.cpp +++ b/test/testother.cpp @@ -33,9 +33,11 @@ public: } private: - + Settings settings_std; void run() { + LOAD_LIB_2(settings_std.library, "std.cfg"); + TEST_CASE(emptyBrackets); TEST_CASE(zeroDiv1); @@ -167,7 +169,9 @@ private: TEST_CASE(checkComparisonFunctionIsAlwaysTrueOrFalse); - TEST_CASE(integerOverflow) // #5895 + TEST_CASE(integerOverflow); // #5895 + + TEST_CASE(testReturnIgnoredReturnValue); } void check(const char code[], const char *filename = nullptr, bool experimental = false, bool inconclusive = true, bool posix = false, bool runSimpleChecks=true, Settings* settings = 0) { @@ -4174,14 +4178,10 @@ private: "}"); ASSERT_EQUALS("", errout.str()); - { - Settings settings; - LOAD_LIB_2(settings.library, "std.cfg"); - check("void foo() {\n" - " if ((strcmp(a, b) == 0) || (strcmp(a, b) == 0)) {}\n" - "}", "test.cpp", false, false, false, true, &settings); - ASSERT_EQUALS("[test.cpp:2] -> [test.cpp:2]: (style) Same expression on both sides of '||'.\n", errout.str()); - } + check("void foo() {\n" + " if ((strcmp(a, b) == 0) || (strcmp(a, b) == 0)) {}\n" + "}", "test.cpp", false, false, false, true, &settings_std); + ASSERT_EQUALS("[test.cpp:2] -> [test.cpp:2]: (style) Same expression on both sides of '||'.\n", errout.str()); check("void GetValue() { return rand(); }\n" "void foo() {\n" @@ -4785,14 +4785,12 @@ private: "}"); ASSERT_EQUALS("[test.cpp:4]: (error) Memory pointed to by 'p' is freed twice.\n", errout.str()); - Settings settings; - LOAD_LIB_2(settings.library, "std.cfg"); check( "void foo(char *p) {\n" " free(p);\n" " printf(\"Freed memory at location %x\", p);\n" " free(p);\n" - "}", nullptr, false, false, false, true, &settings); + "}", nullptr, false, false, false, true, &settings_std); ASSERT_EQUALS("[test.cpp:4]: (error) Memory pointed to by 'p' is freed twice.\n", errout.str()); check( @@ -6260,6 +6258,28 @@ private: "}\n"); ASSERT_EQUALS("", errout.str()); } + + void testReturnIgnoredReturnValue() { + check("void foo() {\n" + " strcmp(a, b);\n" + "}", "test.cpp", false, false, false, true, &settings_std); + ASSERT_EQUALS("[test.cpp:2]: (warning) Return value of function strcmp() is not used.\n", errout.str()); + + check("void foo() {\n" + " return strcmp(a, b);\n" + "}", "test.cpp", false, false, false, true, &settings_std); + ASSERT_EQUALS("", errout.str()); + + check("void foo() {\n" + " if(strcmp(a, b));\n" + "}", "test.cpp", false, false, false, true, &settings_std); + ASSERT_EQUALS("", errout.str()); + + check("void foo() {\n" + " bool b = strcmp(a, b);\n" + "}", "test.cpp", false, false, false, true, &settings_std); + ASSERT_EQUALS("", errout.str()); + } }; REGISTER_TEST(TestOther)