Fix #4724 (Error in calculation shift operation: wrong sign: 1UL << 63)

This commit is contained in:
Alexander Mai 2014-04-10 19:22:14 +02:00
parent b0af67f369
commit e19129a409
3 changed files with 27 additions and 11 deletions

View File

@ -33,6 +33,7 @@
class CPPCHECKLIB MathLib {
public:
typedef long long bigint;
typedef unsigned long long biguint;
static bigint toLongNumber(const std::string & str);
template<class T> static std::string toString(T value) {

View File

@ -800,6 +800,22 @@ static bool isLowerEqualThanMulDiv(const Token* lower)
return isLowerThanMulDiv(lower) || Token::Match(lower, "[*/%]");
}
template <typename T>
std::string typeCorrectShift(const char cop, const Token* left, const Token* right)
{
const T leftInt=MathLib::toLongNumber(left->str());
const T rightInt=MathLib::toLongNumber(right->str());
if (cop == '&' || cop == '|' || cop == '^')
return MathLib::calculate(left->str(), right->str(), cop);
else if (cop == '<') {
if (left->previous()->str() != "<<" && rightInt > 0) // Ensure that its not a shift operator as used for streams
return MathLib::toString(leftInt << rightInt);
} else if (rightInt > 0)
return MathLib::toString(leftInt >> rightInt);
return "";
}
bool TemplateSimplifier::simplifyNumericCalculations(Token *tok)
{
@ -828,18 +844,11 @@ bool TemplateSimplifier::simplifyNumericCalculations(Token *tok)
// Integer operations
if (Token::Match(op, ">>|<<|&|^|%or%")) {
const char cop = op->str()[0];
const MathLib::bigint leftInt(MathLib::toLongNumber(tok->str()));
const MathLib::bigint rightInt(MathLib::toLongNumber(tok->strAt(2)));
std::string result;
if (cop == '&' || cop == '|' || cop == '^')
result = MathLib::calculate(tok->str(), tok->strAt(2), cop);
else if (cop == '<') {
if (tok->previous()->str() != "<<" && rightInt > 0) // Ensure that its not a shift operator as used for streams
result = MathLib::toString(leftInt << rightInt);
} else if (rightInt > 0)
result = MathLib::toString(leftInt >> rightInt);
if (tok->str().find_first_of("uU") != std::string::npos)
result = typeCorrectShift<MathLib::biguint>(cop, tok, tok->tokAt(2));
else
result = typeCorrectShift<MathLib::bigint>(cop, tok, tok->tokAt(2));
if (!result.empty()) {
ret = true;
tok->str(result);

View File

@ -193,6 +193,7 @@ private:
TEST_CASE(simplifyKnownVariables54); // #4913 'x' is not 0 after *--x=0;
TEST_CASE(simplifyKnownVariables55); // pointer alias
TEST_CASE(simplifyKnownVariables56); // ticket #5301 - >>
TEST_CASE(simplifyKnownVariables57); // ticket #4724
TEST_CASE(simplifyKnownVariablesIfEq1); // if (a==5) => a is 5 in the block
TEST_CASE(simplifyKnownVariablesIfEq2); // if (a==5) { buf[a++] = 0; }
TEST_CASE(simplifyKnownVariablesIfEq3); // #4708 - if (a==5) { buf[--a] = 0; }
@ -2923,6 +2924,11 @@ private:
tokenizeAndStringify("void f() { int a=0,b=0; *p>>a>>b; return a/b; }", true));
}
void simplifyKnownVariables57() { // #4724
ASSERT_EQUALS("unsigned long long x ; x = 9223372036854775808 ;", tokenizeAndStringify("unsigned long long x = 1UL << 63 ;", true));
ASSERT_EQUALS("long long x ; x = -9223372036854775808 ;", tokenizeAndStringify("long long x = 1L << 63 ;", true));
}
void simplifyKnownVariablesIfEq1() {
const char code[] = "void f(int x) {\n"
" if (x==5) {\n"