Fixed #2200 (MathLib: Calculation overflow)

This commit is contained in:
Daniel Marjamäki 2010-11-20 10:05:33 +01:00
parent 9ccc57a455
commit e8ca76e02e
5 changed files with 45 additions and 22 deletions

View File

@ -605,7 +605,7 @@ private:
if (Token::Match(tok.tokAt(6), "%num% )")) if (Token::Match(tok.tokAt(6), "%num% )"))
{ {
const unsigned int len = Token::getStrLength(tok.tokAt(4)); const unsigned int len = Token::getStrLength(tok.tokAt(4));
const long sz = MathLib::toLongNumber(tok.strAt(6)); const MathLib::bigint sz = MathLib::toLongNumber(tok.strAt(6));
if (sz >= 0 && len >= static_cast<unsigned long>(sz)) if (sz >= 0 && len >= static_cast<unsigned long>(sz))
{ {
init_strncpy(checks, tok.tokAt(2)); init_strncpy(checks, tok.tokAt(2));

View File

@ -30,23 +30,37 @@
#include <cmath> #include <cmath>
#include <cctype> #include <cctype>
long MathLib::toLongNumber(const std::string &str) MathLib::bigint MathLib::toLongNumber(const std::string &str)
{ {
// hexadecimal numbers:
if (str.compare(0, 2, "0x") == 0 if (str.compare(0, 2, "0x") == 0
|| str.compare(0, 3, "+0x") == 0 || str.compare(0, 3, "+0x") == 0
|| str.compare(0, 3, "-0x") == 0) || str.compare(0, 3, "-0x") == 0)
{ {
return std::strtol(str.c_str(), '\0', 16); bigint ret = 0;
std::istringstream istr(str.substr((str[0]=='0') ? 2 : 3));
istr >> std::hex >> ret;
return (str[0]=='-') ? -ret : ret;
} }
// octal numbers:
if (str.compare(0, 1, "0") == 0 if (str.compare(0, 1, "0") == 0
|| str.compare(0, 2, "+0") == 0 || str.compare(0, 2, "+0") == 0
|| str.compare(0, 2, "-0") == 0) || str.compare(0, 2, "-0") == 0)
{ {
return std::strtol(str.c_str(), '\0', 8); bigint ret = 0;
std::istringstream istr(str.substr((str[0]=='0') ? 1 : 2));
istr >> std::oct >> ret;
return (str[0]=='-') ? -ret : ret;
} }
return (str.find("E", 0) != std::string::npos || str.find("e", 0) != std::string::npos)
? static_cast<long>(std::atof(str.c_str())) if (str.find_first_of("eE") != std::string::npos)
: std::atol(str.c_str()); return static_cast<bigint>(std::atof(str.c_str()));
bigint ret = 0;
std::istringstream istr(str);
istr >> ret;
return ret;
} }
double MathLib::toDoubleNumber(const std::string &str) double MathLib::toDoubleNumber(const std::string &str)
@ -199,7 +213,7 @@ std::string MathLib::add(const std::string & first, const std::string & second)
{ {
if (MathLib::isInt(first) && MathLib::isInt(second)) if (MathLib::isInt(first) && MathLib::isInt(second))
{ {
return toString<long>(toLongNumber(first) + toLongNumber(second)); return toString<bigint>(toLongNumber(first) + toLongNumber(second));
} }
return toString<double>(toDoubleNumber(first) + toDoubleNumber(second)); return toString<double>(toDoubleNumber(first) + toDoubleNumber(second));
} }
@ -208,7 +222,7 @@ std::string MathLib::subtract(const std::string &first, const std::string &secon
{ {
if (MathLib::isInt(first) && MathLib::isInt(second)) if (MathLib::isInt(first) && MathLib::isInt(second))
{ {
return toString<long>(toLongNumber(first) - toLongNumber(second)); return toString<bigint>(toLongNumber(first) - toLongNumber(second));
} }
return toString<double>(toDoubleNumber(first) - toDoubleNumber(second)); return toString<double>(toDoubleNumber(first) - toDoubleNumber(second));
} }
@ -217,7 +231,7 @@ std::string MathLib::divide(const std::string &first, const std::string &second)
{ {
if (MathLib::isInt(first) && MathLib::isInt(second)) if (MathLib::isInt(first) && MathLib::isInt(second))
{ {
return toString<long>(toLongNumber(first) / toLongNumber(second)); return toString<bigint>(toLongNumber(first) / toLongNumber(second));
} }
return toString<double>(toDoubleNumber(first) / toDoubleNumber(second)); return toString<double>(toDoubleNumber(first) / toDoubleNumber(second));
} }
@ -226,7 +240,7 @@ std::string MathLib::multiply(const std::string &first, const std::string &secon
{ {
if (MathLib::isInt(first) && MathLib::isInt(second)) if (MathLib::isInt(first) && MathLib::isInt(second))
{ {
return toString<long>(toLongNumber(first) * toLongNumber(second)); return toString<bigint>(toLongNumber(first) * toLongNumber(second));
} }
return toString<double>(toDoubleNumber(first) * toDoubleNumber(second)); return toString<double>(toDoubleNumber(first) * toDoubleNumber(second));
} }

View File

@ -33,7 +33,16 @@ class Tokenizer;
class MathLib class MathLib
{ {
public: public:
static long toLongNumber(const std::string & str); // To compile Cppcheck on a compiler that doesn't support "long long",
// use NOLONGLONG.
#ifdef NOLONGLONG
typedef long bigint;
#else
typedef long long bigint;
#endif
static bigint toLongNumber(const std::string & str);
static double toDoubleNumber(const std::string & str); static double toDoubleNumber(const std::string & str);
template<typename T> template<typename T>

View File

@ -6571,9 +6571,9 @@ bool Tokenizer::simplifyCalculations()
const std::string after(tok->tokAt(3) ? tok->strAt(3).c_str() : ""); const std::string after(tok->tokAt(3) ? tok->strAt(3).c_str() : "");
if ((prev == "(" || prev == "&&" || prev == "||") && (after == ")" || after == "&&" || after == "||")) if ((prev == "(" || prev == "&&" || prev == "||") && (after == ")" || after == "&&" || after == "||"))
{ {
const int op1(MathLib::toLongNumber(tok->str())); const MathLib::bigint op1(MathLib::toLongNumber(tok->str()));
const std::string &cmp(tok->next()->str()); const std::string &cmp(tok->next()->str());
const int op2(MathLib::toLongNumber(tok->tokAt(2)->str())); const MathLib::bigint op2(MathLib::toLongNumber(tok->tokAt(2)->str()));
std::string result; std::string result;
@ -6598,16 +6598,16 @@ bool Tokenizer::simplifyCalculations()
if (Token::Match(tok->previous(), "[([,=] %num% <<|>> %num%")) if (Token::Match(tok->previous(), "[([,=] %num% <<|>> %num%"))
{ {
const int op1(MathLib::toLongNumber(tok->str())); const MathLib::bigint op1(MathLib::toLongNumber(tok->str()));
const int op2(MathLib::toLongNumber(tok->tokAt(2)->str())); const MathLib::bigint op2(MathLib::toLongNumber(tok->tokAt(2)->str()));
int result; MathLib::bigint result;
if (tok->next()->str() == "<<") if (tok->next()->str() == "<<")
result = op1 << op2; result = op1 << op2;
else else
result = op1 >> op2; result = op1 >> op2;
std::stringstream ss; std::ostringstream ss;
ss << result; ss << result;
tok->str(ss.str()); tok->str(ss.str());
@ -7091,7 +7091,7 @@ void Tokenizer::simplifyEnum()
end = tok1->tokAt(-1)->link(); end = tok1->tokAt(-1)->link();
long lastValue = -1; MathLib::bigint lastValue = -1;
Token * lastEnumValueStart = 0; Token * lastEnumValueStart = 0;
Token * lastEnumValueEnd = 0; Token * lastEnumValueEnd = 0;
@ -7146,7 +7146,7 @@ void Tokenizer::simplifyEnum()
// value is previous expression + 1 // value is previous expression + 1
tok1->insertToken("+"); tok1->insertToken("+");
tok1 = tok1->next(); tok1 = tok1->next();
tok1->insertToken(MathLib::toString<long>(lastValue)); tok1->insertToken(MathLib::toString<MathLib::bigint>(lastValue));
enumValue = 0; enumValue = 0;
enumValueStart = valueStart->next(); enumValueStart = valueStart->next();
enumValueEnd = tok1->next(); enumValueEnd = tok1->next();
@ -7154,7 +7154,7 @@ void Tokenizer::simplifyEnum()
else else
{ {
// value is previous numeric value + 1 // value is previous numeric value + 1
tok1->insertToken(MathLib::toString<long>(lastValue)); tok1->insertToken(MathLib::toString<MathLib::bigint>(lastValue));
enumValue = tok1->next(); enumValue = tok1->next();
} }
} }

View File

@ -68,7 +68,7 @@ private:
ASSERT_EQUALS("-3000" , MathLib::multiply("-1.0E+3", "3")); ASSERT_EQUALS("-3000" , MathLib::multiply("-1.0E+3", "3"));
ASSERT_EQUALS("0" , MathLib::multiply("-1.0E+3", "0")); ASSERT_EQUALS("0" , MathLib::multiply("-1.0E+3", "0"));
ASSERT_EQUALS("0" , MathLib::multiply("+1.0E+3", "0")); ASSERT_EQUALS("0" , MathLib::multiply("+1.0E+3", "0"));
TODO_ASSERT_EQUALS("2147483648" , MathLib::multiply("2","1073741824")); ASSERT_EQUALS("2147483648" , MathLib::multiply("2","1073741824"));
ASSERT_EQUALS("536870912" , MathLib::multiply("512","1048576")); ASSERT_EQUALS("536870912" , MathLib::multiply("512","1048576"));
// divide // divide