From a7086c570bb83422e83a37f7e6116298d1653c30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20St=C3=B6neberg?= Date: Tue, 23 Jan 2024 13:55:53 +0100 Subject: [PATCH 1/7] fixed #12378 FN containerOutOfBounds with scope operator / Library: cleaned up usage of `Container::startPattern2` (#5908) Co-authored-by: chrchr --- lib/library.cpp | 4 ++- test/cfg/std.cpp | 7 +++++ test/testsymboldatabase.cpp | 54 ++++++++++++++++++------------------- 3 files changed, 36 insertions(+), 29 deletions(-) diff --git a/lib/library.cpp b/lib/library.cpp index 3caf7e70a69..96df481171d 100644 --- a/lib/library.cpp +++ b/lib/library.cpp @@ -434,7 +434,9 @@ Library::Error Library::load(const tinyxml2::XMLDocument &doc) const char* const startPattern = node->Attribute("startPattern"); if (startPattern) { container.startPattern = startPattern; - container.startPattern2 = container.startPattern + " !!::"; + container.startPattern2 = startPattern; + if (!endsWith(container.startPattern, '<')) + container.startPattern2 += " !!::"; } const char* const endPattern = node->Attribute("endPattern"); if (endPattern) diff --git a/test/cfg/std.cpp b/test/cfg/std.cpp index e05d43f6f92..4fab6bb6957 100644 --- a/test/cfg/std.cpp +++ b/test/cfg/std.cpp @@ -4925,6 +4925,13 @@ std::string global_scope_std() // #12355 return ss.str(); } +::std::size_t global_scope_std2() // #12378 +{ + std::vector<::std::size_t> v; + // cppcheck-suppress containerOutOfBounds + return v.front(); +} + void unique_lock_const_ref(std::mutex& m) { std::unique_lock lock(m); diff --git a/test/testsymboldatabase.cpp b/test/testsymboldatabase.cpp index 48b166972c5..f4a313171fe 100644 --- a/test/testsymboldatabase.cpp +++ b/test/testsymboldatabase.cpp @@ -8775,35 +8775,33 @@ class TestSymbolDatabase : public TestFixture { } { // Container - Settings sC; - Library::Container c; - c.startPattern = "C"; - c.startPattern2 = "C !!::"; - sC.library.containers["C"] = c; + constexpr char xmldata[] = "\n" + "\n" + " \n" + ""; + const Settings sC = settingsBuilder().libraryxml(xmldata, sizeof(xmldata)).build(); ASSERT_EQUALS("container(C) *", typeOf("C*c=new C;","new","test.cpp",&sC)); ASSERT_EQUALS("container(C) *", typeOf("x=(C*)c;","(","test.cpp",&sC)); ASSERT_EQUALS("container(C)", typeOf("C c = C();","(","test.cpp",&sC)); } { // Container (vector) - Settings set; - Library::Container vector; - vector.startPattern = "Vector <"; - vector.startPattern2 = "Vector !!::"; - vector.type_templateArgNo = 0; - vector.arrayLike_indexOp = true; - vector.functions["front"] = - Library::Container::Function{Library::Container::Action::NO_ACTION, Library::Container::Yield::ITEM}; - vector.functions["data"] = - Library::Container::Function{Library::Container::Action::NO_ACTION, Library::Container::Yield::BUFFER}; - vector.functions["begin"] = Library::Container::Function{Library::Container::Action::NO_ACTION, - Library::Container::Yield::START_ITERATOR}; - set.library.containers["Vector"] = vector; - Library::Container string; - string.startPattern = "test :: string"; - string.startPattern2 = "test :: string !!::"; - string.arrayLike_indexOp = string.stdStringLike = true; - set.library.containers["test::string"] = string; + constexpr char xmldata[] = "\n" + "\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + ""; + const Settings set = settingsBuilder().libraryxml(xmldata, sizeof(xmldata)).build(); ASSERT_EQUALS("signed int", typeOf("Vector v; v[0]=3;", "[", "test.cpp", &set)); ASSERT_EQUALS("container(test :: string)", typeOf("{return test::string();}", "(", "test.cpp", &set)); ASSERT_EQUALS( @@ -8876,11 +8874,11 @@ class TestSymbolDatabase : public TestFixture { // return { // Container - Settings sC; - Library::Container c; - c.startPattern = "C"; - c.startPattern2 = "C !!::"; - sC.library.containers["C"] = c; + constexpr char xmldata[] = "\n" + "\n" + " \n" + ""; + const Settings sC = settingsBuilder().libraryxml(xmldata, sizeof(xmldata)).build(); ASSERT_EQUALS("container(C)", typeOf("C f(char *p) { char data[10]; return data; }", "return", "test.cpp", &sC)); } // Smart pointer From 88e4f2ed32fb25fa9a62e59682f8f477492e28de Mon Sep 17 00:00:00 2001 From: olabetskyi <153490942+olabetskyi@users.noreply.github.com> Date: Wed, 24 Jan 2024 20:03:35 +0200 Subject: [PATCH 2/7] Fix #12131: No warning for missing override specifier for virtual function with different default argument (#5763) added check for the end off both functions parameter lists during compare --- lib/symboldatabase.cpp | 2 +- test/testclass.cpp | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index 25238d797a1..a454d5c0951 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -2874,7 +2874,7 @@ bool Function::argsMatch(const Scope *scope, const Token *first, const Token *se if (second) second = second->tokAt(-2); if (!second) { // End of argument list (second) - return false; + return !first->nextArgument(); } } diff --git a/test/testclass.cpp b/test/testclass.cpp index 1de1e24bcef..5bf9597c40d 100644 --- a/test/testclass.cpp +++ b/test/testclass.cpp @@ -8530,6 +8530,16 @@ class TestClass : public TestFixture { "};\n"); ASSERT_EQUALS("[test.cpp:3] -> [test.cpp:8]: (style) The function 'operator->' overrides a function in a base class but is not marked with a 'override' specifier.\n", errout.str()); + + checkOverride("class Base {\n" // #12131 + " virtual int Calculate(int arg) = 0;\n" + "};\n" + "class Derived : public Base {\n" + " int Calculate(int arg = 0) {\n" + " return arg * 2;\n" + " }\n" + "};\n"); + ASSERT_EQUALS("[test.cpp:2] -> [test.cpp:5]: (style) The function 'Calculate' overrides a function in a base class but is not marked with a 'override' specifier.\n", errout.str()); } void overrideCVRefQualifiers() { From deafea338734bccc408bd536cf43c28000d8ec5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Wed, 24 Jan 2024 22:24:54 +0100 Subject: [PATCH 3/7] Fix #12381 (GUI: The Id column should be shown by default) (#5914) --- gui/resultstree.cpp | 2 +- gui/settingsdialog.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/gui/resultstree.cpp b/gui/resultstree.cpp index c0010dbc79c..8f132c25967 100644 --- a/gui/resultstree.cpp +++ b/gui/resultstree.cpp @@ -421,7 +421,7 @@ void ResultsTree::loadSettings() mSaveAllErrors = mSettings->value(SETTINGS_SAVE_ALL_ERRORS, false).toBool(); mShowFullPath = mSettings->value(SETTINGS_SHOW_FULL_PATH, false).toBool(); - showIdColumn(mSettings->value(SETTINGS_SHOW_ERROR_ID, false).toBool()); + showIdColumn(mSettings->value(SETTINGS_SHOW_ERROR_ID, true).toBool()); showInconclusiveColumn(mSettings->value(SETTINGS_INCONCLUSIVE_ERRORS, false).toBool()); } diff --git a/gui/settingsdialog.cpp b/gui/settingsdialog.cpp index 7144f3793d1..f6a4b3ab22d 100644 --- a/gui/settingsdialog.cpp +++ b/gui/settingsdialog.cpp @@ -73,7 +73,7 @@ SettingsDialog::SettingsDialog(ApplicationList *list, mUI->mInlineSuppressions->setCheckState(boolToCheckState(settings.value(SETTINGS_INLINE_SUPPRESSIONS, false).toBool())); mUI->mEnableInconclusive->setCheckState(boolToCheckState(settings.value(SETTINGS_INCONCLUSIVE_ERRORS, false).toBool())); mUI->mShowStatistics->setCheckState(boolToCheckState(settings.value(SETTINGS_SHOW_STATISTICS, false).toBool())); - mUI->mShowErrorId->setCheckState(boolToCheckState(settings.value(SETTINGS_SHOW_ERROR_ID, false).toBool())); + mUI->mShowErrorId->setCheckState(boolToCheckState(settings.value(SETTINGS_SHOW_ERROR_ID, true).toBool())); mUI->mCheckForUpdates->setCheckState(boolToCheckState(settings.value(SETTINGS_CHECK_FOR_UPDATES, false).toBool())); mUI->mEditPythonPath->setText(settings.value(SETTINGS_PYTHON_PATH, QString()).toString()); validateEditPythonPath(); From cecbe18942b4f40a7a29b4b3b5ce83d10dabb722 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20St=C3=B6neberg?= Date: Sun, 28 Jan 2024 19:04:47 +0100 Subject: [PATCH 4/7] CI-unixish-docker.yml: fixate `hendrikmuhs/ccache-action` on `1.2.11` to fix older images (#5918) See https://github.com/danmar/cppcheck/actions/runs/7677304162/job/20926809147?pr=5917 https://github.com/hendrikmuhs/ccache-action/issues/178 --- .github/workflows/CI-unixish-docker.yml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/CI-unixish-docker.yml b/.github/workflows/CI-unixish-docker.yml index 118cb817f63..82439c9bbe4 100644 --- a/.github/workflows/CI-unixish-docker.yml +++ b/.github/workflows/CI-unixish-docker.yml @@ -53,8 +53,10 @@ jobs: # needs to be called after the package installation since # - it doesn't call "apt-get update" # - it doesn't support centos + # + # needs to be to fixated on 1.2.11 so it works with older images - see https://github.com/hendrikmuhs/ccache-action/issues/178 - name: ccache - uses: hendrikmuhs/ccache-action@v1.2 + uses: hendrikmuhs/ccache-action@v1.2.11 with: key: ${{ github.workflow }}-${{ matrix.image }} @@ -110,8 +112,10 @@ jobs: # needs to be called after the package installation since # - it doesn't call "apt-get update" # - it doesn't support centos + # + # needs to be to fixated on 1.2.11 so it works with older images - see https://github.com/hendrikmuhs/ccache-action/issues/178 - name: ccache - uses: hendrikmuhs/ccache-action@v1.2 + uses: hendrikmuhs/ccache-action@v1.2.11 with: key: ${{ github.workflow }}-${{ matrix.image }} From 381360ba8836a6587201823c377e2dd7ecdd5738 Mon Sep 17 00:00:00 2001 From: orbitcowboy Date: Sun, 28 Jan 2024 19:51:33 +0100 Subject: [PATCH 5/7] windows.cfg: Added constants from . (#5917) Reference: https://learn.microsoft.com/en-us/windows/win32/api/winreg/nf-winreg-regcreatekeyexa --- cfg/windows.cfg | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/cfg/windows.cfg b/cfg/windows.cfg index ccf0a9d8f6d..eb9d382b1d5 100644 --- a/cfg/windows.cfg +++ b/cfg/windows.cfg @@ -17958,6 +17958,46 @@ HFONT CreateFont( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 90d7f725d9b664751a95325b6681928bcf5a76a5 Mon Sep 17 00:00:00 2001 From: Paul Fultz II Date: Mon, 29 Jan 2024 04:07:21 -0600 Subject: [PATCH 6/7] Fix 12060: calculate sizeof(struct) (#5919) --- lib/valueflow.cpp | 65 +++++++++++++++++++++++++++++++++++++++++- test/testvalueflow.cpp | 57 ++++++++++++++++++++++++++++++++++++ 2 files changed, 121 insertions(+), 1 deletion(-) diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index 030b0699452..d3c6b8b2a6b 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -1105,6 +1105,53 @@ static void setTokenValueCast(Token *parent, const ValueType &valueType, const V } } +template +static size_t accumulateStructMembers(const Scope* scope, F f) +{ + size_t total = 0; + for (const Variable& var : scope->varlist) { + if (var.isStatic()) + continue; + if (const ValueType* vt = var.valueType()) { + if (vt->type == ValueType::Type::RECORD && vt->typeScope == scope) + return 0; + total = f(total, *vt); + } + if (total == 0) + return 0; + } + return total; +} + +static size_t bitCeil(size_t x) +{ + if (x <= 1) + return 1; + --x; + x |= x >> 1; + x |= x >> 2; + x |= x >> 4; + x |= x >> 8; + x |= x >> 16; + x |= x >> 32; + return x + 1; +} + +static size_t getAlignOf(const ValueType& vt, const Settings& settings) +{ + if (vt.pointer || vt.isPrimitive()) { + auto align = ValueFlow::getSizeOf(vt, settings); + return align == 0 ? 0 : bitCeil(align); + } + if (vt.type == ValueType::Type::RECORD && vt.typeScope) { + return accumulateStructMembers(vt.typeScope, [&](size_t max, const ValueType& vt2) { + size_t a = getAlignOf(vt2, settings); + return std::max(max, a); + }); + } + return 0; +} + static nonneg int getSizeOfType(const Token *typeTok, const Settings &settings) { const ValueType &valueType = ValueType::parseDecl(typeTok, settings); @@ -1134,7 +1181,23 @@ size_t ValueFlow::getSizeOf(const ValueType &vt, const Settings &settings) return settings.platform.sizeof_double; if (vt.type == ValueType::Type::LONGDOUBLE) return settings.platform.sizeof_long_double; - + if (vt.type == ValueType::Type::RECORD && vt.typeScope) { + size_t total = accumulateStructMembers(vt.typeScope, [&](size_t total, const ValueType& vt2) -> size_t { + size_t n = ValueFlow::getSizeOf(vt2, settings); + size_t a = getAlignOf(vt2, settings); + if (n == 0 || a == 0) + return 0; + size_t padding = (a - (total % a)) % a; + return total + padding + n; + }); + if (total == 0) + return 0; + size_t align = getAlignOf(vt, settings); + if (align == 0) + return 0; + total += (align - (total % align)) % align; + return total; + } return 0; } diff --git a/test/testvalueflow.cpp b/test/testvalueflow.cpp index bf97ca1ced3..7fb5e9c78a6 100644 --- a/test/testvalueflow.cpp +++ b/test/testvalueflow.cpp @@ -1394,6 +1394,63 @@ class TestValueFlow : public TestFixture { values = tokenValues(code, "="); ASSERT_EQUALS(1U, values.size()); ASSERT_EQUALS(sizeof(std::int32_t) * 10 * 20, values.back().intvalue); + + code = "struct X { float a; float b; };\n" + "void f() {\n" + " x = sizeof(X);\n" + "}"; + values = tokenValues(code, "( X )"); + ASSERT_EQUALS(1U, values.size()); + ASSERT_EQUALS(8, values.back().intvalue); + + code = "struct X { char a; char b; };\n" + "void f() {\n" + " x = sizeof(X);\n" + "}"; + values = tokenValues(code, "( X )"); + ASSERT_EQUALS(1U, values.size()); + ASSERT_EQUALS(2, values.back().intvalue); + + code = "struct X { char a; float b; };\n" + "void f() {\n" + " x = sizeof(X);\n" + "}"; + values = tokenValues(code, "( X )"); + ASSERT_EQUALS(1U, values.size()); + ASSERT_EQUALS(8, values.back().intvalue); + + code = "struct X { char a; char b; float c; };\n" + "void f() {\n" + " x = sizeof(X);\n" + "}"; + values = tokenValues(code, "( X )"); + ASSERT_EQUALS(1U, values.size()); + ASSERT_EQUALS(8, values.back().intvalue); + + code = "struct X { float a; char b; };\n" + "void f() {\n" + " x = sizeof(X);\n" + "}"; + values = tokenValues(code, "( X )"); + ASSERT_EQUALS(1U, values.size()); + ASSERT_EQUALS(8, values.back().intvalue); + + code = "struct X { float a; char b; char c; };\n" + "void f() {\n" + " x = sizeof(X);\n" + "}"; + values = tokenValues(code, "( X )"); + ASSERT_EQUALS(1U, values.size()); + ASSERT_EQUALS(8, values.back().intvalue); + + code = "struct A { float a; char b; };\n" + "struct X { A a; char b; };\n" + "void f() {\n" + " x = sizeof(X);\n" + "}"; + values = tokenValues(code, "( X )"); + ASSERT_EQUALS(1U, values.size()); + ASSERT_EQUALS(12, values.back().intvalue); } void valueFlowComma() From bef9e73e60a61a382f4341cfb70730ea67948132 Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Mon, 29 Jan 2024 12:23:03 +0100 Subject: [PATCH 7/7] Fix #11067 FP mismatchingContainerIterator with container holding iterators (#5915) --- lib/checkstl.cpp | 4 +++- test/teststl.cpp | 26 ++++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/lib/checkstl.cpp b/lib/checkstl.cpp index f1e7c01d23c..26fb07c5945 100644 --- a/lib/checkstl.cpp +++ b/lib/checkstl.cpp @@ -704,7 +704,7 @@ static bool isSameIteratorContainerExpression(const Token* tok1, if (kind == ValueFlow::Value::LifetimeKind::Address) { return isSameExpression(true, false, getAddressContainer(tok1), getAddressContainer(tok2), library, false, false); } - return false; + return astContainerYield(tok2) == Library::Container::Yield::ITEM; } static ValueFlow::Value getLifetimeIteratorValue(const Token* tok, MathLib::bigint path = 0) @@ -868,6 +868,8 @@ void CheckStl::mismatchingContainerIterator() continue; if (val.lifetimeKind != ValueFlow::Value::LifetimeKind::Iterator) continue; + if (iterTok->str() == "*" && iterTok->astOperand1()->valueType() && iterTok->astOperand1()->valueType()->type == ValueType::ITERATOR) + continue; if (isSameIteratorContainerExpression(tok, val.tokvalue, mSettings->library)) continue; mismatchingContainerIteratorError(tok, iterTok, val.tokvalue); diff --git a/test/teststl.cpp b/test/teststl.cpp index f02afead149..4426f3460a7 100644 --- a/test/teststl.cpp +++ b/test/teststl.cpp @@ -2135,6 +2135,32 @@ class TestStl : public TestFixture { " s.v.erase(s.v.begin() + m);\n" "}\n"); ASSERT_EQUALS("", errout.str()); + + // #11067 + check("struct S {\n" + " std::vector v;\n" + " std::list::const_iterator> li;\n" + " void f();\n" + "};\n" + "void S::f() {\n" + " v.erase(*li.begin());\n" + " li.pop_front();\n" + "}\n"); + ASSERT_EQUALS("", errout.str()); + + check("void f(std::set& a, std::stack::iterator>& b) {\n" + " while (!b.empty()) {\n" + " a.erase(b.top());\n" + " b.pop();\n" + " }\n" + "}\n"); + ASSERT_EQUALS("", errout.str()); + + check("void f(std::vector& a, std::vector::iterator>& b) {\n" + " auto it = b.begin();\n" + " a.erase(*it);\n" + "}\n"); + ASSERT_EQUALS("", errout.str()); } // Dereferencing invalid pointer