ticket #1513 new check: Detecting obviously wrong math call arguments passed to math functions)

This commit is contained in:
Martin Ettl 2010-04-02 02:19:38 +02:00
parent c7d36b73ed
commit b5fb01c202
6 changed files with 199 additions and 2 deletions

View File

@ -2435,6 +2435,48 @@ void CheckOther::checkZeroDivision()
}
void CheckOther::checkMathFunctions()
{
for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next())
{
// case log(-2)
if (Token::Match(tok, "log ( %num% )") &&
MathLib::isNegative(tok->tokAt(2)->str()) &&
MathLib::isInt(tok->tokAt(2)->str()) &&
MathLib::toLongNumber(tok->tokAt(2)->str()) <= 0)
{
mathfunctionCallError(tok);
}
// case log(-2.0)
else if (Token::Match(tok, "log ( %num% )") &&
MathLib::isNegative(tok->tokAt(2)->str()) &&
MathLib::isFloat(tok->tokAt(2)->str()) &&
MathLib::toDoubleNumber(tok->tokAt(2)->str()) <= 0.)
{
mathfunctionCallError(tok);
}
// case log(0.0)
else if (Token::Match(tok, "log ( %num% )") &&
!MathLib::isNegative(tok->tokAt(2)->str()) &&
MathLib::isFloat(tok->tokAt(2)->str()) &&
MathLib::toDoubleNumber(tok->tokAt(2)->str()) <= 0.)
{
mathfunctionCallError(tok);
}
// case log(0)
else if (Token::Match(tok, "log ( %num% )") &&
!MathLib::isNegative(tok->tokAt(2)->str()) &&
MathLib::isInt(tok->tokAt(2)->str()) &&
MathLib::toLongNumber(tok->tokAt(2)->str()) <= 0)
{
mathfunctionCallError(tok);
}
}
}
void CheckOther::postIncrement()
{
@ -2578,6 +2620,11 @@ void CheckOther::zerodivError(const Token *tok)
reportError(tok, Severity::error, "zerodiv", "Division by zero");
}
void CheckOther::mathfunctionCallError(const Token *tok)
{
reportError(tok, Severity::error, "wrongmathcall","Passing value " + tok->tokAt(2)->str() + " to " + tok->str() + "() leads to undefined result");
}
void CheckOther::postIncrementError(const Token *tok, const std::string &var_name, const bool isIncrement)
{
std::string type = (isIncrement ? "Incrementing" : "Decrementing");

View File

@ -82,6 +82,7 @@ public:
checkOther.strPlusChar();
checkOther.invalidFunctionUsage();
checkOther.checkZeroDivision();
checkOther.checkMathFunctions();
// New type of check: Check execution paths
checkOther.executionPaths();
@ -150,6 +151,9 @@ public:
/** @brief %Check zero division*/
void checkZeroDivision();
/** @brief %Check for parameters given to math function that do not make sense*/
void checkMathFunctions();
/** @brief %Check for post increment/decrement in for loop*/
void postIncrement();
@ -184,6 +188,7 @@ public:
void uninitdataError(const Token *tok, const std::string &varname);
void uninitvarError(const Token *tok, const std::string &varname);
void zerodivError(const Token *tok);
void mathfunctionCallError(const Token *tok);
void postIncrementError(const Token *tok, const std::string &var_name, const bool isIncrement);
void getErrorMessages()
@ -196,6 +201,7 @@ public:
uninitdataError(0, "varname");
uninitvarError(0, "varname");
zerodivError(0);
mathfunctionCallError(0);
// style
cstyleCastError(0);

View File

@ -75,6 +75,32 @@ std::string MathLib::toString(T d)
return result.str();
}
bool MathLib::isFloat(const std::string &s)
{
// every number that contains a . is a float
if (s.find("." , 0) != std::string::npos)
return true;
// scientific notation
else if (s.find("E-", 0) != std::string::npos
|| s.find("e-", 0) != std::string::npos)
return true;
return false;
}
bool MathLib::isNegative(const std::string &s)
{
// remember position
unsigned long n = 0;
// eat up whitespace
while (std::isspace(s[n])) ++n;
// every negative number has a negative sign
if (s[n] == '-')
return true;
return false;
}
bool MathLib::isInt(const std::string & s)
{
// perform prechecks:

View File

@ -37,6 +37,8 @@ public:
static std::string toString(T d);
static bool isInt(const std::string & str);
static bool isFloat(const std::string &str);
static bool isNegative(const std::string &str);
static std::string add(const std::string & first, const std::string & second);
static std::string subtract(const std::string & first, const std::string & second);

View File

@ -34,6 +34,8 @@ private:
TEST_CASE(calculate);
TEST_CASE(convert);
TEST_CASE(isint);
TEST_CASE(isnegative);
TEST_CASE(isfloat);
}
void calculate()
@ -164,6 +166,55 @@ private:
ASSERT_EQUALS(false, MathLib::isInt("-1.E+1"));
ASSERT_EQUALS(false, MathLib::isInt("+1.E-1"));
}
void isnegative()
{
ASSERT_EQUALS(true, MathLib::isNegative("-1"));
ASSERT_EQUALS(true, MathLib::isNegative("-1."));
ASSERT_EQUALS(true, MathLib::isNegative("-1.0"));
ASSERT_EQUALS(true, MathLib::isNegative("-1.0E+2"));
ASSERT_EQUALS(true, MathLib::isNegative("-1.0E-2"));
ASSERT_EQUALS(false, MathLib::isNegative("+1"));
ASSERT_EQUALS(false, MathLib::isNegative("+1."));
ASSERT_EQUALS(false, MathLib::isNegative("+1.0"));
ASSERT_EQUALS(false, MathLib::isNegative("+1.0E+2"));
ASSERT_EQUALS(false, MathLib::isNegative("+1.0E-2"));
}
void isfloat()
{
ASSERT_EQUALS(false, MathLib::isFloat("0"));
ASSERT_EQUALS(true , MathLib::isFloat("0."));
ASSERT_EQUALS(true , MathLib::isFloat("0.0"));
ASSERT_EQUALS(true , MathLib::isFloat("-0."));
ASSERT_EQUALS(true , MathLib::isFloat("+0."));
ASSERT_EQUALS(true , MathLib::isFloat("-0.0"));
ASSERT_EQUALS(true , MathLib::isFloat("+0.0"));
ASSERT_EQUALS(true , MathLib::isFloat("+0.0E+1"));
ASSERT_EQUALS(true , MathLib::isFloat("+0.0E-1"));
ASSERT_EQUALS(true , MathLib::isFloat("-0.0E+1"));
ASSERT_EQUALS(true , MathLib::isFloat("-0.0E-1"));
ASSERT_EQUALS(false , MathLib::isFloat("1"));
ASSERT_EQUALS(false , MathLib::isFloat("-1"));
ASSERT_EQUALS(false , MathLib::isFloat("+1"));
ASSERT_EQUALS(false , MathLib::isFloat("+1E+1"));
ASSERT_EQUALS(false , MathLib::isFloat("+1E+10000"));
ASSERT_EQUALS(false , MathLib::isFloat("-1E+1"));
ASSERT_EQUALS(false , MathLib::isFloat("-1E+10000"));
ASSERT_EQUALS(true , MathLib::isFloat("-1E-1"));
ASSERT_EQUALS(true , MathLib::isFloat("-1E-10000"));
ASSERT_EQUALS(true , MathLib::isFloat("0.4"));
ASSERT_EQUALS(true , MathLib::isFloat("2352.3f"));
ASSERT_EQUALS(true , MathLib::isFloat("0.00004"));
ASSERT_EQUALS(true , MathLib::isFloat("2352.00001f"));
ASSERT_EQUALS(true , MathLib::isFloat(".4"));
ASSERT_EQUALS(true , MathLib::isFloat("1.0E+1"));
ASSERT_EQUALS(true , MathLib::isFloat("1.0E-1"));
ASSERT_EQUALS(true , MathLib::isFloat("-1.0E+1"));
}
};
REGISTER_TEST(TestMathLib)

