From bc33aee25669f7ab8db1f4941ff56e9ce6d22aea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Berder?= <18538310+francois-berder@users.noreply.github.com> Date: Tue, 26 May 2026 08:48:42 +0200 Subject: [PATCH 1/4] Fix #8192: FN condition always false in for loop condition (#8446) When a for loop's condition is impossible given the initial value (e.g. `for (int i = 0; i > 10; i++)`), cppcheck was not emitting a knownConditionTrueFalse warning. Fix by populating memory1, memory2 and memoryAfter with the init state when the condition is immediately false (and no error occured). We can then set the value for the condition token and thus emit a knownConditionTrueFalse warning. Signed-off-by: Francois Berder --- lib/valueflow.cpp | 55 ++++++++++++++++++++++++++++-------------- test/testcondition.cpp | 2 +- 2 files changed, 38 insertions(+), 19 deletions(-) diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index 3819bfc4b41..a63995a9728 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -5181,8 +5181,18 @@ static bool valueFlowForLoop2(const Token *tok, if (error) return false; execute(secondExpression, programMemory, &result, &error, settings); - if (result == 0) // 2nd expression is false => no looping + if (result == 0) { + if (!error) { // 2nd expression is false => no looping + ProgramMemory startMemory(programMemory); + ProgramMemory endMemory(programMemory); + + memory1.swap(startMemory); + memory2.swap(endMemory); + memoryAfter.swap(programMemory); + return true; + } return false; + } if (error) { // If a variable is reassigned in second expression, return false bool reassign = false; @@ -5388,23 +5398,32 @@ static void valueFlowForLoop(const TokenList &tokenlist, const SymbolDatabase& s } else { ProgramMemory mem1, mem2, memAfter; if (valueFlowForLoop2(tok, mem1, mem2, memAfter, settings)) { - for (const auto& p : mem1) { - if (!p.second.isIntValue()) - continue; - if (p.second.isImpossible()) - continue; - if (p.first.tok->varId() == 0) - continue; - valueFlowForLoopSimplify(bodyStart, p.first.tok, false, p.second.intvalue, tokenlist, errorLogger, settings); - } - for (const auto& p : mem2) { - if (!p.second.isIntValue()) - continue; - if (p.second.isImpossible()) - continue; - if (p.first.tok->varId() == 0) - continue; - valueFlowForLoopSimplify(bodyStart, p.first.tok, false, p.second.intvalue, tokenlist, errorLogger, settings); + if (mem1 == memAfter) { // #8192 check if loop never runs + Token* condTok = getCondTok(tok); + if (condTok && !condTok->hasKnownIntValue()) { + ValueFlow::Value v(0); + v.setKnown(); + ValueFlow::setTokenValue(condTok, std::move(v), settings); + } + } else { + for (const auto& p : mem1) { + if (!p.second.isIntValue()) + continue; + if (p.second.isImpossible()) + continue; + if (p.first.tok->varId() == 0) + continue; + valueFlowForLoopSimplify(bodyStart, p.first.tok, false, p.second.intvalue, tokenlist, errorLogger, settings); + } + for (const auto& p : mem2) { + if (!p.second.isIntValue()) + continue; + if (p.second.isImpossible()) + continue; + if (p.first.tok->varId() == 0) + continue; + valueFlowForLoopSimplify(bodyStart, p.first.tok, false, p.second.intvalue, tokenlist, errorLogger, settings); + } } for (const auto& p : memAfter) { if (!p.second.isIntValue()) diff --git a/test/testcondition.cpp b/test/testcondition.cpp index 8172f74aab6..46860d9f939 100644 --- a/test/testcondition.cpp +++ b/test/testcondition.cpp @@ -5680,7 +5680,7 @@ class TestCondition : public TestFixture { check("void f() {\n" // #8192 " for (int i = 0; i > 10; ++i) {}\n" "}\n"); - TODO_ASSERT_EQUALS("[test.cpp:2]: (style) Condition 'i>10' is always false\n", "", errout_str()); + ASSERT_EQUALS("[test.cpp:2:23]: (style) Condition 'i>10' is always false [knownConditionTrueFalse]\n", errout_str()); check("void f() {\n" " for (int i = 1000; i < 20; ++i) {}\n" From 5e8ab5e2ac461a6568893519110ce6191ac2fe29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20St=C3=B6neberg?= Date: Tue, 26 May 2026 20:22:14 +0200 Subject: [PATCH 2/4] release-windows.yml: fixed build with Visual Studio 2026 [skip ci] (#8563) this is caused by `vs2025` now using Visual Studio 2026 --- .github/workflows/release-windows.yml | 2 +- releasenotes.txt | 1 + win_installer/config.wxi | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release-windows.yml b/.github/workflows/release-windows.yml index bacf32c8eaf..f59e77a2dca 100644 --- a/.github/workflows/release-windows.yml +++ b/.github/workflows/release-windows.yml @@ -56,7 +56,7 @@ jobs: cd pcre-%PCRE_VERSION% || exit /b !errorlevel! git apply --ignore-space-change ..\externals\pcre.patch || exit /b !errorlevel! cmake . -A x64 -DPCRE_BUILD_PCRECPP=OFF -DPCRE_BUILD_PCREGREP=OFF -DPCRE_BUILD_TESTS=OFF -DCMAKE_POLICY_VERSION_MINIMUM=3.5 -DCMAKE_COMPILE_WARNING_AS_ERROR=On || exit /b !errorlevel! - msbuild -m PCRE.sln -p:Configuration=Release -p:Platform=x64 || exit /b !errorlevel! + msbuild -m PCRE.slnx -p:Configuration=Release -p:Platform=x64 || exit /b !errorlevel! copy pcre.h ..\externals || exit /b !errorlevel! copy Release\pcre.lib ..\externals\pcre64.lib || exit /b !errorlevel! diff --git a/releasenotes.txt b/releasenotes.txt index 5d94da2ebc3..86aa9573ca4 100644 --- a/releasenotes.txt +++ b/releasenotes.txt @@ -26,4 +26,5 @@ Other: - Make it possible to specify the regular expression engine using the `engine` element in a rule XML. - Added CLI option `--exitcode-suppress` to specify an error ID which should not result in a non-zero exitcode. - Moved source code from https://github.com/danmar/cppcheck to https://github.com/cppcheck-opensource/cppcheck +- The official Windows binary is now built with Visual Studio 2026. - diff --git a/win_installer/config.wxi b/win_installer/config.wxi index 7bc613d1669..ae7fc8329f3 100644 --- a/win_installer/config.wxi +++ b/win_installer/config.wxi @@ -9,6 +9,6 @@ - + From 47aaa76dc9fb5fa65177cf2322b52cb518cd20a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20St=C3=B6neberg?= Date: Tue, 26 May 2026 20:22:35 +0200 Subject: [PATCH 3/4] iwyu.yml: disabled `HAVE_RULES` for now since Fedora no longer provides PCRE [skip ci] (#8564) --- .github/workflows/iwyu.yml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/workflows/iwyu.yml b/.github/workflows/iwyu.yml index 05d5643bdf7..3b972dca443 100644 --- a/.github/workflows/iwyu.yml +++ b/.github/workflows/iwyu.yml @@ -71,7 +71,7 @@ jobs: - name: Install missing software on Fedora if: contains(matrix.image, 'fedora') run: | - dnf install -y cmake clang pcre-devel + dnf install -y cmake clang dnf install -y libglvnd-devel # fixes missing dependency for Qt in CMake dnf install -y p7zip-plugins # required as fallback for py7zr in Qt installation dnf install -y python3-pip # fixes missing pip module in jurplel/install-qt-action @@ -125,7 +125,8 @@ jobs: - name: Prepare CMake run: | - cmake -S . -B cmake.output -Werror=dev -DCMAKE_BUILD_TYPE=Release -DHAVE_RULES=On -DBUILD_TESTING=On -DBUILD_GUI=On -DWITH_QCHART=On -DBUILD_TRIAGE=On -DENABLE_CHECK_INTERNAL=On -DCMAKE_GLOBAL_AUTOGEN_TARGET=On -DDISABLE_DMAKE=On -DCMAKE_DISABLE_PRECOMPILE_HEADERS=On -DCPPCHK_GLIBCXX_DEBUG=Off -DUSE_MATCHCOMPILER=Off -DEXTERNALS_AS_SYSTEM=On -DUSE_LIBCXX=${{ matrix.stdlib == 'libc++' }} + # TODO: re-enable HAVE_RULES + cmake -S . -B cmake.output -Werror=dev -DCMAKE_BUILD_TYPE=Release -DHAVE_RULES=Off -DBUILD_TESTING=On -DBUILD_GUI=On -DWITH_QCHART=On -DBUILD_TRIAGE=On -DENABLE_CHECK_INTERNAL=On -DCMAKE_GLOBAL_AUTOGEN_TARGET=On -DDISABLE_DMAKE=On -DCMAKE_DISABLE_PRECOMPILE_HEADERS=On -DCPPCHK_GLIBCXX_DEBUG=Off -DUSE_MATCHCOMPILER=Off -DEXTERNALS_AS_SYSTEM=On -DUSE_LIBCXX=${{ matrix.stdlib == 'libc++' }} env: CC: clang CXX: clang++ @@ -232,7 +233,8 @@ jobs: - name: Prepare CMake run: | - cmake -S . -B cmake.output -Werror=dev -DCMAKE_BUILD_TYPE=Release -DHAVE_RULES=On -DBUILD_TESTING=On -DBUILD_GUI=On -DWITH_QCHART=On -DBUILD_TRIAGE=On -DENABLE_CHECK_INTERNAL=On -DCMAKE_GLOBAL_AUTOGEN_TARGET=On -DDISABLE_DMAKE=On -DCMAKE_DISABLE_PRECOMPILE_HEADERS=On -DCPPCHK_GLIBCXX_DEBUG=Off -DUSE_MATCHCOMPILER=Off -DEXTERNALS_AS_SYSTEM=On -DUSE_LIBCXX=${{ matrix.use_libcxx }} + # TODO: re-enable HAVE_RULES + cmake -S . -B cmake.output -Werror=dev -DCMAKE_BUILD_TYPE=Release -DHAVE_RULES=Off -DBUILD_TESTING=On -DBUILD_GUI=On -DWITH_QCHART=On -DBUILD_TRIAGE=On -DENABLE_CHECK_INTERNAL=On -DCMAKE_GLOBAL_AUTOGEN_TARGET=On -DDISABLE_DMAKE=On -DCMAKE_DISABLE_PRECOMPILE_HEADERS=On -DCPPCHK_GLIBCXX_DEBUG=Off -DUSE_MATCHCOMPILER=Off -DEXTERNALS_AS_SYSTEM=On -DUSE_LIBCXX=${{ matrix.use_libcxx }} env: CC: clang-22 CXX: clang++-22 From 96d4a9626ada9075c9c1b0a76ee08b9ddae483c7 Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Wed, 27 May 2026 09:37:54 +0200 Subject: [PATCH 4/4] Fix #14774 FP bufferAccessOutOfBounds: Wrong size for sizeof( ref ) (#8572) --- lib/vf_common.cpp | 12 +++++++----- test/testvalueflow.cpp | 24 ++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 5 deletions(-) diff --git a/lib/vf_common.cpp b/lib/vf_common.cpp index 261972cba63..282e0b9fddb 100644 --- a/lib/vf_common.cpp +++ b/lib/vf_common.cpp @@ -160,11 +160,13 @@ namespace ValueFlow value.setKnown(); setTokenValue(tok, std::move(value), settings); } else if (Token::simpleMatch(tok, "sizeof (")) { - if (tok->next()->astOperand2() && !tok->next()->astOperand2()->isLiteral() && tok->next()->astOperand2()->valueType() && - (tok->next()->astOperand2()->valueType()->pointer == 0 || // <- TODO this is a bailout, abort when there are array->pointer conversions - (tok->next()->astOperand2()->variable() && !tok->next()->astOperand2()->variable()->isArray())) && - !tok->next()->astOperand2()->valueType()->isEnum()) { // <- TODO this is a bailout, handle enum with non-int types - const size_t sz = tok->next()->astOperand2()->valueType()->getSizeOf(settings, ValueType::Accuracy::ExactOrZero, ValueType::SizeOf::Pointer); + const Token* const obj = tok->next()->astOperand2(); + if (obj && !obj->isLiteral() && obj->valueType() && + (obj->valueType()->pointer == 0 || // <- TODO this is a bailout, abort when there are array->pointer conversions + (obj->variable() && !obj->variable()->isArray())) && + !obj->valueType()->isEnum()) { // <- TODO this is a bailout, handle enum with non-int types + const auto ptrPointee = obj->valueType()->pointer > 0 ? ValueType::SizeOf::Pointer : ValueType::SizeOf::Pointee; + const size_t sz = obj->valueType()->getSizeOf(settings, ValueType::Accuracy::ExactOrZero, ptrPointee); if (sz) { Value value(sz); value.setKnown(); diff --git a/test/testvalueflow.cpp b/test/testvalueflow.cpp index c879b9cffd5..1f4879b7cca 100644 --- a/test/testvalueflow.cpp +++ b/test/testvalueflow.cpp @@ -1396,6 +1396,30 @@ class TestValueFlow : public TestFixture { ASSERT_EQUALS(1U, values.size()); ASSERT_EQUALS(4, values.back().intvalue); + code = "char& r = i;\n" + "sizeof(r);"; + values = tokenValues(code, "( r"); + ASSERT_EQUALS(1U, values.size()); + ASSERT_EQUALS(1, values.back().intvalue); + + code = "char* p;\n" + "sizeof(p);"; + values = tokenValues(code, "( p"); + ASSERT_EQUALS(1U, values.size()); + ASSERT_EQUALS(settings.platform.sizeof_pointer, values.back().intvalue); + + code = "char*& pr = p;\n" + "sizeof(pr);"; + values = tokenValues(code, "( pr"); + ASSERT_EQUALS(1U, values.size()); + ASSERT_EQUALS(settings.platform.sizeof_pointer, values.back().intvalue); + + code = "struct { char& r; char* p; } s{ x, y };\n" + "sizeof(s);\n"; + values = tokenValues(code, "( s"); + ASSERT_EQUALS(1U, values.size()); + ASSERT_EQUALS(2 * settings.platform.sizeof_pointer, values.back().intvalue); + #define CHECK3(A, B, C) \ do { \ code = "void f() {\n" \