From f5b81ac583369d48a1be8bbb59d6cac38b7d9f2d Mon Sep 17 00:00:00 2001 From: chrchr Date: Mon, 24 Jul 2023 14:06:16 +0200 Subject: [PATCH] Fix FP truncLongCastReturn on Windows --- lib/checktype.cpp | 32 +++++++++++++++++++++----------- test/testtype.cpp | 26 +++++++++++++++++--------- 2 files changed, 38 insertions(+), 20 deletions(-) diff --git a/lib/checktype.cpp b/lib/checktype.cpp index 7cc2d4d7643..68e857d4a1d 100644 --- a/lib/checktype.cpp +++ b/lib/checktype.cpp @@ -290,6 +290,17 @@ void CheckType::signConversionError(const Token *tok, const ValueFlow::Value *ne // Checking for long cast of int result const long x = var1 * var2; //--------------------------------------------------------------------------- +static bool isSmallerTypeSize(const ValueType* a, const ValueType* b, const Tokenizer* tokenizer) +{ + std::string strArr[] = { a->str(), b->str() }; + for (std::string& s : strArr) { + const std::size_t pos = s.rfind(' '); // get bare type string + if (pos != std::string::npos) + s.erase(s.begin(), s.begin() + pos + 1); + } + return tokenizer->sizeOfType(strArr[0]) < tokenizer->sizeOfType(strArr[1]); +} + void CheckType::checkLongCast() { if (!mSettings->severity.isEnabled(Severity::style)) @@ -319,7 +330,8 @@ void CheckType::checkLongCast() (lhstype->type == ValueType::Type::LONG || lhstype->type == ValueType::Type::LONGLONG) && lhstype->pointer == 0U && lhstype->constness == 1U && - lhstype->originalTypeName.empty()) + lhstype->originalTypeName.empty() && + isSmallerTypeSize(rhstype, lhstype, mTokenizer)) longCastAssignError(tok); } @@ -329,15 +341,10 @@ void CheckType::checkLongCast() // function must return long data const Token * def = scope->classDef; - bool islong = false; - while (Token::Match(def, "%type%|::")) { - if (def->str() == "long" && def->originalName().empty()) { - islong = true; - break; - } - def = def->previous(); - } - if (!islong) + if (!Token::Match(def, "%name% (") || !def->next()->valueType()) + continue; + const ValueType* retVt = def->next()->valueType(); + if (retVt->type != ValueType::Type::LONG && retVt->type != ValueType::Type::LONGLONG) continue; // return statements @@ -346,7 +353,10 @@ void CheckType::checkLongCast() if (tok->str() == "return") { if (Token::Match(tok->astOperand1(), "<<|*")) { const ValueType *type = tok->astOperand1()->valueType(); - if (type && type->type == ValueType::Type::INT && type->pointer == 0U && type->originalTypeName.empty()) + if (type && type->type == ValueType::Type::INT && + type->pointer == 0U && + type->originalTypeName.empty() && + isSmallerTypeSize(type, retVt, mTokenizer)) ret = tok; } // All return statements must have problem otherwise no warning diff --git a/test/testtype.cpp b/test/testtype.cpp index b8a60e4c813..cb5b2b1b3e7 100644 --- a/test/testtype.cpp +++ b/test/testtype.cpp @@ -326,12 +326,16 @@ class TestType : public TestFixture { void longCastAssign() { const Settings settings = settingsBuilder().severity(Severity::style).platform(cppcheck::Platform::Type::Unix64).build(); + const Settings settingsWin = settingsBuilder().severity(Severity::style).platform(cppcheck::Platform::Type::Win64).build(); - check("long f(int x, int y) {\n" - " const long ret = x * y;\n" - " return ret;\n" - "}\n", settings); + const char code[] = "long f(int x, int y) {\n" + " const long ret = x * y;\n" + " return ret;\n" + "}\n"; + check(code, settings); ASSERT_EQUALS("[test.cpp:2]: (style) int result is assigned to long variable. If the variable is long to avoid loss of information, then you have loss of information.\n", errout.str()); + check(code, settingsWin); + ASSERT_EQUALS("", errout.str()); check("long f() {\n" " const long long ret = 256 * (1 << 10);\n" @@ -355,18 +359,22 @@ class TestType : public TestFixture { } void longCastReturn() { - const Settings settings = settingsBuilder().severity(Severity::style).build(); + const Settings settings = settingsBuilder().severity(Severity::style).platform(cppcheck::Platform::Type::Unix64).build(); + const Settings settingsWin = settingsBuilder().severity(Severity::style).platform(cppcheck::Platform::Type::Win64).build(); - check("long f(int x, int y) {\n" - " return x * y;\n" - "}\n", settings); + const char code[] = "long f(int x, int y) {\n" + " return x * y;\n" + "}\n"; + check(code, settings); ASSERT_EQUALS("[test.cpp:2]: (style) int result is returned as long value. If the return value is long to avoid loss of information, then you have loss of information.\n", errout.str()); + check(code, settingsWin); + ASSERT_EQUALS("", errout.str()); // typedef check("size_t f(int x, int y) {\n" " return x * y;\n" "}\n", settings); - ASSERT_EQUALS("", errout.str()); + ASSERT_EQUALS("[test.cpp:2]: (style) int result is returned as long value. If the return value is long to avoid loss of information, then you have loss of information.\n", errout.str()); } // This function ensure that test works with different compilers. Floats can