From 65ce55e675e29c8b0f787ca9ee99f1fb6de9ad46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Sun, 8 Jan 2012 12:07:25 +0100 Subject: [PATCH] Fixed #3472 (false positive: (error) Passing value 0 to log() leads to undefined result) --- lib/checkother.cpp | 100 ++++++++++++++++++++++++--------------------- test/testother.cpp | 3 ++ 2 files changed, 57 insertions(+), 46 deletions(-) diff --git a/lib/checkother.cpp b/lib/checkother.cpp index 60e01621c..61cb54782 100644 --- a/lib/checkother.cpp +++ b/lib/checkother.cpp @@ -2160,53 +2160,61 @@ void CheckOther::zerodivError(const Token *tok) //--------------------------------------------------------------------------- void CheckOther::checkMathFunctions() { - for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) { - if (tok->varId() == 0 && Token::Match(tok, "log|log10 ( %num% )")) { - bool isNegative = MathLib::isNegative(tok->strAt(2)); - bool isInt = MathLib::isInt(tok->strAt(2)); - bool isFloat = MathLib::isFloat(tok->strAt(2)); - if (isNegative && isInt && MathLib::toLongNumber(tok->strAt(2)) <= 0) { - mathfunctionCallError(tok); // case log(-2) - } else if (isNegative && isFloat && MathLib::toDoubleNumber(tok->strAt(2)) <= 0.) { - mathfunctionCallError(tok); // case log(-2.0) - } else if (!isNegative && isFloat && MathLib::toDoubleNumber(tok->strAt(2)) <= 0.) { - mathfunctionCallError(tok); // case log(0.0) - } else if (!isNegative && isInt && MathLib::toLongNumber(tok->strAt(2)) <= 0) { - mathfunctionCallError(tok); // case log(0) - } - } + const SymbolDatabase *db = _tokenizer->getSymbolDatabase(); - // acos( x ), asin( x ) where x is defined for intervall [-1,+1], but not beyound - else if (tok->varId() == 0 && - Token::Match(tok, "acos|asin ( %num% )") && - std::fabs(MathLib::toDoubleNumber(tok->strAt(2))) > 1.0) { - mathfunctionCallError(tok); - } - // sqrt( x ): if x is negative the result is undefined - else if (tok->varId() == 0 && - Token::Match(tok, "sqrt|sqrtf|sqrtl ( %num% )") && - MathLib::isNegative(tok->strAt(2))) { - mathfunctionCallError(tok); - } - // atan2 ( x , y): x and y can not be zero, because this is mathematically not defined - else if (tok->varId() == 0 && - Token::Match(tok, "atan2 ( %num% , %num% )") && - MathLib::isNullValue(tok->strAt(2)) && - MathLib::isNullValue(tok->strAt(4))) { - mathfunctionCallError(tok, 2); - } - // fmod ( x , y) If y is zero, then either a range error will occur or the function will return zero (implementation-defined). - else if (tok->varId() == 0 && - Token::Match(tok, "fmod ( %num% , %num% )") && - MathLib::isNullValue(tok->strAt(4))) { - mathfunctionCallError(tok, 2); - } - // pow ( x , y) If x is zero, and y is negative --> division by zero - else if (tok->varId() == 0 && - Token::Match(tok, "pow ( %num% , %num% )") && - MathLib::isNullValue(tok->strAt(2)) && - MathLib::isNegative(tok->strAt(4))) { - mathfunctionCallError(tok, 2); + std::list::const_iterator scope; + for (scope = db->scopeList.begin(); scope != db->scopeList.end(); ++scope) { + if (scope->type != Scope::eFunction) + continue; + + for (const Token *tok = scope->classStart; tok && tok != scope->classEnd; tok = tok->next()) { + if (tok->varId() == 0 && Token::Match(tok, "log|log10 ( %num% )")) { + bool isNegative = MathLib::isNegative(tok->strAt(2)); + bool isInt = MathLib::isInt(tok->strAt(2)); + bool isFloat = MathLib::isFloat(tok->strAt(2)); + if (isNegative && isInt && MathLib::toLongNumber(tok->strAt(2)) <= 0) { + mathfunctionCallError(tok); // case log(-2) + } else if (isNegative && isFloat && MathLib::toDoubleNumber(tok->strAt(2)) <= 0.) { + mathfunctionCallError(tok); // case log(-2.0) + } else if (!isNegative && isFloat && MathLib::toDoubleNumber(tok->strAt(2)) <= 0.) { + mathfunctionCallError(tok); // case log(0.0) + } else if (!isNegative && isInt && MathLib::toLongNumber(tok->strAt(2)) <= 0) { + mathfunctionCallError(tok); // case log(0) + } + } + + // acos( x ), asin( x ) where x is defined for intervall [-1,+1], but not beyound + else if (tok->varId() == 0 && + Token::Match(tok, "acos|asin ( %num% )") && + std::fabs(MathLib::toDoubleNumber(tok->strAt(2))) > 1.0) { + mathfunctionCallError(tok); + } + // sqrt( x ): if x is negative the result is undefined + else if (tok->varId() == 0 && + Token::Match(tok, "sqrt|sqrtf|sqrtl ( %num% )") && + MathLib::isNegative(tok->strAt(2))) { + mathfunctionCallError(tok); + } + // atan2 ( x , y): x and y can not be zero, because this is mathematically not defined + else if (tok->varId() == 0 && + Token::Match(tok, "atan2 ( %num% , %num% )") && + MathLib::isNullValue(tok->strAt(2)) && + MathLib::isNullValue(tok->strAt(4))) { + mathfunctionCallError(tok, 2); + } + // fmod ( x , y) If y is zero, then either a range error will occur or the function will return zero (implementation-defined). + else if (tok->varId() == 0 && + Token::Match(tok, "fmod ( %num% , %num% )") && + MathLib::isNullValue(tok->strAt(4))) { + mathfunctionCallError(tok, 2); + } + // pow ( x , y) If x is zero, and y is negative --> division by zero + else if (tok->varId() == 0 && + Token::Match(tok, "pow ( %num% , %num% )") && + MathLib::isNullValue(tok->strAt(2)) && + MathLib::isNegative(tok->strAt(4))) { + mathfunctionCallError(tok, 2); + } } } } diff --git a/test/testother.cpp b/test/testother.cpp index fafc0578b..1756d9bf9 100644 --- a/test/testother.cpp +++ b/test/testother.cpp @@ -929,6 +929,9 @@ private: "}"); ASSERT_EQUALS("", errout.str()); + // #3473 - no warning if "log" is a variable + check("Fred::Fred() : log(0) { }"); + ASSERT_EQUALS("", errout.str()); // acos check("void foo()\n"