#5805 'Passing value -1.0 to sqrt() leads to undefined result' is incorrect. Degrade wrongmathcall from error to warning, since it deals with implementation-defined behaviour

This commit is contained in:
Alexander Mai 2014-09-01 19:29:59 +02:00
parent 80df3dc642
commit a4ff30301a
3 changed files with 63 additions and 54 deletions

View File

@ -1894,57 +1894,57 @@ void CheckOther::checkMathFunctions()
bool isInt = MathLib::isInt(tok->strAt(2)); bool isInt = MathLib::isInt(tok->strAt(2));
bool isFloat = MathLib::isFloat(tok->strAt(2)); bool isFloat = MathLib::isFloat(tok->strAt(2));
if (isNegative && isInt && MathLib::toLongNumber(tok->strAt(2)) <= 0) { if (isNegative && isInt && MathLib::toLongNumber(tok->strAt(2)) <= 0) {
mathfunctionCallError(tok); // case log(-2) mathfunctionCallWarning(tok); // case log(-2)
} else if (isNegative && isFloat && MathLib::toDoubleNumber(tok->strAt(2)) <= 0.) { } else if (isNegative && isFloat && MathLib::toDoubleNumber(tok->strAt(2)) <= 0.) {
mathfunctionCallError(tok); // case log(-2.0) mathfunctionCallWarning(tok); // case log(-2.0)
} else if (!isNegative && isFloat && MathLib::toDoubleNumber(tok->strAt(2)) <= 0.) { } else if (!isNegative && isFloat && MathLib::toDoubleNumber(tok->strAt(2)) <= 0.) {
mathfunctionCallError(tok); // case log(0.0) mathfunctionCallWarning(tok); // case log(0.0)
} else if (!isNegative && isInt && MathLib::toLongNumber(tok->strAt(2)) <= 0) { } else if (!isNegative && isInt && MathLib::toLongNumber(tok->strAt(2)) <= 0) {
mathfunctionCallError(tok); // case log(0) mathfunctionCallWarning(tok); // case log(0)
} }
} }
// acos( x ), asin( x ) where x is defined for interval [-1,+1], but not beyond // acos( x ), asin( x ) where x is defined for interval [-1,+1], but not beyond
else if (Token::Match(tok, "acos|acosl|acosf|asin|asinf|asinl ( %num% )") && else if (Token::Match(tok, "acos|acosl|acosf|asin|asinf|asinl ( %num% )") &&
std::fabs(MathLib::toDoubleNumber(tok->strAt(2))) > 1.0) { std::fabs(MathLib::toDoubleNumber(tok->strAt(2))) > 1.0) {
mathfunctionCallError(tok); mathfunctionCallWarning(tok);
} }
// sqrt( x ): if x is negative the result is undefined // sqrt( x ): if x is negative the result is undefined
else if (Token::Match(tok, "sqrt|sqrtf|sqrtl ( %num% )") && else if (Token::Match(tok, "sqrt|sqrtf|sqrtl ( %num% )") &&
MathLib::isNegative(tok->strAt(2))) { MathLib::isNegative(tok->strAt(2))) {
mathfunctionCallError(tok); mathfunctionCallWarning(tok);
} }
// atan2 ( x , y): x and y can not be zero, because this is mathematically not defined // atan2 ( x , y): x and y can not be zero, because this is mathematically not defined
else if (Token::Match(tok, "atan2|atan2f|atan2l ( %num% , %num% )") && else if (Token::Match(tok, "atan2|atan2f|atan2l ( %num% , %num% )") &&
MathLib::isNullValue(tok->strAt(2)) && MathLib::isNullValue(tok->strAt(2)) &&
MathLib::isNullValue(tok->strAt(4))) { MathLib::isNullValue(tok->strAt(4))) {
mathfunctionCallError(tok, 2); mathfunctionCallWarning(tok, 2);
} }
// fmod ( x , y) If y is zero, then either a range error will occur or the function will return zero (implementation-defined). // fmod ( x , y) If y is zero, then either a range error will occur or the function will return zero (implementation-defined).
else if (Token::Match(tok, "fmod|fmodf|fmodl ( %any%")) { else if (Token::Match(tok, "fmod|fmodf|fmodl ( %any%")) {
const Token* nextArg = tok->tokAt(2)->nextArgument(); const Token* nextArg = tok->tokAt(2)->nextArgument();
if (nextArg && nextArg->isNumber() && MathLib::isNullValue(nextArg->str())) if (nextArg && nextArg->isNumber() && MathLib::isNullValue(nextArg->str()))
mathfunctionCallError(tok, 2); mathfunctionCallWarning(tok, 2);
} }
// pow ( x , y) If x is zero, and y is negative --> division by zero // pow ( x , y) If x is zero, and y is negative --> division by zero
else if (Token::Match(tok, "pow|powf|powl ( %num% , %num% )") && else if (Token::Match(tok, "pow|powf|powl ( %num% , %num% )") &&
MathLib::isNullValue(tok->strAt(2)) && MathLib::isNullValue(tok->strAt(2)) &&
MathLib::isNegative(tok->strAt(4))) { MathLib::isNegative(tok->strAt(4))) {
mathfunctionCallError(tok, 2); mathfunctionCallWarning(tok, 2);
} }
} }
} }
} }
void CheckOther::mathfunctionCallError(const Token *tok, const unsigned int numParam) void CheckOther::mathfunctionCallWarning(const Token *tok, const unsigned int numParam)
{ {
if (tok) { if (tok) {
if (numParam == 1) if (numParam == 1)
reportError(tok, Severity::error, "wrongmathcall", "Passing value " + tok->strAt(2) + " to " + tok->str() + "() leads to undefined result."); reportError(tok, Severity::warning, "wrongmathcall", "Passing value " + tok->strAt(2) + " to " + tok->str() + "() leads to implementation-defined result.");
else if (numParam == 2) else if (numParam == 2)
reportError(tok, Severity::error, "wrongmathcall", "Passing values " + tok->strAt(2) + " and " + tok->strAt(4) + " to " + tok->str() + "() leads to undefined result."); reportError(tok, Severity::warning, "wrongmathcall", "Passing values " + tok->strAt(2) + " and " + tok->strAt(4) + " to " + tok->str() + "() leads to implementation-defined result.");
} else } else
reportError(tok, Severity::error, "wrongmathcall", "Passing value '#' to #() leads to undefined result."); reportError(tok, Severity::warning, "wrongmathcall", "Passing value '#' to #() leads to implementation-defined result.");
} }
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------

