diff --git a/lib/checktype.cpp b/lib/checktype.cpp index 9f3e0993868..3e00c941980 100644 --- a/lib/checktype.cpp +++ b/lib/checktype.cpp @@ -198,9 +198,12 @@ void CheckType::checkIntegerOverflow() const MathLib::bigint maxvalue = (((MathLib::biguint)1) << (bits - 1)) - 1; // is there a overflow result value + bool isOverflow = true; const ValueFlow::Value *value = tok->getValueGE(maxvalue + 1, *mSettings); - if (!value) + if (!value) { value = tok->getValueLE(-maxvalue - 2, *mSettings); + isOverflow = false; + } if (!value || !mSettings->isEnabled(value,false)) continue; @@ -208,25 +211,26 @@ void CheckType::checkIntegerOverflow() if (tok->str() == "<<" && value->intvalue > 0 && value->intvalue < (((MathLib::bigint)1) << bits)) continue; - integerOverflowError(tok, *value); + integerOverflowError(tok, *value, isOverflow); } } -void CheckType::integerOverflowError(const Token *tok, const ValueFlow::Value &value) +void CheckType::integerOverflowError(const Token *tok, const ValueFlow::Value &value, bool isOverflow) { const std::string expr(tok ? tok->expressionString() : ""); + const std::string type = isOverflow ? "overflow" : "underflow"; std::string msg; if (value.condition) msg = ValueFlow::eitherTheConditionIsRedundant(value.condition) + - " or there is signed integer overflow for expression '" + expr + "'."; + " or there is signed integer " + type + " for expression '" + expr + "'."; else - msg = "Signed integer overflow for expression '" + expr + "'."; + msg = "Signed integer " + type + " for expression '" + expr + "'."; if (value.safe) msg = "Safe checks: " + msg; - reportError(getErrorPath(tok, &value, "Integer overflow"), + reportError(getErrorPath(tok, &value, "Integer " + type), value.errorSeverity() ? Severity::error : Severity::warning, getMessageId(value, "integerOverflow").c_str(), msg, diff --git a/lib/checktype.h b/lib/checktype.h index 57c0dedbfbf..e76276c4ccf 100644 --- a/lib/checktype.h +++ b/lib/checktype.h @@ -81,7 +81,7 @@ class CPPCHECKLIB CheckType : public Check { // Error messages.. void tooBigBitwiseShiftError(const Token *tok, int lhsbits, const ValueFlow::Value &rhsbits); void tooBigSignedBitwiseShiftError(const Token *tok, int lhsbits, const ValueFlow::Value &rhsbits); - void integerOverflowError(const Token *tok, const ValueFlow::Value &value); + void integerOverflowError(const Token *tok, const ValueFlow::Value &value, bool isOverflow = true); void signConversionError(const Token *tok, const ValueFlow::Value *negativeValue, bool constvalue); void longCastAssignError(const Token *tok, const ValueType* src = nullptr, const ValueType* tgt = nullptr); void longCastReturnError(const Token *tok, const ValueType* src = nullptr, const ValueType* tgt = nullptr); diff --git a/test/testtype.cpp b/test/testtype.cpp index 8d3f4acb421..8ae4fa4b954 100644 --- a/test/testtype.cpp +++ b/test/testtype.cpp @@ -291,7 +291,7 @@ class TestType : public TestFixture { " if (x==123456) {}\n" " return -123456 * x;\n" "}",settings); - ASSERT_EQUALS("[test.cpp:2] -> [test.cpp:3]: (warning) Either the condition 'x==123456' is redundant or there is signed integer overflow for expression '-123456*x'.\n", errout_str()); + ASSERT_EQUALS("[test.cpp:2] -> [test.cpp:3]: (warning) Either the condition 'x==123456' is redundant or there is signed integer underflow for expression '-123456*x'.\n", errout_str()); check("int foo(signed int x) {\n" " if (x==123456) {}\n" @@ -303,6 +303,16 @@ class TestType : public TestFixture { " return (i == 31) ? 1 << i : 0;\n" "}", settings); ASSERT_EQUALS("[test.cpp:2] -> [test.cpp:2]: (warning) Shifting signed 32-bit value by 31 bits is undefined behaviour. See condition at line 2.\n", errout_str()); + + check("void f() {\n" // #13092 + " int n = 0;\n" + " for (int i = 0; i < 10; i++) {\n" + " n = n * 47163 - 57412;\n" + " }\n" + "}", settings); + ASSERT_EQUALS("[test.cpp:4]: (error) Signed integer underflow for expression 'n*47163'.\n" + "[test.cpp:4]: (error) Signed integer underflow for expression 'n*47163-57412'.\n", + errout_str()); } void signConversion() {