From 28c0045f3678f10c79dd2b0966296d20f4753db3 Mon Sep 17 00:00:00 2001 From: Zachary Blair Date: Sun, 9 Jun 2013 23:13:08 -0700 Subject: [PATCH] Fixed #4173: New check: arithmetical usage of inf/nan result --- lib/checkother.cpp | 24 ++++++++++++++++++++++++ lib/checkother.h | 9 ++++++++- test/testother.cpp | 43 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 75 insertions(+), 1 deletion(-) diff --git a/lib/checkother.cpp b/lib/checkother.cpp index ab6525537..bae7ea263 100644 --- a/lib/checkother.cpp +++ b/lib/checkother.cpp @@ -2112,6 +2112,30 @@ void CheckOther::zerodivError(const Token *tok) reportError(tok, Severity::error, "zerodiv", "Division by zero."); } +//--------------------------------------------------------------------------- +//--------------------------------------------------------------------------- + +/** @brief Check for NaN (not-a-number) in an arithmetic expression + * @note e.g. double d = 1.0 / 0.0 + 100.0; + */ +void CheckOther::checkNanInArithmeticExpression() +{ + for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) { + if (Token::Match(tok, "inf.0 +|-") || + Token::Match(tok, "+|- inf.0") || + Token::Match(tok, "+|- %num% / 0.0")) { + nanInArithmeticExpressionError(tok); + } + } +} + +void CheckOther::nanInArithmeticExpressionError(const Token *tok) +{ + reportError(tok, Severity::style, "nanInArithmeticExpression", + "Using NaN/Inf in a computation.\n" + "Although nothing bad really happens, it is suspicious."); +} + //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- void CheckOther::checkMathFunctions() diff --git a/lib/checkother.h b/lib/checkother.h index 7b5b0a3c4..c1af985c4 100644 --- a/lib/checkother.h +++ b/lib/checkother.h @@ -72,6 +72,7 @@ public: checkOther.checkIncompleteArrayFill(); checkOther.checkSuspiciousStringCompare(); checkOther.checkVarFuncNullUB(); + checkOther.checkNanInArithmeticExpression(); } /** @brief Run checks against the simplified token list */ @@ -158,6 +159,9 @@ public: /** @brief %Check zero division*/ void checkZeroDivision(); + /** @brief Check for NaN (not-a-number) in an arithmetic expression */ + void checkNanInArithmeticExpression(); + /** @brief %Check for parameters given to math function that do not make sense*/ void checkMathFunctions(); @@ -278,6 +282,7 @@ private: void variableScopeError(const Token *tok, const std::string &varname); void strPlusCharError(const Token *tok); void zerodivError(const Token *tok); + void nanInArithmeticExpressionError(const Token *tok); void mathfunctionCallError(const Token *tok, const unsigned int numParam = 1); void cctypefunctionCallError(const Token *tok, const std::string &functionName, const std::string &value); void redundantAssignmentError(const Token *tok1, const Token* tok2, const std::string& var, bool inconclusive); @@ -377,6 +382,7 @@ private: c.moduloAlwaysTrueFalseError(0, "1"); c.incompleteArrayFillError(0, "buffer", "memset", false); c.varFuncNullUBError(0); + c.nanInArithmeticExpressionError(0); } static std::string myName() { @@ -438,7 +444,8 @@ private: "* Comparisons of modulo results that are always true/false.\n" "* Array filled incompletely using memset/memcpy/memmove.\n" "* redundant get and set function of user id (--std=posix).\n" - "* Passing NULL pointer to function with variable number of arguments leads to UB on some platforms.\n"; + "* Passing NULL pointer to function with variable number of arguments leads to UB on some platforms.\n" + "* NaN (not a number) value used in arithmetic expression.\n"; } void checkExpressionRange(const std::list &constFunctions, diff --git a/test/testother.cpp b/test/testother.cpp index 423816cde..c5d67c409 100644 --- a/test/testother.cpp +++ b/test/testother.cpp @@ -43,6 +43,8 @@ private: TEST_CASE(zeroDiv5); TEST_CASE(zeroDiv6); + TEST_CASE(nanInArithmeticExpression); + TEST_CASE(sprintf1); // Dangerous usage of sprintf TEST_CASE(sprintf2); TEST_CASE(sprintf3); @@ -410,6 +412,47 @@ private: ASSERT_EQUALS("[test.cpp:3]: (error) Division by zero.\n", errout.str()); } + void nanInArithmeticExpression() { + check("void f()\n" + "{\n" + " double x = 3.0 / 0.0 + 1.0\n" + " printf(\"%f\n\", x);\n" + "}"); + ASSERT_EQUALS( + "[test.cpp:3]: (style) Using NaN/Inf in a computation.\n", errout.str()); + + check("void f()\n" + "{\n" + " double x = 3.0 / 0.0 - 1.0\n" + " printf(\"%f\n\", x);\n" + "}"); + ASSERT_EQUALS( + "[test.cpp:3]: (style) Using NaN/Inf in a computation.\n", errout.str()); + + check("void f()\n" + "{\n" + " double x = 1.0 + 3.0 / 0.0\n" + " printf(\"%f\n\", x);\n" + "}"); + ASSERT_EQUALS( + "[test.cpp:3]: (style) Using NaN/Inf in a computation.\n", errout.str()); + + check("void f()\n" + "{\n" + " double x = 1.0 - 3.0 / 0.0\n" + " printf(\"%f\n\", x);\n" + "}"); + ASSERT_EQUALS( + "[test.cpp:3]: (style) Using NaN/Inf in a computation.\n", errout.str()); + + check("void f()\n" + "{\n" + " double x = 3.0 / 0.0\n" + " printf(\"%f\n\", x);\n" + "}"); + ASSERT_EQUALS("", errout.str()); + + } void sprintfUsage(const char code[]) { // Clear the error buffer..