Fixed #4173: New check: arithmetical usage of inf/nan result
This commit is contained in:
parent
f359bfca9c
commit
28c0045f36
|
@ -2112,6 +2112,30 @@ void CheckOther::zerodivError(const Token *tok)
|
||||||
reportError(tok, Severity::error, "zerodiv", "Division by zero.");
|
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()
|
void CheckOther::checkMathFunctions()
|
||||||
|
|
|
@ -72,6 +72,7 @@ public:
|
||||||
checkOther.checkIncompleteArrayFill();
|
checkOther.checkIncompleteArrayFill();
|
||||||
checkOther.checkSuspiciousStringCompare();
|
checkOther.checkSuspiciousStringCompare();
|
||||||
checkOther.checkVarFuncNullUB();
|
checkOther.checkVarFuncNullUB();
|
||||||
|
checkOther.checkNanInArithmeticExpression();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @brief Run checks against the simplified token list */
|
/** @brief Run checks against the simplified token list */
|
||||||
|
@ -158,6 +159,9 @@ public:
|
||||||
/** @brief %Check zero division*/
|
/** @brief %Check zero division*/
|
||||||
void checkZeroDivision();
|
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*/
|
/** @brief %Check for parameters given to math function that do not make sense*/
|
||||||
void checkMathFunctions();
|
void checkMathFunctions();
|
||||||
|
|
||||||
|
@ -278,6 +282,7 @@ private:
|
||||||
void variableScopeError(const Token *tok, const std::string &varname);
|
void variableScopeError(const Token *tok, const std::string &varname);
|
||||||
void strPlusCharError(const Token *tok);
|
void strPlusCharError(const Token *tok);
|
||||||
void zerodivError(const Token *tok);
|
void zerodivError(const Token *tok);
|
||||||
|
void nanInArithmeticExpressionError(const Token *tok);
|
||||||
void mathfunctionCallError(const Token *tok, const unsigned int numParam = 1);
|
void mathfunctionCallError(const Token *tok, const unsigned int numParam = 1);
|
||||||
void cctypefunctionCallError(const Token *tok, const std::string &functionName, const std::string &value);
|
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);
|
void redundantAssignmentError(const Token *tok1, const Token* tok2, const std::string& var, bool inconclusive);
|
||||||
|
@ -377,6 +382,7 @@ private:
|
||||||
c.moduloAlwaysTrueFalseError(0, "1");
|
c.moduloAlwaysTrueFalseError(0, "1");
|
||||||
c.incompleteArrayFillError(0, "buffer", "memset", false);
|
c.incompleteArrayFillError(0, "buffer", "memset", false);
|
||||||
c.varFuncNullUBError(0);
|
c.varFuncNullUBError(0);
|
||||||
|
c.nanInArithmeticExpressionError(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string myName() {
|
static std::string myName() {
|
||||||
|
@ -438,7 +444,8 @@ private:
|
||||||
"* Comparisons of modulo results that are always true/false.\n"
|
"* Comparisons of modulo results that are always true/false.\n"
|
||||||
"* Array filled incompletely using memset/memcpy/memmove.\n"
|
"* Array filled incompletely using memset/memcpy/memmove.\n"
|
||||||
"* redundant get and set function of user id (--std=posix).\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<const Function*> &constFunctions,
|
void checkExpressionRange(const std::list<const Function*> &constFunctions,
|
||||||
|
|
|
@ -43,6 +43,8 @@ private:
|
||||||
TEST_CASE(zeroDiv5);
|
TEST_CASE(zeroDiv5);
|
||||||
TEST_CASE(zeroDiv6);
|
TEST_CASE(zeroDiv6);
|
||||||
|
|
||||||
|
TEST_CASE(nanInArithmeticExpression);
|
||||||
|
|
||||||
TEST_CASE(sprintf1); // Dangerous usage of sprintf
|
TEST_CASE(sprintf1); // Dangerous usage of sprintf
|
||||||
TEST_CASE(sprintf2);
|
TEST_CASE(sprintf2);
|
||||||
TEST_CASE(sprintf3);
|
TEST_CASE(sprintf3);
|
||||||
|
@ -410,6 +412,47 @@ private:
|
||||||
ASSERT_EQUALS("[test.cpp:3]: (error) Division by zero.\n", errout.str());
|
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[]) {
|
void sprintfUsage(const char code[]) {
|
||||||
// Clear the error buffer..
|
// Clear the error buffer..
|
||||||
|
|
Loading…
Reference in New Issue