View File

@ -257,7 +257,7 @@ private:
void zerodivError(const Token *tok, bool inconclusive); void zerodivError(const Token *tok, bool inconclusive);
void zerodivcondError(const Token *tokcond, const Token *tokdiv, bool inconclusive); void zerodivcondError(const Token *tokcond, const Token *tokdiv, bool inconclusive);
void nanInArithmeticExpressionError(const Token *tok); void nanInArithmeticExpressionError(const Token *tok);
void mathfunctionCallError(const Token *tok, const unsigned int numParam = 1); void mathfunctionCallWarning(const Token *tok, const unsigned int numParam = 1);
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);
void redundantAssignmentInSwitchError(const Token *tok1, const Token *tok2, const std::string &var); void redundantAssignmentInSwitchError(const Token *tok1, const Token *tok2, const std::string &var);
void redundantCopyError(const Token *tok1, const Token* tok2, const std::string& var); void redundantCopyError(const Token *tok1, const Token* tok2, const std::string& var);
@ -299,7 +299,6 @@ private:
c.udivError(0, false); c.udivError(0, false);
c.zerodivError(0, false); c.zerodivError(0, false);
c.zerodivcondError(0,0,false); c.zerodivcondError(0,0,false);
c.mathfunctionCallError(0);
c.misusedScopeObjectError(NULL, "varname"); c.misusedScopeObjectError(NULL, "varname");
c.doubleFreeError(0, "varname"); c.doubleFreeError(0, "varname");
c.invalidPointerCastError(0, "float", "double", false); c.invalidPointerCastError(0, "float", "double", false);
@ -326,6 +325,7 @@ private:
c.suspiciousCaseInSwitchError(0, "||"); c.suspiciousCaseInSwitchError(0, "||");
c.suspiciousEqualityComparisonError(0); c.suspiciousEqualityComparisonError(0);
c.selfAssignmentError(0, "varname"); c.selfAssignmentError(0, "varname");
c.mathfunctionCallWarning(0);
c.memsetZeroBytesError(0, "varname"); c.memsetZeroBytesError(0, "varname");
c.memsetFloatError(0, "varname"); c.memsetFloatError(0, "varname");
c.memsetValueOutOfRangeError(0, "varname"); c.memsetValueOutOfRangeError(0, "varname");