View File

@ -89,6 +89,8 @@ private:
TEST_CASE(dangerousStrolUsage);
TEST_CASE(passedByValue);
TEST_CASE(mathfunctionCall1);
}
void check(const char code[])
@ -110,11 +112,10 @@ private:
checkOther.warningRedundantCode();
checkOther.checkZeroDivision();
checkOther.unreachableCode();
checkOther.checkMathFunctions();
}
void zeroDiv1()
{
check("void foo()\n"
@ -2157,6 +2158,70 @@ private:
ASSERT_EQUALS("[test.cpp:1]: (style) Function parameter 'v' is passed by value. It could be passed by reference instead.\n", errout.str());
}
void mathfunctionCall1()
{
check("void foo()\n"
"{\n"
" std::cout << log(-2) << std::endl;\n"
"}");
ASSERT_EQUALS("[test.cpp:3]: (error) Passing value -2 to log() leads to undefined result\n", errout.str());
check("void foo()\n"
"{\n"
" std::cout << log(-1.) << std::endl;\n"
"}");
ASSERT_EQUALS("[test.cpp:3]: (error) Passing value -1. to log() leads to undefined result\n", errout.str());
check("void foo()\n"
"{\n"
" std::cout << log(-1.0) << std::endl;\n"
"}");
ASSERT_EQUALS("[test.cpp:3]: (error) Passing value -1.0 to log() leads to undefined result\n", errout.str());
check("void foo()\n"
"{\n"
" std::cout << log(-0.1) << std::endl;\n"
"}");
ASSERT_EQUALS("[test.cpp:3]: (error) Passing value -0.1 to log() leads to undefined result\n", errout.str());
check("void foo()\n"
"{\n"
" std::cout << log(0) << std::endl;\n"
"}");
ASSERT_EQUALS("[test.cpp:3]: (error) Passing value 0 to log() leads to undefined result\n", errout.str());
check("void foo()\n"
"{\n"
" std::cout << log(0.) << std::endl;\n"
"}");
ASSERT_EQUALS("[test.cpp:3]: (error) Passing value 0. to log() leads to undefined result\n", errout.str());
check("void foo()\n"
"{\n"
" std::cout << log(0.0) << std::endl;\n"
"}");
ASSERT_EQUALS("[test.cpp:3]: (error) Passing value 0.0 to log() leads to undefined result\n", errout.str());
check("void foo()\n"
"{\n"
" std::cout << log(1.0E+3) << std::endl;\n"
"}");
ASSERT_EQUALS("", errout.str());
check("void foo()\n"
"{\n"
" std::cout << log(1.0E-3) << std::endl;\n"
"}");
TODO_ASSERT_EQUALS("", errout.str());
check("void foo()\n"
"{\n"
" std::cout << log(1E-3) << std::endl;\n"
"}");
TODO_ASSERT_EQUALS("", errout.str());
}
};
REGISTER_TEST(TestOther)