From e19129a409bad36a3302c1e379bd41d1f86d85fa Mon Sep 17 00:00:00 2001 From: Alexander Mai Date: Thu, 10 Apr 2014 19:22:14 +0200 Subject: [PATCH] Fix #4724 (Error in calculation shift operation: wrong sign: 1UL << 63) --- lib/mathlib.h | 1 + lib/templatesimplifier.cpp | 31 ++++++++++++++++++++----------- test/testtokenize.cpp | 6 ++++++ 3 files changed, 27 insertions(+), 11 deletions(-) diff --git a/lib/mathlib.h b/lib/mathlib.h index 049fd147b..246baa05f 100644 --- a/lib/mathlib.h +++ b/lib/mathlib.h @@ -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 static std::string toString(T value) { diff --git a/lib/templatesimplifier.cpp b/lib/templatesimplifier.cpp index 737c4990d..c46f87641 100644 --- a/lib/templatesimplifier.cpp +++ b/lib/templatesimplifier.cpp @@ -800,6 +800,22 @@ static bool isLowerEqualThanMulDiv(const Token* lower) return isLowerThanMulDiv(lower) || Token::Match(lower, "[*/%]"); } +template +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(cop, tok, tok->tokAt(2)); + else + result = typeCorrectShift(cop, tok, tok->tokAt(2)); if (!result.empty()) { ret = true; tok->str(result); diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp index bb339026e..d491c0982 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -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"