View File

@ -1336,9 +1336,18 @@ private:
" std::cout << sqrtf(-1) << std::endl;\n" " std::cout << sqrtf(-1) << std::endl;\n"
" std::cout << sqrtl(-1) << std::endl;\n" " std::cout << sqrtl(-1) << std::endl;\n"
"}"); "}");
ASSERT_EQUALS("[test.cpp:3]: (error) Passing value -1 to sqrt() leads to undefined result.\n" ASSERT_EQUALS("[test.cpp:3]: (warning) Passing value -1 to sqrt() leads to implementation-defined result.\n"
"[test.cpp:4]: (error) Passing value -1 to sqrtf() leads to undefined result.\n" "[test.cpp:4]: (warning) Passing value -1 to sqrtf() leads to implementation-defined result.\n"
"[test.cpp:5]: (error) Passing value -1 to sqrtl() leads to undefined result.\n", errout.str()); "[test.cpp:5]: (warning) Passing value -1 to sqrtl() leads to implementation-defined result.\n", errout.str());
// implementation-defined behaviour for "finite values of x<0" only:
check("void foo()\n"
"{\n"
" std::cout << sqrt(-0.) << std::endl;\n"
" std::cout << sqrtf(-0.) << std::endl;\n"
" std::cout << sqrtl(-0.) << std::endl;\n"
"}");
ASSERT_EQUALS("", errout.str());
check("void foo()\n" check("void foo()\n"
"{\n" "{\n"
@ -1357,9 +1366,9 @@ private:
" std::cout << logf(-2) << std::endl;\n" " std::cout << logf(-2) << std::endl;\n"
" std::cout << logl(-2) << std::endl;\n" " std::cout << logl(-2) << std::endl;\n"
"}"); "}");
ASSERT_EQUALS("[test.cpp:3]: (error) Passing value -2 to log() leads to undefined result.\n" ASSERT_EQUALS("[test.cpp:3]: (warning) Passing value -2 to log() leads to implementation-defined result.\n"
"[test.cpp:4]: (error) Passing value -2 to logf() leads to undefined result.\n" "[test.cpp:4]: (warning) Passing value -2 to logf() leads to implementation-defined result.\n"
"[test.cpp:5]: (error) Passing value -2 to logl() leads to undefined result.\n", errout.str()); "[test.cpp:5]: (warning) Passing value -2 to logl() leads to implementation-defined result.\n", errout.str());
check("void foo()\n" check("void foo()\n"
"{\n" "{\n"
@ -1367,9 +1376,9 @@ private:
" std::cout << logf(-1) << std::endl;\n" " std::cout << logf(-1) << std::endl;\n"
" std::cout << logl(-1) << std::endl;\n" " std::cout << logl(-1) << std::endl;\n"
"}"); "}");
ASSERT_EQUALS("[test.cpp:3]: (error) Passing value -1 to log() leads to undefined result.\n" ASSERT_EQUALS("[test.cpp:3]: (warning) Passing value -1 to log() leads to implementation-defined result.\n"
"[test.cpp:4]: (error) Passing value -1 to logf() leads to undefined result.\n" "[test.cpp:4]: (warning) Passing value -1 to logf() leads to implementation-defined result.\n"
"[test.cpp:5]: (error) Passing value -1 to logl() leads to undefined result.\n", errout.str()); "[test.cpp:5]: (warning) Passing value -1 to logl() leads to implementation-defined result.\n", errout.str());
check("void foo()\n" check("void foo()\n"
"{\n" "{\n"
@ -1377,9 +1386,9 @@ private:
" std::cout << logf(-1.0) << std::endl;\n" " std::cout << logf(-1.0) << std::endl;\n"
" std::cout << logl(-1.0) << std::endl;\n" " std::cout << logl(-1.0) << std::endl;\n"
"}"); "}");
ASSERT_EQUALS("[test.cpp:3]: (error) Passing value -1.0 to log() leads to undefined result.\n" ASSERT_EQUALS("[test.cpp:3]: (warning) Passing value -1.0 to log() leads to implementation-defined result.\n"
"[test.cpp:4]: (error) Passing value -1.0 to logf() leads to undefined result.\n" "[test.cpp:4]: (warning) Passing value -1.0 to logf() leads to implementation-defined result.\n"
"[test.cpp:5]: (error) Passing value -1.0 to logl() leads to undefined result.\n", errout.str()); "[test.cpp:5]: (warning) Passing value -1.0 to logl() leads to implementation-defined result.\n", errout.str());
check("void foo()\n" check("void foo()\n"
"{\n" "{\n"
@ -1387,9 +1396,9 @@ private:
" std::cout << logf(-0.1) << std::endl;\n" " std::cout << logf(-0.1) << std::endl;\n"
" std::cout << logl(-0.1) << std::endl;\n" " std::cout << logl(-0.1) << std::endl;\n"
"}"); "}");
ASSERT_EQUALS("[test.cpp:3]: (error) Passing value -0.1 to log() leads to undefined result.\n" ASSERT_EQUALS("[test.cpp:3]: (warning) Passing value -0.1 to log() leads to implementation-defined result.\n"
"[test.cpp:4]: (error) Passing value -0.1 to logf() leads to undefined result.\n" "[test.cpp:4]: (warning) Passing value -0.1 to logf() leads to implementation-defined result.\n"
"[test.cpp:5]: (error) Passing value -0.1 to logl() leads to undefined result.\n", errout.str()); "[test.cpp:5]: (warning) Passing value -0.1 to logl() leads to implementation-defined result.\n", errout.str());
check("void foo()\n" check("void foo()\n"
"{\n" "{\n"
@ -1397,9 +1406,9 @@ private:
" std::cout << logf(0.) << std::endl;\n" " std::cout << logf(0.) << std::endl;\n"
" std::cout << logl(0.0) << std::endl;\n" " std::cout << logl(0.0) << std::endl;\n"
"}"); "}");
ASSERT_EQUALS("[test.cpp:3]: (error) Passing value 0 to log() leads to undefined result.\n" ASSERT_EQUALS("[test.cpp:3]: (warning) Passing value 0 to log() leads to implementation-defined result.\n"
"[test.cpp:4]: (error) Passing value 0. to logf() leads to undefined result.\n" "[test.cpp:4]: (warning) Passing value 0. to logf() leads to implementation-defined result.\n"
"[test.cpp:5]: (error) Passing value 0.0 to logl() leads to undefined result.\n", errout.str()); "[test.cpp:5]: (warning) Passing value 0.0 to logl() leads to implementation-defined result.\n", errout.str());
check("void foo()\n" check("void foo()\n"
"{\n" "{\n"
@ -1476,9 +1485,9 @@ private:
" std::cout << acosf(1.1) << std::endl;\n" " std::cout << acosf(1.1) << std::endl;\n"
" std::cout << acosl(1.1) << std::endl;\n" " std::cout << acosl(1.1) << std::endl;\n"
"}"); "}");
ASSERT_EQUALS("[test.cpp:3]: (error) Passing value 1.1 to acos() leads to undefined result.\n" ASSERT_EQUALS("[test.cpp:3]: (warning) Passing value 1.1 to acos() leads to implementation-defined result.\n"
"[test.cpp:4]: (error) Passing value 1.1 to acosf() leads to undefined result.\n" "[test.cpp:4]: (warning) Passing value 1.1 to acosf() leads to implementation-defined result.\n"
"[test.cpp:5]: (error) Passing value 1.1 to acosl() leads to undefined result.\n", errout.str()); "[test.cpp:5]: (warning) Passing value 1.1 to acosl() leads to implementation-defined result.\n", errout.str());
check("void foo()\n" check("void foo()\n"
"{\n" "{\n"
@ -1486,9 +1495,9 @@ private:
" std::cout << acosf(-1.1) << std::endl;\n" " std::cout << acosf(-1.1) << std::endl;\n"
" std::cout << acosl(-1.1) << std::endl;\n" " std::cout << acosl(-1.1) << std::endl;\n"
"}"); "}");
ASSERT_EQUALS("[test.cpp:3]: (error) Passing value -1.1 to acos() leads to undefined result.\n" ASSERT_EQUALS("[test.cpp:3]: (warning) Passing value -1.1 to acos() leads to implementation-defined result.\n"
"[test.cpp:4]: (error) Passing value -1.1 to acosf() leads to undefined result.\n" "[test.cpp:4]: (warning) Passing value -1.1 to acosf() leads to implementation-defined result.\n"
"[test.cpp:5]: (error) Passing value -1.1 to acosl() leads to undefined result.\n", errout.str()); "[test.cpp:5]: (warning) Passing value -1.1 to acosl() leads to implementation-defined result.\n", errout.str());
} }
void mathfunctionCall_asin() { void mathfunctionCall_asin() {
@ -1537,9 +1546,9 @@ private:
" std::cout << asinf(1.1) << std::endl;\n" " std::cout << asinf(1.1) << std::endl;\n"
" std::cout << asinl(1.1) << std::endl;\n" " std::cout << asinl(1.1) << std::endl;\n"
"}"); "}");
ASSERT_EQUALS("[test.cpp:3]: (error) Passing value 1.1 to asin() leads to undefined result.\n" ASSERT_EQUALS("[test.cpp:3]: (warning) Passing value 1.1 to asin() leads to implementation-defined result.\n"
"[test.cpp:4]: (error) Passing value 1.1 to asinf() leads to undefined result.\n" "[test.cpp:4]: (warning) Passing value 1.1 to asinf() leads to implementation-defined result.\n"
"[test.cpp:5]: (error) Passing value 1.1 to asinl() leads to undefined result.\n", errout.str()); "[test.cpp:5]: (warning) Passing value 1.1 to asinl() leads to implementation-defined result.\n", errout.str());
check("void foo()\n" check("void foo()\n"
"{\n" "{\n"
@ -1547,9 +1556,9 @@ private:
" std::cout << asinf(-1.1) << std::endl;\n" " std::cout << asinf(-1.1) << std::endl;\n"
" std::cout << asinl(-1.1) << std::endl;\n" " std::cout << asinl(-1.1) << std::endl;\n"
"}"); "}");
ASSERT_EQUALS("[test.cpp:3]: (error) Passing value -1.1 to asin() leads to undefined result.\n" ASSERT_EQUALS("[test.cpp:3]: (warning) Passing value -1.1 to asin() leads to implementation-defined result.\n"
"[test.cpp:4]: (error) Passing value -1.1 to asinf() leads to undefined result.\n" "[test.cpp:4]: (warning) Passing value -1.1 to asinf() leads to implementation-defined result.\n"
"[test.cpp:5]: (error) Passing value -1.1 to asinl() leads to undefined result.\n", errout.str()); "[test.cpp:5]: (warning) Passing value -1.1 to asinl() leads to implementation-defined result.\n", errout.str());
} }
void mathfunctionCall_pow() { void mathfunctionCall_pow() {
@ -1560,9 +1569,9 @@ private:
" std::cout << powf(0,-10) << std::endl;\n" " std::cout << powf(0,-10) << std::endl;\n"
" std::cout << powl(0,-10) << std::endl;\n" " std::cout << powl(0,-10) << std::endl;\n"
"}"); "}");
ASSERT_EQUALS("[test.cpp:3]: (error) Passing values 0 and -10 to pow() leads to undefined result.\n" ASSERT_EQUALS("[test.cpp:3]: (warning) Passing values 0 and -10 to pow() leads to implementation-defined result.\n"
"[test.cpp:4]: (error) Passing values 0 and -10 to powf() leads to undefined result.\n" "[test.cpp:4]: (warning) Passing values 0 and -10 to powf() leads to implementation-defined result.\n"
"[test.cpp:5]: (error) Passing values 0 and -10 to powl() leads to undefined result.\n", errout.str()); "[test.cpp:5]: (warning) Passing values 0 and -10 to powl() leads to implementation-defined result.\n", errout.str());
check("void foo()\n" check("void foo()\n"
"{\n" "{\n"
@ -1619,9 +1628,9 @@ private:
" std::cout << atan2f(0,0) << std::endl;\n" " std::cout << atan2f(0,0) << std::endl;\n"
" std::cout << atan2l(0,0) << std::endl;\n" " std::cout << atan2l(0,0) << std::endl;\n"
"}"); "}");
ASSERT_EQUALS("[test.cpp:3]: (error) Passing values 0 and 0 to atan2() leads to undefined result.\n" ASSERT_EQUALS("[test.cpp:3]: (warning) Passing values 0 and 0 to atan2() leads to implementation-defined result.\n"
"[test.cpp:4]: (error) Passing values 0 and 0 to atan2f() leads to undefined result.\n" "[test.cpp:4]: (warning) Passing values 0 and 0 to atan2f() leads to implementation-defined result.\n"
"[test.cpp:5]: (error) Passing values 0 and 0 to atan2l() leads to undefined result.\n", errout.str()); "[test.cpp:5]: (warning) Passing values 0 and 0 to atan2l() leads to implementation-defined result.\n", errout.str());
} }
void mathfunctionCall_fmod() { void mathfunctionCall_fmod() {
@ -1632,9 +1641,9 @@ private:
" std::cout << fmodf(1.0,0) << std::endl;\n" " std::cout << fmodf(1.0,0) << std::endl;\n"
" std::cout << fmodl(1.0,0) << std::endl;\n" " std::cout << fmodl(1.0,0) << std::endl;\n"
"}"); "}");
ASSERT_EQUALS("[test.cpp:3]: (error) Passing values 1.0 and 0 to fmod() leads to undefined result.\n" ASSERT_EQUALS("[test.cpp:3]: (warning) Passing values 1.0 and 0 to fmod() leads to implementation-defined result.\n"
"[test.cpp:4]: (error) Passing values 1.0 and 0 to fmodf() leads to undefined result.\n" "[test.cpp:4]: (warning) Passing values 1.0 and 0 to fmodf() leads to implementation-defined result.\n"
"[test.cpp:5]: (error) Passing values 1.0 and 0 to fmodl() leads to undefined result.\n", errout.str()); "[test.cpp:5]: (warning) Passing values 1.0 and 0 to fmodl() leads to implementation-defined result.\n", errout.str());
check("void foo()\n" check("void foo()\n"
"{\n" "{\n"