diff --git a/lib/checkother.cpp b/lib/checkother.cpp index bf25cca09..0b289bf98 100644 --- a/lib/checkother.cpp +++ b/lib/checkother.cpp @@ -254,6 +254,19 @@ void CheckOther::checkEmptyStringTest() } } } +//--------------------------------------------------------------------------- +// fflush(stdin) <- fflush only applies to output streams in ANSI C +//--------------------------------------------------------------------------- +void CheckOther::checkFflushOnInputStream() +{ + for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) + { + if (Token::Match(tok, "fflush ( stdin )")) + { + fflushOnInputStreamError(tok, tok->strAt(2)); + } + } +} //--------------------------------------------------------------------------- // strtol(str, 0, radix) <- radix must be 0 or 2-36 @@ -3502,3 +3515,9 @@ void CheckOther::emptyStringTestError(const Token *tok, const std::string &var_n "emptyStringTest", "Non-empty string test can be simplified to \"*" + var_name + " != '\\0'\""); } } + +void CheckOther::fflushOnInputStreamError(const Token *tok, const std::string &varname) +{ + reportError(tok, Severity::possibleError, + "fflushOnInputStream", "fflush() called on input stream \"" + varname + "\" may result in undefined behaviour"); +} diff --git a/lib/checkother.h b/lib/checkother.h index 2e24fa9b9..fd09cc5db 100644 --- a/lib/checkother.h +++ b/lib/checkother.h @@ -77,6 +77,7 @@ public: checkOther.invalidFunctionUsage(); checkOther.checkZeroDivision(); checkOther.checkMathFunctions(); + checkOther.checkFflushOnInputStream(); // New type of check: Check execution paths checkOther.executionPaths(); @@ -158,6 +159,9 @@ public: /** @brief %Check for inefficient empty string test*/ void checkEmptyStringTest(); + /** @brief %Check for using fflush() on an input stream*/ + void checkFflushOnInputStream(); + // Error messages.. void cstyleCastError(const Token *tok); void redundantIfDelete0Error(const Token *tok); @@ -184,6 +188,7 @@ public: void mathfunctionCallError(const Token *tok, const unsigned int numParam = 1); void postIncrementError(const Token *tok, const std::string &var_name, const bool isIncrement); void emptyStringTestError(const Token *tok, const std::string &var_name, const bool isTestForEmpty); + void fflushOnInputStreamError(const Token *tok, const std::string &varname); void getErrorMessages() { @@ -196,6 +201,7 @@ public: uninitvarError(0, "varname"); zerodivError(0); mathfunctionCallError(0); + fflushOnInputStreamError(0, "stdin"); // style cstyleCastError(0); @@ -232,6 +238,9 @@ public: "* null pointer dereferencing\n" "* using uninitialized variables and data\n" + // possible error + "* using fflush() on an input stream\n" + // style "* C-style pointer cast in cpp file\n" "* redundant if\n" @@ -246,7 +255,8 @@ public: "* unusal pointer arithmetic. For example: \"abc\" + 'd'\n" // optimisations - "* optimisation: detect post increment/decrement\n"; + "* optimisation: detect post increment/decrement\n" + "* optimisation: simplify empty string tests\n"; } private: diff --git a/test/testother.cpp b/test/testother.cpp index a50af5678..e9ee0b7b3 100644 --- a/test/testother.cpp +++ b/test/testother.cpp @@ -92,6 +92,8 @@ private: TEST_CASE(mathfunctionCall1); TEST_CASE(emptyStringTest); + + TEST_CASE(fflushOnInputStreamTest); } void check(const char code[]) @@ -115,6 +117,7 @@ private: checkOther.checkZeroDivision(); checkOther.checkMathFunctions(); checkOther.checkEmptyStringTest(); + checkOther.checkFflushOnInputStream(); } @@ -2471,6 +2474,21 @@ private: check("if (0 < strlen(str)) { }"); ASSERT_EQUALS("[test.cpp:1]: (possible style) Non-empty string test can be simplified to \"*str != '\\0'\"\n", errout.str()); } + + void fflushOnInputStreamTest() + { + check("void foo()\n" + "{\n" + " fflush(stdin);\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:3]: (possible error) fflush() called on input stream \"stdin\" may result in undefined behaviour\n", errout.str()); + + check("void foo()\n" + "{\n" + " fflush(stdout);\n" + "}\n"); + ASSERT_EQUALS("", errout.str()); + } }; REGISTER_TEST(TestOther)