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% )"))
{
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))
{
init_strncpy(checks, tok.tokAt(2));

View File

@ -30,23 +30,37 @@
#include <cmath>
#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
|| 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
|| 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()))
: std::atol(str.c_str());
if (str.find_first_of("eE") != std::string::npos)
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)
@ -199,7 +213,7 @@ std::string MathLib::add(const std::string & first, const std::string & 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));
}
@ -208,7 +222,7 @@ std::string MathLib::subtract(const std::string &first, const std::string &secon
{
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));
}
@ -217,7 +231,7 @@ std::string MathLib::divide(const std::string &first, const std::string &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));
}
@ -226,7 +240,7 @@ std::string MathLib::multiply(const std::string &first, const std::string &secon
{
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));
}

View File

@ -33,7 +33,16 @@ class Tokenizer;
class MathLib
{
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);
template<typename T>

View File

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

View File

@ -68,7 +68,7 @@ private:
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"));
TODO_ASSERT_EQUALS("2147483648" , MathLib::multiply("2","1073741824"));
ASSERT_EQUALS("2147483648" , MathLib::multiply("2","1073741824"));
ASSERT_EQUALS("536870912" , MathLib::multiply("512","1048576"));
// divide