From 49b8c2aade94ccb592411a7fd35a0aafe91d7914 Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Wed, 3 Jun 2026 19:32:41 +0200 Subject: [PATCH 001/165] Add test for #12041 (#8626) --- test/testsimplifytypedef.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/test/testsimplifytypedef.cpp b/test/testsimplifytypedef.cpp index 022412139f1..84a95a81cfc 100644 --- a/test/testsimplifytypedef.cpp +++ b/test/testsimplifytypedef.cpp @@ -232,6 +232,7 @@ class TestSimplifyTypedef : public TestFixture { TEST_CASE(simplifyTypedef159); TEST_CASE(simplifyTypedef160); TEST_CASE(simplifyTypedef161); + TEST_CASE(simplifyTypedef162); TEST_CASE(simplifyTypedefFunction1); TEST_CASE(simplifyTypedefFunction2); // ticket #1685 @@ -3859,6 +3860,14 @@ class TestSimplifyTypedef : public TestFixture { TODO_ASSERT_EQUALS(exp2, cur2, tok(code2)); } + void simplifyTypedef162() { + const char code[] = "using std::vector;\n" // #12041 + "typedef vector ints;\n" + "void f(ints v);\n"; + const char exp[] = "void f ( std :: vector < int > v ) ;"; + ASSERT_EQUALS(exp, tok(code)); + } + void simplifyTypedefFunction1() { { const char code[] = "typedef void (*my_func)();\n" From 9f74c2db8bc800b1f1e612dd8cccf868725eaaf4 Mon Sep 17 00:00:00 2001 From: William Jakobsson <50847546+wjakobsson@users.noreply.github.com> Date: Thu, 4 Jun 2026 09:06:25 +0200 Subject: [PATCH 002/165] fix #14813 crash: recheck in gui sometimes crashes (#8628) --- gui/resultstree.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gui/resultstree.cpp b/gui/resultstree.cpp index c553855e99e..fc70fdb84af 100644 --- a/gui/resultstree.cpp +++ b/gui/resultstree.cpp @@ -427,8 +427,8 @@ void ResultsTree::clear(const QString &filename) if (stripped == fileItem->text() || filename == fileItem->errorItem->file0) { - mModel->removeRow(i); mErrorList.removeAll(fileItem->errorItem->toString()); + mModel->removeRow(i); break; } } @@ -445,8 +445,8 @@ void ResultsTree::clearRecheckFile(const QString &filename) QString storedfile = fileItem->getErrorPathItem().file; storedfile = ((!mCheckPath.isEmpty() && storedfile.startsWith(mCheckPath)) ? storedfile.mid(mCheckPath.length() + 1) : storedfile); if (actualfile == storedfile) { - mModel->removeRow(i); mErrorList.removeAll(fileItem->errorItem->toString()); + mModel->removeRow(i); break; } } From bb69f669438f9d243a2a12aec509b0431aae4fe4 Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Thu, 4 Jun 2026 09:44:08 +0200 Subject: [PATCH 003/165] Fix #14772 FN returnDanglingLifetime for new expression (#8570) --- lib/checkautovariables.cpp | 7 +++++-- test/testautovariables.cpp | 8 ++++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/lib/checkautovariables.cpp b/lib/checkautovariables.cpp index 0493f3ea459..b848928ebf4 100644 --- a/lib/checkautovariables.cpp +++ b/lib/checkautovariables.cpp @@ -614,8 +614,11 @@ void CheckAutoVariablesImpl::checkVarLifetimeScope(const Token * start, const To } } } - const bool escape = Token::simpleMatch(tok->astParent(), "throw") || - (Token::simpleMatch(tok->astParent(), "return") && !Function::returnsStandardType(scope->function)); + const Token* retThrow = tok->astParent(); + if (Token::simpleMatch(retThrow, "new")) + retThrow = retThrow->astParent(); + const bool escape = Token::simpleMatch(retThrow, "throw") || + (Token::simpleMatch(retThrow, "return") && !Function::returnsStandardType(scope->function)); std::unordered_set exprs; for (const ValueFlow::Value& val:tok->values()) { if (!val.isLocalLifetimeValue() && !val.isSubFunctionLifetimeValue()) diff --git a/test/testautovariables.cpp b/test/testautovariables.cpp index 47484d7023e..9fe3e126660 100644 --- a/test/testautovariables.cpp +++ b/test/testautovariables.cpp @@ -4062,6 +4062,14 @@ class TestAutoVariables : public TestFixture { " struct S s = { .i = 0, true };\n" "}\n"); // don't crash ASSERT_EQUALS("", errout_str()); + + check("struct A { int& r; };\n" // #14772 + "A* f() {\n" + " int x = 0;\n" + " return new A{ x };\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:4:19] -> [test.cpp:3:9] -> [test.cpp:4:17]: (error) Returning object that points to local variable 'x' that will be invalid when returning. [returnDanglingLifetime]\n", + errout_str()); } void danglingLifetimeInitList() { From 56d86d3fabb33f2d2ca392d008dcbb80301bd1cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20St=C3=B6neberg?= Date: Thu, 4 Jun 2026 09:59:14 +0200 Subject: [PATCH 004/165] settings.h: forward declare `AddonInfo` (#8602) --- Makefile | 248 +++++++++++------------ gui/test/projectfile/testprojectfile.cpp | 1 + lib/settings.cpp | 1 + lib/settings.h | 2 +- oss-fuzz/Makefile | 88 ++++---- 5 files changed, 171 insertions(+), 169 deletions(-) diff --git a/Makefile b/Makefile index 0fc1d8e94e6..42b754733ec 100644 --- a/Makefile +++ b/Makefile @@ -483,13 +483,13 @@ check-nonneg: ###### Build -$(libcppdir)/valueflow.o: lib/valueflow.cpp lib/addoninfo.h lib/analyzer.h lib/astutils.h lib/calculate.h lib/check.h lib/checkers.h lib/checkimpl.h lib/checkuninitvar.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/findtoken.h lib/forwardanalyzer.h lib/infer.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/programmemory.h lib/reverseanalyzer.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenlist.h lib/utils.h lib/valueflow.h lib/valueptr.h lib/vf_analyzers.h lib/vf_common.h lib/vf_settokenvalue.h lib/vfvalue.h +$(libcppdir)/valueflow.o: lib/valueflow.cpp lib/analyzer.h lib/astutils.h lib/calculate.h lib/check.h lib/checkers.h lib/checkimpl.h lib/checkuninitvar.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/findtoken.h lib/forwardanalyzer.h lib/infer.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/programmemory.h lib/reverseanalyzer.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenlist.h lib/utils.h lib/valueflow.h lib/valueptr.h lib/vf_analyzers.h lib/vf_common.h lib/vf_settokenvalue.h lib/vfvalue.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/valueflow.cpp -$(libcppdir)/tokenize.o: lib/tokenize.cpp externals/simplecpp/simplecpp.h lib/addoninfo.h lib/astutils.h lib/checkers.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/preprocessor.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/summaries.h lib/symboldatabase.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h lib/vfvalue.h +$(libcppdir)/tokenize.o: lib/tokenize.cpp externals/simplecpp/simplecpp.h lib/astutils.h lib/checkers.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/preprocessor.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/summaries.h lib/symboldatabase.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h lib/vfvalue.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/tokenize.cpp -$(libcppdir)/symboldatabase.o: lib/symboldatabase.cpp lib/addoninfo.h lib/astutils.h lib/checkers.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/keywords.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h lib/vfvalue.h +$(libcppdir)/symboldatabase.o: lib/symboldatabase.cpp lib/astutils.h lib/checkers.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/keywords.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h lib/vfvalue.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/symboldatabase.cpp $(libcppdir)/addoninfo.o: lib/addoninfo.cpp externals/picojson/picojson.h lib/addoninfo.h lib/config.h lib/json.h lib/path.h lib/standards.h lib/utils.h @@ -498,28 +498,28 @@ $(libcppdir)/addoninfo.o: lib/addoninfo.cpp externals/picojson/picojson.h lib/ad $(libcppdir)/analyzerinfo.o: lib/analyzerinfo.cpp externals/tinyxml2/tinyxml2.h lib/analyzerinfo.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/mathlib.h lib/path.h lib/platform.h lib/standards.h lib/utils.h lib/xml.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/analyzerinfo.cpp -$(libcppdir)/astutils.o: lib/astutils.cpp lib/addoninfo.h lib/astutils.h lib/check.h lib/checkclass.h lib/checkers.h lib/checkimpl.h lib/config.h lib/errortypes.h lib/findtoken.h lib/infer.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/utils.h lib/valueflow.h lib/valueptr.h lib/vfvalue.h +$(libcppdir)/astutils.o: lib/astutils.cpp lib/astutils.h lib/check.h lib/checkclass.h lib/checkers.h lib/checkimpl.h lib/config.h lib/errortypes.h lib/findtoken.h lib/infer.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/utils.h lib/valueflow.h lib/valueptr.h lib/vfvalue.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/astutils.cpp -$(libcppdir)/check64bit.o: lib/check64bit.cpp lib/addoninfo.h lib/check.h lib/check64bit.h lib/checkers.h lib/checkimpl.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h +$(libcppdir)/check64bit.o: lib/check64bit.cpp lib/check.h lib/check64bit.h lib/checkers.h lib/checkimpl.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/check64bit.cpp -$(libcppdir)/checkassert.o: lib/checkassert.cpp lib/addoninfo.h lib/astutils.h lib/check.h lib/checkassert.h lib/checkers.h lib/checkimpl.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h +$(libcppdir)/checkassert.o: lib/checkassert.cpp lib/astutils.h lib/check.h lib/checkassert.h lib/checkers.h lib/checkimpl.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkassert.cpp -$(libcppdir)/checkautovariables.o: lib/checkautovariables.cpp lib/addoninfo.h lib/astutils.h lib/check.h lib/checkautovariables.h lib/checkers.h lib/checkimpl.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h lib/vfvalue.h +$(libcppdir)/checkautovariables.o: lib/checkautovariables.cpp lib/astutils.h lib/check.h lib/checkautovariables.h lib/checkers.h lib/checkimpl.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h lib/vfvalue.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkautovariables.cpp -$(libcppdir)/checkbool.o: lib/checkbool.cpp lib/addoninfo.h lib/astutils.h lib/check.h lib/checkbool.h lib/checkers.h lib/checkimpl.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h +$(libcppdir)/checkbool.o: lib/checkbool.cpp lib/astutils.h lib/check.h lib/checkbool.h lib/checkers.h lib/checkimpl.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkbool.cpp -$(libcppdir)/checkbufferoverrun.o: lib/checkbufferoverrun.cpp externals/tinyxml2/tinyxml2.h lib/addoninfo.h lib/astutils.h lib/check.h lib/checkbufferoverrun.h lib/checkers.h lib/checkimpl.h lib/config.h lib/ctu.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h lib/vf_common.h lib/vfvalue.h lib/xml.h +$(libcppdir)/checkbufferoverrun.o: lib/checkbufferoverrun.cpp externals/tinyxml2/tinyxml2.h lib/astutils.h lib/check.h lib/checkbufferoverrun.h lib/checkers.h lib/checkimpl.h lib/config.h lib/ctu.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h lib/vf_common.h lib/vfvalue.h lib/xml.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkbufferoverrun.cpp -$(libcppdir)/checkclass.o: lib/checkclass.cpp externals/tinyxml2/tinyxml2.h lib/addoninfo.h lib/astutils.h lib/check.h lib/checkclass.h lib/checkers.h lib/checkimpl.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h lib/xml.h +$(libcppdir)/checkclass.o: lib/checkclass.cpp externals/tinyxml2/tinyxml2.h lib/astutils.h lib/check.h lib/checkclass.h lib/checkers.h lib/checkimpl.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h lib/xml.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkclass.cpp -$(libcppdir)/checkcondition.o: lib/checkcondition.cpp lib/addoninfo.h lib/astutils.h lib/check.h lib/checkcondition.h lib/checkers.h lib/checkimpl.h lib/checkother.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h +$(libcppdir)/checkcondition.o: lib/checkcondition.cpp lib/astutils.h lib/check.h lib/checkcondition.h lib/checkers.h lib/checkimpl.h lib/checkother.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkcondition.cpp $(libcppdir)/checkers.o: lib/checkers.cpp lib/checkers.h lib/config.h @@ -531,61 +531,61 @@ $(libcppdir)/checkersidmapping.o: lib/checkersidmapping.cpp lib/checkers.h lib/c $(libcppdir)/checkersreport.o: lib/checkersreport.cpp lib/addoninfo.h lib/checkers.h lib/checkersreport.h lib/config.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/utils.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkersreport.cpp -$(libcppdir)/checkexceptionsafety.o: lib/checkexceptionsafety.cpp lib/addoninfo.h lib/astutils.h lib/check.h lib/checkers.h lib/checkexceptionsafety.h lib/checkimpl.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h +$(libcppdir)/checkexceptionsafety.o: lib/checkexceptionsafety.cpp lib/astutils.h lib/check.h lib/checkers.h lib/checkexceptionsafety.h lib/checkimpl.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkexceptionsafety.cpp -$(libcppdir)/checkfunctions.o: lib/checkfunctions.cpp lib/addoninfo.h lib/astutils.h lib/check.h lib/checkers.h lib/checkfunctions.h lib/checkimpl.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h lib/vfvalue.h +$(libcppdir)/checkfunctions.o: lib/checkfunctions.cpp lib/astutils.h lib/check.h lib/checkers.h lib/checkfunctions.h lib/checkimpl.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h lib/vfvalue.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkfunctions.cpp -$(libcppdir)/checkimpl.o: lib/checkimpl.cpp lib/addoninfo.h lib/checkers.h lib/checkimpl.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/standards.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h +$(libcppdir)/checkimpl.o: lib/checkimpl.cpp lib/checkers.h lib/checkimpl.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/standards.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkimpl.cpp -$(libcppdir)/checkinternal.o: lib/checkinternal.cpp lib/addoninfo.h lib/astutils.h lib/check.h lib/checkers.h lib/checkimpl.h lib/checkinternal.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h +$(libcppdir)/checkinternal.o: lib/checkinternal.cpp lib/astutils.h lib/check.h lib/checkers.h lib/checkimpl.h lib/checkinternal.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkinternal.cpp -$(libcppdir)/checkio.o: lib/checkio.cpp lib/addoninfo.h lib/astutils.h lib/check.h lib/checkers.h lib/checkimpl.h lib/checkio.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h +$(libcppdir)/checkio.o: lib/checkio.cpp lib/astutils.h lib/check.h lib/checkers.h lib/checkimpl.h lib/checkio.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkio.cpp -$(libcppdir)/checkleakautovar.o: lib/checkleakautovar.cpp lib/addoninfo.h lib/astutils.h lib/check.h lib/checkers.h lib/checkimpl.h lib/checkleakautovar.h lib/checkmemoryleak.h lib/checknullpointer.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h +$(libcppdir)/checkleakautovar.o: lib/checkleakautovar.cpp lib/astutils.h lib/check.h lib/checkers.h lib/checkimpl.h lib/checkleakautovar.h lib/checkmemoryleak.h lib/checknullpointer.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkleakautovar.cpp -$(libcppdir)/checkmemoryleak.o: lib/checkmemoryleak.cpp lib/addoninfo.h lib/astutils.h lib/check.h lib/checkers.h lib/checkimpl.h lib/checkmemoryleak.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h +$(libcppdir)/checkmemoryleak.o: lib/checkmemoryleak.cpp lib/astutils.h lib/check.h lib/checkers.h lib/checkimpl.h lib/checkmemoryleak.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkmemoryleak.cpp -$(libcppdir)/checknullpointer.o: lib/checknullpointer.cpp lib/addoninfo.h lib/astutils.h lib/check.h lib/checkers.h lib/checkimpl.h lib/checknullpointer.h lib/config.h lib/ctu.h lib/errorlogger.h lib/errortypes.h lib/findtoken.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h lib/vfvalue.h +$(libcppdir)/checknullpointer.o: lib/checknullpointer.cpp lib/astutils.h lib/check.h lib/checkers.h lib/checkimpl.h lib/checknullpointer.h lib/config.h lib/ctu.h lib/errorlogger.h lib/errortypes.h lib/findtoken.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h lib/vfvalue.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checknullpointer.cpp -$(libcppdir)/checkother.o: lib/checkother.cpp lib/addoninfo.h lib/astutils.h lib/check.h lib/checkers.h lib/checkimpl.h lib/checkother.h lib/config.h lib/errortypes.h lib/fwdanalysis.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h lib/vfvalue.h +$(libcppdir)/checkother.o: lib/checkother.cpp lib/astutils.h lib/check.h lib/checkers.h lib/checkimpl.h lib/checkother.h lib/config.h lib/errortypes.h lib/fwdanalysis.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h lib/vfvalue.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkother.cpp -$(libcppdir)/checkpostfixoperator.o: lib/checkpostfixoperator.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checkimpl.h lib/checkpostfixoperator.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h +$(libcppdir)/checkpostfixoperator.o: lib/checkpostfixoperator.cpp lib/check.h lib/checkers.h lib/checkimpl.h lib/checkpostfixoperator.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkpostfixoperator.cpp $(libcppdir)/checks.o: lib/checks.cpp lib/check.h lib/check64bit.h lib/checkassert.h lib/checkautovariables.h lib/checkbool.h lib/checkbufferoverrun.h lib/checkclass.h lib/checkcondition.h lib/checkexceptionsafety.h lib/checkfunctions.h lib/checkimpl.h lib/checkinternal.h lib/checkio.h lib/checkleakautovar.h lib/checkmemoryleak.h lib/checknullpointer.h lib/checkother.h lib/checkpostfixoperator.h lib/checks.h lib/checksizeof.h lib/checkstl.h lib/checkstring.h lib/checktype.h lib/checkuninitvar.h lib/checkunusedvar.h lib/checkvaarg.h lib/config.h lib/ctu.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/standards.h lib/vfvalue.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checks.cpp -$(libcppdir)/checksizeof.o: lib/checksizeof.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checkimpl.h lib/checksizeof.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h +$(libcppdir)/checksizeof.o: lib/checksizeof.cpp lib/check.h lib/checkers.h lib/checkimpl.h lib/checksizeof.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checksizeof.cpp -$(libcppdir)/checkstl.o: lib/checkstl.cpp lib/addoninfo.h lib/astutils.h lib/check.h lib/checkers.h lib/checkimpl.h lib/checknullpointer.h lib/checkstl.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/pathanalysis.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h lib/vfvalue.h +$(libcppdir)/checkstl.o: lib/checkstl.cpp lib/astutils.h lib/check.h lib/checkers.h lib/checkimpl.h lib/checknullpointer.h lib/checkstl.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/pathanalysis.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h lib/vfvalue.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkstl.cpp -$(libcppdir)/checkstring.o: lib/checkstring.cpp lib/addoninfo.h lib/astutils.h lib/check.h lib/checkers.h lib/checkimpl.h lib/checkstring.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h +$(libcppdir)/checkstring.o: lib/checkstring.cpp lib/astutils.h lib/check.h lib/checkers.h lib/checkimpl.h lib/checkstring.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkstring.cpp -$(libcppdir)/checktype.o: lib/checktype.cpp lib/addoninfo.h lib/astutils.h lib/check.h lib/checkers.h lib/checkimpl.h lib/checktype.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h lib/vfvalue.h +$(libcppdir)/checktype.o: lib/checktype.cpp lib/astutils.h lib/check.h lib/checkers.h lib/checkimpl.h lib/checktype.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h lib/vfvalue.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checktype.cpp -$(libcppdir)/checkuninitvar.o: lib/checkuninitvar.cpp lib/addoninfo.h lib/astutils.h lib/check.h lib/checkers.h lib/checkimpl.h lib/checknullpointer.h lib/checkuninitvar.h lib/config.h lib/ctu.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h +$(libcppdir)/checkuninitvar.o: lib/checkuninitvar.cpp lib/astutils.h lib/check.h lib/checkers.h lib/checkimpl.h lib/checknullpointer.h lib/checkuninitvar.h lib/config.h lib/ctu.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkuninitvar.cpp -$(libcppdir)/checkunusedfunctions.o: lib/checkunusedfunctions.cpp externals/tinyxml2/tinyxml2.h lib/addoninfo.h lib/analyzerinfo.h lib/astutils.h lib/checkers.h lib/checkunusedfunctions.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h lib/xml.h +$(libcppdir)/checkunusedfunctions.o: lib/checkunusedfunctions.cpp externals/tinyxml2/tinyxml2.h lib/analyzerinfo.h lib/astutils.h lib/checkers.h lib/checkunusedfunctions.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h lib/xml.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkunusedfunctions.cpp -$(libcppdir)/checkunusedvar.o: lib/checkunusedvar.cpp lib/addoninfo.h lib/astutils.h lib/check.h lib/checkers.h lib/checkimpl.h lib/checkunusedvar.h lib/config.h lib/errortypes.h lib/fwdanalysis.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h lib/vfvalue.h +$(libcppdir)/checkunusedvar.o: lib/checkunusedvar.cpp lib/astutils.h lib/check.h lib/checkers.h lib/checkimpl.h lib/checkunusedvar.h lib/config.h lib/errortypes.h lib/fwdanalysis.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h lib/vfvalue.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkunusedvar.cpp -$(libcppdir)/checkvaarg.o: lib/checkvaarg.cpp lib/addoninfo.h lib/astutils.h lib/check.h lib/checkers.h lib/checkimpl.h lib/checkvaarg.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h +$(libcppdir)/checkvaarg.o: lib/checkvaarg.cpp lib/astutils.h lib/check.h lib/checkers.h lib/checkimpl.h lib/checkvaarg.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkvaarg.cpp $(libcppdir)/clangimport.o: lib/clangimport.cpp lib/clangimport.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h @@ -600,7 +600,7 @@ $(libcppdir)/cppcheck.o: lib/cppcheck.cpp externals/picojson/picojson.h external $(libcppdir)/ctu.o: lib/ctu.cpp externals/tinyxml2/tinyxml2.h lib/astutils.h lib/check.h lib/config.h lib/ctu.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h lib/xml.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/ctu.cpp -$(libcppdir)/errorlogger.o: lib/errorlogger.cpp externals/tinyxml2/tinyxml2.h lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/cppcheck.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/smallvector.h lib/standards.h lib/suppressions.h lib/templatesimplifier.h lib/token.h lib/tokenlist.h lib/utils.h lib/vfvalue.h lib/xml.h +$(libcppdir)/errorlogger.o: lib/errorlogger.cpp externals/tinyxml2/tinyxml2.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/cppcheck.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/smallvector.h lib/standards.h lib/suppressions.h lib/templatesimplifier.h lib/token.h lib/tokenlist.h lib/utils.h lib/vfvalue.h lib/xml.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/errorlogger.cpp $(libcppdir)/errortypes.o: lib/errortypes.cpp lib/config.h lib/errortypes.h lib/utils.h @@ -609,13 +609,13 @@ $(libcppdir)/errortypes.o: lib/errortypes.cpp lib/config.h lib/errortypes.h lib/ $(libcppdir)/findtoken.o: lib/findtoken.cpp lib/astutils.h lib/config.h lib/errortypes.h lib/findtoken.h lib/library.h lib/mathlib.h lib/smallvector.h lib/standards.h lib/templatesimplifier.h lib/token.h lib/utils.h lib/vfvalue.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/findtoken.cpp -$(libcppdir)/forwardanalyzer.o: lib/forwardanalyzer.cpp lib/addoninfo.h lib/analyzer.h lib/astutils.h lib/checkers.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/forwardanalyzer.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenlist.h lib/utils.h lib/valueptr.h lib/vfvalue.h +$(libcppdir)/forwardanalyzer.o: lib/forwardanalyzer.cpp lib/analyzer.h lib/astutils.h lib/checkers.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/forwardanalyzer.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenlist.h lib/utils.h lib/valueptr.h lib/vfvalue.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/forwardanalyzer.cpp -$(libcppdir)/fwdanalysis.o: lib/fwdanalysis.cpp lib/addoninfo.h lib/astutils.h lib/checkers.h lib/config.h lib/errortypes.h lib/fwdanalysis.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/utils.h lib/vfvalue.h +$(libcppdir)/fwdanalysis.o: lib/fwdanalysis.cpp lib/astutils.h lib/checkers.h lib/config.h lib/errortypes.h lib/fwdanalysis.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/utils.h lib/vfvalue.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/fwdanalysis.cpp -$(libcppdir)/importproject.o: lib/importproject.cpp externals/picojson/picojson.h externals/tinyxml2/tinyxml2.h lib/addoninfo.h lib/checkers.h lib/config.h lib/errortypes.h lib/filesettings.h lib/importproject.h lib/json.h lib/library.h lib/mathlib.h lib/path.h lib/pathmatch.h lib/platform.h lib/settings.h lib/smallvector.h lib/standards.h lib/suppressions.h lib/templatesimplifier.h lib/token.h lib/tokenlist.h lib/utils.h lib/vfvalue.h lib/xml.h +$(libcppdir)/importproject.o: lib/importproject.cpp externals/picojson/picojson.h externals/tinyxml2/tinyxml2.h lib/checkers.h lib/config.h lib/errortypes.h lib/filesettings.h lib/importproject.h lib/json.h lib/library.h lib/mathlib.h lib/path.h lib/pathmatch.h lib/platform.h lib/settings.h lib/smallvector.h lib/standards.h lib/suppressions.h lib/templatesimplifier.h lib/token.h lib/tokenlist.h lib/utils.h lib/vfvalue.h lib/xml.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/importproject.cpp $(libcppdir)/infer.o: lib/infer.cpp lib/calculate.h lib/config.h lib/errortypes.h lib/infer.h lib/mathlib.h lib/smallvector.h lib/templatesimplifier.h lib/token.h lib/utils.h lib/valueptr.h lib/vfvalue.h @@ -642,19 +642,19 @@ $(libcppdir)/pathmatch.o: lib/pathmatch.cpp lib/config.h lib/path.h lib/pathmatc $(libcppdir)/platform.o: lib/platform.cpp externals/tinyxml2/tinyxml2.h lib/config.h lib/mathlib.h lib/path.h lib/platform.h lib/standards.h lib/utils.h lib/xml.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/platform.cpp -$(libcppdir)/preprocessor.o: lib/preprocessor.cpp externals/simplecpp/simplecpp.h lib/addoninfo.h lib/checkers.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/preprocessor.h lib/settings.h lib/standards.h lib/suppressions.h lib/utils.h +$(libcppdir)/preprocessor.o: lib/preprocessor.cpp externals/simplecpp/simplecpp.h lib/checkers.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/preprocessor.h lib/settings.h lib/standards.h lib/suppressions.h lib/utils.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/preprocessor.cpp -$(libcppdir)/programmemory.o: lib/programmemory.cpp lib/addoninfo.h lib/astutils.h lib/calculate.h lib/checkers.h lib/config.h lib/errortypes.h lib/infer.h lib/library.h lib/mathlib.h lib/platform.h lib/programmemory.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenlist.h lib/utils.h lib/valueflow.h lib/valueptr.h lib/vfvalue.h +$(libcppdir)/programmemory.o: lib/programmemory.cpp lib/astutils.h lib/calculate.h lib/checkers.h lib/config.h lib/errortypes.h lib/infer.h lib/library.h lib/mathlib.h lib/platform.h lib/programmemory.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenlist.h lib/utils.h lib/valueflow.h lib/valueptr.h lib/vfvalue.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/programmemory.cpp $(libcppdir)/regex.o: lib/regex.cpp lib/config.h lib/regex.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/regex.cpp -$(libcppdir)/reverseanalyzer.o: lib/reverseanalyzer.cpp lib/addoninfo.h lib/analyzer.h lib/astutils.h lib/checkers.h lib/config.h lib/errortypes.h lib/forwardanalyzer.h lib/library.h lib/mathlib.h lib/platform.h lib/reverseanalyzer.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/utils.h lib/valueptr.h lib/vfvalue.h +$(libcppdir)/reverseanalyzer.o: lib/reverseanalyzer.cpp lib/analyzer.h lib/astutils.h lib/checkers.h lib/config.h lib/errortypes.h lib/forwardanalyzer.h lib/library.h lib/mathlib.h lib/platform.h lib/reverseanalyzer.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/utils.h lib/valueptr.h lib/vfvalue.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/reverseanalyzer.cpp -$(libcppdir)/sarifreport.o: lib/sarifreport.cpp externals/picojson/picojson.h lib/addoninfo.h lib/check.h lib/checkers.h lib/config.h lib/cppcheck.h lib/errorlogger.h lib/errortypes.h lib/json.h lib/library.h lib/mathlib.h lib/platform.h lib/sarifreport.h lib/settings.h lib/standards.h lib/utils.h +$(libcppdir)/sarifreport.o: lib/sarifreport.cpp externals/picojson/picojson.h lib/check.h lib/checkers.h lib/config.h lib/cppcheck.h lib/errorlogger.h lib/errortypes.h lib/json.h lib/library.h lib/mathlib.h lib/platform.h lib/sarifreport.h lib/settings.h lib/standards.h lib/utils.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/sarifreport.cpp $(libcppdir)/settings.o: lib/settings.cpp externals/picojson/picojson.h lib/addoninfo.h lib/checkers.h lib/config.h lib/errortypes.h lib/json.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/rule.h lib/settings.h lib/standards.h lib/summaries.h lib/suppressions.h lib/utils.h lib/vfvalue.h @@ -663,49 +663,49 @@ $(libcppdir)/settings.o: lib/settings.cpp externals/picojson/picojson.h lib/addo $(libcppdir)/standards.o: lib/standards.cpp externals/simplecpp/simplecpp.h lib/config.h lib/standards.h lib/utils.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/standards.cpp -$(libcppdir)/summaries.o: lib/summaries.cpp lib/addoninfo.h lib/analyzerinfo.h lib/checkers.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/summaries.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h +$(libcppdir)/summaries.o: lib/summaries.cpp lib/analyzerinfo.h lib/checkers.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/summaries.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/summaries.cpp $(libcppdir)/suppressions.o: lib/suppressions.cpp externals/tinyxml2/tinyxml2.h lib/addoninfo.h lib/checkers.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/library.h lib/mathlib.h lib/path.h lib/pathmatch.h lib/platform.h lib/settings.h lib/smallvector.h lib/standards.h lib/suppressions.h lib/templatesimplifier.h lib/token.h lib/tokenlist.h lib/utils.h lib/vfvalue.h lib/xml.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/suppressions.cpp -$(libcppdir)/templatesimplifier.o: lib/templatesimplifier.cpp lib/addoninfo.h lib/checkers.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/standards.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h +$(libcppdir)/templatesimplifier.o: lib/templatesimplifier.cpp lib/checkers.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/standards.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/templatesimplifier.cpp $(libcppdir)/timer.o: lib/timer.cpp lib/config.h lib/timer.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/timer.cpp -$(libcppdir)/token.o: lib/token.cpp externals/simplecpp/simplecpp.h lib/addoninfo.h lib/astutils.h lib/checkers.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenlist.h lib/tokenrange.h lib/utils.h lib/valueflow.h lib/vfvalue.h +$(libcppdir)/token.o: lib/token.cpp externals/simplecpp/simplecpp.h lib/astutils.h lib/checkers.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenlist.h lib/tokenrange.h lib/utils.h lib/valueflow.h lib/vfvalue.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/token.cpp -$(libcppdir)/tokenlist.o: lib/tokenlist.cpp externals/simplecpp/simplecpp.h lib/addoninfo.h lib/astutils.h lib/checkers.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/keywords.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/smallvector.h lib/standards.h lib/templatesimplifier.h lib/token.h lib/tokenlist.h lib/utils.h lib/vfvalue.h +$(libcppdir)/tokenlist.o: lib/tokenlist.cpp externals/simplecpp/simplecpp.h lib/astutils.h lib/checkers.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/keywords.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/smallvector.h lib/standards.h lib/templatesimplifier.h lib/token.h lib/tokenlist.h lib/utils.h lib/vfvalue.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/tokenlist.cpp $(libcppdir)/utils.o: lib/utils.cpp lib/config.h lib/utils.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/utils.cpp -$(libcppdir)/vf_analyzers.o: lib/vf_analyzers.cpp lib/addoninfo.h lib/analyzer.h lib/astutils.h lib/calculate.h lib/checkers.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/programmemory.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/utils.h lib/valueflow.h lib/valueptr.h lib/vf_analyzers.h lib/vf_common.h lib/vf_settokenvalue.h lib/vfvalue.h +$(libcppdir)/vf_analyzers.o: lib/vf_analyzers.cpp lib/analyzer.h lib/astutils.h lib/calculate.h lib/checkers.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/programmemory.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/utils.h lib/valueflow.h lib/valueptr.h lib/vf_analyzers.h lib/vf_common.h lib/vf_settokenvalue.h lib/vfvalue.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/vf_analyzers.cpp -$(libcppdir)/vf_common.o: lib/vf_common.cpp lib/addoninfo.h lib/astutils.h lib/checkers.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/utils.h lib/vf_common.h lib/vf_settokenvalue.h lib/vfvalue.h +$(libcppdir)/vf_common.o: lib/vf_common.cpp lib/astutils.h lib/checkers.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/utils.h lib/vf_common.h lib/vf_settokenvalue.h lib/vfvalue.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/vf_common.cpp -$(libcppdir)/vf_settokenvalue.o: lib/vf_settokenvalue.cpp lib/addoninfo.h lib/astutils.h lib/calculate.h lib/checkers.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/utils.h lib/valueflow.h lib/vf_common.h lib/vf_settokenvalue.h lib/vfvalue.h +$(libcppdir)/vf_settokenvalue.o: lib/vf_settokenvalue.cpp lib/astutils.h lib/calculate.h lib/checkers.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/utils.h lib/valueflow.h lib/vf_common.h lib/vf_settokenvalue.h lib/vfvalue.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/vf_settokenvalue.cpp $(libcppdir)/vfvalue.o: lib/vfvalue.cpp lib/config.h lib/errortypes.h lib/mathlib.h lib/smallvector.h lib/templatesimplifier.h lib/token.h lib/utils.h lib/vfvalue.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/vfvalue.cpp -frontend/frontend.o: frontend/frontend.cpp frontend/frontend.h lib/addoninfo.h lib/checkers.h lib/config.h lib/filesettings.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/utils.h +frontend/frontend.o: frontend/frontend.cpp frontend/frontend.h lib/checkers.h lib/config.h lib/filesettings.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/utils.h $(CXX) ${INCLUDE_FOR_FE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ frontend/frontend.cpp cli/cmdlineparser.o: cli/cmdlineparser.cpp cli/cmdlinelogger.h cli/cmdlineparser.h cli/filelister.h externals/tinyxml2/tinyxml2.h lib/addoninfo.h lib/check.h lib/checkers.h lib/checks.h lib/color.h lib/config.h lib/cppcheck.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/importproject.h lib/library.h lib/mathlib.h lib/path.h lib/pathmatch.h lib/platform.h lib/regex.h lib/rule.h lib/settings.h lib/standards.h lib/suppressions.h lib/utils.h lib/xml.h $(CXX) ${INCLUDE_FOR_CLI} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ cli/cmdlineparser.cpp -cli/cppcheckexecutor.o: cli/cppcheckexecutor.cpp cli/cmdlinelogger.h cli/cmdlineparser.h cli/cppcheckexecutor.h cli/executor.h cli/processexecutor.h cli/sehwrapper.h cli/signalhandler.h cli/singleexecutor.h cli/threadexecutor.h externals/picojson/picojson.h lib/addoninfo.h lib/analyzerinfo.h lib/check.h lib/checkers.h lib/checkersreport.h lib/color.h lib/config.h lib/cppcheck.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/json.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/sarifreport.h lib/settings.h lib/standards.h lib/suppressions.h lib/timer.h lib/utils.h +cli/cppcheckexecutor.o: cli/cppcheckexecutor.cpp cli/cmdlinelogger.h cli/cmdlineparser.h cli/cppcheckexecutor.h cli/executor.h cli/processexecutor.h cli/sehwrapper.h cli/signalhandler.h cli/singleexecutor.h cli/threadexecutor.h externals/picojson/picojson.h lib/analyzerinfo.h lib/check.h lib/checkers.h lib/checkersreport.h lib/color.h lib/config.h lib/cppcheck.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/json.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/sarifreport.h lib/settings.h lib/standards.h lib/suppressions.h lib/timer.h lib/utils.h $(CXX) ${INCLUDE_FOR_CLI} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ cli/cppcheckexecutor.cpp -cli/executor.o: cli/executor.cpp cli/executor.h lib/addoninfo.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/utils.h +cli/executor.o: cli/executor.cpp cli/executor.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/utils.h $(CXX) ${INCLUDE_FOR_CLI} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ cli/executor.cpp cli/filelister.o: cli/filelister.cpp cli/filelister.h lib/config.h lib/filesettings.h lib/mathlib.h lib/path.h lib/pathmatch.h lib/platform.h lib/standards.h lib/utils.h @@ -714,7 +714,7 @@ cli/filelister.o: cli/filelister.cpp cli/filelister.h lib/config.h lib/filesetti cli/main.o: cli/main.cpp cli/cppcheckexecutor.h lib/config.h lib/filesettings.h lib/mathlib.h lib/path.h lib/platform.h lib/standards.h lib/utils.h $(CXX) ${INCLUDE_FOR_CLI} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ cli/main.cpp -cli/processexecutor.o: cli/processexecutor.cpp cli/executor.h cli/processexecutor.h lib/addoninfo.h lib/check.h lib/checkers.h lib/config.h lib/cppcheck.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/timer.h lib/utils.h +cli/processexecutor.o: cli/processexecutor.cpp cli/executor.h cli/processexecutor.h lib/check.h lib/checkers.h lib/config.h lib/cppcheck.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/timer.h lib/utils.h $(CXX) ${INCLUDE_FOR_CLI} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ cli/processexecutor.cpp cli/sehwrapper.o: cli/sehwrapper.cpp cli/sehwrapper.h lib/config.h lib/utils.h @@ -723,247 +723,247 @@ cli/sehwrapper.o: cli/sehwrapper.cpp cli/sehwrapper.h lib/config.h lib/utils.h cli/signalhandler.o: cli/signalhandler.cpp cli/signalhandler.h cli/stacktrace.h lib/config.h $(CXX) ${INCLUDE_FOR_CLI} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ cli/signalhandler.cpp -cli/singleexecutor.o: cli/singleexecutor.cpp cli/executor.h cli/singleexecutor.h lib/addoninfo.h lib/check.h lib/checkers.h lib/config.h lib/cppcheck.h lib/filesettings.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/utils.h +cli/singleexecutor.o: cli/singleexecutor.cpp cli/executor.h cli/singleexecutor.h lib/check.h lib/checkers.h lib/config.h lib/cppcheck.h lib/filesettings.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/utils.h $(CXX) ${INCLUDE_FOR_CLI} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ cli/singleexecutor.cpp cli/stacktrace.o: cli/stacktrace.cpp cli/stacktrace.h lib/config.h lib/utils.h $(CXX) ${INCLUDE_FOR_CLI} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ cli/stacktrace.cpp -cli/threadexecutor.o: cli/threadexecutor.cpp cli/executor.h cli/threadexecutor.h lib/addoninfo.h lib/check.h lib/checkers.h lib/config.h lib/cppcheck.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/utils.h +cli/threadexecutor.o: cli/threadexecutor.cpp cli/executor.h cli/threadexecutor.h lib/check.h lib/checkers.h lib/config.h lib/cppcheck.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/utils.h $(CXX) ${INCLUDE_FOR_CLI} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ cli/threadexecutor.cpp -test/fixture.o: test/fixture.cpp externals/tinyxml2/tinyxml2.h lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/timer.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/xml.h test/fixture.h test/helpers.h test/options.h test/redirect.h +test/fixture.o: test/fixture.cpp externals/tinyxml2/tinyxml2.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/timer.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/xml.h test/fixture.h test/helpers.h test/options.h test/redirect.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/fixture.cpp -test/helpers.o: test/helpers.cpp cli/filelister.h externals/simplecpp/simplecpp.h externals/tinyxml2/tinyxml2.h lib/addoninfo.h lib/checkers.h lib/config.h lib/filesettings.h lib/library.h lib/mathlib.h lib/path.h lib/pathmatch.h lib/platform.h lib/preprocessor.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/xml.h test/helpers.h +test/helpers.o: test/helpers.cpp cli/filelister.h externals/simplecpp/simplecpp.h externals/tinyxml2/tinyxml2.h lib/checkers.h lib/config.h lib/filesettings.h lib/library.h lib/mathlib.h lib/path.h lib/pathmatch.h lib/platform.h lib/preprocessor.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/xml.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/helpers.cpp -test/main.o: test/main.cpp externals/simplecpp/simplecpp.h lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/preprocessor.h lib/settings.h lib/standards.h lib/utils.h test/fixture.h test/options.h +test/main.o: test/main.cpp externals/simplecpp/simplecpp.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/preprocessor.h lib/settings.h lib/standards.h lib/utils.h test/fixture.h test/options.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/main.cpp test/options.o: test/options.cpp lib/config.h lib/timer.h test/options.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/options.cpp -test/test64bit.o: test/test64bit.cpp lib/addoninfo.h lib/check.h lib/check64bit.h lib/checkers.h lib/checkimpl.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h +test/test64bit.o: test/test64bit.cpp lib/check.h lib/check64bit.h lib/checkers.h lib/checkimpl.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/test64bit.cpp -test/testanalyzerinformation.o: test/testanalyzerinformation.cpp externals/tinyxml2/tinyxml2.h lib/addoninfo.h lib/analyzerinfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/utils.h lib/xml.h test/fixture.h +test/testanalyzerinformation.o: test/testanalyzerinformation.cpp externals/tinyxml2/tinyxml2.h lib/analyzerinfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/utils.h lib/xml.h test/fixture.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testanalyzerinformation.cpp -test/testassert.o: test/testassert.cpp lib/addoninfo.h lib/check.h lib/checkassert.h lib/checkers.h lib/checkimpl.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h +test/testassert.o: test/testassert.cpp lib/check.h lib/checkassert.h lib/checkers.h lib/checkimpl.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testassert.cpp -test/testastutils.o: test/testastutils.cpp lib/addoninfo.h lib/astutils.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h +test/testastutils.o: test/testastutils.cpp lib/astutils.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testastutils.cpp -test/testautovariables.o: test/testautovariables.cpp lib/addoninfo.h lib/check.h lib/checkautovariables.h lib/checkers.h lib/checkimpl.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h +test/testautovariables.o: test/testautovariables.cpp lib/check.h lib/checkautovariables.h lib/checkers.h lib/checkimpl.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testautovariables.cpp -test/testbool.o: test/testbool.cpp lib/addoninfo.h lib/check.h lib/checkbool.h lib/checkers.h lib/checkimpl.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h +test/testbool.o: test/testbool.cpp lib/check.h lib/checkbool.h lib/checkers.h lib/checkimpl.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testbool.cpp -test/testbufferoverrun.o: test/testbufferoverrun.cpp lib/addoninfo.h lib/check.h lib/checkbufferoverrun.h lib/checkers.h lib/checkimpl.h lib/color.h lib/config.h lib/ctu.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h +test/testbufferoverrun.o: test/testbufferoverrun.cpp lib/check.h lib/checkbufferoverrun.h lib/checkers.h lib/checkimpl.h lib/color.h lib/config.h lib/ctu.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testbufferoverrun.cpp -test/testcharvar.o: test/testcharvar.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checkimpl.h lib/checkother.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h +test/testcharvar.o: test/testcharvar.cpp lib/check.h lib/checkers.h lib/checkimpl.h lib/checkother.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testcharvar.cpp -test/testcheck.o: test/testcheck.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checks.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/utils.h test/fixture.h +test/testcheck.o: test/testcheck.cpp lib/check.h lib/checkers.h lib/checks.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/utils.h test/fixture.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testcheck.cpp test/testcheckersreport.o: test/testcheckersreport.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checkersreport.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/utils.h test/fixture.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testcheckersreport.cpp -test/testclangimport.o: test/testclangimport.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/clangimport.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h +test/testclangimport.o: test/testclangimport.cpp lib/check.h lib/checkers.h lib/clangimport.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testclangimport.cpp -test/testclass.o: test/testclass.cpp lib/addoninfo.h lib/check.h lib/checkclass.h lib/checkers.h lib/checkimpl.h lib/color.h lib/config.h lib/ctu.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h +test/testclass.o: test/testclass.cpp lib/check.h lib/checkclass.h lib/checkers.h lib/checkimpl.h lib/color.h lib/config.h lib/ctu.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testclass.cpp -test/testcmdlineparser.o: test/testcmdlineparser.cpp cli/cmdlinelogger.h cli/cmdlineparser.h lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/rule.h lib/settings.h lib/standards.h lib/suppressions.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h test/redirect.h +test/testcmdlineparser.o: test/testcmdlineparser.cpp cli/cmdlinelogger.h cli/cmdlineparser.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/rule.h lib/settings.h lib/standards.h lib/suppressions.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h test/redirect.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testcmdlineparser.cpp -test/testcolor.o: test/testcolor.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/utils.h test/fixture.h +test/testcolor.o: test/testcolor.cpp lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/utils.h test/fixture.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testcolor.cpp -test/testcondition.o: test/testcondition.cpp lib/addoninfo.h lib/check.h lib/checkcondition.h lib/checkers.h lib/checkimpl.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h +test/testcondition.o: test/testcondition.cpp lib/check.h lib/checkcondition.h lib/checkers.h lib/checkimpl.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testcondition.cpp -test/testconstructors.o: test/testconstructors.cpp lib/addoninfo.h lib/check.h lib/checkclass.h lib/checkers.h lib/checkimpl.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h +test/testconstructors.o: test/testconstructors.cpp lib/check.h lib/checkclass.h lib/checkers.h lib/checkimpl.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testconstructors.cpp test/testcppcheck.o: test/testcppcheck.cpp externals/simplecpp/simplecpp.h lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/cppcheck.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/preprocessor.h lib/settings.h lib/standards.h lib/suppressions.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h test/redirect.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testcppcheck.cpp -test/testerrorlogger.o: test/testerrorlogger.cpp externals/tinyxml2/tinyxml2.h lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/cppcheck.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/xml.h test/fixture.h test/helpers.h +test/testerrorlogger.o: test/testerrorlogger.cpp externals/tinyxml2/tinyxml2.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/cppcheck.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/xml.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testerrorlogger.cpp -test/testexceptionsafety.o: test/testexceptionsafety.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checkexceptionsafety.h lib/checkimpl.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h +test/testexceptionsafety.o: test/testexceptionsafety.cpp lib/check.h lib/checkers.h lib/checkexceptionsafety.h lib/checkimpl.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testexceptionsafety.cpp -test/testexecutor.o: test/testexecutor.cpp cli/executor.h lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h +test/testexecutor.o: test/testexecutor.cpp cli/executor.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testexecutor.cpp -test/testfilelister.o: test/testfilelister.cpp cli/filelister.h lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/library.h lib/mathlib.h lib/path.h lib/pathmatch.h lib/platform.h lib/settings.h lib/standards.h lib/utils.h test/fixture.h +test/testfilelister.o: test/testfilelister.cpp cli/filelister.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/library.h lib/mathlib.h lib/path.h lib/pathmatch.h lib/platform.h lib/settings.h lib/standards.h lib/utils.h test/fixture.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testfilelister.cpp -test/testfilesettings.o: test/testfilesettings.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/utils.h test/fixture.h +test/testfilesettings.o: test/testfilesettings.cpp lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/utils.h test/fixture.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testfilesettings.cpp -test/testfrontend.o: test/testfrontend.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/utils.h test/fixture.h +test/testfrontend.o: test/testfrontend.cpp lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/utils.h test/fixture.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testfrontend.cpp -test/testfunctions.o: test/testfunctions.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checkfunctions.h lib/checkimpl.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h +test/testfunctions.o: test/testfunctions.cpp lib/check.h lib/checkers.h lib/checkfunctions.h lib/checkimpl.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testfunctions.cpp -test/testgarbage.o: test/testgarbage.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checks.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/smallvector.h lib/standards.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h +test/testgarbage.o: test/testgarbage.cpp lib/check.h lib/checkers.h lib/checks.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/smallvector.h lib/standards.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testgarbage.cpp -test/testimportproject.o: test/testimportproject.cpp externals/tinyxml2/tinyxml2.h lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/importproject.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/utils.h lib/xml.h test/fixture.h test/redirect.h +test/testimportproject.o: test/testimportproject.cpp externals/tinyxml2/tinyxml2.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/importproject.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/utils.h lib/xml.h test/fixture.h test/redirect.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testimportproject.cpp -test/testincompletestatement.o: test/testincompletestatement.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checkimpl.h lib/checkother.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h +test/testincompletestatement.o: test/testincompletestatement.cpp lib/check.h lib/checkers.h lib/checkimpl.h lib/checkother.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testincompletestatement.cpp -test/testinternal.o: test/testinternal.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checkimpl.h lib/checkinternal.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h +test/testinternal.o: test/testinternal.cpp lib/check.h lib/checkers.h lib/checkimpl.h lib/checkinternal.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testinternal.cpp -test/testio.o: test/testio.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checkimpl.h lib/checkio.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h +test/testio.o: test/testio.cpp lib/check.h lib/checkers.h lib/checkimpl.h lib/checkio.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testio.cpp -test/testleakautovar.o: test/testleakautovar.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checkimpl.h lib/checkleakautovar.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h +test/testleakautovar.o: test/testleakautovar.cpp lib/check.h lib/checkers.h lib/checkimpl.h lib/checkleakautovar.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testleakautovar.cpp -test/testlibrary.o: test/testlibrary.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/smallvector.h lib/standards.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h +test/testlibrary.o: test/testlibrary.cpp lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/smallvector.h lib/standards.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testlibrary.cpp -test/testmathlib.o: test/testmathlib.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/standards.h lib/templatesimplifier.h lib/token.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h +test/testmathlib.o: test/testmathlib.cpp lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/standards.h lib/templatesimplifier.h lib/token.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testmathlib.cpp -test/testmemleak.o: test/testmemleak.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checkimpl.h lib/checkmemoryleak.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h +test/testmemleak.o: test/testmemleak.cpp lib/check.h lib/checkers.h lib/checkimpl.h lib/checkmemoryleak.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testmemleak.cpp -test/testnullpointer.o: test/testnullpointer.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checkimpl.h lib/checknullpointer.h lib/color.h lib/config.h lib/ctu.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/smallvector.h lib/standards.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h +test/testnullpointer.o: test/testnullpointer.cpp lib/check.h lib/checkers.h lib/checkimpl.h lib/checknullpointer.h lib/color.h lib/config.h lib/ctu.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/smallvector.h lib/standards.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testnullpointer.cpp -test/testoptions.o: test/testoptions.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/utils.h test/fixture.h test/options.h +test/testoptions.o: test/testoptions.cpp lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/utils.h test/fixture.h test/options.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testoptions.cpp -test/testother.o: test/testother.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checkimpl.h lib/checkother.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h +test/testother.o: test/testother.cpp lib/check.h lib/checkers.h lib/checkimpl.h lib/checkother.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testother.cpp -test/testpath.o: test/testpath.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h +test/testpath.o: test/testpath.cpp lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testpath.cpp -test/testpathmatch.o: test/testpathmatch.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/pathmatch.h lib/platform.h lib/settings.h lib/standards.h lib/utils.h test/fixture.h +test/testpathmatch.o: test/testpathmatch.cpp lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/pathmatch.h lib/platform.h lib/settings.h lib/standards.h lib/utils.h test/fixture.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testpathmatch.cpp -test/testplatform.o: test/testplatform.cpp externals/tinyxml2/tinyxml2.h lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/utils.h lib/xml.h test/fixture.h +test/testplatform.o: test/testplatform.cpp externals/tinyxml2/tinyxml2.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/utils.h lib/xml.h test/fixture.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testplatform.cpp -test/testpostfixoperator.o: test/testpostfixoperator.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checkimpl.h lib/checkpostfixoperator.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h +test/testpostfixoperator.o: test/testpostfixoperator.cpp lib/check.h lib/checkers.h lib/checkimpl.h lib/checkpostfixoperator.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testpostfixoperator.cpp -test/testpreprocessor.o: test/testpreprocessor.cpp externals/simplecpp/simplecpp.h lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/preprocessor.h lib/settings.h lib/standards.h lib/suppressions.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h +test/testpreprocessor.o: test/testpreprocessor.cpp externals/simplecpp/simplecpp.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/preprocessor.h lib/settings.h lib/standards.h lib/suppressions.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testpreprocessor.cpp -test/testprocessexecutor.o: test/testprocessexecutor.cpp cli/executor.h cli/processexecutor.h lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/cppcheck.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/timer.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h test/redirect.h +test/testprocessexecutor.o: test/testprocessexecutor.cpp cli/executor.h cli/processexecutor.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/cppcheck.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/timer.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h test/redirect.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testprocessexecutor.cpp -test/testprogrammemory.o: test/testprogrammemory.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/programmemory.h lib/settings.h lib/smallvector.h lib/standards.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h +test/testprogrammemory.o: test/testprogrammemory.cpp lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/programmemory.h lib/settings.h lib/smallvector.h lib/standards.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testprogrammemory.cpp -test/testregex.o: test/testregex.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/utils.h test/fixture.h +test/testregex.o: test/testregex.cpp lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/utils.h test/fixture.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testregex.cpp -test/testsarifreport.o: test/testsarifreport.cpp externals/picojson/picojson.h lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/json.h lib/library.h lib/mathlib.h lib/platform.h lib/sarifreport.h lib/settings.h lib/standards.h lib/utils.h test/fixture.h +test/testsarifreport.o: test/testsarifreport.cpp externals/picojson/picojson.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/json.h lib/library.h lib/mathlib.h lib/platform.h lib/sarifreport.h lib/settings.h lib/standards.h lib/utils.h test/fixture.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testsarifreport.cpp -test/testsettings.o: test/testsettings.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h +test/testsettings.o: test/testsettings.cpp lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testsettings.cpp -test/testsimplifytemplate.o: test/testsimplifytemplate.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/smallvector.h lib/standards.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h +test/testsimplifytemplate.o: test/testsimplifytemplate.cpp lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/smallvector.h lib/standards.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testsimplifytemplate.cpp -test/testsimplifytokens.o: test/testsimplifytokens.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/smallvector.h lib/standards.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h +test/testsimplifytokens.o: test/testsimplifytokens.cpp lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/smallvector.h lib/standards.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testsimplifytokens.cpp -test/testsimplifytypedef.o: test/testsimplifytypedef.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/smallvector.h lib/standards.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h +test/testsimplifytypedef.o: test/testsimplifytypedef.cpp lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/smallvector.h lib/standards.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testsimplifytypedef.cpp -test/testsimplifyusing.o: test/testsimplifyusing.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/smallvector.h lib/standards.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h +test/testsimplifyusing.o: test/testsimplifyusing.cpp lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/smallvector.h lib/standards.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testsimplifyusing.cpp -test/testsingleexecutor.o: test/testsingleexecutor.cpp cli/executor.h cli/singleexecutor.h lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/cppcheck.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/timer.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h test/redirect.h +test/testsingleexecutor.o: test/testsingleexecutor.cpp cli/executor.h cli/singleexecutor.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/cppcheck.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/timer.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h test/redirect.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testsingleexecutor.cpp -test/testsizeof.o: test/testsizeof.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checkimpl.h lib/checksizeof.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h +test/testsizeof.o: test/testsizeof.cpp lib/check.h lib/checkers.h lib/checkimpl.h lib/checksizeof.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testsizeof.cpp -test/teststandards.o: test/teststandards.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/utils.h test/fixture.h +test/teststandards.o: test/teststandards.cpp lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/utils.h test/fixture.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/teststandards.cpp -test/teststl.o: test/teststl.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checkimpl.h lib/checkstl.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h +test/teststl.o: test/teststl.cpp lib/check.h lib/checkers.h lib/checkimpl.h lib/checkstl.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/teststl.cpp -test/teststring.o: test/teststring.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checkimpl.h lib/checkstring.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h +test/teststring.o: test/teststring.cpp lib/check.h lib/checkers.h lib/checkimpl.h lib/checkstring.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/teststring.cpp -test/testsummaries.o: test/testsummaries.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/summaries.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h +test/testsummaries.o: test/testsummaries.cpp lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/summaries.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testsummaries.cpp test/testsuppressions.o: test/testsuppressions.cpp cli/cppcheckexecutor.h cli/executor.h cli/processexecutor.h cli/singleexecutor.h cli/threadexecutor.h lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/cppcheck.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testsuppressions.cpp -test/testsymboldatabase.o: test/testsymboldatabase.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h +test/testsymboldatabase.o: test/testsymboldatabase.cpp lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testsymboldatabase.cpp -test/testthreadexecutor.o: test/testthreadexecutor.cpp cli/executor.h cli/threadexecutor.h lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/cppcheck.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/timer.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h test/redirect.h +test/testthreadexecutor.o: test/testthreadexecutor.cpp cli/executor.h cli/threadexecutor.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/cppcheck.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/timer.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h test/redirect.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testthreadexecutor.cpp -test/testtimer.o: test/testtimer.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/timer.h lib/utils.h test/fixture.h test/redirect.h +test/testtimer.o: test/testtimer.cpp lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/timer.h lib/utils.h test/fixture.h test/redirect.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testtimer.cpp -test/testtoken.o: test/testtoken.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/smallvector.h lib/standards.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h +test/testtoken.o: test/testtoken.cpp lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/smallvector.h lib/standards.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testtoken.cpp -test/testtokenize.o: test/testtokenize.cpp externals/simplecpp/simplecpp.h lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/preprocessor.h lib/settings.h lib/smallvector.h lib/standards.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h +test/testtokenize.o: test/testtokenize.cpp externals/simplecpp/simplecpp.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/preprocessor.h lib/settings.h lib/smallvector.h lib/standards.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testtokenize.cpp -test/testtokenlist.o: test/testtokenlist.cpp externals/simplecpp/simplecpp.h lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/preprocessor.h lib/settings.h lib/smallvector.h lib/standards.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h +test/testtokenlist.o: test/testtokenlist.cpp externals/simplecpp/simplecpp.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/preprocessor.h lib/settings.h lib/smallvector.h lib/standards.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testtokenlist.cpp -test/testtokenrange.o: test/testtokenrange.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/tokenrange.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h +test/testtokenrange.o: test/testtokenrange.cpp lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/tokenrange.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testtokenrange.cpp -test/testtype.o: test/testtype.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checkimpl.h lib/checktype.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h +test/testtype.o: test/testtype.cpp lib/check.h lib/checkers.h lib/checkimpl.h lib/checktype.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testtype.cpp -test/testuninitvar.o: test/testuninitvar.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checkimpl.h lib/checkuninitvar.h lib/color.h lib/config.h lib/ctu.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h +test/testuninitvar.o: test/testuninitvar.cpp lib/check.h lib/checkers.h lib/checkimpl.h lib/checkuninitvar.h lib/color.h lib/config.h lib/ctu.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testuninitvar.cpp -test/testunusedfunctions.o: test/testunusedfunctions.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checkunusedfunctions.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h +test/testunusedfunctions.o: test/testunusedfunctions.cpp lib/check.h lib/checkers.h lib/checkunusedfunctions.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testunusedfunctions.cpp -test/testunusedprivfunc.o: test/testunusedprivfunc.cpp lib/addoninfo.h lib/check.h lib/checkclass.h lib/checkers.h lib/checkimpl.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h +test/testunusedprivfunc.o: test/testunusedprivfunc.cpp lib/check.h lib/checkclass.h lib/checkers.h lib/checkimpl.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testunusedprivfunc.cpp -test/testunusedvar.o: test/testunusedvar.cpp externals/simplecpp/simplecpp.h lib/addoninfo.h lib/check.h lib/checkers.h lib/checkimpl.h lib/checkunusedvar.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/preprocessor.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h +test/testunusedvar.o: test/testunusedvar.cpp externals/simplecpp/simplecpp.h lib/check.h lib/checkers.h lib/checkimpl.h lib/checkunusedvar.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/preprocessor.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testunusedvar.cpp -test/testutils.o: test/testutils.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/utils.h test/fixture.h +test/testutils.o: test/testutils.cpp lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/utils.h test/fixture.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testutils.cpp -test/testvaarg.o: test/testvaarg.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checkimpl.h lib/checkvaarg.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h +test/testvaarg.o: test/testvaarg.cpp lib/check.h lib/checkers.h lib/checkimpl.h lib/checkvaarg.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testvaarg.cpp -test/testvalueflow.o: test/testvalueflow.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/smallvector.h lib/standards.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h +test/testvalueflow.o: test/testvalueflow.cpp lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/smallvector.h lib/standards.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testvalueflow.cpp -test/testvarid.o: test/testvarid.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/smallvector.h lib/standards.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h +test/testvarid.o: test/testvarid.cpp lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/smallvector.h lib/standards.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testvarid.cpp -test/testvfvalue.o: test/testvfvalue.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/utils.h lib/vfvalue.h test/fixture.h +test/testvfvalue.o: test/testvfvalue.cpp lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/utils.h lib/vfvalue.h test/fixture.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testvfvalue.cpp externals/simplecpp/simplecpp.o: externals/simplecpp/simplecpp.cpp externals/simplecpp/simplecpp.h diff --git a/gui/test/projectfile/testprojectfile.cpp b/gui/test/projectfile/testprojectfile.cpp index 3eaa2b10386..efc1dce6c4f 100644 --- a/gui/test/projectfile/testprojectfile.cpp +++ b/gui/test/projectfile/testprojectfile.cpp @@ -18,6 +18,7 @@ #include "testprojectfile.h" +#include "addoninfo.h" #include "library.h" #include "platform.h" #include "projectfile.h" diff --git a/lib/settings.cpp b/lib/settings.cpp index a9ba14dd72b..95d4c4e953b 100644 --- a/lib/settings.cpp +++ b/lib/settings.cpp @@ -16,6 +16,7 @@ * along with this program. If not, see . */ +#include "addoninfo.h" #include "config.h" #include "errortypes.h" #include "settings.h" diff --git a/lib/settings.h b/lib/settings.h index 80f3853bde6..04ddb9adb9a 100644 --- a/lib/settings.h +++ b/lib/settings.h @@ -21,7 +21,6 @@ #define settingsH //--------------------------------------------------------------------------- -#include "addoninfo.h" #include "config.h" #include "library.h" #include "platform.h" @@ -47,6 +46,7 @@ struct Rule; #endif struct Suppressions; +struct AddonInfo; namespace ValueFlow { class Value; } diff --git a/oss-fuzz/Makefile b/oss-fuzz/Makefile index 988b5cb901b..eeb795bd35c 100644 --- a/oss-fuzz/Makefile +++ b/oss-fuzz/Makefile @@ -153,13 +153,13 @@ simplecpp.o: ../externals/simplecpp/simplecpp.cpp ../externals/simplecpp/simplec tinyxml2.o: ../externals/tinyxml2/tinyxml2.cpp ../externals/tinyxml2/tinyxml2.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -w -D_LARGEFILE_SOURCE -c -o $@ ../externals/tinyxml2/tinyxml2.cpp -$(libcppdir)/valueflow.o: ../lib/valueflow.cpp ../lib/addoninfo.h ../lib/analyzer.h ../lib/astutils.h ../lib/calculate.h ../lib/check.h ../lib/checkers.h ../lib/checkimpl.h ../lib/checkuninitvar.h ../lib/config.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/findtoken.h ../lib/forwardanalyzer.h ../lib/infer.h ../lib/library.h ../lib/mathlib.h ../lib/path.h ../lib/platform.h ../lib/programmemory.h ../lib/reverseanalyzer.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/timer.h ../lib/token.h ../lib/tokenlist.h ../lib/utils.h ../lib/valueflow.h ../lib/valueptr.h ../lib/vf_analyzers.h ../lib/vf_common.h ../lib/vf_settokenvalue.h ../lib/vfvalue.h +$(libcppdir)/valueflow.o: ../lib/valueflow.cpp ../lib/analyzer.h ../lib/astutils.h ../lib/calculate.h ../lib/check.h ../lib/checkers.h ../lib/checkimpl.h ../lib/checkuninitvar.h ../lib/config.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/findtoken.h ../lib/forwardanalyzer.h ../lib/infer.h ../lib/library.h ../lib/mathlib.h ../lib/path.h ../lib/platform.h ../lib/programmemory.h ../lib/reverseanalyzer.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/timer.h ../lib/token.h ../lib/tokenlist.h ../lib/utils.h ../lib/valueflow.h ../lib/valueptr.h ../lib/vf_analyzers.h ../lib/vf_common.h ../lib/vf_settokenvalue.h ../lib/vfvalue.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/valueflow.cpp -$(libcppdir)/tokenize.o: ../lib/tokenize.cpp ../externals/simplecpp/simplecpp.h ../lib/addoninfo.h ../lib/astutils.h ../lib/checkers.h ../lib/config.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/path.h ../lib/platform.h ../lib/preprocessor.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/summaries.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/timer.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/valueflow.h ../lib/vfvalue.h +$(libcppdir)/tokenize.o: ../lib/tokenize.cpp ../externals/simplecpp/simplecpp.h ../lib/astutils.h ../lib/checkers.h ../lib/config.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/path.h ../lib/platform.h ../lib/preprocessor.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/summaries.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/timer.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/valueflow.h ../lib/vfvalue.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/tokenize.cpp -$(libcppdir)/symboldatabase.o: ../lib/symboldatabase.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/checkers.h ../lib/config.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/keywords.h ../lib/library.h ../lib/mathlib.h ../lib/path.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/valueflow.h ../lib/vfvalue.h +$(libcppdir)/symboldatabase.o: ../lib/symboldatabase.cpp ../lib/astutils.h ../lib/checkers.h ../lib/config.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/keywords.h ../lib/library.h ../lib/mathlib.h ../lib/path.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/valueflow.h ../lib/vfvalue.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/symboldatabase.cpp $(libcppdir)/addoninfo.o: ../lib/addoninfo.cpp ../externals/picojson/picojson.h ../lib/addoninfo.h ../lib/config.h ../lib/json.h ../lib/path.h ../lib/standards.h ../lib/utils.h @@ -168,28 +168,28 @@ $(libcppdir)/addoninfo.o: ../lib/addoninfo.cpp ../externals/picojson/picojson.h $(libcppdir)/analyzerinfo.o: ../lib/analyzerinfo.cpp ../externals/tinyxml2/tinyxml2.h ../lib/analyzerinfo.h ../lib/config.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/filesettings.h ../lib/mathlib.h ../lib/path.h ../lib/platform.h ../lib/standards.h ../lib/utils.h ../lib/xml.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/analyzerinfo.cpp -$(libcppdir)/astutils.o: ../lib/astutils.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkclass.h ../lib/checkers.h ../lib/checkimpl.h ../lib/config.h ../lib/errortypes.h ../lib/findtoken.h ../lib/infer.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/utils.h ../lib/valueflow.h ../lib/valueptr.h ../lib/vfvalue.h +$(libcppdir)/astutils.o: ../lib/astutils.cpp ../lib/astutils.h ../lib/check.h ../lib/checkclass.h ../lib/checkers.h ../lib/checkimpl.h ../lib/config.h ../lib/errortypes.h ../lib/findtoken.h ../lib/infer.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/utils.h ../lib/valueflow.h ../lib/valueptr.h ../lib/vfvalue.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/astutils.cpp -$(libcppdir)/check64bit.o: ../lib/check64bit.cpp ../lib/addoninfo.h ../lib/check.h ../lib/check64bit.h ../lib/checkers.h ../lib/checkimpl.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h +$(libcppdir)/check64bit.o: ../lib/check64bit.cpp ../lib/check.h ../lib/check64bit.h ../lib/checkers.h ../lib/checkimpl.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/check64bit.cpp -$(libcppdir)/checkassert.o: ../lib/checkassert.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkassert.h ../lib/checkers.h ../lib/checkimpl.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h +$(libcppdir)/checkassert.o: ../lib/checkassert.cpp ../lib/astutils.h ../lib/check.h ../lib/checkassert.h ../lib/checkers.h ../lib/checkimpl.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkassert.cpp -$(libcppdir)/checkautovariables.o: ../lib/checkautovariables.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkautovariables.h ../lib/checkers.h ../lib/checkimpl.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/valueflow.h ../lib/vfvalue.h +$(libcppdir)/checkautovariables.o: ../lib/checkautovariables.cpp ../lib/astutils.h ../lib/check.h ../lib/checkautovariables.h ../lib/checkers.h ../lib/checkimpl.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/valueflow.h ../lib/vfvalue.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkautovariables.cpp -$(libcppdir)/checkbool.o: ../lib/checkbool.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkbool.h ../lib/checkers.h ../lib/checkimpl.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h +$(libcppdir)/checkbool.o: ../lib/checkbool.cpp ../lib/astutils.h ../lib/check.h ../lib/checkbool.h ../lib/checkers.h ../lib/checkimpl.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkbool.cpp -$(libcppdir)/checkbufferoverrun.o: ../lib/checkbufferoverrun.cpp ../externals/tinyxml2/tinyxml2.h ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkbufferoverrun.h ../lib/checkers.h ../lib/checkimpl.h ../lib/config.h ../lib/ctu.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/path.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/valueflow.h ../lib/vf_common.h ../lib/vfvalue.h ../lib/xml.h +$(libcppdir)/checkbufferoverrun.o: ../lib/checkbufferoverrun.cpp ../externals/tinyxml2/tinyxml2.h ../lib/astutils.h ../lib/check.h ../lib/checkbufferoverrun.h ../lib/checkers.h ../lib/checkimpl.h ../lib/config.h ../lib/ctu.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/path.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/valueflow.h ../lib/vf_common.h ../lib/vfvalue.h ../lib/xml.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkbufferoverrun.cpp -$(libcppdir)/checkclass.o: ../lib/checkclass.cpp ../externals/tinyxml2/tinyxml2.h ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkclass.h ../lib/checkers.h ../lib/checkimpl.h ../lib/config.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/path.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h ../lib/xml.h +$(libcppdir)/checkclass.o: ../lib/checkclass.cpp ../externals/tinyxml2/tinyxml2.h ../lib/astutils.h ../lib/check.h ../lib/checkclass.h ../lib/checkers.h ../lib/checkimpl.h ../lib/config.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/path.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h ../lib/xml.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkclass.cpp -$(libcppdir)/checkcondition.o: ../lib/checkcondition.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkcondition.h ../lib/checkers.h ../lib/checkimpl.h ../lib/checkother.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h +$(libcppdir)/checkcondition.o: ../lib/checkcondition.cpp ../lib/astutils.h ../lib/check.h ../lib/checkcondition.h ../lib/checkers.h ../lib/checkimpl.h ../lib/checkother.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkcondition.cpp $(libcppdir)/checkers.o: ../lib/checkers.cpp ../lib/checkers.h ../lib/config.h @@ -201,61 +201,61 @@ $(libcppdir)/checkersidmapping.o: ../lib/checkersidmapping.cpp ../lib/checkers.h $(libcppdir)/checkersreport.o: ../lib/checkersreport.cpp ../lib/addoninfo.h ../lib/checkers.h ../lib/checkersreport.h ../lib/config.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/settings.h ../lib/standards.h ../lib/utils.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkersreport.cpp -$(libcppdir)/checkexceptionsafety.o: ../lib/checkexceptionsafety.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkers.h ../lib/checkexceptionsafety.h ../lib/checkimpl.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h +$(libcppdir)/checkexceptionsafety.o: ../lib/checkexceptionsafety.cpp ../lib/astutils.h ../lib/check.h ../lib/checkers.h ../lib/checkexceptionsafety.h ../lib/checkimpl.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkexceptionsafety.cpp -$(libcppdir)/checkfunctions.o: ../lib/checkfunctions.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkers.h ../lib/checkfunctions.h ../lib/checkimpl.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/valueflow.h ../lib/vfvalue.h +$(libcppdir)/checkfunctions.o: ../lib/checkfunctions.cpp ../lib/astutils.h ../lib/check.h ../lib/checkers.h ../lib/checkfunctions.h ../lib/checkimpl.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/valueflow.h ../lib/vfvalue.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkfunctions.cpp -$(libcppdir)/checkimpl.o: ../lib/checkimpl.cpp ../lib/addoninfo.h ../lib/checkers.h ../lib/checkimpl.h ../lib/config.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/standards.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h +$(libcppdir)/checkimpl.o: ../lib/checkimpl.cpp ../lib/checkers.h ../lib/checkimpl.h ../lib/config.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/standards.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkimpl.cpp -$(libcppdir)/checkinternal.o: ../lib/checkinternal.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkers.h ../lib/checkimpl.h ../lib/checkinternal.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h +$(libcppdir)/checkinternal.o: ../lib/checkinternal.cpp ../lib/astutils.h ../lib/check.h ../lib/checkers.h ../lib/checkimpl.h ../lib/checkinternal.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkinternal.cpp -$(libcppdir)/checkio.o: ../lib/checkio.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkers.h ../lib/checkimpl.h ../lib/checkio.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h +$(libcppdir)/checkio.o: ../lib/checkio.cpp ../lib/astutils.h ../lib/check.h ../lib/checkers.h ../lib/checkimpl.h ../lib/checkio.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkio.cpp -$(libcppdir)/checkleakautovar.o: ../lib/checkleakautovar.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkers.h ../lib/checkimpl.h ../lib/checkleakautovar.h ../lib/checkmemoryleak.h ../lib/checknullpointer.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h +$(libcppdir)/checkleakautovar.o: ../lib/checkleakautovar.cpp ../lib/astutils.h ../lib/check.h ../lib/checkers.h ../lib/checkimpl.h ../lib/checkleakautovar.h ../lib/checkmemoryleak.h ../lib/checknullpointer.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkleakautovar.cpp -$(libcppdir)/checkmemoryleak.o: ../lib/checkmemoryleak.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkers.h ../lib/checkimpl.h ../lib/checkmemoryleak.h ../lib/config.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h +$(libcppdir)/checkmemoryleak.o: ../lib/checkmemoryleak.cpp ../lib/astutils.h ../lib/check.h ../lib/checkers.h ../lib/checkimpl.h ../lib/checkmemoryleak.h ../lib/config.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkmemoryleak.cpp -$(libcppdir)/checknullpointer.o: ../lib/checknullpointer.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkers.h ../lib/checkimpl.h ../lib/checknullpointer.h ../lib/config.h ../lib/ctu.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/findtoken.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/valueflow.h ../lib/vfvalue.h +$(libcppdir)/checknullpointer.o: ../lib/checknullpointer.cpp ../lib/astutils.h ../lib/check.h ../lib/checkers.h ../lib/checkimpl.h ../lib/checknullpointer.h ../lib/config.h ../lib/ctu.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/findtoken.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/valueflow.h ../lib/vfvalue.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checknullpointer.cpp -$(libcppdir)/checkother.o: ../lib/checkother.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkers.h ../lib/checkimpl.h ../lib/checkother.h ../lib/config.h ../lib/errortypes.h ../lib/fwdanalysis.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/valueflow.h ../lib/vfvalue.h +$(libcppdir)/checkother.o: ../lib/checkother.cpp ../lib/astutils.h ../lib/check.h ../lib/checkers.h ../lib/checkimpl.h ../lib/checkother.h ../lib/config.h ../lib/errortypes.h ../lib/fwdanalysis.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/valueflow.h ../lib/vfvalue.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkother.cpp -$(libcppdir)/checkpostfixoperator.o: ../lib/checkpostfixoperator.cpp ../lib/addoninfo.h ../lib/check.h ../lib/checkers.h ../lib/checkimpl.h ../lib/checkpostfixoperator.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h +$(libcppdir)/checkpostfixoperator.o: ../lib/checkpostfixoperator.cpp ../lib/check.h ../lib/checkers.h ../lib/checkimpl.h ../lib/checkpostfixoperator.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkpostfixoperator.cpp $(libcppdir)/checks.o: ../lib/checks.cpp ../lib/check.h ../lib/check64bit.h ../lib/checkassert.h ../lib/checkautovariables.h ../lib/checkbool.h ../lib/checkbufferoverrun.h ../lib/checkclass.h ../lib/checkcondition.h ../lib/checkexceptionsafety.h ../lib/checkfunctions.h ../lib/checkimpl.h ../lib/checkinternal.h ../lib/checkio.h ../lib/checkleakautovar.h ../lib/checkmemoryleak.h ../lib/checknullpointer.h ../lib/checkother.h ../lib/checkpostfixoperator.h ../lib/checks.h ../lib/checksizeof.h ../lib/checkstl.h ../lib/checkstring.h ../lib/checktype.h ../lib/checkuninitvar.h ../lib/checkunusedvar.h ../lib/checkvaarg.h ../lib/config.h ../lib/ctu.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/standards.h ../lib/vfvalue.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checks.cpp -$(libcppdir)/checksizeof.o: ../lib/checksizeof.cpp ../lib/addoninfo.h ../lib/check.h ../lib/checkers.h ../lib/checkimpl.h ../lib/checksizeof.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h +$(libcppdir)/checksizeof.o: ../lib/checksizeof.cpp ../lib/check.h ../lib/checkers.h ../lib/checkimpl.h ../lib/checksizeof.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checksizeof.cpp -$(libcppdir)/checkstl.o: ../lib/checkstl.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkers.h ../lib/checkimpl.h ../lib/checknullpointer.h ../lib/checkstl.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/pathanalysis.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/valueflow.h ../lib/vfvalue.h +$(libcppdir)/checkstl.o: ../lib/checkstl.cpp ../lib/astutils.h ../lib/check.h ../lib/checkers.h ../lib/checkimpl.h ../lib/checknullpointer.h ../lib/checkstl.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/pathanalysis.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/valueflow.h ../lib/vfvalue.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkstl.cpp -$(libcppdir)/checkstring.o: ../lib/checkstring.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkers.h ../lib/checkimpl.h ../lib/checkstring.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h +$(libcppdir)/checkstring.o: ../lib/checkstring.cpp ../lib/astutils.h ../lib/check.h ../lib/checkers.h ../lib/checkimpl.h ../lib/checkstring.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkstring.cpp -$(libcppdir)/checktype.o: ../lib/checktype.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkers.h ../lib/checkimpl.h ../lib/checktype.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/valueflow.h ../lib/vfvalue.h +$(libcppdir)/checktype.o: ../lib/checktype.cpp ../lib/astutils.h ../lib/check.h ../lib/checkers.h ../lib/checkimpl.h ../lib/checktype.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/valueflow.h ../lib/vfvalue.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checktype.cpp -$(libcppdir)/checkuninitvar.o: ../lib/checkuninitvar.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkers.h ../lib/checkimpl.h ../lib/checknullpointer.h ../lib/checkuninitvar.h ../lib/config.h ../lib/ctu.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h +$(libcppdir)/checkuninitvar.o: ../lib/checkuninitvar.cpp ../lib/astutils.h ../lib/check.h ../lib/checkers.h ../lib/checkimpl.h ../lib/checknullpointer.h ../lib/checkuninitvar.h ../lib/config.h ../lib/ctu.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkuninitvar.cpp -$(libcppdir)/checkunusedfunctions.o: ../lib/checkunusedfunctions.cpp ../externals/tinyxml2/tinyxml2.h ../lib/addoninfo.h ../lib/analyzerinfo.h ../lib/astutils.h ../lib/checkers.h ../lib/checkunusedfunctions.h ../lib/config.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/path.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h ../lib/xml.h +$(libcppdir)/checkunusedfunctions.o: ../lib/checkunusedfunctions.cpp ../externals/tinyxml2/tinyxml2.h ../lib/analyzerinfo.h ../lib/astutils.h ../lib/checkers.h ../lib/checkunusedfunctions.h ../lib/config.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/path.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h ../lib/xml.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkunusedfunctions.cpp -$(libcppdir)/checkunusedvar.o: ../lib/checkunusedvar.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkers.h ../lib/checkimpl.h ../lib/checkunusedvar.h ../lib/config.h ../lib/errortypes.h ../lib/fwdanalysis.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/valueflow.h ../lib/vfvalue.h +$(libcppdir)/checkunusedvar.o: ../lib/checkunusedvar.cpp ../lib/astutils.h ../lib/check.h ../lib/checkers.h ../lib/checkimpl.h ../lib/checkunusedvar.h ../lib/config.h ../lib/errortypes.h ../lib/fwdanalysis.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/valueflow.h ../lib/vfvalue.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkunusedvar.cpp -$(libcppdir)/checkvaarg.o: ../lib/checkvaarg.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkers.h ../lib/checkimpl.h ../lib/checkvaarg.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h +$(libcppdir)/checkvaarg.o: ../lib/checkvaarg.cpp ../lib/astutils.h ../lib/check.h ../lib/checkers.h ../lib/checkimpl.h ../lib/checkvaarg.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkvaarg.cpp $(libcppdir)/clangimport.o: ../lib/clangimport.cpp ../lib/clangimport.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h @@ -270,7 +270,7 @@ $(libcppdir)/cppcheck.o: ../lib/cppcheck.cpp ../externals/picojson/picojson.h .. $(libcppdir)/ctu.o: ../lib/ctu.cpp ../externals/tinyxml2/tinyxml2.h ../lib/astutils.h ../lib/check.h ../lib/config.h ../lib/ctu.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/path.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h ../lib/xml.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/ctu.cpp -$(libcppdir)/errorlogger.o: ../lib/errorlogger.cpp ../externals/tinyxml2/tinyxml2.h ../lib/addoninfo.h ../lib/check.h ../lib/checkers.h ../lib/color.h ../lib/config.h ../lib/cppcheck.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/path.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/standards.h ../lib/suppressions.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h ../lib/xml.h +$(libcppdir)/errorlogger.o: ../lib/errorlogger.cpp ../externals/tinyxml2/tinyxml2.h ../lib/check.h ../lib/checkers.h ../lib/color.h ../lib/config.h ../lib/cppcheck.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/path.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/standards.h ../lib/suppressions.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h ../lib/xml.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/errorlogger.cpp $(libcppdir)/errortypes.o: ../lib/errortypes.cpp ../lib/config.h ../lib/errortypes.h ../lib/utils.h @@ -279,13 +279,13 @@ $(libcppdir)/errortypes.o: ../lib/errortypes.cpp ../lib/config.h ../lib/errortyp $(libcppdir)/findtoken.o: ../lib/findtoken.cpp ../lib/astutils.h ../lib/config.h ../lib/errortypes.h ../lib/findtoken.h ../lib/library.h ../lib/mathlib.h ../lib/smallvector.h ../lib/standards.h ../lib/templatesimplifier.h ../lib/token.h ../lib/utils.h ../lib/vfvalue.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/findtoken.cpp -$(libcppdir)/forwardanalyzer.o: ../lib/forwardanalyzer.cpp ../lib/addoninfo.h ../lib/analyzer.h ../lib/astutils.h ../lib/checkers.h ../lib/config.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/forwardanalyzer.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenlist.h ../lib/utils.h ../lib/valueptr.h ../lib/vfvalue.h +$(libcppdir)/forwardanalyzer.o: ../lib/forwardanalyzer.cpp ../lib/analyzer.h ../lib/astutils.h ../lib/checkers.h ../lib/config.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/forwardanalyzer.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenlist.h ../lib/utils.h ../lib/valueptr.h ../lib/vfvalue.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/forwardanalyzer.cpp -$(libcppdir)/fwdanalysis.o: ../lib/fwdanalysis.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/checkers.h ../lib/config.h ../lib/errortypes.h ../lib/fwdanalysis.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/utils.h ../lib/vfvalue.h +$(libcppdir)/fwdanalysis.o: ../lib/fwdanalysis.cpp ../lib/astutils.h ../lib/checkers.h ../lib/config.h ../lib/errortypes.h ../lib/fwdanalysis.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/utils.h ../lib/vfvalue.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/fwdanalysis.cpp -$(libcppdir)/importproject.o: ../lib/importproject.cpp ../externals/picojson/picojson.h ../externals/tinyxml2/tinyxml2.h ../lib/addoninfo.h ../lib/checkers.h ../lib/config.h ../lib/errortypes.h ../lib/filesettings.h ../lib/importproject.h ../lib/json.h ../lib/library.h ../lib/mathlib.h ../lib/path.h ../lib/pathmatch.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/standards.h ../lib/suppressions.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h ../lib/xml.h +$(libcppdir)/importproject.o: ../lib/importproject.cpp ../externals/picojson/picojson.h ../externals/tinyxml2/tinyxml2.h ../lib/checkers.h ../lib/config.h ../lib/errortypes.h ../lib/filesettings.h ../lib/importproject.h ../lib/json.h ../lib/library.h ../lib/mathlib.h ../lib/path.h ../lib/pathmatch.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/standards.h ../lib/suppressions.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h ../lib/xml.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/importproject.cpp $(libcppdir)/infer.o: ../lib/infer.cpp ../lib/calculate.h ../lib/config.h ../lib/errortypes.h ../lib/infer.h ../lib/mathlib.h ../lib/smallvector.h ../lib/templatesimplifier.h ../lib/token.h ../lib/utils.h ../lib/valueptr.h ../lib/vfvalue.h @@ -312,19 +312,19 @@ $(libcppdir)/pathmatch.o: ../lib/pathmatch.cpp ../lib/config.h ../lib/path.h ../ $(libcppdir)/platform.o: ../lib/platform.cpp ../externals/tinyxml2/tinyxml2.h ../lib/config.h ../lib/mathlib.h ../lib/path.h ../lib/platform.h ../lib/standards.h ../lib/utils.h ../lib/xml.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/platform.cpp -$(libcppdir)/preprocessor.o: ../lib/preprocessor.cpp ../externals/simplecpp/simplecpp.h ../lib/addoninfo.h ../lib/checkers.h ../lib/config.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/path.h ../lib/platform.h ../lib/preprocessor.h ../lib/settings.h ../lib/standards.h ../lib/suppressions.h ../lib/utils.h +$(libcppdir)/preprocessor.o: ../lib/preprocessor.cpp ../externals/simplecpp/simplecpp.h ../lib/checkers.h ../lib/config.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/path.h ../lib/platform.h ../lib/preprocessor.h ../lib/settings.h ../lib/standards.h ../lib/suppressions.h ../lib/utils.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/preprocessor.cpp -$(libcppdir)/programmemory.o: ../lib/programmemory.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/calculate.h ../lib/checkers.h ../lib/config.h ../lib/errortypes.h ../lib/infer.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/programmemory.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenlist.h ../lib/utils.h ../lib/valueflow.h ../lib/valueptr.h ../lib/vfvalue.h +$(libcppdir)/programmemory.o: ../lib/programmemory.cpp ../lib/astutils.h ../lib/calculate.h ../lib/checkers.h ../lib/config.h ../lib/errortypes.h ../lib/infer.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/programmemory.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenlist.h ../lib/utils.h ../lib/valueflow.h ../lib/valueptr.h ../lib/vfvalue.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/programmemory.cpp $(libcppdir)/regex.o: ../lib/regex.cpp ../lib/config.h ../lib/regex.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/regex.cpp -$(libcppdir)/reverseanalyzer.o: ../lib/reverseanalyzer.cpp ../lib/addoninfo.h ../lib/analyzer.h ../lib/astutils.h ../lib/checkers.h ../lib/config.h ../lib/errortypes.h ../lib/forwardanalyzer.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/reverseanalyzer.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/utils.h ../lib/valueptr.h ../lib/vfvalue.h +$(libcppdir)/reverseanalyzer.o: ../lib/reverseanalyzer.cpp ../lib/analyzer.h ../lib/astutils.h ../lib/checkers.h ../lib/config.h ../lib/errortypes.h ../lib/forwardanalyzer.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/reverseanalyzer.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/utils.h ../lib/valueptr.h ../lib/vfvalue.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/reverseanalyzer.cpp -$(libcppdir)/sarifreport.o: ../lib/sarifreport.cpp ../externals/picojson/picojson.h ../lib/addoninfo.h ../lib/check.h ../lib/checkers.h ../lib/config.h ../lib/cppcheck.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/json.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/sarifreport.h ../lib/settings.h ../lib/standards.h ../lib/utils.h +$(libcppdir)/sarifreport.o: ../lib/sarifreport.cpp ../externals/picojson/picojson.h ../lib/check.h ../lib/checkers.h ../lib/config.h ../lib/cppcheck.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/json.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/sarifreport.h ../lib/settings.h ../lib/standards.h ../lib/utils.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/sarifreport.cpp $(libcppdir)/settings.o: ../lib/settings.cpp ../externals/picojson/picojson.h ../lib/addoninfo.h ../lib/checkers.h ../lib/config.h ../lib/errortypes.h ../lib/json.h ../lib/library.h ../lib/mathlib.h ../lib/path.h ../lib/platform.h ../lib/rule.h ../lib/settings.h ../lib/standards.h ../lib/summaries.h ../lib/suppressions.h ../lib/utils.h ../lib/vfvalue.h @@ -333,34 +333,34 @@ $(libcppdir)/settings.o: ../lib/settings.cpp ../externals/picojson/picojson.h .. $(libcppdir)/standards.o: ../lib/standards.cpp ../externals/simplecpp/simplecpp.h ../lib/config.h ../lib/standards.h ../lib/utils.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/standards.cpp -$(libcppdir)/summaries.o: ../lib/summaries.cpp ../lib/addoninfo.h ../lib/analyzerinfo.h ../lib/checkers.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/path.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/summaries.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h +$(libcppdir)/summaries.o: ../lib/summaries.cpp ../lib/analyzerinfo.h ../lib/checkers.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/path.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/summaries.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/summaries.cpp $(libcppdir)/suppressions.o: ../lib/suppressions.cpp ../externals/tinyxml2/tinyxml2.h ../lib/addoninfo.h ../lib/checkers.h ../lib/config.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/filesettings.h ../lib/library.h ../lib/mathlib.h ../lib/path.h ../lib/pathmatch.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/standards.h ../lib/suppressions.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h ../lib/xml.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/suppressions.cpp -$(libcppdir)/templatesimplifier.o: ../lib/templatesimplifier.cpp ../lib/addoninfo.h ../lib/checkers.h ../lib/config.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/standards.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h +$(libcppdir)/templatesimplifier.o: ../lib/templatesimplifier.cpp ../lib/checkers.h ../lib/config.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/standards.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/templatesimplifier.cpp $(libcppdir)/timer.o: ../lib/timer.cpp ../lib/config.h ../lib/timer.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/timer.cpp -$(libcppdir)/token.o: ../lib/token.cpp ../externals/simplecpp/simplecpp.h ../lib/addoninfo.h ../lib/astutils.h ../lib/checkers.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenlist.h ../lib/tokenrange.h ../lib/utils.h ../lib/valueflow.h ../lib/vfvalue.h +$(libcppdir)/token.o: ../lib/token.cpp ../externals/simplecpp/simplecpp.h ../lib/astutils.h ../lib/checkers.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenlist.h ../lib/tokenrange.h ../lib/utils.h ../lib/valueflow.h ../lib/vfvalue.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/token.cpp -$(libcppdir)/tokenlist.o: ../lib/tokenlist.cpp ../externals/simplecpp/simplecpp.h ../lib/addoninfo.h ../lib/astutils.h ../lib/checkers.h ../lib/config.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/keywords.h ../lib/library.h ../lib/mathlib.h ../lib/path.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/standards.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h +$(libcppdir)/tokenlist.o: ../lib/tokenlist.cpp ../externals/simplecpp/simplecpp.h ../lib/astutils.h ../lib/checkers.h ../lib/config.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/keywords.h ../lib/library.h ../lib/mathlib.h ../lib/path.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/standards.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/tokenlist.cpp $(libcppdir)/utils.o: ../lib/utils.cpp ../lib/config.h ../lib/utils.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/utils.cpp -$(libcppdir)/vf_analyzers.o: ../lib/vf_analyzers.cpp ../lib/addoninfo.h ../lib/analyzer.h ../lib/astutils.h ../lib/calculate.h ../lib/checkers.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/programmemory.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/utils.h ../lib/valueflow.h ../lib/valueptr.h ../lib/vf_analyzers.h ../lib/vf_common.h ../lib/vf_settokenvalue.h ../lib/vfvalue.h +$(libcppdir)/vf_analyzers.o: ../lib/vf_analyzers.cpp ../lib/analyzer.h ../lib/astutils.h ../lib/calculate.h ../lib/checkers.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/programmemory.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/utils.h ../lib/valueflow.h ../lib/valueptr.h ../lib/vf_analyzers.h ../lib/vf_common.h ../lib/vf_settokenvalue.h ../lib/vfvalue.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/vf_analyzers.cpp -$(libcppdir)/vf_common.o: ../lib/vf_common.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/checkers.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/path.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/utils.h ../lib/vf_common.h ../lib/vf_settokenvalue.h ../lib/vfvalue.h +$(libcppdir)/vf_common.o: ../lib/vf_common.cpp ../lib/astutils.h ../lib/checkers.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/path.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/utils.h ../lib/vf_common.h ../lib/vf_settokenvalue.h ../lib/vfvalue.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/vf_common.cpp -$(libcppdir)/vf_settokenvalue.o: ../lib/vf_settokenvalue.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/calculate.h ../lib/checkers.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/utils.h ../lib/valueflow.h ../lib/vf_common.h ../lib/vf_settokenvalue.h ../lib/vfvalue.h +$(libcppdir)/vf_settokenvalue.o: ../lib/vf_settokenvalue.cpp ../lib/astutils.h ../lib/calculate.h ../lib/checkers.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/utils.h ../lib/valueflow.h ../lib/vf_common.h ../lib/vf_settokenvalue.h ../lib/vfvalue.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/vf_settokenvalue.cpp $(libcppdir)/vfvalue.o: ../lib/vfvalue.cpp ../lib/config.h ../lib/errortypes.h ../lib/mathlib.h ../lib/smallvector.h ../lib/templatesimplifier.h ../lib/token.h ../lib/utils.h ../lib/vfvalue.h From 550189be664fa27e754df5eb8f182748e7dd56df Mon Sep 17 00:00:00 2001 From: William Jakobsson <50847546+wjakobsson@users.noreply.github.com> Date: Thu, 4 Jun 2026 10:26:32 +0200 Subject: [PATCH 005/165] fixed #14738 gui recheck file not working properly when importing compile_commands.json (#8625) --- gui/mainwindow.cpp | 11 +++++++++-- gui/mainwindow.h | 2 +- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/gui/mainwindow.cpp b/gui/mainwindow.cpp index 15f3e8e0665..bf73828bed4 100644 --- a/gui/mainwindow.cpp +++ b/gui/mainwindow.cpp @@ -559,13 +559,20 @@ void MainWindow::saveSettings() const mUI->mResults->saveSettings(mSettings); } -void MainWindow::doAnalyzeProject(ImportProject p, const bool checkLib, const bool checkConfig) +void MainWindow::doAnalyzeProject(ImportProject p, const bool checkLib, const bool checkConfig, const QStringList& recheckFiles) { Settings checkSettings; auto supprs = std::make_shared(); if (!getCppcheckSettings(checkSettings, *supprs)) return; + // filter requested files + if (!recheckFiles.isEmpty()) { + p.fileSettings.remove_if([&](const FileSettings& fs) { + return !recheckFiles.contains(QString::fromStdString(fs.filename())); + }); + } + clearResults(); mIsLogfileLoaded = false; @@ -1958,7 +1965,7 @@ void MainWindow::analyzeProject(const ProjectFile *projectFile, const QStringLis msg.exec(); return; } - doAnalyzeProject(p, checkLib, checkConfig); // TODO: avoid copy + doAnalyzeProject(p, checkLib, checkConfig, recheckFiles); // TODO: avoid copy return; } diff --git a/gui/mainwindow.h b/gui/mainwindow.h index febd3a41d4c..c654a2c94f0 100644 --- a/gui/mainwindow.h +++ b/gui/mainwindow.h @@ -309,7 +309,7 @@ private slots: * @param checkLib Flag to indicate if library should be checked * @param checkConfig Flag to indicate if the configuration should be checked. */ - void doAnalyzeProject(ImportProject p, bool checkLib = false, bool checkConfig = false); + void doAnalyzeProject(ImportProject p, bool checkLib = false, bool checkConfig = false, const QStringList& recheckFiles = QStringList()); /** * @brief Analyze all files specified in parameter files From 0491f5911627315760adcda62217a2763b3d71bb Mon Sep 17 00:00:00 2001 From: William Jakobsson <50847546+wjakobsson@users.noreply.github.com> Date: Thu, 4 Jun 2026 10:37:08 +0200 Subject: [PATCH 006/165] Clear releasenotes [skip ci] (#8623) --- releasenotes.txt | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/releasenotes.txt b/releasenotes.txt index 4fb45b90070..185f06390e3 100644 --- a/releasenotes.txt +++ b/releasenotes.txt @@ -1,14 +1,11 @@ -Release Notes for Cppcheck 2.21 +Release Notes for Cppcheck 2.22 Major bug fixes & crashes: - New checks: -- MISRA C 2012 rule 10.3 now warns on assigning integer literals 0 and 1 to bool in C99 and later while preserving the existing C89 behavior. -- funcArgNamesDifferentUnnamed warns on function declarations/definitions where a parameter in either location is unnamed -- uninitMemberVarNoCtor warns on user-defined types where (1) some but not all members requiring initialization have in-class initializers or (2) there is a mixture of members which do/do not require initialization. -- fcloseInLoopCondition warns when fclose() is used as a while loop condition, which may skip the loop body or double-close the file handle. +- C/C++ support: - @@ -23,9 +20,4 @@ Infrastructure & dependencies: - 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. -- Updated simplecpp to 1.7.0. - From 2285c1daf9e61ce9f27c16a62a362130c799422f Mon Sep 17 00:00:00 2001 From: Tomo Dote Date: Fri, 5 Jun 2026 05:02:53 +0900 Subject: [PATCH 007/165] Update Japanese translation for v2.21 (#8630) Update only Japanese translation - modified: gui/cppcheck_ja.ts --- gui/cppcheck_ja.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/gui/cppcheck_ja.ts b/gui/cppcheck_ja.ts index b3252ec769d..a071727ad56 100644 --- a/gui/cppcheck_ja.ts +++ b/gui/cppcheck_ja.ts @@ -1732,17 +1732,17 @@ Options: Include file - + インクルードファイル <html><head/><body><p><span style=" font-family:'monospace'; color:#000000; background-color:#ffffff;">Force inclusion of a header file</span></p></body></html> - + <html><head/><body><p><span style=" font-family:'monospace'; color:#000000; background-color:#ffffff;">ヘッダファイルを強制的にインクルードします</span></p></body></html> Browse.. - + ブラウズ.. @@ -2091,12 +2091,12 @@ Options: C/C++ header - + C/C++のヘッダー Include file - + ファイルのインクルード From 70af35891e33d2d077137910437e8f2626b0a08f Mon Sep 17 00:00:00 2001 From: William Jakobsson <50847546+wjakobsson@users.noreply.github.com> Date: Fri, 5 Jun 2026 12:57:55 +0200 Subject: [PATCH 008/165] createrelease: tweaks [skip ci] (#8635) --- createrelease | 93 ++++++++++++++++++++++++++++----------------------- 1 file changed, 52 insertions(+), 41 deletions(-) diff --git a/createrelease b/createrelease index de85d64395b..6a611a5a469 100755 --- a/createrelease +++ b/createrelease @@ -1,6 +1,6 @@ #!/bin/bash # -# A script for creating release packages. The release packages are create in the home directory. +# A script for creating release packages. The release packages are created in the home directory. # # Create release candidate # ======================== @@ -8,15 +8,22 @@ # Review trac roadmap, are tickets closed properly? # Only tickets that should be retargeted should be open. # -# update cppcheck used in premium addon CI -# create jira issue "CI: update cppcheck binary" -# cd ~/cppchecksolutions/addon/tools && python3 ci-update-cppcheck.py +# Versioning scheme +# ======================== +# VERSION=2.22.0 # the new release tag created +# PREV=2.21.0 # the previous release +# BRANCH=2.22.x # release branch +# +# 2.22.x BRANCH - release branch +# 2.22.0 TAG - the release +# 2.22.1, ... TAG - patch releases +# 2.22.0-rc1 TAG - release candidate # -# update mappings.. +# Update mappings: # cd ~/cppchecksolutions/addon/coverage # CPPCHECK_REPO=~/cppchecksolutions/cppcheck python3 coverage.py --code # -# check every isPremiumEnabled call: TODO write helper script +# Check every isPremiumEnabled call: TODO write helper script # - every id should be in --errorlist # git grep 'isPremiumEnabled[(]"' | sed 's/.*isPremiumEnabled[(]"//' | sed 's/".*//' | sort | uniq > ids1.txt # ./cppcheck --errorlist | grep ' id="' | sed 's/.* id="//' | sed 's/".*//' | sort | uniq > ids2.txt @@ -29,93 +36,97 @@ # - ensure latest build was successful # - ensure cfg files etc are included (win_installer/cppcheck.wxs) # -# self check, fix critical issues: +# Self check, fix critical issues: # make clean && make CXXOPTS=-O2 MATCHCOMPILER=yes -j4 # ./cppcheck -D__CPPCHECK__ -D__GNUC__ -DCHECK_INTERNAL -DHAVE_RULES --std=c++11 --library=cppcheck-lib --library=qt --enable=style --inconclusive --inline-suppr --suppress=bitwiseOnBoolean --suppress=shadowFunction --suppress=useStlAlgorithm --suppress=*:externals/picojson.h --suppress=functionConst --suppress=functionStatic --suppress=normalCheckLevelMaxBranches --xml cli gui/*.cpp lib 2> selfcheck.xml # -# Generate lib/checkers.cpp (TODO the premium checkers should not be statically coded) +# Generate lib/checkers.cpp: (TODO the premium checkers should not be statically coded) # cd ~/cppchecksolutions/cppcheck && python3 tools/get_checkers.py > lib/checkers.cpp # -# Update copyright year TODO release script -# git diff 2.8 -- */*.cpp */*.h | grep '^diff --git a/' | sed 's|.* b/||' | xargs sed -i 's/Copyright (C) 2007-20[12]./Copyright (C) 2007-2022/' +# Update copyright year: TODO release script +# git diff $PREV -- */*.cpp */*.h | grep '^diff --git a/' | sed 's|.* b/||' | xargs sed -i "s/Copyright (C) 2007-20[12]./Copyright (C) 2007-$(date +%Y)/" # git diff | grep '^diff --git a/' # # Make sure "cppcheck --errorlist" works: # make clean && make -j4 && ./cppcheck --errorlist > errlist.xml && xmllint --noout errlist.xml # # Update AUTHORS using output from: -# git log --format='%aN' 2.7..HEAD | sort -u > AUTHORS2 && diff -y AUTHORS AUTHORS2 | less +# git log --format='%aN' $PREV..HEAD | sort -u > AUTHORS2 && diff -y AUTHORS AUTHORS2 | less +# Include github usernames in PR title and commit message # -# Update GUI translations -# lupdate gui.pro +# Update GUI translations: +# cd ~/cppchecksolutions/cppcheck/gui && lupdate gui.pro # -# Create 2.18.x branch -# git checkout -b 2.18.x ; git push -u origin 2.18.x +# Create new release branch: +# git checkout -b $BRANCH && git push -u origin $BRANCH # in fork: -# * add upstream: git remote add upstream git@github.com:/cppcheck-opensource//cppcheck.git -# * add branch: git fetch upstream 2.19.x +# * add upstream: git remote add upstream git@github.com:cppcheck-opensource/cppcheck.git +# * add branch: git fetch upstream $BRANCH # # Release notes: # - ensure safety critical issues are listed properly # - empty the releasenotes.txt in main branch # # Update version numbers in: -# python3 tools/release-set-version.py 2.19.0 +# python3 tools/release-set-version.py $VERSION # Verify: # grep '\.99' */*.[ch]* && grep '[0-9][0-9] dev' */*.[ch]* # egrep "2\.[0-9]+" */*.h */*.cpp man/*.md | grep -v "test/test" | less -# git commit -a -m "2.8: Set versions" +# git commit -a -m "$VERSION: Set versions" # # Build and test the windows installer # # Update the Makefile: # make dmake && ./dmake --release -# git commit -a -m "2.8: Updated Makefile" +# git commit -a -m "$VERSION: Updated Makefile" +# +# Push changes: +# git push # # Ensure that CI is happy # # Tag: -# git tag 2.8-rc1 +# git tag $VERSION-rc1 # git push --tags # # Release -# ======= +# ======================== # # Remove "-rc1" from versions. Test: git grep "\-rc[0-9]" # # Create a release folder on sourceforge: # https://sourceforge.net/projects/cppcheck/files/cppcheck/ # -# git tag 2.8 ; git push --tags -# ./createrelease 2.8 +# git tag $VERSION && git push --tags +# ./createrelease $VERSION # -# copy msi from release-windows, install and test cppcheck -# copy manual from build-manual +# Copy msi from release-windows, install and test cppcheck +# Copy manual from build-manual # # Update download link on index.php main page # # Trac: -# 1. Create ticket "2.18 safety cosmetic changes" -# git log --format=oneline 2.17.0..HEAD | egrep -v "^[0-9a-f]*[ ][ ]*([Ff]ix|fixed|Fixup|Fixes|refs)?[ ]*#*[0-9]+" +# 1. Create ticket "$VERSION safety cosmetic changes" +# git log --format=oneline $PREV..HEAD | egrep -v "^[0-9a-f]*[ ][ ]*([Ff]ix|fixed|Fixup|Fixes|refs)?[ ]*#*[0-9]+" # 2. Check priorities for all tickets in milestone. Should be: safety-* # 3. Create new milestone # 4. Close old milestone # -# write a news +# Write a news # -# save "cppcheck --doc" output on wiki +# Save "cppcheck --doc" output on wiki # -# compile new democlient: +# Compile new democlient: # ssh -t danielmarjamaki,cppcheck@shell.sourceforge.net create # ./build-cppcheck.sh # -# create a ticket with data from http://cppcheck1.osuosl.org:8000/time_gt.html for performance tracking +# Create a ticket with data from http://cppcheck1.osuosl.org:8000/time_gt.html for performance tracking # (example: https://trac.cppcheck.net/ticket/13715) # - type: defect # - component: Performance -# - summary: [meta] performance regressions in 2.x +# - summary: [meta] performance regressions in $VERSION # -# run daca with new release +# Run daca with new release: # 1. edit tools/donate-cpu-server.py. Update OLD_VERSION and SERVER_VERSION # 2. scp -i ~/.ssh/osuosl_id_rsa tools/donate-cpu-server.py danielmarjamaki@cppcheck1.osuosl.org:/var/daca@home/ # @@ -123,14 +134,14 @@ # * trac: cd /var && nice tar -cJf ~/trac.tar.xz trac-cppcheck/db/trac.db # * daca: cd /var && nice tar -cJf ~/daca.tar.xz daca@home # * git: git checkout -f && git checkout main && git pull && tar -cJf git.tar.xz .git -# * git log 2.16.0..2.17.0 > Changelog -# * mkdir out && python3 ~/cppchecksolutions/release/getWorkflowAndIssueLogs.py -r /cppcheck-opensource//cppcheck -t 2.15.0 -p out +# * git log $PREV..$VERSION > Changelog +# * mkdir out && python3 ~/cppchecksolutions/release/getWorkflowAndIssueLogs.py -r /cppcheck-opensource//cppcheck -t $VERSION -p out -# Folder/tag to use -folder=$1 -tag=$folder.0 +# Folder/tag to use: +tag=$1 +folder=${tag%.*} -# Name of release +# Name of release: releasename=cppcheck-$tag set -e @@ -162,7 +173,7 @@ scp htdocs/* danielmarjamaki,cppcheck@web.sourceforge.net:htdocs/ cd .. rm -rf upload -# Local cppcheck binary +# Local cppcheck binary: mkdir -p ~/.cppcheck/$tag cd ~/.cppcheck/$tag cp -R ~/cppcheck/cfg . From 117bdff20d2355c669b8bb56dd53db7b90d5dc48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20St=C3=B6neberg?= Date: Fri, 5 Jun 2026 16:55:36 +0200 Subject: [PATCH 009/165] bumped version to 2.21.99/2.22 (#8633) --- CMakeLists.txt | 2 +- cli/main.cpp | 2 +- lib/version.h | 4 ++-- man/manual.md | 2 +- man/reference-cfg-format.md | 2 +- man/writing-addons.md | 2 +- win_installer/productInfo.wxi | 4 ++-- 7 files changed, 9 insertions(+), 9 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3c037a10b36..b5857a8413a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.22) -project(Cppcheck VERSION 2.20.99 LANGUAGES CXX) +project(Cppcheck VERSION 2.21.99 LANGUAGES CXX) include(cmake/options.cmake) diff --git a/cli/main.cpp b/cli/main.cpp index 9bea4336c84..d1a635e1f6f 100644 --- a/cli/main.cpp +++ b/cli/main.cpp @@ -20,7 +20,7 @@ /** * * @mainpage Cppcheck - * @version 2.20.99 + * @version 2.21.99 * * @section overview_sec Overview * Cppcheck is a simple tool for static analysis of C/C++ code. diff --git a/lib/version.h b/lib/version.h index 2a64885ffa8..6d25dd4c158 100644 --- a/lib/version.h +++ b/lib/version.h @@ -20,8 +20,8 @@ #ifndef versionH #define versionH -#define CPPCHECK_VERSION_STRING "2.21 dev" -#define CPPCHECK_VERSION 2,20,99,0 +#define CPPCHECK_VERSION_STRING "2.22 dev" +#define CPPCHECK_VERSION 2,21,99,0 #define LEGALCOPYRIGHT L"Copyright (C) 2007-2026 Cppcheck team." diff --git a/man/manual.md b/man/manual.md index 8d8d5b22350..47a3a43fd36 100644 --- a/man/manual.md +++ b/man/manual.md @@ -1,6 +1,6 @@ --- title: Cppcheck manual -subtitle: Version 2.21 dev +subtitle: Version 2.22 dev author: Cppcheck team lang: en documentclass: report diff --git a/man/reference-cfg-format.md b/man/reference-cfg-format.md index 3067d0a8f2c..f426057ab47 100644 --- a/man/reference-cfg-format.md +++ b/man/reference-cfg-format.md @@ -1,6 +1,6 @@ --- title: Cppcheck .cfg format -subtitle: Version 2.21 dev +subtitle: Version 2.22 dev author: Cppcheck team lang: en documentclass: report diff --git a/man/writing-addons.md b/man/writing-addons.md index e593c2e9cce..2627671fa87 100644 --- a/man/writing-addons.md +++ b/man/writing-addons.md @@ -1,6 +1,6 @@ --- title: Writing addons -subtitle: Version 2.21 dev +subtitle: Version 2.22 dev author: Cppcheck team lang: en documentclass: report diff --git a/win_installer/productInfo.wxi b/win_installer/productInfo.wxi index f89e956dbb8..85e73ea3ca2 100644 --- a/win_installer/productInfo.wxi +++ b/win_installer/productInfo.wxi @@ -1,8 +1,8 @@ - + - + From 707f262560ac3be5136a0e6e9cf62b388fd6d946 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Fri, 5 Jun 2026 16:56:00 +0200 Subject: [PATCH 010/165] daca: update OLD_VERSION (#8631) --- tools/donate-cpu-server.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/donate-cpu-server.py b/tools/donate-cpu-server.py index 6f44ea679a7..63a55f5b338 100755 --- a/tools/donate-cpu-server.py +++ b/tools/donate-cpu-server.py @@ -26,10 +26,10 @@ # Version scheme (MAJOR.MINOR.PATCH) should orientate on "Semantic Versioning" https://semver.org/ # Every change in this script should result in increasing the version number accordingly (exceptions may be cosmetic # changes) -SERVER_VERSION = "1.3.68" +SERVER_VERSION = "1.3.69" # TODO: fetch from GitHub tags -OLD_VERSION = '2.20.0' +OLD_VERSION = '2.21.0' HEAD_MARKER = 'head results:' INFO_MARKER = 'info messages:' From fdbb42c76083d717b9b1206ec368c7f0431fb12a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20St=C3=B6neberg?= Date: Mon, 8 Jun 2026 08:35:56 +0200 Subject: [PATCH 011/165] removed unnecessary friend declarations from checks (#8613) --- lib/check64bit.h | 2 -- lib/checkclass.h | 4 ---- lib/checkio.h | 2 -- lib/checkmemoryleak.h | 8 -------- lib/checknullpointer.h | 2 -- lib/checkother.h | 4 ---- lib/checkpostfixoperator.h | 2 -- lib/checkuninitvar.h | 2 -- lib/checkunusedvar.h | 2 -- 9 files changed, 28 deletions(-) diff --git a/lib/check64bit.h b/lib/check64bit.h index 4354d2217ba..cab82cf1148 100644 --- a/lib/check64bit.h +++ b/lib/check64bit.h @@ -41,8 +41,6 @@ class Tokenizer; */ class CPPCHECKLIB Check64BitPortability : public Check { - friend class Test64BitPortability; - public: /** This constructor is used when registering the Check64BitPortability */ Check64BitPortability() : Check("64-bit portability") {} diff --git a/lib/checkclass.h b/lib/checkclass.h index a5d20432351..2573d99f2f5 100644 --- a/lib/checkclass.h +++ b/lib/checkclass.h @@ -49,10 +49,6 @@ enum class FunctionType : std::uint8_t; /** @brief %Check classes. Uninitialized member variables, non-conforming operators, missing virtual destructor, etc */ class CPPCHECKLIB CheckClass : public Check { - friend class TestClass; - friend class TestConstructors; - friend class TestUnusedPrivateFunction; - public: /** @brief This constructor is used when registering the CheckClass */ CheckClass() : Check("Class") {} diff --git a/lib/checkio.h b/lib/checkio.h index 6fb3c9f80c2..9f125e6bd7b 100644 --- a/lib/checkio.h +++ b/lib/checkio.h @@ -42,8 +42,6 @@ enum class Severity : std::uint8_t; /** @brief %Check input output operations. */ class CPPCHECKLIB CheckIO : public Check { - friend class TestIO; - public: /** @brief This constructor is used when registering CheckIO */ CheckIO() : Check("IO using format string") {} diff --git a/lib/checkmemoryleak.h b/lib/checkmemoryleak.h index 037363160de..fdb7748f9ed 100644 --- a/lib/checkmemoryleak.h +++ b/lib/checkmemoryleak.h @@ -65,8 +65,6 @@ enum class Severity : std::uint8_t; */ class CPPCHECKLIB CheckMemoryLeakInFunction : public Check { - friend class TestMemleakInFunction; - public: /** @brief This constructor is used when registering this class */ CheckMemoryLeakInFunction() : Check("Memory leaks (function variables)") {} @@ -92,8 +90,6 @@ class CPPCHECKLIB CheckMemoryLeakInFunction : public Check { */ class CPPCHECKLIB CheckMemoryLeakInClass : public Check { - friend class TestMemleakInClass; - public: CheckMemoryLeakInClass() : Check("Memory leaks (class variables)") {} @@ -112,8 +108,6 @@ class CPPCHECKLIB CheckMemoryLeakInClass : public Check { /** @brief detect simple memory leaks for struct members */ class CPPCHECKLIB CheckMemoryLeakStructMember : public Check { - friend class TestMemleakStructMember; - public: CheckMemoryLeakStructMember() : Check("Memory leaks (struct members)") {} @@ -132,8 +126,6 @@ class CPPCHECKLIB CheckMemoryLeakStructMember : public Check { /** @brief detect simple memory leaks (address not taken) */ class CPPCHECKLIB CheckMemoryLeakNoVar : public Check { - friend class TestMemleakNoVar; - public: CheckMemoryLeakNoVar() : Check("Memory leaks (address not taken)") {} diff --git a/lib/checknullpointer.h b/lib/checknullpointer.h index d0bc44899a9..bc494dad70f 100644 --- a/lib/checknullpointer.h +++ b/lib/checknullpointer.h @@ -48,8 +48,6 @@ namespace ValueFlow /** @brief check for null pointer dereferencing */ class CPPCHECKLIB CheckNullPointer : public Check { - friend class TestNullPointer; - public: /** @brief This constructor is used when registering the CheckNullPointer */ CheckNullPointer() : Check("Null pointer") {} diff --git a/lib/checkother.h b/lib/checkother.h index 58a61ff772a..7f21ffc00f8 100644 --- a/lib/checkother.h +++ b/lib/checkother.h @@ -50,10 +50,6 @@ struct UnionMember; /** @brief Various small checks */ class CPPCHECKLIB CheckOther : public Check { - friend class TestCharVar; - friend class TestIncompleteStatement; - friend class TestOther; - public: /** @brief This constructor is used when registering the CheckClass */ CheckOther() : Check("Other") {} diff --git a/lib/checkpostfixoperator.h b/lib/checkpostfixoperator.h index ac1a053afe8..5898cefcc3c 100644 --- a/lib/checkpostfixoperator.h +++ b/lib/checkpostfixoperator.h @@ -41,8 +41,6 @@ class Tokenizer; */ class CPPCHECKLIB CheckPostfixOperator : public Check { - friend class TestPostfixOperator; - public: /** This constructor is used when registering the CheckPostfixOperator */ CheckPostfixOperator() : Check("Using postfix operators") {} diff --git a/lib/checkuninitvar.h b/lib/checkuninitvar.h index 47d9061be18..a9156adfe36 100644 --- a/lib/checkuninitvar.h +++ b/lib/checkuninitvar.h @@ -58,8 +58,6 @@ struct VariableValue { /** @brief Checking for uninitialized variables */ class CPPCHECKLIB CheckUninitVar : public Check { - friend class TestUninitVar; - public: /** @brief This constructor is used when registering the CheckUninitVar */ CheckUninitVar() : Check("Uninitialized variables") {} diff --git a/lib/checkunusedvar.h b/lib/checkunusedvar.h index 693d3213869..2239b4a60d8 100644 --- a/lib/checkunusedvar.h +++ b/lib/checkunusedvar.h @@ -43,8 +43,6 @@ class Tokenizer; /** @brief Various small checks */ class CPPCHECKLIB CheckUnusedVar : public Check { - friend class TestUnusedVar; - public: /** @brief This constructor is used when registering the CheckClass */ CheckUnusedVar() : Check("UnusedVar") {} From 22b3464e06086b68a31ed4200054834191c0b528 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20St=C3=B6neberg?= Date: Mon, 8 Jun 2026 08:40:06 +0200 Subject: [PATCH 012/165] constified more pointers in containers (#8615) --- lib/clangimport.cpp | 2 +- lib/symboldatabase.cpp | 8 ++++---- lib/templatesimplifier.cpp | 4 ++-- lib/templatesimplifier.h | 8 ++++---- lib/tokenize.cpp | 20 ++++++++++---------- 5 files changed, 21 insertions(+), 21 deletions(-) diff --git a/lib/clangimport.cpp b/lib/clangimport.cpp index c96a678347a..417e94e8798 100644 --- a/lib/clangimport.cpp +++ b/lib/clangimport.cpp @@ -303,7 +303,7 @@ namespace clangimport { } // "}" tokens that are not end-of-scope - std::set mNotScope; + std::set mNotScope; std::map scopeAccessControl; private: diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index dda3e9b1e0b..4b923a328ca 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -175,9 +175,9 @@ void SymbolDatabase::createSymbolDatabaseFindAllScopes() // Store current access in each scope (depends on evaluation progress) std::map access; - std::map> forwardDecls; + std::map> forwardDecls; - const std::function findForwardDeclScope = [&](const Token *tok, Scope *startScope) { + const std::function findForwardDeclScope = [&](const Token *tok, const Scope *startScope) { if (tok->str() == "::") return findForwardDeclScope(tok->next(), &scopeList.front()); @@ -187,14 +187,14 @@ void SymbolDatabase::createSymbolDatabaseFindAllScopes() }); if (it == startScope->nestedList.cend()) - return static_cast(nullptr); + return static_cast(nullptr); return findForwardDeclScope(tok->tokAt(2), *it); } auto it = forwardDecls.find(startScope); if (it == forwardDecls.cend()) - return static_cast(nullptr); + return static_cast(nullptr); return it->second.count(tok->str()) > 0 ? startScope : nullptr; }; diff --git a/lib/templatesimplifier.cpp b/lib/templatesimplifier.cpp index 1fe1df10037..9c8c8fdde9a 100644 --- a/lib/templatesimplifier.cpp +++ b/lib/templatesimplifier.cpp @@ -623,7 +623,7 @@ void TemplateSimplifier::deleteToken(Token *tok) tok->deleteThis(); } -static void invalidateForwardDecls(const Token* beg, const Token* end, std::map* forwardDecls) { +static void invalidateForwardDecls(const Token* beg, const Token* end, std::map* forwardDecls) { if (!forwardDecls) return; for (auto& fwd : *forwardDecls) { @@ -635,7 +635,7 @@ static void invalidateForwardDecls(const Token* beg, const Token* end, std::map< } } -bool TemplateSimplifier::removeTemplate(Token *tok, std::map* forwardDecls) +bool TemplateSimplifier::removeTemplate(Token *tok, std::map* forwardDecls) { if (!Token::simpleMatch(tok, "template <")) return false; diff --git a/lib/templatesimplifier.h b/lib/templatesimplifier.h index f6e507459a9..3c5fed3ea1c 100644 --- a/lib/templatesimplifier.h +++ b/lib/templatesimplifier.h @@ -463,7 +463,7 @@ class CPPCHECKLIB TemplateSimplifier { /** * Remove a specific "template < ..." template class/function */ - static bool removeTemplate(Token *tok, std::map* forwardDecls = nullptr); + static bool removeTemplate(Token *tok, std::map* forwardDecls = nullptr); /** Syntax error * @throws InternalError thrown unconditionally @@ -512,9 +512,9 @@ class CPPCHECKLIB TemplateSimplifier { std::list mTemplateDeclarations; std::list mTemplateForwardDeclarations; - std::map mTemplateForwardDeclarationsMap; - std::map mTemplateSpecializationMap; - std::map mTemplatePartialSpecializationMap; + std::map mTemplateForwardDeclarationsMap; + std::map mTemplateSpecializationMap; + std::map mTemplatePartialSpecializationMap; std::list mTemplateInstantiations; std::list mInstantiatedTemplates; std::list mMemberFunctionsToDelete; diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 6305e0f021a..c5b001f5d32 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -549,9 +549,9 @@ namespace { private: Token* mTypedefToken; // The "typedef" token Token* mEndToken{nullptr}; // Semicolon - std::pair mRangeType; - std::pair mRangeTypeQualifiers; - std::pair mRangeAfterVar; + std::pair mRangeType; + std::pair mRangeTypeQualifiers; + std::pair mRangeAfterVar; Token* mNameToken{nullptr}; bool mFail = false; bool mReplaceFailed = false; @@ -565,13 +565,13 @@ namespace { // TODO handle unnamed structs etc if (Token::Match(start, "const| enum|struct|union|class %name%| {")) { - const std::pair rangeBefore(start, Token::findsimplematch(start, "{")); + const std::pair rangeBefore(start, Token::findsimplematch(start, "{")); // find typedef name token Token* nameToken = rangeBefore.second->link()->next(); while (Token::Match(nameToken, "%name%|* %name%|*")) nameToken = nameToken->next(); - const std::pair rangeQualifiers(rangeBefore.second->link()->next(), nameToken); + const std::pair rangeQualifiers(rangeBefore.second->link()->next(), nameToken); if (Token::Match(nameToken, "%name% ;")) { if (Token::Match(rangeBefore.second->previous(), "enum|struct|union|class {")) @@ -723,7 +723,7 @@ namespace { // Special handling of function pointer cast if (isFunctionPointer && isCast(tok->previous())) { tok->insertToken("*"); - Token* const tok_1 = insertTokens(tok, std::pair(mRangeType.first, mNameToken->linkAt(1))); + Token* const tok_1 = insertTokens(tok, std::pair(mRangeType.first, mNameToken->linkAt(1))); tok_1->originalName(originalname); tok->deleteThis(); return; @@ -998,7 +998,7 @@ namespace { return false; } - static Token* insertTokens(Token* to, std::pair range) { + static Token* insertTokens(Token* to, std::pair range) { for (const Token* from = range.first; from != range.second; from = from->next()) { to->insertToken(from->str()); to->next()->column(to->column()); @@ -5537,7 +5537,7 @@ void Tokenizer::createLinks2() bool isStruct = false; std::stack type; - std::stack templateTokens; + std::stack templateTokens; for (Token *token = list.front(); token; token = token->next()) { if (Token::Match(token, "%name%|> %name% [:<]")) isStruct = true; @@ -7026,7 +7026,7 @@ void Tokenizer::simplifyFunctionParameters() // We have found old style function, now we need to change it // First step: Get list of argument names in parentheses - std::map argumentNames; + std::map argumentNames; bool bailOut = false; const Token * tokparam = nullptr; @@ -7145,7 +7145,7 @@ void Tokenizer::simplifyFunctionParameters() if (argumentNames.size() != argumentNames2.size()) { //move back 'tok1' to the last ';' tok1 = tok1->previous(); - for (const std::pair& argumentName : argumentNames) { + for (const std::pair& argumentName : argumentNames) { if (argumentNames2.find(argumentName.first) == argumentNames2.end()) { //add the missing parameter argument declaration tok1->insertToken(";"); From ac63eb55d1c2ea30ee663542f1a040af67364a5a Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Wed, 10 Jun 2026 20:43:09 +0200 Subject: [PATCH 013/165] Fix #14180 FN intToPointerCast with binary integer literal (#8643) Co-authored-by: chrchr-github --- lib/checkother.cpp | 2 ++ test/testother.cpp | 3 +++ 2 files changed, 5 insertions(+) diff --git a/lib/checkother.cpp b/lib/checkother.cpp index b5fd0dda361..801dc529568 100644 --- a/lib/checkother.cpp +++ b/lib/checkother.cpp @@ -464,6 +464,8 @@ void CheckOtherImpl::warningIntToPointerCast() format = "decimal"; else if (MathLib::isOct(from->str())) format = "octal"; + else if (MathLib::isBin(from->str())) + format = "binary"; else continue; intToPointerCastError(tok, format); diff --git a/test/testother.cpp b/test/testother.cpp index 93e67229f43..73f10cbe76e 100644 --- a/test/testother.cpp +++ b/test/testother.cpp @@ -2362,6 +2362,9 @@ class TestOther : public TestFixture { checkIntToPointerCast("struct S { int i; };\n" // #13886, don't crash "int f() { return sizeof(((struct S*)0)->i); }"); ASSERT_EQUALS("", errout_str()); + + checkIntToPointerCast("auto p = (int*)0b10;"); // #14180 + ASSERT_EQUALS("[test.cpp:1:10]: (portability) Casting non-zero binary integer literal to pointer. [intToPointerCast]\n", errout_str()); } struct CheckInvalidPointerCastOptions From 21de4faec57386799dff4abe7acdfd9b1c43f244 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20St=C3=B6neberg?= Date: Wed, 10 Jun 2026 20:43:28 +0200 Subject: [PATCH 014/165] updated *.ts [skip ci] (#8634) --- gui/cppcheck_de.ts | 182 +++++++++++++++++++++--------------------- gui/cppcheck_es.ts | 182 +++++++++++++++++++++--------------------- gui/cppcheck_fi.ts | 182 +++++++++++++++++++++--------------------- gui/cppcheck_fr.ts | 182 +++++++++++++++++++++--------------------- gui/cppcheck_it.ts | 182 +++++++++++++++++++++--------------------- gui/cppcheck_ja.ts | 182 +++++++++++++++++++++--------------------- gui/cppcheck_ka.ts | 182 +++++++++++++++++++++--------------------- gui/cppcheck_ko.ts | 182 +++++++++++++++++++++--------------------- gui/cppcheck_nl.ts | 182 +++++++++++++++++++++--------------------- gui/cppcheck_ru.ts | 182 +++++++++++++++++++++--------------------- gui/cppcheck_sr.ts | 182 +++++++++++++++++++++--------------------- gui/cppcheck_sv.ts | 182 +++++++++++++++++++++--------------------- gui/cppcheck_zh_CN.ts | 182 +++++++++++++++++++++--------------------- gui/cppcheck_zh_TW.ts | 182 +++++++++++++++++++++--------------------- 14 files changed, 1274 insertions(+), 1274 deletions(-) diff --git a/gui/cppcheck_de.ts b/gui/cppcheck_de.ts index 3f9d9ed53d7..1361296b8ca 100644 --- a/gui/cppcheck_de.ts +++ b/gui/cppcheck_de.ts @@ -485,18 +485,18 @@ Parameter: -l(line) (file) - - - - - - - - - - - - + + + + + + + + + + + + Cppcheck Cppcheck @@ -636,14 +636,14 @@ Parameter: -l(line) (file) - + Show errors Zeige Fehler - + Show warnings Zeige Warnungen @@ -659,8 +659,8 @@ Parameter: -l(line) (file) Zeige &versteckte - - + + Information Information @@ -1083,17 +1083,17 @@ Parameter: -l(line) (file) - + Quick Filter: Schnellfilter: - + Select configuration Konfiguration wählen - + Found project file: %1 Do you want to load this project file instead? @@ -1102,97 +1102,97 @@ Do you want to load this project file instead? Möchten Sie stattdessen diese öffnen? - + File not found Datei nicht gefunden - + Bad XML Fehlerhaftes XML - + Missing attribute Fehlendes Attribut - + Bad attribute value Falscher Attributwert - + Duplicate platform type Plattformtyp doppelt - + Platform type redefined Plattformtyp neu definiert - + Duplicate define - + Failed to load the selected library '%1'. %2 Laden der ausgewählten Bibliothek '%1' schlug fehl. %2 - + File not found: '%1' - + Failed to load/setup addon %1: %2 - + Failed to load %1. Your Cppcheck installation is broken. You can use --data-dir=<directory> at the command line to specify where this file is located. Please note that --data-dir is supposed to be used by installation scripts and therefore the GUI does not start when it is used, all that happens is that the setting is configured. Analysis is aborted. - + Failed to load %1 - %2 Analysis is aborted. - - + + %1 Analysis is aborted. - + License Lizenz - + Authors Autoren - + Save the report file Speichert die Berichtdatei - - + + XML files (*.xml) XML-Dateien (*.xml) @@ -1206,32 +1206,32 @@ This is probably because the settings were changed between the Cppcheck versions Dies wurde vermutlich durch einen Wechsel der Cppcheck-Version hervorgerufen. Bitte prüfen (und korrigieren) Sie die Einstellungen, andernfalls könnte die Editor-Anwendung nicht korrekt starten. - + You must close the project file before selecting new files or directories! Sie müssen die Projektdatei schließen, bevor Sie neue Dateien oder Verzeichnisse auswählen! - + The library '%1' contains unknown elements: %2 Die Bibliothek '%1' enthält unbekannte Elemente: %2 - + Unsupported format Nicht unterstütztes Format - + Unknown element Unbekanntes Element - - - - + + + + Error Fehler @@ -1240,80 +1240,80 @@ Dies wurde vermutlich durch einen Wechsel der Cppcheck-Version hervorgerufen. Bi Laden von %1 fehlgeschlagen. Ihre Cppcheck-Installation ist defekt. Sie können --data-dir=<Verzeichnis> als Kommandozeilenparameter verwenden, um anzugeben, wo die Datei sich befindet. Bitte beachten Sie, dass --data-dir in Installationsroutinen genutzt werden soll, und die GUI bei dessen Nutzung nicht startet, sondern die Einstellungen konfiguriert. - + Open the report file Berichtdatei öffnen - + Text files (*.txt) Textdateien (*.txt) - + CSV files (*.csv) CSV-Dateien (*.csv) - + Project files (*.cppcheck);;All files(*.*) Projektdateien (*.cppcheck);;Alle Dateien(*.*) - + Select Project File Projektdatei auswählen - - - + + + Project: Projekt: - + No suitable files found to analyze! Keine passenden Dateien für Analyse gefunden! - + C/C++ Source C/C++-Quellcode - + Compile database Compilerdatenbank - + Visual Studio Visual Studio - + Borland C++ Builder 6 Borland C++-Builder 6 - + Select files to analyze Dateien für Analyse auswählen - + Select directory to analyze Verzeichnis für Analyse auswählen - + Select the configuration that will be analyzed Zu analysierende Konfiguration auswählen - + Found project files from the directory. Do you want to proceed analysis without using any of these project files? @@ -1322,7 +1322,7 @@ Do you want to proceed analysis without using any of these project files? - + Current results will be cleared. Opening a new XML file will clear current results. @@ -1333,7 +1333,7 @@ Eine neue XML-Datei zu öffnen wird die aktuellen Ergebnisse löschen Möchten sie fortfahren? - + Analyzer is running. Do you want to stop the analysis and exit Cppcheck? @@ -1342,104 +1342,104 @@ Do you want to stop the analysis and exit Cppcheck? Wollen sie die Analyse abbrechen und Cppcheck beenden? - + About - + XML files (*.xml);;Text files (*.txt);;CSV files (*.csv) XML-Dateien (*.xml);;Textdateien (*.txt);;CSV-Dateien (*.csv) - + Build dir '%1' does not exist, create it? Erstellungsverzeichnis '%1' existiert nicht. Erstellen? - + To check the project using addons, you need a build directory. - + Failed to open file - + Unknown project file format - + Failed to import project file - + Failed to import '%1': %2 Analysis is stopped. - + Failed to import '%1' (%2), analysis is stopped - + Show Mandatory - + Show Required - + Show Advisory - + Show Document - + Show L1 - + Show L2 - + Show L3 - + Show style - + Show portability - + Show performance - + Show information @@ -1448,22 +1448,22 @@ Analysis is stopped. Import von '%1' fehlgeschlagen; Analyse wurde abgebrochen. - + Project files (*.cppcheck) Projektdateien (*.cppcheck) - + Select Project Filename Projektnamen auswählen - + No project file loaded Keine Projektdatei geladen - + The project file %1 @@ -1480,12 +1480,12 @@ Do you want to remove the file from the recently used projects -list? Möchten Sie die Datei von der Liste der zuletzt benutzten Projekte entfernen? - + Install - + New version available: %1. %2 diff --git a/gui/cppcheck_es.ts b/gui/cppcheck_es.ts index 32485d556f3..bbe8bed24d5 100644 --- a/gui/cppcheck_es.ts +++ b/gui/cppcheck_es.ts @@ -414,18 +414,18 @@ Parameters: -l(line) (file) - - - - - - - - - - - - + + + + + + + + + + + + Cppcheck Cppcheck @@ -580,13 +580,13 @@ Parameters: -l(line) (file) - + Show errors Mostrar errores - - + + Information Información @@ -1000,7 +1000,7 @@ Parameters: -l(line) (file) - + Show warnings Mostrar advertencias @@ -1023,117 +1023,117 @@ This is probably because the settings were changed between the Cppcheck versions - + You must close the project file before selecting new files or directories! ¡Tienes que cerrar el proyecto antes de seleccionar nuevos ficheros o carpetas! - + Select configuration - + File not found Archivo no encontrado - + Bad XML XML malformado - + Missing attribute Falta el atributo - + Bad attribute value - + Unsupported format Formato no soportado - + Duplicate define - + Failed to load the selected library '%1'. %2 - + File not found: '%1' - + Failed to load/setup addon %1: %2 - + Failed to load %1. Your Cppcheck installation is broken. You can use --data-dir=<directory> at the command line to specify where this file is located. Please note that --data-dir is supposed to be used by installation scripts and therefore the GUI does not start when it is used, all that happens is that the setting is configured. Analysis is aborted. - + Failed to load %1 - %2 Analysis is aborted. - - + + %1 Analysis is aborted. - - + + XML files (*.xml) Archivos XML (*.xml) - + Open the report file Abrir informe - + License Licencia - + Authors Autores - + Save the report file Guardar informe - + Quick Filter: Filtro rápido: - + Found project file: %1 Do you want to load this project file instead? @@ -1142,112 +1142,112 @@ Do you want to load this project file instead? ¿Quiere cargar este fichero de proyecto en su lugar? - + The library '%1' contains unknown elements: %2 La biblioteca '%1' contiene elementos deconocidos: %2 - + Duplicate platform type - + Platform type redefined - + Unknown element - - - - + + + + Error Error - + Text files (*.txt) Ficheros de texto (*.txt) - + CSV files (*.csv) Ficheros CVS (*.cvs) - + Project files (*.cppcheck);;All files(*.*) Ficheros de proyecto (*.cppcheck;;Todos los ficheros (*.*) - + Select Project File Selecciona el archivo de proyecto - - - + + + Project: Proyecto: - + No suitable files found to analyze! - + C/C++ Source - + Compile database - + Visual Studio - + Borland C++ Builder 6 - + Select files to analyze - + Select directory to analyze - + Select the configuration that will be analyzed - + Found project files from the directory. Do you want to proceed analysis without using any of these project files? - + Current results will be cleared. Opening a new XML file will clear current results. @@ -1255,76 +1255,76 @@ Do you want to proceed? - + Analyzer is running. Do you want to stop the analysis and exit Cppcheck? - + About - + XML files (*.xml);;Text files (*.txt);;CSV files (*.csv) - + Build dir '%1' does not exist, create it? - + To check the project using addons, you need a build directory. - + Failed to open file - + Unknown project file format - + Failed to import project file - + Failed to import '%1': %2 Analysis is stopped. - + Failed to import '%1' (%2), analysis is stopped - + Project files (*.cppcheck) - + Select Project Filename Selecciona el nombre del proyecto - + No project file loaded No hay ningún proyecto cargado - + The project file %1 @@ -1341,67 +1341,67 @@ Do you want to remove the file from the recently used projects -list? ¿Quiere eliminar el fichero de la lista de proyectos recientes? - + Install - + New version available: %1. %2 - + Show Mandatory - + Show Required - + Show Advisory - + Show Document - + Show L1 - + Show L2 - + Show L3 - + Show style - + Show portability - + Show performance - + Show information diff --git a/gui/cppcheck_fi.ts b/gui/cppcheck_fi.ts index 5a41a1cb41d..517362d852b 100644 --- a/gui/cppcheck_fi.ts +++ b/gui/cppcheck_fi.ts @@ -417,18 +417,18 @@ Parameters: -l(line) (file) - - - - - - - - - - - - + + + + + + + + + + + + Cppcheck Cppcheck @@ -572,14 +572,14 @@ Parameters: -l(line) (file) - + Show errors - + Show warnings @@ -595,8 +595,8 @@ Parameters: -l(line) (file) - - + + Information @@ -1020,103 +1020,103 @@ Parameters: -l(line) (file) - + Quick Filter: - + Select configuration - + Found project file: %1 Do you want to load this project file instead? - + File not found - + Bad XML - + Missing attribute - + Bad attribute value - + Duplicate define - + Failed to load the selected library '%1'. %2 - + File not found: '%1' - + Failed to load/setup addon %1: %2 - + Failed to load %1. Your Cppcheck installation is broken. You can use --data-dir=<directory> at the command line to specify where this file is located. Please note that --data-dir is supposed to be used by installation scripts and therefore the GUI does not start when it is used, all that happens is that the setting is configured. Analysis is aborted. - + Failed to load %1 - %2 Analysis is aborted. - - + + %1 Analysis is aborted. - + License Lisenssi - + Authors Tekijät - + Save the report file Tallenna raportti - - + + XML files (*.xml) XML-tiedostot (*xml) @@ -1128,126 +1128,126 @@ This is probably because the settings were changed between the Cppcheck versions - + You must close the project file before selecting new files or directories! - + The library '%1' contains unknown elements: %2 - + Unsupported format - + Duplicate platform type - + Platform type redefined - + Unknown element - - - - + + + + Error - + Open the report file - + Text files (*.txt) Tekstitiedostot (*.txt) - + CSV files (*.csv) - + Project files (*.cppcheck);;All files(*.*) - + Select Project File - - - + + + Project: - + No suitable files found to analyze! - + C/C++ Source - + Compile database - + Visual Studio - + Borland C++ Builder 6 - + Select files to analyze - + Select directory to analyze - + Select the configuration that will be analyzed - + Found project files from the directory. Do you want to proceed analysis without using any of these project files? - + Current results will be cleared. Opening a new XML file will clear current results. @@ -1255,76 +1255,76 @@ Do you want to proceed? - + Analyzer is running. Do you want to stop the analysis and exit Cppcheck? - + About - + XML files (*.xml);;Text files (*.txt);;CSV files (*.csv) - + Build dir '%1' does not exist, create it? - + To check the project using addons, you need a build directory. - + Failed to open file - + Unknown project file format - + Failed to import project file - + Failed to import '%1': %2 Analysis is stopped. - + Failed to import '%1' (%2), analysis is stopped - + Project files (*.cppcheck) - + Select Project Filename - + No project file loaded - + The project file %1 @@ -1335,67 +1335,67 @@ Do you want to remove the file from the recently used projects -list? - + Install - + New version available: %1. %2 - + Show Mandatory - + Show Required - + Show Advisory - + Show Document - + Show L1 - + Show L2 - + Show L3 - + Show style - + Show portability - + Show performance - + Show information diff --git a/gui/cppcheck_fr.ts b/gui/cppcheck_fr.ts index 828dffa7ad2..7e8651d8ec3 100644 --- a/gui/cppcheck_fr.ts +++ b/gui/cppcheck_fr.ts @@ -423,18 +423,18 @@ Paramètres : -l(ligne) (fichier) - - - - - - - - - - - - + + + + + + + + + + + + Cppcheck @@ -645,38 +645,38 @@ Paramètres : -l(ligne) (fichier) - + License Licence - + Authors Auteurs - + Save the report file Sauvegarder le rapport - - + + XML files (*.xml) Fichiers XML (*.xml) - + About - + Text files (*.txt) Fichiers Texte (*.txt) - + CSV files (*.csv) Fichiers CSV (*.csv) @@ -699,7 +699,7 @@ Paramètres : -l(ligne) (fichier) - + Show errors Afficher les erreurs @@ -771,7 +771,7 @@ Paramètres : -l(ligne) (fichier) - + Show warnings Afficher les avertissements @@ -787,8 +787,8 @@ Paramètres : -l(ligne) (fichier) - - + + Information Information @@ -803,129 +803,129 @@ Paramètres : -l(ligne) (fichier) Afficher les problèmes de portabilité - + You must close the project file before selecting new files or directories! Vous devez d'abord fermer le projet avant de choisir des fichiers/répertoires - + Open the report file Ouvrir le rapport - + Project files (*.cppcheck);;All files(*.*) - + Select Project File - + To check the project using addons, you need a build directory. - + Failed to open file - + Unknown project file format - + Failed to import project file - + Failed to import '%1': %2 Analysis is stopped. - + Failed to import '%1' (%2), analysis is stopped - + Select Project Filename - + No project file loaded - + Install - + New version available: %1. %2 - + Show Mandatory - + Show Required - + Show Advisory - + Show Document - + Show L1 - + Show L2 - + Show L3 - + Show style - + Show portability - + Show performance - + Show information @@ -948,12 +948,12 @@ This is probably because the settings were changed between the Cppcheck versions - + Quick Filter: Filtre rapide : - + Found project file: %1 Do you want to load this project file instead? @@ -961,14 +961,14 @@ Do you want to load this project file instead? - - - + + + Project: Projet : - + The project file %1 @@ -1019,59 +1019,59 @@ Do you want to remove the file from the recently used projects -list? - - - - + + + + Error Erreur - + File not found Fichier introuvable - + Bad XML Mauvais fichier XML - + Missing attribute Attribut manquant - + Bad attribute value Mauvaise valeur d'attribut - + Failed to load the selected library '%1'. %2 Echec lors du chargement de la bibliothèque '%1'. %2 - + Unsupported format Format non supporté - + The library '%1' contains unknown elements: %2 La bibliothèque '%1' contient des éléments inconnus: %2 - + Duplicate platform type - + Platform type redefined @@ -1101,12 +1101,12 @@ Do you want to remove the file from the recently used projects -list? - + Unknown element - + Select configuration @@ -1129,7 +1129,7 @@ Options: - + Build dir '%1' does not exist, create it? @@ -1157,76 +1157,76 @@ Options: - + XML files (*.xml);;Text files (*.txt);;CSV files (*.csv) - + No suitable files found to analyze! - + Select files to analyze - + Select directory to analyze - + Select the configuration that will be analyzed - + Found project files from the directory. Do you want to proceed analysis without using any of these project files? - + Duplicate define - + File not found: '%1' - + Failed to load/setup addon %1: %2 - + Failed to load %1. Your Cppcheck installation is broken. You can use --data-dir=<directory> at the command line to specify where this file is located. Please note that --data-dir is supposed to be used by installation scripts and therefore the GUI does not start when it is used, all that happens is that the setting is configured. Analysis is aborted. - + Failed to load %1 - %2 Analysis is aborted. - - + + %1 Analysis is aborted. - + Analyzer is running. Do you want to stop the analysis and exit Cppcheck? @@ -1373,7 +1373,7 @@ Do you want to stop the analysis and exit Cppcheck? - + Project files (*.cppcheck) @@ -1398,27 +1398,27 @@ Do you want to stop the analysis and exit Cppcheck? - + C/C++ Source - + Compile database - + Visual Studio - + Borland C++ Builder 6 - + Current results will be cleared. Opening a new XML file will clear current results. diff --git a/gui/cppcheck_it.ts b/gui/cppcheck_it.ts index 46ec9cb51d8..2c19aa2e50b 100644 --- a/gui/cppcheck_it.ts +++ b/gui/cppcheck_it.ts @@ -426,18 +426,18 @@ Parametri: -l(line) (file) - - - - - - - - - - - - + + + + + + + + + + + + Cppcheck Cppcheck @@ -581,14 +581,14 @@ Parametri: -l(line) (file) - + Show errors Mostra gli errori - + Show warnings Mostra gli avvisi @@ -604,8 +604,8 @@ Parametri: -l(line) (file) Mostra &i nascosti - - + + Information Informazione @@ -1029,17 +1029,17 @@ Parametri: -l(line) (file) - + Quick Filter: Rapido filtro: - + Select configuration - + Found project file: %1 Do you want to load this project file instead? @@ -1048,91 +1048,91 @@ Do you want to load this project file instead? Vuoi piuttosto caricare questo file di progetto? - + File not found - + Bad XML - + Missing attribute - + Bad attribute value - + Unsupported format - + Duplicate define - + Failed to load the selected library '%1'. %2 - + File not found: '%1' - + Failed to load/setup addon %1: %2 - + Failed to load %1. Your Cppcheck installation is broken. You can use --data-dir=<directory> at the command line to specify where this file is located. Please note that --data-dir is supposed to be used by installation scripts and therefore the GUI does not start when it is used, all that happens is that the setting is configured. Analysis is aborted. - + Failed to load %1 - %2 Analysis is aborted. - - + + %1 Analysis is aborted. - + License Licenza - + Authors Autori - + Save the report file Salva il file di rapporto - - + + XML files (*.xml) File XML (*.xml) @@ -1146,121 +1146,121 @@ This is probably because the settings were changed between the Cppcheck versions Probabilmente ciò è avvenuto perché le impostazioni sono state modificate tra le versioni di Cppcheck. Per favore controlla (e sistema) le impostazioni delle applicazioni editor, altrimenti il programma editor può non partire correttamente. - + You must close the project file before selecting new files or directories! Devi chiudere il file di progetto prima di selezionare nuovi file o cartelle! - + The library '%1' contains unknown elements: %2 - + Duplicate platform type - + Platform type redefined - + Unknown element - - - - + + + + Error - + Open the report file Apri il file di rapporto - + Text files (*.txt) File di testo (*.txt) - + CSV files (*.csv) Files CSV (*.csv) - + Project files (*.cppcheck);;All files(*.*) Files di progetto (*.cppcheck);;Tutti i files(*.*) - + Select Project File Seleziona il file di progetto - - - + + + Project: Progetto: - + No suitable files found to analyze! - + C/C++ Source - + Compile database - + Visual Studio - + Borland C++ Builder 6 - + Select files to analyze - + Select directory to analyze - + Select the configuration that will be analyzed - + Found project files from the directory. Do you want to proceed analysis without using any of these project files? - + Current results will be cleared. Opening a new XML file will clear current results. @@ -1268,76 +1268,76 @@ Do you want to proceed? - + Analyzer is running. Do you want to stop the analysis and exit Cppcheck? - + About - + XML files (*.xml);;Text files (*.txt);;CSV files (*.csv) - + Build dir '%1' does not exist, create it? - + To check the project using addons, you need a build directory. - + Failed to open file - + Unknown project file format - + Failed to import project file - + Failed to import '%1': %2 Analysis is stopped. - + Failed to import '%1' (%2), analysis is stopped - + Project files (*.cppcheck) - + Select Project Filename Seleziona il nome del file di progetto - + No project file loaded Nessun file di progetto caricato - + The project file %1 @@ -1354,67 +1354,67 @@ Do you want to remove the file from the recently used projects -list? Vuoi rimuovere il file dalla lista dei progetti recentemente usati? - + Install - + New version available: %1. %2 - + Show Mandatory - + Show Required - + Show Advisory - + Show Document - + Show L1 - + Show L2 - + Show L3 - + Show style - + Show portability - + Show performance - + Show information diff --git a/gui/cppcheck_ja.ts b/gui/cppcheck_ja.ts index a071727ad56..6c8269b4143 100644 --- a/gui/cppcheck_ja.ts +++ b/gui/cppcheck_ja.ts @@ -491,18 +491,18 @@ Parameters: -l(line) (file) - - - - - - - - - - - - + + + + + + + + + + + + Cppcheck Cppcheck @@ -657,13 +657,13 @@ Parameters: -l(line) (file) - + Show errors エラーを表示 - - + + Information 情報 @@ -770,7 +770,7 @@ Parameters: -l(line) (file) - + Show warnings 警告を表示 @@ -1102,23 +1102,23 @@ This is probably because the settings were changed between the Cppcheck versions Cppcheckの古いバージョンの設定には互換性がありません。エディタアプリケーションの設定を確認して修正してください、そうしないと正しく起動できないかもしれません。 - + You must close the project file before selecting new files or directories! 新しいファイル/ディレクトリをチェックするには現在のプロジェクトを閉じてください! - + Quick Filter: クイックフィルタ: - + Select configuration コンフィグレーションの選択 - + Found project file: %1 Do you want to load this project file instead? @@ -1127,64 +1127,64 @@ Do you want to load this project file instead? 現在のプロジェクトの代わりにこのプロジェクトファイルを読み込んでもかまいませんか? - + The library '%1' contains unknown elements: %2 このライブラリ '%1' には次の不明な要素が含まれています。 %2 - + File not found ファイルがありません - + Bad XML 不正なXML - + Missing attribute 属性がありません - + Bad attribute value 不正な属性があります - + Unsupported format サポートされていないフォーマット - + Duplicate platform type プラットフォームの種類が重複しています - + Platform type redefined プラットフォームの種類が再定義されました - + Unknown element 不明な要素 - + Failed to load the selected library '%1'. %2 選択したライブラリの読み込みに失敗しました '%1' %2 - - - - + + + + Error エラー @@ -1197,38 +1197,38 @@ Do you want to load this project file instead? %1 - %2 の読み込みに失敗 - - + + XML files (*.xml) XML ファイル (*.xml) - + Open the report file レポートを開く - + License ライセンス - + Authors 作者 - + Save the report file レポートを保存 - + Text files (*.txt) テキストファイル (*.txt) - + CSV files (*.csv) CSV形式ファイル (*.csv) @@ -1237,32 +1237,32 @@ Do you want to load this project file instead? コンプライアンスレポートをすぐに生成できません。解析が完了し成功していなければなりません。コードを再解析して、致命的なエラーがないことを確認してください。 - + Project files (*.cppcheck);;All files(*.*) プロジェクトファイル (*.cppcheck);;すべてのファイル(*.*) - + Select Project File プロジェクトファイルを選択 - + Failed to open file ファイルを開くのに失敗しました - + Unknown project file format プロジェクトファイルの形式が不明です - + Failed to import project file プロジェクトファイルのインポートに失敗しました - + Failed to import '%1': %2 Analysis is stopped. @@ -1271,70 +1271,70 @@ Analysis is stopped. 解析を停止しました。 - + Failed to import '%1' (%2), analysis is stopped '%1' (%2) のインポートに失敗しました。解析は停止 - + Install インストール - + New version available: %1. %2 新しいバージョンが利用可能です。: %1. %2 - - - + + + Project: プロジェクト: - + No suitable files found to analyze! チェック対象のファイルがみつかりません! - + C/C++ Source C/C++のソースコード - + Compile database コンパイルデータベース - + Visual Studio Visual Studio - + Borland C++ Builder 6 Borland C++ Builder 6 - + Select files to analyze チェック対象のファイルを選択 - + Select directory to analyze チェックするディレクトリを選択してください - + Select the configuration that will be analyzed チェックの設定を選択 - + Found project files from the directory. Do you want to proceed analysis without using any of these project files? @@ -1343,37 +1343,37 @@ Do you want to proceed analysis without using any of these project files? - + Duplicate define 重複した定義 - + File not found: '%1' ファイルがありません: '%1' - + Failed to load/setup addon %1: %2 アドオンの読み込みまたは設定に失敗 %1 - %2 - + Failed to load %1. Your Cppcheck installation is broken. You can use --data-dir=<directory> at the command line to specify where this file is located. Please note that --data-dir is supposed to be used by installation scripts and therefore the GUI does not start when it is used, all that happens is that the setting is configured. Analysis is aborted. %1のロードに失敗しました。あなたの Cppcheck は正しくインストールされていません。あなたは --data-dir=<directory> コマンドラインオプションを使ってこのファイルの場所を指定できます。ただし、この --data-dir はインストールスクリプトによって使用されていなければなりません。またGUI版はこれを使用しません。さらに、全ての設定は調整済みでなければなりません。 - + Failed to load %1 - %2 Analysis is aborted. 読み込みに失敗 %1 - %2 - - + + %1 Analysis is aborted. @@ -1382,7 +1382,7 @@ Analysis is aborted. 解析は中止した。 - + Current results will be cleared. Opening a new XML file will clear current results. @@ -1392,7 +1392,7 @@ Do you want to proceed? 新しくXMLファイルを開くと現在の結果が削除されます。実行しますか? - + Analyzer is running. Do you want to stop the analysis and exit Cppcheck? @@ -1401,77 +1401,77 @@ Do you want to stop the analysis and exit Cppcheck? チェックを中断して、Cppcheckを終了しますか? - + About CppCheckについて - + XML files (*.xml);;Text files (*.txt);;CSV files (*.csv) XML ファイル (*.xml);;テキストファイル (*.txt);;CSVファイル (*.csv) - + Build dir '%1' does not exist, create it? ビルドディレクトリ'%1'がありません。作成しますか? - + To check the project using addons, you need a build directory. アドオンを使用してプロジェクトをチェックするためには、ビルドディレクトリが必要です。 - + Show Mandatory 必須を表示 - + Show Required 要求を表示 - + Show Advisory 推奨を表示 - + Show Document ドキュメントを表示 - + Show L1 L1を表示 - + Show L2 L2を表示 - + Show L3 L3を表示 - + Show style スタイルを表示 - + Show portability 移植可能性を表示 - + Show performance パフォーマンスを表示 - + Show information 情報を表示 @@ -1480,22 +1480,22 @@ Do you want to stop the analysis and exit Cppcheck? '%1'のインポートに失敗しました。(チェック中断) - + Project files (*.cppcheck) プロジェクトファイル (*.cppcheck) - + Select Project Filename プロジェクトファイル名を選択 - + No project file loaded プロジェクトファイルが読み込まれていません - + The project file %1 diff --git a/gui/cppcheck_ka.ts b/gui/cppcheck_ka.ts index f6d571ab3f5..52c0657f646 100644 --- a/gui/cppcheck_ka.ts +++ b/gui/cppcheck_ka.ts @@ -467,18 +467,18 @@ Parameters: -l(line) (file) - - - - - - - - - - - - + + + + + + + + + + + + Cppcheck Cppcheck @@ -622,14 +622,14 @@ Parameters: -l(line) (file) - + Show errors შეცდომების ჩვენება - + Show warnings გაფრთხილების ჩვენება @@ -645,8 +645,8 @@ Parameters: -l(line) (file) დამალულის &ჩვენება - - + + Information ინფორმაცია @@ -1070,17 +1070,17 @@ Parameters: -l(line) (file) - + Quick Filter: სწრაფი ფილტრი: - + Select configuration აირჩიეთ კონფიგურაცია - + Found project file: %1 Do you want to load this project file instead? @@ -1089,61 +1089,61 @@ Do you want to load this project file instead? გნებავთ, სამაგიეროდ, ეს პროექტის ფაილი ჩატვირთოთ? - + File not found ფაილი ნაპოვნი არაა - + Bad XML არასწორი XML - + Missing attribute აკლია ატრიბუტი - + Bad attribute value არასწორი ატრიბუტის მნიშვნელობა - + Unsupported format მხარდაუჭერელი ფორმატი - + Duplicate define გამეორებული აღწერა - + Failed to load the selected library '%1'. %2 ჩავარდა ჩატვირთვა მონიშნული ბიბლიოთეკისთვის '%1'. %2 - + File not found: '%1' ფაილი ვერ ვიპოვე: '%1' - + Failed to load/setup addon %1: %2 დამატების (%1) ჩატვირთვა/მორგება ჩავარდა: %2 - + Failed to load %1. Your Cppcheck installation is broken. You can use --data-dir=<directory> at the command line to specify where this file is located. Please note that --data-dir is supposed to be used by installation scripts and therefore the GUI does not start when it is used, all that happens is that the setting is configured. Analysis is aborted. - + Failed to load %1 - %2 Analysis is aborted. @@ -1152,8 +1152,8 @@ Analysis is aborted. ანალიზი შეწყდა. - - + + %1 Analysis is aborted. @@ -1162,23 +1162,23 @@ Analysis is aborted. ანალიზი შეწყვეტილია. - + License ლიცენზია - + Authors ავტორები - + Save the report file ანგარიშის ფაილში ჩაწერა - - + + XML files (*.xml) XML ფაილები (*.xml) @@ -1190,115 +1190,115 @@ This is probably because the settings were changed between the Cppcheck versions - + You must close the project file before selecting new files or directories! ახალი ფაილების ან საქაღალდეების არჩევამდე პრორექტის ფაილი უნდა დახუროთ! - + The library '%1' contains unknown elements: %2 ბიბლიოთეკა '%1' უცნობ ელემენტებს შეიცავს: %2 - + Duplicate platform type გამეორებული პლატფორმის ტიპი - + Platform type redefined პლატფორმის ტიპი თავდან აღიწერა - + Unknown element უცნობი ელემენტი - - - - + + + + Error შეცდომა - + Open the report file ანგარიშის ფაილის გახსნა - + Text files (*.txt) ტექსტური ფაილები (*.txt) - + CSV files (*.csv) CSV ფაილები (*.csv) - + Project files (*.cppcheck);;All files(*.*) პროექტის ფაილები (*.cppcheck);;ყველა ფაილი(*.*) - + Select Project File აირჩიეთ პროექტის ფაილი - - - + + + Project: პროექტი: - + No suitable files found to analyze! ანალიზისათვის შესაფერისი ფაილები აღმოჩენილი არაა! - + C/C++ Source C/C++ საწყისი კოდი - + Compile database მონაცემთა ბაზის კომპილაცია - + Visual Studio Visual Studio - + Borland C++ Builder 6 Borland C++ Builder 6 - + Select files to analyze აირჩეთ ფაილები ანალიზისთვის - + Select directory to analyze აირჩიეთ საქაღალდე ანალიზისთვის - + Select the configuration that will be analyzed აირჩიეთ კონფიგურაცია ანალიზისთვის - + Found project files from the directory. Do you want to proceed analysis without using any of these project files? @@ -1307,7 +1307,7 @@ Do you want to proceed analysis without using any of these project files? - + Current results will be cleared. Opening a new XML file will clear current results. @@ -1318,7 +1318,7 @@ Do you want to proceed? გნებავთ, გააგრძელოთ? - + Analyzer is running. Do you want to stop the analysis and exit Cppcheck? @@ -1327,12 +1327,12 @@ Do you want to stop the analysis and exit Cppcheck? გნებავთ, გააჩეროთ ანალიზი და გახვიდეთ Cppcheck-დან? - + About შესახებ - + XML files (*.xml);;Text files (*.txt);;CSV files (*.csv) XML ფაილები (*.xml);;ტექსტური ფაილები (*.txt);;CSV ფაილები (*.csv) @@ -1341,32 +1341,32 @@ Do you want to stop the analysis and exit Cppcheck? შესაბამისობის ანგარიშის გენერაცია ახლა შეუძლებელია, რადგან ჯერ ანალიზი წარმატებით უნდა დასრულდეს. სცადეთ, კოდის ანალიზი თავიდან გაუშვათ და დარწმუნდეთ, რომ კრიტიკული შეცდომები არ არსებობს. - + Build dir '%1' does not exist, create it? აგების საქაღალდე (%1) არ არსებობს. შევქმნა? - + To check the project using addons, you need a build directory. პროექტის დამატებებით შესამოწმებლად აგების საქაღალდე გჭირდებათ. - + Failed to open file ფაილის გახსნის შეცდომა - + Unknown project file format უცნობი პროექტის ფაილის ფორმატი - + Failed to import project file პროექტის ფაილის შემოტანა ჩავარდა - + Failed to import '%1': %2 Analysis is stopped. @@ -1375,27 +1375,27 @@ Analysis is stopped. ანალიზი შეწყდა. - + Failed to import '%1' (%2), analysis is stopped '%1'-ის (%2) შემოტანა ჩავარდა. ანალიზი შეწყდა - + Project files (*.cppcheck) პროექტის ფაილები (*.cppcheck) - + Select Project Filename აირჩიეთ პროექტის ფაილის სახელი - + No project file loaded პროექტის ფაილი ჩატვირთული არაა - + The project file %1 @@ -1412,67 +1412,67 @@ Do you want to remove the file from the recently used projects -list? გნებავთ წაშალოთ ეს ფაილი ახლახან გამოყენებული პროექტების სიიდან? - + Install დაყენება - + New version available: %1. %2 ხელმისაწვდომია ახალი ვერსია: %1. %2 - + Show Mandatory - + Show Required - + Show Advisory - + Show Document - + Show L1 - + Show L2 - + Show L3 - + Show style - + Show portability - + Show performance - + Show information diff --git a/gui/cppcheck_ko.ts b/gui/cppcheck_ko.ts index 18720477f08..611eede0491 100644 --- a/gui/cppcheck_ko.ts +++ b/gui/cppcheck_ko.ts @@ -423,18 +423,18 @@ Kate로 파일을 열고, 해당 행으로 이동하는 예제: - - - - - - - - - - - - + + + + + + + + + + + + Cppcheck Cppcheck @@ -578,7 +578,7 @@ Kate로 파일을 열고, 해당 행으로 이동하는 예제: - + Show errors 애러 표시 @@ -685,7 +685,7 @@ Kate로 파일을 열고, 해당 행으로 이동하는 예제: - + Show warnings 경고 표시 @@ -756,8 +756,8 @@ Kate로 파일을 열고, 해당 행으로 이동하는 예제: - - + + Information 정보 @@ -808,7 +808,7 @@ Kate로 파일을 열고, 해당 행으로 이동하는 예제: - + Quick Filter: 빠른 필터: @@ -822,12 +822,12 @@ This is probably because the settings were changed between the Cppcheck versions Cppcheck 버전간 설정 방법 차이때문인 것으로 보입니다. 편집기 설정을 검사(및 수정)해주세요, 그렇지 않으면 편집기가 제대로 시작하지 않습니다. - + You must close the project file before selecting new files or directories! 새로운 파일이나 디렉토리를 선택하기 전에 프로젝트 파일을 닫으세요! - + Found project file: %1 Do you want to load this project file instead? @@ -836,210 +836,210 @@ Do you want to load this project file instead? 이 프로젝트 파일을 불러오겠습니까? - - + + XML files (*.xml) XML 파일 (*.xml) - + Open the report file 보고서 파일 열기 - + License 저작권 - + Authors 제작자 - + Save the report file 보고서 파일 저장 - + Text files (*.txt) 텍스트 파일 (*.txt) - + CSV files (*.csv) CSV 파일 (*.csv) - + Project files (*.cppcheck);;All files(*.*) 프로젝트 파일 (*.cppcheck);;모든 파일(*.*) - + Select Project File 프로젝트 파일 선택 - + Failed to open file - + Unknown project file format - + Failed to import project file - + Failed to import '%1': %2 Analysis is stopped. - + Failed to import '%1' (%2), analysis is stopped - + Install - + New version available: %1. %2 - + Show Mandatory - + Show Required - + Show Advisory - + Show Document - + Show L1 - + Show L2 - + Show L3 - + Show style - + Show portability - + Show performance - + Show information - - - + + + Project: 프로젝트: - + Duplicate define - + File not found: '%1' - + Failed to load/setup addon %1: %2 - + Failed to load %1. Your Cppcheck installation is broken. You can use --data-dir=<directory> at the command line to specify where this file is located. Please note that --data-dir is supposed to be used by installation scripts and therefore the GUI does not start when it is used, all that happens is that the setting is configured. Analysis is aborted. - + Failed to load %1 - %2 Analysis is aborted. - - + + %1 Analysis is aborted. - + About - + To check the project using addons, you need a build directory. - + Select Project Filename 프로젝트 파일이름 선택 - + No project file loaded 프로젝트 파일 불러오기 실패 - + The project file %1 @@ -1066,57 +1066,57 @@ Do you want to remove the file from the recently used projects -list? - - - - + + + + Error - + File not found - + Bad XML - + Missing attribute - + Bad attribute value - + Failed to load the selected library '%1'. %2 - + Unsupported format - + The library '%1' contains unknown elements: %2 - + Duplicate platform type - + Platform type redefined @@ -1146,12 +1146,12 @@ Do you want to remove the file from the recently used projects -list? - + Unknown element - + Select configuration @@ -1174,7 +1174,7 @@ Options: - + Build dir '%1' does not exist, create it? @@ -1202,39 +1202,39 @@ Options: - + XML files (*.xml);;Text files (*.txt);;CSV files (*.csv) - + No suitable files found to analyze! - + Select files to analyze - + Select directory to analyze - + Select the configuration that will be analyzed - + Found project files from the directory. Do you want to proceed analysis without using any of these project files? - + Analyzer is running. Do you want to stop the analysis and exit Cppcheck? @@ -1381,7 +1381,7 @@ Do you want to stop the analysis and exit Cppcheck? C++14 - + Project files (*.cppcheck) @@ -1406,27 +1406,27 @@ Do you want to stop the analysis and exit Cppcheck? C++20 - + C/C++ Source - + Compile database - + Visual Studio - + Borland C++ Builder 6 - + Current results will be cleared. Opening a new XML file will clear current results. diff --git a/gui/cppcheck_nl.ts b/gui/cppcheck_nl.ts index cd14a92bdc2..7c58587662b 100644 --- a/gui/cppcheck_nl.ts +++ b/gui/cppcheck_nl.ts @@ -427,18 +427,18 @@ Parameters: -l(lijn) (bestand) - - - - - - - - - - - - + + + + + + + + + + + + Cppcheck Cppcheck @@ -582,14 +582,14 @@ Parameters: -l(lijn) (bestand) - + Show errors Toon fouten - + Show warnings Toon waarschuwingen @@ -605,8 +605,8 @@ Parameters: -l(lijn) (bestand) Toon &verborgen - - + + Information Informatie @@ -1030,17 +1030,17 @@ Parameters: -l(lijn) (bestand) - + Quick Filter: Snel Filter: - + Select configuration - + Found project file: %1 Do you want to load this project file instead? @@ -1048,86 +1048,86 @@ Do you want to load this project file instead? Wilt u dit project laden in plaats van? - + File not found - + Bad XML - + Missing attribute - + Bad attribute value - + Duplicate define - + Failed to load the selected library '%1'. %2 - + File not found: '%1' - + Failed to load/setup addon %1: %2 - + Failed to load %1. Your Cppcheck installation is broken. You can use --data-dir=<directory> at the command line to specify where this file is located. Please note that --data-dir is supposed to be used by installation scripts and therefore the GUI does not start when it is used, all that happens is that the setting is configured. Analysis is aborted. - + Failed to load %1 - %2 Analysis is aborted. - - + + %1 Analysis is aborted. - + License Licentie - + Authors Auteurs - + Save the report file Rapport opslaan - - + + XML files (*.xml) XML bestanden (*.xml) @@ -1141,126 +1141,126 @@ This is probably because the settings were changed between the Cppcheck versions Dit is waarschijnlijk omdat de instellingen zijn gewijzigd tussen de versies van cppcheck. Controleer (en maak) de bewerker instellingen, anders zal de bewerker niet correct starten. - + You must close the project file before selecting new files or directories! Je moet project bestanden sluiten voordat je nieuwe bestanden of mappen selekteerd! - + The library '%1' contains unknown elements: %2 - + Unsupported format - + Duplicate platform type - + Platform type redefined - + Unknown element - - - - + + + + Error - + Open the report file Open het rapport bestand - + Text files (*.txt) Tekst bestanden (*.txt) - + CSV files (*.csv) CSV bestanden (*.csv) - + Project files (*.cppcheck);;All files(*.*) Project bestanden (*.cppcheck);;Alle bestanden(*.*) - + Select Project File Selecteer project bestand - - - + + + Project: Project: - + No suitable files found to analyze! - + C/C++ Source - + Compile database - + Visual Studio - + Borland C++ Builder 6 - + Select files to analyze - + Select directory to analyze - + Select the configuration that will be analyzed - + Found project files from the directory. Do you want to proceed analysis without using any of these project files? - + Current results will be cleared. Opening a new XML file will clear current results. @@ -1268,76 +1268,76 @@ Do you want to proceed? - + Analyzer is running. Do you want to stop the analysis and exit Cppcheck? - + About - + XML files (*.xml);;Text files (*.txt);;CSV files (*.csv) - + Build dir '%1' does not exist, create it? - + To check the project using addons, you need a build directory. - + Failed to open file - + Unknown project file format - + Failed to import project file - + Failed to import '%1': %2 Analysis is stopped. - + Failed to import '%1' (%2), analysis is stopped - + Project files (*.cppcheck) - + Select Project Filename Selecteer project bestandsnaam - + No project file loaded Geen project bestand geladen - + The project file %1 @@ -1353,67 +1353,67 @@ Kan niet worden gevonden! Wilt u het bestand van de onlangs gebruikte project verwijderen -lijst? - + Install - + New version available: %1. %2 - + Show Mandatory - + Show Required - + Show Advisory - + Show Document - + Show L1 - + Show L2 - + Show L3 - + Show style - + Show portability - + Show performance - + Show information diff --git a/gui/cppcheck_ru.ts b/gui/cppcheck_ru.ts index 464bfb0d34b..a6608d90f7d 100644 --- a/gui/cppcheck_ru.ts +++ b/gui/cppcheck_ru.ts @@ -427,18 +427,18 @@ Parameters: -l(line) (file) - - - - - - - - - - - - + + + + + + + + + + + + Cppcheck Cppcheck @@ -582,14 +582,14 @@ Parameters: -l(line) (file) - + Show errors Показать ошибки - + Show warnings Показать предупреждения @@ -605,8 +605,8 @@ Parameters: -l(line) (file) Показать скрытые - - + + Information Информационные сообщения @@ -1030,17 +1030,17 @@ Parameters: -l(line) (file) - + Quick Filter: Быстрый фильтр: - + Select configuration Выбор конфигурации - + Found project file: %1 Do you want to load this project file instead? @@ -1049,92 +1049,92 @@ Do you want to load this project file instead? Вы хотите загрузить этот проект? - + File not found Файл не найден - + Bad XML Некорректный XML - + Missing attribute Пропущен атрибут - + Bad attribute value Некорректное значение атрибута - + Unsupported format Неподдерживаемый формат - + Duplicate define - + Failed to load the selected library '%1'. %2 Не удалось загрузить выбранную библиотеку '%1'. %2 - + File not found: '%1' - + Failed to load/setup addon %1: %2 - + Failed to load %1. Your Cppcheck installation is broken. You can use --data-dir=<directory> at the command line to specify where this file is located. Please note that --data-dir is supposed to be used by installation scripts and therefore the GUI does not start when it is used, all that happens is that the setting is configured. Analysis is aborted. - + Failed to load %1 - %2 Analysis is aborted. - - + + %1 Analysis is aborted. - + License Лицензия - + Authors Авторы - + Save the report file Сохранить файл с отчетом - - + + XML files (*.xml) XML-файлы (*.xml) @@ -1148,37 +1148,37 @@ This is probably because the settings were changed between the Cppcheck versions Возможно, это связано с изменениями в версии программы. Пожалуйста, проверьте (и исправьте) настройки приложения. - + You must close the project file before selecting new files or directories! Вы должны закрыть проект перед выбором новых файлов или каталогов! - + The library '%1' contains unknown elements: %2 Библиотека '%1' содержит неизвестные элементы: %2 - + Duplicate platform type Дубликат типа платформы - + Platform type redefined Переобъявление типа платформы - + Unknown element Неизвестный элемент - - - - + + + + Error Ошибка @@ -1187,80 +1187,80 @@ This is probably because the settings were changed between the Cppcheck versions Невозможно загрузить %1. Cppcheck установлен некорректно. Вы можете использовать --data-dir=<directory> в командной строке для указания расположения файлов конфигурации. Обратите внимание, что --data-dir предназначен для использования сценариями установки. При включении данной опции, графический интерфейс пользователя не запускается. - + Open the report file Открыть файл с отчетом - + Text files (*.txt) Текстовые файлы (*.txt) - + CSV files (*.csv) CSV файлы(*.csv) - + Project files (*.cppcheck);;All files(*.*) Файлы проекта (*.cppcheck);;Все файлы(*.*) - + Select Project File Выберите файл проекта - - - + + + Project: Проект: - + No suitable files found to analyze! Не найдено подходящих файлов для анализа - + C/C++ Source Исходный код C/C++ - + Compile database - + Visual Studio Visual Studio - + Borland C++ Builder 6 Borland C++ Builder 6 - + Select files to analyze Выбор файлов для анализа - + Select directory to analyze Выбор каталога для анализа - + Select the configuration that will be analyzed Выбор используемой конфигурации - + Found project files from the directory. Do you want to proceed analysis without using any of these project files? @@ -1269,7 +1269,7 @@ Do you want to proceed analysis without using any of these project files? - + Current results will be cleared. Opening a new XML file will clear current results. @@ -1280,7 +1280,7 @@ Do you want to proceed? Вы хотите продолжить? - + Analyzer is running. Do you want to stop the analysis and exit Cppcheck? @@ -1289,104 +1289,104 @@ Do you want to stop the analysis and exit Cppcheck? Вы хотите остановить анализ и выйти из Cppcheck? - + About - + XML files (*.xml);;Text files (*.txt);;CSV files (*.csv) XML файлы (*.xml);;Текстовые файлы (*.txt);;CSV файлы (*.csv) - + Build dir '%1' does not exist, create it? Директория для сборки '%1' не существует, создать? - + To check the project using addons, you need a build directory. - + Failed to open file - + Unknown project file format - + Failed to import project file - + Failed to import '%1': %2 Analysis is stopped. - + Failed to import '%1' (%2), analysis is stopped - + Show Mandatory - + Show Required - + Show Advisory - + Show Document - + Show L1 - + Show L2 - + Show L3 - + Show style - + Show portability - + Show performance - + Show information @@ -1395,22 +1395,22 @@ Analysis is stopped. Невозможно импортировать '%1', анализ остановлен - + Project files (*.cppcheck) Файлы проекта (*.cppcheck) - + Select Project Filename Выберите имя файла для проекта - + No project file loaded Файл с проектом не загружен - + The project file %1 @@ -1426,12 +1426,12 @@ Do you want to remove the file from the recently used projects -list? Хотите удалить его из списка проектов? - + Install - + New version available: %1. %2 diff --git a/gui/cppcheck_sr.ts b/gui/cppcheck_sr.ts index 190dbdbe751..07e8059f724 100644 --- a/gui/cppcheck_sr.ts +++ b/gui/cppcheck_sr.ts @@ -415,18 +415,18 @@ Parameters: -l(line) (file) - - - - - - - - - - - - + + + + + + + + + + + + Cppcheck Cppcheck @@ -570,14 +570,14 @@ Parameters: -l(line) (file) - + Show errors - + Show warnings @@ -593,8 +593,8 @@ Parameters: -l(line) (file) - - + + Information @@ -1018,103 +1018,103 @@ Parameters: -l(line) (file) - + Quick Filter: - + Select configuration - + Found project file: %1 Do you want to load this project file instead? - + File not found - + Bad XML - + Missing attribute - + Bad attribute value - + Duplicate define - + Failed to load the selected library '%1'. %2 - + File not found: '%1' - + Failed to load/setup addon %1: %2 - + Failed to load %1. Your Cppcheck installation is broken. You can use --data-dir=<directory> at the command line to specify where this file is located. Please note that --data-dir is supposed to be used by installation scripts and therefore the GUI does not start when it is used, all that happens is that the setting is configured. Analysis is aborted. - + Failed to load %1 - %2 Analysis is aborted. - - + + %1 Analysis is aborted. - + License License - + Authors Authors - + Save the report file Save the report file - - + + XML files (*.xml) XML files (*.xml) @@ -1126,126 +1126,126 @@ This is probably because the settings were changed between the Cppcheck versions - + You must close the project file before selecting new files or directories! - + The library '%1' contains unknown elements: %2 - + Unsupported format - + Duplicate platform type - + Platform type redefined - + Unknown element - - - - + + + + Error - + Open the report file - + Text files (*.txt) Text files (*.txt) - + CSV files (*.csv) - + Project files (*.cppcheck);;All files(*.*) - + Select Project File - - - + + + Project: - + No suitable files found to analyze! - + C/C++ Source - + Compile database - + Visual Studio - + Borland C++ Builder 6 - + Select files to analyze - + Select directory to analyze - + Select the configuration that will be analyzed - + Found project files from the directory. Do you want to proceed analysis without using any of these project files? - + Current results will be cleared. Opening a new XML file will clear current results. @@ -1253,76 +1253,76 @@ Do you want to proceed? - + Analyzer is running. Do you want to stop the analysis and exit Cppcheck? - + About - + XML files (*.xml);;Text files (*.txt);;CSV files (*.csv) - + Build dir '%1' does not exist, create it? - + To check the project using addons, you need a build directory. - + Failed to open file - + Unknown project file format - + Failed to import project file - + Failed to import '%1': %2 Analysis is stopped. - + Failed to import '%1' (%2), analysis is stopped - + Project files (*.cppcheck) - + Select Project Filename - + No project file loaded - + The project file %1 @@ -1333,67 +1333,67 @@ Do you want to remove the file from the recently used projects -list? - + Install - + New version available: %1. %2 - + Show Mandatory - + Show Required - + Show Advisory - + Show Document - + Show L1 - + Show L2 - + Show L3 - + Show style - + Show portability - + Show performance - + Show information diff --git a/gui/cppcheck_sv.ts b/gui/cppcheck_sv.ts index 4f548b454d0..4b8164d7775 100644 --- a/gui/cppcheck_sv.ts +++ b/gui/cppcheck_sv.ts @@ -433,18 +433,18 @@ Exempel: - - - - - - - - - - - - + + + + + + + + + + + + Cppcheck Cppcheck @@ -588,14 +588,14 @@ Exempel: - + Show errors Visa fel - + Show warnings Visa varningar @@ -611,8 +611,8 @@ Exempel: Visa dolda - - + + Information Information @@ -1037,17 +1037,17 @@ Exempel: - + Quick Filter: Snabbfilter: - + Select configuration Välj konfiguration - + Found project file: %1 Do you want to load this project file instead? @@ -1056,92 +1056,92 @@ Do you want to load this project file instead? Vill du ladda denna projektfil istället? - + File not found Filen hittades ej - + Bad XML Ogiltig XML - + Missing attribute Attribut finns ej - + Bad attribute value Ogiltigt attribut värde - + Unsupported format Format stöds ej - + Duplicate define - + Failed to load the selected library '%1'. %2 Misslyckades att ladda valda library '%1'. %2 - + File not found: '%1' - + Failed to load/setup addon %1: %2 - + Failed to load %1. Your Cppcheck installation is broken. You can use --data-dir=<directory> at the command line to specify where this file is located. Please note that --data-dir is supposed to be used by installation scripts and therefore the GUI does not start when it is used, all that happens is that the setting is configured. Analysis is aborted. - + Failed to load %1 - %2 Analysis is aborted. - - + + %1 Analysis is aborted. - + License Licens - + Authors Utvecklare - + Save the report file Spara rapport - - + + XML files (*.xml) XML filer (*.xml) @@ -1155,37 +1155,37 @@ This is probably because the settings were changed between the Cppcheck versions En trolig orsak är att inställningarna ändrats för olika Cppcheck versioner. Kontrollera programinställningarna. - + You must close the project file before selecting new files or directories! Du måste stänga projektfilen innan nya filer eller sökvägar kan väljas! - + The library '%1' contains unknown elements: %2 Library filen '%1' har element som ej hanteras: %2 - + Duplicate platform type Dubbel plattformstyp - + Platform type redefined Plattformstyp definieras igen - + Unknown element Element hanteras ej - - - - + + + + Error Fel @@ -1194,80 +1194,80 @@ En trolig orsak är att inställningarna ändrats för olika Cppcheck versioner. Misslyckades att ladda %1. Din Cppcheck installation är ej komplett. Du kan använda --data-dir<directory> på kommandoraden för att specificera var denna fil finns. Det är meningen att --data-dir kommandot skall köras under installationen,så GUIt kommer ej visas när --data-dir används allt som händer är att en inställning görs. - + Open the report file Öppna rapportfilen - + Text files (*.txt) Text filer (*.txt) - + CSV files (*.csv) CSV filer (*.csv) - + Project files (*.cppcheck);;All files(*.*) Projektfiler (*.cppcheck);;Alla filer(*.*) - + Select Project File Välj projektfil - - - + + + Project: Projekt: - + No suitable files found to analyze! Inga filer hittades att analysera! - + C/C++ Source - + Compile database - + Visual Studio Visual Studio - + Borland C++ Builder 6 - + Select files to analyze Välj filer att analysera - + Select directory to analyze Välj mapp att analysera - + Select the configuration that will be analyzed Välj konfiguration som kommer analyseras - + Found project files from the directory. Do you want to proceed analysis without using any of these project files? @@ -1276,7 +1276,7 @@ Do you want to proceed analysis without using any of these project files? - + Current results will be cleared. Opening a new XML file will clear current results. @@ -1284,7 +1284,7 @@ Do you want to proceed? - + Analyzer is running. Do you want to stop the analysis and exit Cppcheck? @@ -1293,104 +1293,104 @@ Do you want to stop the analysis and exit Cppcheck? Vill du stoppa analysen och avsluta Cppcheck? - + About - + XML files (*.xml);;Text files (*.txt);;CSV files (*.csv) XML filer (*.xml);;Text filer (*.txt);;CSV filer (*.csv) - + Build dir '%1' does not exist, create it? Build dir '%1' existerar ej, skapa den? - + To check the project using addons, you need a build directory. - + Failed to open file - + Unknown project file format - + Failed to import project file - + Failed to import '%1': %2 Analysis is stopped. - + Failed to import '%1' (%2), analysis is stopped - + Show Mandatory - + Show Required - + Show Advisory - + Show Document - + Show L1 - + Show L2 - + Show L3 - + Show style - + Show portability - + Show performance - + Show information @@ -1399,22 +1399,22 @@ Analysis is stopped. Misslyckades att importera '%1', analysen stoppas - + Project files (*.cppcheck) Projekt filer (*.cppcheck) - + Select Project Filename Välj Projektfil - + No project file loaded Inget projekt laddat - + The project file %1 @@ -1431,12 +1431,12 @@ Do you want to remove the file from the recently used projects -list? Vill du ta bort filen från 'senast använda projekt'-listan? - + Install - + New version available: %1. %2 diff --git a/gui/cppcheck_zh_CN.ts b/gui/cppcheck_zh_CN.ts index 952fbcd4d14..5860c842a16 100644 --- a/gui/cppcheck_zh_CN.ts +++ b/gui/cppcheck_zh_CN.ts @@ -434,18 +434,18 @@ Parameters: -l(line) (file) - - - - - - - - - - - - + + + + + + + + + + + + Cppcheck Cppcheck @@ -600,13 +600,13 @@ Parameters: -l(line) (file) - + Show errors 显示错误 - - + + Information 信息 @@ -713,7 +713,7 @@ Parameters: -l(line) (file) - + Show warnings 显示警告 @@ -1045,23 +1045,23 @@ This is probably because the settings were changed between the Cppcheck versions 这可能是因为 Cppcheck 不同版本间的设置有所不同。请检查(并修复)编辑器应用程序设置,否则编辑器程序可能不会正确启动。 - + You must close the project file before selecting new files or directories! 在选择新的文件或目录之前,你必须先关闭此项目文件! - + Quick Filter: 快速滤器: - + Select configuration 选择配置 - + Found project file: %1 Do you want to load this project file instead? @@ -1070,64 +1070,64 @@ Do you want to load this project file instead? 你是否想加载该项目文件? - + The library '%1' contains unknown elements: %2 库 '%1' 包含未知元素: %2 - + File not found 文件未找到 - + Bad XML 无效的 XML - + Missing attribute 缺失属性 - + Bad attribute value 无效的属性值 - + Unsupported format 不支持的格式 - + Duplicate platform type 重复的平台类型 - + Platform type redefined 平台类型重定义 - + Unknown element 位置元素 - + Failed to load the selected library '%1'. %2 选择的库 '%1' 加载失败。 %2 - - - - + + + + Error 错误 @@ -1136,138 +1136,138 @@ Do you want to load this project file instead? 加载 %1 失败。您的 Cppcheck 安装已损坏。您可以在命令行添加 --data-dir=<目录> 参数来指定文件位置。请注意,'--data-dir' 参数应当由安装脚本使用,因此,当使用此参数时,GUI不会启动,所发生的一切只是配置了设置。 - - + + XML files (*.xml) XML 文件(*.xml) - + Open the report file 打开报告文件 - + License 许可证 - + Authors 作者 - + Save the report file 保存报告文件 - + Text files (*.txt) 文本文件(*.txt) - + CSV files (*.csv) CSV 文件(*.csv) - + Project files (*.cppcheck);;All files(*.*) 项目文件(*.cppcheck);;所有文件(*.*) - + Select Project File 选择项目文件 - + Failed to open file - + Unknown project file format - + Failed to import project file - + Failed to import '%1': %2 Analysis is stopped. - + Failed to import '%1' (%2), analysis is stopped - + Install - + New version available: %1. %2 - - - + + + Project: 项目: - + No suitable files found to analyze! 没有找到合适的文件来分析! - + C/C++ Source C/C++ 源码 - + Compile database Compile database - + Visual Studio Visual Studio - + Borland C++ Builder 6 Borland C++ Builder 6 - + Select files to analyze 选择要分析的文件 - + Select directory to analyze 选择要分析的目录 - + Select the configuration that will be analyzed 选择要分析的配置 - + Found project files from the directory. Do you want to proceed analysis without using any of these project files? @@ -1276,44 +1276,44 @@ Do you want to proceed analysis without using any of these project files? - + Duplicate define - + File not found: '%1' - + Failed to load/setup addon %1: %2 - + Failed to load %1. Your Cppcheck installation is broken. You can use --data-dir=<directory> at the command line to specify where this file is located. Please note that --data-dir is supposed to be used by installation scripts and therefore the GUI does not start when it is used, all that happens is that the setting is configured. Analysis is aborted. - + Failed to load %1 - %2 Analysis is aborted. - - + + %1 Analysis is aborted. - + Current results will be cleared. Opening a new XML file will clear current results. @@ -1324,7 +1324,7 @@ Do you want to proceed? 你想继续吗? - + Analyzer is running. Do you want to stop the analysis and exit Cppcheck? @@ -1333,77 +1333,77 @@ Do you want to stop the analysis and exit Cppcheck? 您想停止分析并退出 Cppcheck 吗? - + About - + XML files (*.xml);;Text files (*.txt);;CSV files (*.csv) XML 文件 (*.xml);;文本文件 (*.txt);;CSV 文件 (*.csv) - + Build dir '%1' does not exist, create it? 构建文件夹 '%1' 不能存在,创建它吗? - + To check the project using addons, you need a build directory. 要使用插件检查项目,您需要一个构建目录。 - + Show Mandatory - + Show Required - + Show Advisory - + Show Document - + Show L1 - + Show L2 - + Show L3 - + Show style - + Show portability - + Show performance - + Show information @@ -1412,22 +1412,22 @@ Do you want to stop the analysis and exit Cppcheck? 导入 '%1' 失败,分析已停止 - + Project files (*.cppcheck) 项目文件 (*.cppcheck) - + Select Project Filename 选择项目文件名 - + No project file loaded 项目文件未加载 - + The project file %1 diff --git a/gui/cppcheck_zh_TW.ts b/gui/cppcheck_zh_TW.ts index 1de96423481..841650ba5b1 100644 --- a/gui/cppcheck_zh_TW.ts +++ b/gui/cppcheck_zh_TW.ts @@ -427,18 +427,18 @@ Parameters: -l(line) (file) - - - - - - - - - - - - + + + + + + + + + + + + Cppcheck Cppcheck @@ -640,7 +640,7 @@ Parameters: -l(line) (file) - + Show errors 顯示錯誤 @@ -768,7 +768,7 @@ Parameters: -l(line) (file) - + Show warnings 顯示警告 @@ -1043,15 +1043,15 @@ Options: - + Quick Filter: 快速篩選: - - - + + + Project: 專案: @@ -1063,175 +1063,175 @@ This is probably because the settings were changed between the Cppcheck versions - + No suitable files found to analyze! 找不到適合的檔案來分析! - + You must close the project file before selecting new files or directories! 您必須在選取新檔案或目錄之前關閉該專案檔! - + C/C++ Source C/C++ 來源檔 - + Compile database 編譯資料庫 - + Visual Studio Visual Studio - + Borland C++ Builder 6 Borland C++ Builder 6 - + Select files to analyze 選取要分析的檔案 - + Select directory to analyze 選取要分析的目錄 - + Select configuration 選取組態 - + Select the configuration that will be analyzed 選取要分析的組態 - + Found project file: %1 Do you want to load this project file instead? - + Found project files from the directory. Do you want to proceed analysis without using any of these project files? - - + + Information 資訊 - + The library '%1' contains unknown elements: %2 - + File not found 找不到檔案 - + Bad XML - + Missing attribute - + Bad attribute value - + Unsupported format 未支援的格式 - + Duplicate platform type 重複的平臺型別 - + Platform type redefined 平臺型別重定義 - + Duplicate define - + Unknown element 未知的元素 - + Failed to load the selected library '%1'. %2 無法載入選取的程式庫 '%1'。 %2 - + File not found: '%1' - + Failed to load/setup addon %1: %2 - - - - + + + + Error 錯誤 - + Failed to load %1. Your Cppcheck installation is broken. You can use --data-dir=<directory> at the command line to specify where this file is located. Please note that --data-dir is supposed to be used by installation scripts and therefore the GUI does not start when it is used, all that happens is that the setting is configured. Analysis is aborted. - + Failed to load %1 - %2 Analysis is aborted. - - + + %1 Analysis is aborted. - + Current results will be cleared. Opening a new XML file will clear current results. @@ -1239,18 +1239,18 @@ Do you want to proceed? - - + + XML files (*.xml) XML 檔案 (*.xml) - + Open the report file 開啟報告檔 - + Analyzer is running. Do you want to stop the analysis and exit Cppcheck? @@ -1259,77 +1259,77 @@ Do you want to stop the analysis and exit Cppcheck? 您想停止分析並離開 Cppcheck 嗎? - + About 關於 - + License 授權 - + Authors 作者 - + XML files (*.xml);;Text files (*.txt);;CSV files (*.csv) XML 檔案 (*.xml);;文字檔 (*.txt);;CSV 檔案 (*.csv) - + Save the report file 儲存報告檔 - + Text files (*.txt) 文字檔 (*.txt) - + CSV files (*.csv) CSV 檔案 (*.csv) - + Project files (*.cppcheck);;All files(*.*) 專案檔 (*.cppcheck);;所有檔案 (*.*) - + Select Project File 選取專案檔 - + Build dir '%1' does not exist, create it? 建置目錄 '%1' 不存在,是否建立它? - + To check the project using addons, you need a build directory. - + Failed to open file 無法開啟檔案 - + Unknown project file format 未知的專案檔格式 - + Failed to import project file 無法匯入專案檔 - + Failed to import '%1': %2 Analysis is stopped. @@ -1338,62 +1338,62 @@ Analysis is stopped. 停止分析。 - + Failed to import '%1' (%2), analysis is stopped - + Show Mandatory - + Show Required - + Show Advisory - + Show Document - + Show L1 - + Show L2 - + Show L3 - + Show style - + Show portability - + Show performance - + Show information @@ -1402,22 +1402,22 @@ Analysis is stopped. 無法匯入 '%1',停止分析 - + Project files (*.cppcheck) 專案檔 (*.cppcheck) - + Select Project Filename 選取專案檔案名稱 - + No project file loaded - + The project file %1 @@ -1434,12 +1434,12 @@ Do you want to remove the file from the recently used projects -list? 您要從最近使用的專案列表中移除該檔案嗎? - + Install 安章 - + New version available: %1. %2 可用的新版本: %1. %2 From 9becbb6e8a3b98f080fbf2a44e18997602f65c5b Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Fri, 12 Jun 2026 15:50:12 +0200 Subject: [PATCH 015/165] Partial fix for #14833 FN returnDanglingLifetime with memcpy() (#8647) --- cfg/std.cfg | 28 ++++++++++++++-------------- test/cfg/std.cpp | 18 +++++++++++++++--- 2 files changed, 29 insertions(+), 17 deletions(-) diff --git a/cfg/std.cfg b/cfg/std.cfg index ec5fbb72548..245142c091d 100644 --- a/cfg/std.cfg +++ b/cfg/std.cfg @@ -3989,7 +3989,7 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun - + arg1 false @@ -4010,7 +4010,7 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun - + arg1 false @@ -4056,7 +4056,7 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun false - + arg1 @@ -4077,7 +4077,7 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun false - + arg1 @@ -4118,7 +4118,7 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun - + arg1 false @@ -4136,7 +4136,7 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun - + arg1 false @@ -4812,7 +4812,7 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun - + arg1 false @@ -4828,9 +4828,9 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun - + - + arg1 false @@ -4942,7 +4942,7 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun - + arg1 false @@ -5057,7 +5057,7 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun - + arg1 false @@ -5123,10 +5123,10 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun - + false - + arg1 @@ -5373,7 +5373,7 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun - + arg1 false diff --git a/test/cfg/std.cpp b/test/cfg/std.cpp index 0344b98455c..77c9d99cd5d 100644 --- a/test/cfg/std.cpp +++ b/test/cfg/std.cpp @@ -869,7 +869,7 @@ char * overlappingWriteFunction_strncat(const char *src, char *dest, const std:: // cppcheck-suppress overlappingWriteFunction (void)strncat(dest, dest+1, 2); char buffer[] = "strncat"; - // cppcheck-suppress overlappingWriteFunction + // cppcheck-suppress [overlappingWriteFunction,returnDanglingLifetime] return strncat(buffer, buffer + 1, 3); } @@ -882,7 +882,7 @@ wchar_t * overlappingWriteFunction_wcsncat(const wchar_t *src, wchar_t *dest, co // cppcheck-suppress overlappingWriteFunction (void)wcsncat(dest, dest+1, 2); wchar_t buffer[] = L"strncat"; - // cppcheck-suppress overlappingWriteFunction + // cppcheck-suppress [overlappingWriteFunction,returnDanglingLifetime] return wcsncat(buffer, buffer + 1, 3); } @@ -917,8 +917,8 @@ char * overlappingWriteFunction_strncpy(char *buf, const std::size_t count) void * overlappingWriteFunction_memmove(void) { - // No warning shall be shown: char str[] = "memmove handles overlapping data well"; + // cppcheck-suppress returnDanglingLifetime return memmove(str,str+3,4); } @@ -4982,6 +4982,18 @@ std::span returnDanglingLifetime_std_span1() { } #endif +void* returnDanglingLifetime_memcpy() { // #14833 + char a[4]; + // cppcheck-suppress returnDanglingLifetime + return memcpy(a, "abc", 4); +} + +wchar_t* returnDanglingLifetime_wcscat() { + wchar_t a[10]{L"abc"}; + // cppcheck-suppress returnDanglingLifetime + return wcscat(a, L"def"); +} + void beginEnd() { std::vector v; From 2fac13df7df98b719c411e9b26bc2a8e641a8372 Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Sun, 14 Jun 2026 22:32:36 +0200 Subject: [PATCH 016/165] Fix #14838 FP invalidLifetime, objectIndex with copy to pointer alias (#8649) Co-authored-by: chrchr-github --- lib/valueflow.cpp | 2 +- test/testvalueflow.cpp | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index 64a48285fdc..68e989c0738 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -2591,7 +2591,7 @@ static void valueFlowLifetimeFunction(Token *tok, const TokenList &tokenlist, Er std::vector args = getArguments(tok); if (iArg > 0 && iArg <= args.size()) { const Token* varTok = args[iArg - 1]; - if (varTok->variable() && varTok->variable()->isLocal()) + if (varTok->variable() && varTok->variable()->isLocal() && varTok->variable()->isArray()) LifetimeStore{ varTok, "Passed to '" + tok->str() + "'.", ValueFlow::Value::LifetimeKind::Address }.byRef( tok->next(), tokenlist, errorLogger, settings); } diff --git a/test/testvalueflow.cpp b/test/testvalueflow.cpp index 65f198dcbab..0c8addb3b94 100644 --- a/test/testvalueflow.cpp +++ b/test/testvalueflow.cpp @@ -908,6 +908,19 @@ class TestValueFlow : public TestFixture { ASSERT_EQUALS(true, lifetimes.size() == 1); ASSERT_EQUALS(true, lifetimes.front() == "a"); } + { + const char code[] = "void f(const char *s, size_t len) {\n" + " char buf[10];\n" + " {\n" + " char *tmp = buf;\n" + " s = strcpy(tmp, s);\n" + " }\n" + " if (s[len] == '\0') {}\n" + "}\n"; + lifetimes = lifetimeValues(code, "s ["); + ASSERT_EQUALS(true, lifetimes.size() == 1); + ASSERT_EQUALS(true, lifetimes.front() == "buf"); + } } void valueFlowArrayElement() { From 987d3b48a3fe1591444e9586da59e62feb4a7510 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Berder?= <18538310+francois-berder@users.noreply.github.com> Date: Mon, 15 Jun 2026 00:30:27 +0200 Subject: [PATCH 017/165] fwdanalysis: Remove unused What::ValueFlow mode (#8650) The What::ValueFlow mode and its state (mValueFlow, mValueFlowKnown, KnownAndToken) are not used since commit 921887a281, which switched to valueFlowForwardExpression instead of FwdAnalysis::valueFlow(). --- lib/fwdanalysis.cpp | 85 ++++----------------------------------------- lib/fwdanalysis.h | 14 ++------ 2 files changed, 9 insertions(+), 90 deletions(-) diff --git a/lib/fwdanalysis.cpp b/lib/fwdanalysis.cpp index c45213a4be9..ddcbbbd1fa9 100644 --- a/lib/fwdanalysis.cpp +++ b/lib/fwdanalysis.cpp @@ -30,6 +30,7 @@ #include #include #include +#include static bool isUnchanged(const Token *startToken, const Token *endToken, const std::set &exprVarIds, bool local) { @@ -94,7 +95,7 @@ static bool hasVolatileCastOrVar(const Token *expr) return ret; } -FwdAnalysis::Result FwdAnalysis::checkRecursive(const Token *expr, const Token *startToken, const Token *endToken, const std::set &exprVarIds, bool local, bool inInnerClass, int depth) +FwdAnalysis::Result FwdAnalysis::checkRecursive(const Token *expr, const Token *startToken, const Token *endToken, const std::set &exprVarIds, bool local, bool inInnerClass, int depth) const { // Parse the given tokens if (++depth > 1000) @@ -155,10 +156,6 @@ FwdAnalysis::Result FwdAnalysis::checkRecursive(const Token *expr, const Token * } if (tok->str() == "}") { - // Known value => possible value - if (tok->scope() == expr->scope()) - mValueFlowKnown = false; - if (tok->scope()->isLoopScope()) { // check condition const Token *conditionStart = nullptr; @@ -195,65 +192,6 @@ FwdAnalysis::Result FwdAnalysis::checkRecursive(const Token *expr, const Token * if (Token::simpleMatch(tok, "asm (")) return Result(Result::Type::BAILOUT); - if (mWhat == What::ValueFlow && (Token::Match(tok, "while|for (") || Token::simpleMatch(tok, "do {"))) { - const Token *bodyStart = nullptr; - const Token *conditionStart = nullptr; - if (Token::simpleMatch(tok, "do {")) { - bodyStart = tok->next(); - if (Token::simpleMatch(bodyStart->link(), "} while (")) - conditionStart = bodyStart->link()->tokAt(2); - } else { - conditionStart = tok->next(); - if (Token::simpleMatch(conditionStart->link(), ") {")) - bodyStart = conditionStart->link()->next(); - } - - if (!bodyStart || !conditionStart) - return Result(Result::Type::BAILOUT); - - // Is expr changed in condition? - if (!isUnchanged(conditionStart, conditionStart->link(), exprVarIds, local)) - return Result(Result::Type::BAILOUT); - - // Is expr changed in loop body? - if (!isUnchanged(bodyStart, bodyStart->link(), exprVarIds, local)) - return Result(Result::Type::BAILOUT); - } - - if (mWhat == What::ValueFlow && Token::simpleMatch(tok, "if (") && Token::simpleMatch(tok->linkAt(1), ") {")) { - const Token *bodyStart = tok->linkAt(1)->next(); - const Token *conditionStart = tok->next(); - const Token *condTok = conditionStart->astOperand2(); - if (const ValueFlow::Value* v = condTok->getKnownValue(ValueFlow::Value::ValueType::INT)) { - const bool cond = !!v->intvalue; - if (cond) { - FwdAnalysis::Result result = checkRecursive(expr, bodyStart, bodyStart->link(), exprVarIds, local, true, depth); - if (result.type != Result::Type::NONE) - return result; - } else if (Token::simpleMatch(bodyStart->link(), "} else {")) { - bodyStart = bodyStart->link()->tokAt(2); - FwdAnalysis::Result result = checkRecursive(expr, bodyStart, bodyStart->link(), exprVarIds, local, true, depth); - if (result.type != Result::Type::NONE) - return result; - } - } - tok = bodyStart->link(); - if (isReturnScope(tok, mSettings.library)) - return Result(Result::Type::BAILOUT); - if (Token::simpleMatch(tok, "} else {")) - tok = tok->linkAt(2); - if (!tok) - return Result(Result::Type::BAILOUT); - - // Is expr changed in condition? - if (!isUnchanged(conditionStart, conditionStart->link(), exprVarIds, local)) - return Result(Result::Type::BAILOUT); - - // Is expr changed in condition body? - if (!isUnchanged(bodyStart, bodyStart->link(), exprVarIds, local)) - return Result(Result::Type::BAILOUT); - } - if (!local && Token::Match(tok, "%name% (") && !Token::simpleMatch(tok->linkAt(1), ") {")) { // TODO: this is a quick bailout return Result(Result::Type::BAILOUT); @@ -279,22 +217,15 @@ FwdAnalysis::Result FwdAnalysis::checkRecursive(const Token *expr, const Token * parent = parent->astParent(); if (parent->str() == "(" && !parent->isCast()) break; - if (isSameExpression(false, expr, parent, mSettings, true, false, nullptr)) { + if (isSameExpression(false, expr, parent, mSettings, true, false, nullptr)) same = true; - if (mWhat == What::ValueFlow) { - KnownAndToken v; - v.known = mValueFlowKnown; - v.token = parent; - mValueFlow.push_back(v); - } - } if (Token::Match(parent, ". %var%") && parent->next()->varId() && exprVarIds.find(parent->next()->varId()) == exprVarIds.end() && isSameExpression(false, expr->astOperand1(), parent->astOperand1(), mSettings, true, false, nullptr)) { other = true; break; } } - if (mWhat != What::ValueFlow && same && Token::simpleMatch(parent->astParent(), "[") && parent == parent->astParent()->astOperand2()) { + if (same && Token::simpleMatch(parent->astParent(), "[") && parent == parent->astParent()->astOperand2()) { return Result(Result::Type::READ); } if (other) @@ -381,8 +312,6 @@ FwdAnalysis::Result FwdAnalysis::checkRecursive(const Token *expr, const Token * return result1; if (mWhat == What::UnusedValue && result1.type == Result::Type::WRITE && expr->variable() && expr->variable()->isReference()) return result1; - if (mWhat == What::ValueFlow && result1.type == Result::Type::WRITE) - mValueFlowKnown = false; if (mWhat == What::Reassign && result1.type == Result::Type::BREAK) { const Token *scopeEndToken = findNextTokenFromBreak(result1.token); if (scopeEndToken) { @@ -394,8 +323,6 @@ FwdAnalysis::Result FwdAnalysis::checkRecursive(const Token *expr, const Token * if (Token::simpleMatch(tok->linkAt(1), "} else {")) { const Token *elseStart = tok->linkAt(1)->tokAt(2); const Result &result2 = checkRecursive(expr, elseStart, elseStart->link(), exprVarIds, local, inInnerClass, depth); - if (mWhat == What::ValueFlow && result2.type == Result::Type::WRITE) - mValueFlowKnown = false; if (result2.type == Result::Type::READ || result2.type == Result::Type::BAILOUT) return result2; if (result1.type == Result::Type::WRITE && result2.type == Result::Type::WRITE) @@ -454,7 +381,7 @@ std::set FwdAnalysis::getExprVarIds(const Token* expr, bool* localOu return exprVarIds; } -FwdAnalysis::Result FwdAnalysis::check(const Token* expr, const Token* startToken, const Token* endToken) +FwdAnalysis::Result FwdAnalysis::check(const Token* expr, const Token* startToken, const Token* endToken) const { // all variable ids in expr. bool local = true; @@ -475,7 +402,7 @@ FwdAnalysis::Result FwdAnalysis::check(const Token* expr, const Token* startToke Result result = checkRecursive(expr, startToken, endToken, exprVarIds, local, false); // Break => continue checking in outer scope - while (mWhat!=What::ValueFlow && result.type == FwdAnalysis::Result::Type::BREAK) { + while (result.type == FwdAnalysis::Result::Type::BREAK) { const Token *scopeEndToken = findNextTokenFromBreak(result.token); if (!scopeEndToken) break; diff --git a/lib/fwdanalysis.h b/lib/fwdanalysis.h index 389ea195da2..34d0da24d4d 100644 --- a/lib/fwdanalysis.h +++ b/lib/fwdanalysis.h @@ -25,7 +25,6 @@ #include #include -#include class Token; class Settings; @@ -60,11 +59,6 @@ class FwdAnalysis { */ bool unusedValue(const Token *expr, const Token *startToken, const Token *endToken); - struct KnownAndToken { - bool known{}; - const Token* token{}; - }; - /** Is there some possible alias for given expression */ bool possiblyAliased(const Token *expr, const Token *startToken) const; @@ -80,13 +74,11 @@ class FwdAnalysis { const Token* token{}; }; - Result check(const Token *expr, const Token *startToken, const Token *endToken); - Result checkRecursive(const Token *expr, const Token *startToken, const Token *endToken, const std::set &exprVarIds, bool local, bool inInnerClass, int depth=0); + Result check(const Token *expr, const Token *startToken, const Token *endToken) const; + Result checkRecursive(const Token *expr, const Token *startToken, const Token *endToken, const std::set &exprVarIds, bool local, bool inInnerClass, int depth=0) const; const Settings &mSettings; - enum class What : std::uint8_t { Reassign, UnusedValue, ValueFlow } mWhat = What::Reassign; - std::vector mValueFlow; - bool mValueFlowKnown = true; + enum class What : std::uint8_t { Reassign, UnusedValue } mWhat = What::Reassign; }; #endif // fwdanalysisH From a7faefc9203cf14850ea4e4d35aed0f854eaeccd Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Tue, 16 Jun 2026 08:53:23 +0200 Subject: [PATCH 018/165] Fix #14847 Function pointer argument triggers false positive funcArgNamesDifferentUnnamed (#8653) --- lib/checkother.cpp | 4 ++-- test/testother.cpp | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/checkother.cpp b/lib/checkother.cpp index 801dc529568..551c3a47543 100644 --- a/lib/checkother.cpp +++ b/lib/checkother.cpp @@ -4043,7 +4043,7 @@ void CheckOtherImpl::checkFuncArgNamesDifferent() definitions[j] = variable->nameToken(); } // get the declaration (search for first token with varId) - while (decl && !Token::Match(decl, ",|)|;")) { + while (decl && !Token::Match(decl, "[,;]")) { // skip everything after the assignment because // it could also have a varId or be the first // token with a varId if there is no name token @@ -4052,7 +4052,7 @@ void CheckOtherImpl::checkFuncArgNamesDifferent() break; } // skip over templates and arrays - if (decl->link() && decl->str() != "(") + if (decl->link() && !Token::Match(decl, "[()]")) decl = decl->link(); else if (decl->varId()) declarations[j] = decl; diff --git a/test/testother.cpp b/test/testother.cpp index 73f10cbe76e..c8a95c9882b 100644 --- a/test/testother.cpp +++ b/test/testother.cpp @@ -12955,6 +12955,10 @@ class TestOther : public TestFixture { "[test.cpp:1:12]: (style, inconclusive) Function 'f' argument 1 names different: declaration 'a' definition ''. [funcArgNamesDifferentUnnamed]\n" "[test.cpp:4:12]: (style, inconclusive) Function 'g' argument 1 names different: declaration '' definition 'b'. [funcArgNamesDifferentUnnamed]\n", errout_str()); + + check("void f(void (*fp)(), int x);\n" // #14847 + "void f(void (*fp)(), int x) {}\n"); + ASSERT_EQUALS("", errout_str()); } void funcArgOrderDifferent() { From 051584cdbd6b0292e55492ea29cc1ef762eab7e1 Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Tue, 16 Jun 2026 19:28:59 +0200 Subject: [PATCH 019/165] Refs #12986: Tokenizer: don't simplify init list containing default-constructed element (#8640) --- lib/tokenize.cpp | 3 ++- test/testsimplifytokens.cpp | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index c5b001f5d32..f195cdd7ad6 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -3862,7 +3862,8 @@ void Tokenizer::simplifyRedundantConsecutiveBraces() for (Token *tok = list.front(); tok;) { if (Token::simpleMatch(tok, "= {")) { tok = tok->linkAt(1); - } else if (Token::simpleMatch(tok, "{ {") && Token::simpleMatch(tok->linkAt(1), "} }")) { + } else if (Token::simpleMatch(tok, "{ {") && Token::simpleMatch(tok->linkAt(1), "} }") && + !Token::Match(tok->previous(), "%name%")) { //remove internal parentheses tok->linkAt(1)->deleteThis(); tok->deleteNext(); diff --git a/test/testsimplifytokens.cpp b/test/testsimplifytokens.cpp index 6077438a9cf..2f04653a379 100644 --- a/test/testsimplifytokens.cpp +++ b/test/testsimplifytokens.cpp @@ -1422,6 +1422,7 @@ class TestSimplifyTokens : public TestFixture { ASSERT_EQUALS("void f ( ) { }", tok("void f(){{{}}}")); ASSERT_EQUALS("void f ( ) { for ( ; ; ) { } }", tok("void f () { for(;;){} }")); ASSERT_EQUALS("void f ( ) { { scope_lock lock ; foo ( ) ; } { scope_lock lock ; bar ( ) ; } }", tok("void f () { {scope_lock lock; foo();} {scope_lock lock; bar();} }")); + ASSERT_EQUALS("std :: map < int , int > m { { } } ;", tok("std::map m{ {} };")); } void simplifyOverride() { // ticket #5069 From 1d0ff1a3518ea32b87f175957dfe65cb92e94607 Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Tue, 16 Jun 2026 21:39:44 +0200 Subject: [PATCH 020/165] Fix #14842 FN memleak in function with trailing return type (regression) (#8651) Co-authored-by: chrchr-github --- lib/tokenize.cpp | 19 +++++++++++++++++-- test/testtokenize.cpp | 27 +++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 2 deletions(-) diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index f195cdd7ad6..59da46a0b28 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -7334,6 +7334,19 @@ void Tokenizer::simplifyVarDecl(const bool only_k_r_fpar) simplifyVarDecl(list.front(), nullptr, only_k_r_fpar); } +static Token* isTrailingReturnType(Token* tok) +{ + while (Token::Match(tok, "%name%|::|>")) { + if (Token* open = tok->findOpeningBracket()) + tok = open->tokAt(-1); + else + tok = tok->tokAt(-1); + } + if (tok && Token::simpleMatch(tok->tokAt(-1), ") .")) + return tok->tokAt(-1); + return nullptr; +} + // cppcheck-suppress functionConst - has side effects void Tokenizer::simplifyVarDecl(Token * tokBegin, const Token * const tokEnd, const bool only_k_r_fpar) { @@ -7361,14 +7374,16 @@ void Tokenizer::simplifyVarDecl(Token * tokBegin, const Token * const tokEnd, co if (!tok->linkAt(1)) syntaxError(tokBegin); // Check for lambdas before skipping - if (Token::Match(tok->tokAt(-2), ") . %name%")) { // trailing return type + if (Token* trailingStart = isTrailingReturnType(tok)) { // TODO: support lambda without parameter clause? - Token* lambdaStart = tok->linkAt(-2)->previous(); + Token* lambdaStart = trailingStart->link()->tokAt(-1); if (Token::simpleMatch(lambdaStart, "]")) lambdaStart = lambdaStart->link(); Token* lambdaEnd = findLambdaEndScope(lambdaStart); if (lambdaEnd) simplifyVarDecl(lambdaEnd->link()->next(), lambdaEnd, only_k_r_fpar); + else + simplifyVarDecl(tok->tokAt(2), tok->linkAt(1), only_k_r_fpar); } else { for (Token* tok2 = tok->next(); tok2 != tok->linkAt(1); tok2 = tok2->next()) { Token* lambdaEnd = findLambdaEndScope(tok2); diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp index 5f4d59503e2..b1e3e87cdcf 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -233,6 +233,7 @@ class TestTokenizer : public TestFixture { TEST_CASE(vardecl32); TEST_CASE(vardecl33); TEST_CASE(vardecl34); + TEST_CASE(vardecl35); TEST_CASE(vardecl_stl_1); TEST_CASE(vardecl_stl_2); TEST_CASE(vardecl_stl_3); @@ -2857,6 +2858,32 @@ class TestTokenizer : public TestFixture { } } + void vardecl35() { // #14842 + { + const char code[] = "auto f() -> void {\n" + " auto p = new int;\n" + " *p = 0;\n" + "}\n"; + ASSERT_EQUALS("auto f ( ) . void {\n" + "auto p ; p = new int ;\n" + "* p = 0 ;\n" + "}", tokenizeAndStringify(code)); + ignore_errout(); + } + { + const char code[] = "auto f() -> ::std::vector {\n" + " int i = 0;\n" + " return { i };\n" + "}"; + ASSERT_EQUALS("auto f ( ) . :: std :: vector < int > {\n" + "int i ; i = 0 ;\n" + "return { i } ;\n" + "}", + tokenizeAndStringify(code)); + ignore_errout(); + } + } + void volatile_variables() { { const char code[] = "volatile int a=0;\n" From 6f17c161fddd038b82072027097de58b4b5f35c0 Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Tue, 16 Jun 2026 21:48:38 +0200 Subject: [PATCH 021/165] Fix #11751 FP accessMoved after passing value to function (#8646) --- lib/forwardanalyzer.cpp | 2 +- test/testvalueflow.cpp | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/lib/forwardanalyzer.cpp b/lib/forwardanalyzer.cpp index 5c97528372b..0999a08d908 100644 --- a/lib/forwardanalyzer.cpp +++ b/lib/forwardanalyzer.cpp @@ -845,7 +845,7 @@ namespace { return Break(); } else if (Token* callTok = callExpr(tok)) { // TODO: Dont traverse tokens a second time - if (start != callTok && tok != callTok && updateRecursive(callTok->astOperand1()) == Progress::Break) + if (start != callTok && tok != callTok && (tok->str() != "." || tok != callTok->astOperand1()) && updateRecursive(callTok->astOperand1()) == Progress::Break) return Break(); // Since the call could be an unknown macro, traverse the tokens as a range instead of recursively if (!Token::simpleMatch(callTok, "( )") && diff --git a/test/testvalueflow.cpp b/test/testvalueflow.cpp index 0c8addb3b94..247d2ae6012 100644 --- a/test/testvalueflow.cpp +++ b/test/testvalueflow.cpp @@ -1090,6 +1090,14 @@ class TestValueFlow : public TestFixture { " }\n" "}\n"; ASSERT_EQUALS(false, testValueOfX(code, 13U, ValueFlow::Value::MoveKind::MovedVariable)); + + code = "struct S { int f(int); };\n" // #11751 + "S g(S);\n" + "void h() {\n" + " S x;\n" + " g(std::move(x)).f(1);\n" + "}\n"; + ASSERT_EQUALS(false, testValueOfX(code, 5U, ValueFlow::Value::MoveKind::MovedVariable)); } void valueFlowCalculations() { From 4a4e12d323cefc23ed5066cffbfbcf988c80b351 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20St=C3=B6neberg?= Date: Tue, 16 Jun 2026 22:13:05 +0200 Subject: [PATCH 022/165] fixed #14084 - run CMake with `--warn-uninitialized` in CI (#8290) --- .github/workflows/CI-unixish-docker.yml | 2 +- .github/workflows/CI-unixish.yml | 40 +++++++++++++------------ .github/workflows/CI-windows.yml | 6 ++-- .github/workflows/clang-tidy.yml | 2 +- .github/workflows/iwyu.yml | 4 +-- .github/workflows/release-windows.yml | 2 +- .github/workflows/sanitizers.yml | 2 +- .github/workflows/selfcheck.yml | 10 +++---- cmake/options.cmake | 2 +- 9 files changed, 36 insertions(+), 34 deletions(-) diff --git a/.github/workflows/CI-unixish-docker.yml b/.github/workflows/CI-unixish-docker.yml index a38feb452f0..16c1615ed04 100644 --- a/.github/workflows/CI-unixish-docker.yml +++ b/.github/workflows/CI-unixish-docker.yml @@ -72,7 +72,7 @@ jobs: - name: Run CMake run: | - cmake -S . -B cmake.output -Werror=dev -DHAVE_RULES=On -DBUILD_TESTING=On -DBUILD_GUI=${{ matrix.with_gui }} -DWITH_QCHART=On -DBUILD_TRIAGE=${{ matrix.with_gui }} -DCMAKE_COMPILE_WARNING_AS_ERROR=On -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache + cmake -S . -B cmake.output -Werror=dev --warn-uninitialized -DHAVE_RULES=On -DBUILD_TESTING=On -DBUILD_GUI=${{ matrix.with_gui }} -DWITH_QCHART=On -DBUILD_TRIAGE=${{ matrix.with_gui }} -DCMAKE_COMPILE_WARNING_AS_ERROR=On -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache - name: CMake build if: matrix.full_build diff --git a/.github/workflows/CI-unixish.yml b/.github/workflows/CI-unixish.yml index 3251a6b5adb..4a7d94c4057 100644 --- a/.github/workflows/CI-unixish.yml +++ b/.github/workflows/CI-unixish.yml @@ -58,13 +58,13 @@ jobs: - name: CMake build on ubuntu (with GUI / system tinyxml2) if: contains(matrix.os, 'ubuntu') run: | - cmake -S . -B cmake.output.tinyxml2 -Werror=dev -DHAVE_RULES=On -DBUILD_TESTING=On -DBUILD_GUI=On -DWITH_QCHART=On -DBUILD_TRIAGE=On -DUSE_BUNDLED_TINYXML2=Off -DCMAKE_DISABLE_PRECOMPILE_HEADERS=On -DCMAKE_COMPILE_WARNING_AS_ERROR=On -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache + cmake -S . -B cmake.output.tinyxml2 -Werror=dev --warn-uninitialized -DHAVE_RULES=On -DBUILD_TESTING=On -DBUILD_GUI=On -DWITH_QCHART=On -DBUILD_TRIAGE=On -DUSE_BUNDLED_TINYXML2=Off -DCMAKE_DISABLE_PRECOMPILE_HEADERS=On -DCMAKE_COMPILE_WARNING_AS_ERROR=On -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache cmake --build cmake.output.tinyxml2 -- -j$(nproc) - name: CMake build on macos (with GUI / system tinyxml2) if: contains(matrix.os, 'macos') run: | - cmake -S . -B cmake.output.tinyxml2 -Werror=dev -DHAVE_RULES=On -DBUILD_TESTING=On -DBUILD_GUI=On -DWITH_QCHART=On -DBUILD_TRIAGE=On -DUSE_BUNDLED_TINYXML2=Off -DCMAKE_DISABLE_PRECOMPILE_HEADERS=On -DCMAKE_COMPILE_WARNING_AS_ERROR=On -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DQt6_DIR=$(brew --prefix qt@6)/lib/cmake/Qt6 + cmake -S . -B cmake.output.tinyxml2 -Werror=dev --warn-uninitialized -DHAVE_RULES=On -DBUILD_TESTING=On -DBUILD_GUI=On -DWITH_QCHART=On -DBUILD_TRIAGE=On -DUSE_BUNDLED_TINYXML2=Off -DCMAKE_DISABLE_PRECOMPILE_HEADERS=On -DCMAKE_COMPILE_WARNING_AS_ERROR=On -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DQt6_DIR=$(brew --prefix qt@6)/lib/cmake/Qt6 cmake --build cmake.output.tinyxml2 -- -j$(nproc) - name: Run CMake test (system tinyxml2) @@ -127,12 +127,12 @@ jobs: - name: Run CMake on ubuntu (with GUI) if: contains(matrix.os, 'ubuntu') run: | - cmake -S . -B cmake.output -Werror=dev -DHAVE_RULES=On -DBUILD_TESTING=On -DBUILD_GUI=On -DWITH_QCHART=On -DBUILD_TRIAGE=On -DCMAKE_DISABLE_PRECOMPILE_HEADERS=On -DCMAKE_COMPILE_WARNING_AS_ERROR=On -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_INSTALL_PREFIX=cppcheck-cmake-install + cmake -S . -B cmake.output -Werror=dev --warn-uninitialized -DHAVE_RULES=On -DBUILD_TESTING=On -DBUILD_GUI=On -DWITH_QCHART=On -DBUILD_TRIAGE=On -DCMAKE_DISABLE_PRECOMPILE_HEADERS=On -DCMAKE_COMPILE_WARNING_AS_ERROR=On -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_INSTALL_PREFIX=cppcheck-cmake-install - name: Run CMake on macos (with GUI) if: contains(matrix.os, 'macos') run: | - cmake -S . -B cmake.output -Werror=dev -DHAVE_RULES=On -DBUILD_TESTING=On -DBUILD_GUI=On -DWITH_QCHART=On -DBUILD_TRIAGE=On -DCMAKE_DISABLE_PRECOMPILE_HEADERS=On -DCMAKE_COMPILE_WARNING_AS_ERROR=On -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_INSTALL_PREFIX=cppcheck-cmake-install -DQt6_DIR=$(brew --prefix qt@6)/lib/cmake/Qt6 + cmake -S . -B cmake.output -Werror=dev --warn-uninitialized -DHAVE_RULES=On -DBUILD_TESTING=On -DBUILD_GUI=On -DWITH_QCHART=On -DBUILD_TRIAGE=On -DCMAKE_DISABLE_PRECOMPILE_HEADERS=On -DCMAKE_COMPILE_WARNING_AS_ERROR=On -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_INSTALL_PREFIX=cppcheck-cmake-install -DQt6_DIR=$(brew --prefix qt@6)/lib/cmake/Qt6 - name: Run CMake build run: | @@ -154,13 +154,13 @@ jobs: - name: Run CMake on ubuntu (no CLI) if: matrix.os == 'ubuntu-22.04' run: | - cmake -S . -B cmake.output_nocli -Werror=dev -DBUILD_TESTING=Off -DBUILD_CLI=Off + cmake -S . -B cmake.output_nocli -Werror=dev --warn-uninitialized -DBUILD_TESTING=Off -DBUILD_CLI=Off - name: Run CMake on ubuntu (no CLI / with tests) if: matrix.os == 'ubuntu-22.04' run: | # the test and CLI code are too intertwined so for now we need to reject that - if cmake -S . -B cmake.output_nocli_tests -Werror=dev -DBUILD_TESTING=On -DBUILD_CLI=Off; then + if cmake -S . -B cmake.output_nocli_tests -Werror=dev --warn-uninitialized -DBUILD_TESTING=On -DBUILD_CLI=Off; then exit 1 else exit 0 @@ -169,18 +169,18 @@ jobs: - name: Run CMake on ubuntu (no CLI / with GUI) if: matrix.os == 'ubuntu-22.04' run: | - cmake -S . -B cmake.output_nocli_gui -Werror=dev -DBUILD_TESTING=Off -DBUILD_CLI=Off -DBUILD_GUI=On + cmake -S . -B cmake.output_nocli_gui -Werror=dev --warn-uninitialized -DBUILD_TESTING=Off -DBUILD_CLI=Off -DBUILD_GUI=On - name: Run CMake on ubuntu (no GUI) if: matrix.os == 'ubuntu-22.04' run: | - cmake -S . -B cmake.output_nogui -Werror=dev -DBUILD_TESTING=Off -DBUILD_GUI=Off + cmake -S . -B cmake.output_nogui -Werror=dev --warn-uninitialized -DBUILD_TESTING=Off -DBUILD_GUI=Off - name: Run CMake on ubuntu (no GUI / with triage) if: matrix.os == 'ubuntu-22.04' run: | # cannot build triage without GUI - if cmake -S . -B cmake.output_nogui_triage -Werror=dev -DBUILD_TESTING=Off -DBUILD_GUI=Off -DBUILD_TRIAGE=On; then + if cmake -S . -B cmake.output_nogui_triage -Werror=dev --warn-uninitialized -DBUILD_TESTING=Off -DBUILD_GUI=Off -DBUILD_TRIAGE=On; then exit 1 else exit 0 @@ -189,7 +189,7 @@ jobs: - name: Run CMake on ubuntu (no CLI / no GUI) if: matrix.os == 'ubuntu-22.04' run: | - cmake -S . -B cmake.output_nocli_nogui -Werror=dev -DBUILD_TESTING=Off -DBUILD_GUI=Off + cmake -S . -B cmake.output_nocli_nogui -Werror=dev --warn-uninitialized -DBUILD_TESTING=Off -DBUILD_GUI=Off build_cmake_cxxstd: @@ -243,12 +243,12 @@ jobs: - name: Run CMake on ubuntu (with GUI) if: contains(matrix.os, 'ubuntu') run: | - cmake -S . -B cmake.output -Werror=dev -DCMAKE_CXX_STANDARD=${{ matrix.cxxstd }} -DHAVE_RULES=On -DBUILD_TESTING=On -DBUILD_GUI=On -DWITH_QCHART=On -DBUILD_TRIAGE=On -DCMAKE_DISABLE_PRECOMPILE_HEADERS=On -DCMAKE_COMPILE_WARNING_AS_ERROR=On -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache + cmake -S . -B cmake.output -Werror=dev --warn-uninitialized -DCMAKE_CXX_STANDARD=${{ matrix.cxxstd }} -DHAVE_RULES=On -DBUILD_TESTING=On -DBUILD_GUI=On -DWITH_QCHART=On -DBUILD_TRIAGE=On -DCMAKE_DISABLE_PRECOMPILE_HEADERS=On -DCMAKE_COMPILE_WARNING_AS_ERROR=On -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache - name: Run CMake on macos (with GUI) if: contains(matrix.os, 'macos') run: | - cmake -S . -B cmake.output -Werror=dev -DCMAKE_CXX_STANDARD=${{ matrix.cxxstd }} -DHAVE_RULES=On -DBUILD_TESTING=On -DBUILD_GUI=On -DWITH_QCHART=On -DBUILD_TRIAGE=On -DCMAKE_DISABLE_PRECOMPILE_HEADERS=On -DCMAKE_COMPILE_WARNING_AS_ERROR=On -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DQt6_DIR=$(brew --prefix qt@6)/lib/cmake/Qt6 + cmake -S . -B cmake.output -Werror=dev --warn-uninitialized -DCMAKE_CXX_STANDARD=${{ matrix.cxxstd }} -DHAVE_RULES=On -DBUILD_TESTING=On -DBUILD_GUI=On -DWITH_QCHART=On -DBUILD_TRIAGE=On -DCMAKE_DISABLE_PRECOMPILE_HEADERS=On -DCMAKE_COMPILE_WARNING_AS_ERROR=On -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DQt6_DIR=$(brew --prefix qt@6)/lib/cmake/Qt6 - name: Run CMake build run: | @@ -373,7 +373,7 @@ jobs: run: | # make sure we fail when Boost is requested and not available. # will fail because no package configuration is available. - if cmake -S . -B cmake.output.boost-force-noavail -Werror=dev -DBUILD_TESTING=Off -DUSE_BOOST=On; then + if cmake -S . -B cmake.output.boost-force-noavail -Werror=dev --warn-uninitialized -DBUILD_TESTING=Off -DUSE_BOOST=On; then exit 1 else exit 0 @@ -386,12 +386,12 @@ jobs: - name: Run CMake on macOS (force Boost) run: | - cmake -S . -B cmake.output.boost-force -Werror=dev -DBUILD_TESTING=Off -DUSE_BOOST=On + cmake -S . -B cmake.output.boost-force -Werror=dev --warn-uninitialized -DBUILD_TESTING=Off -DUSE_BOOST=On - name: Run CMake on macOS (no Boost) run: | # make sure Boost is not used when disabled even though it is available - cmake -S . -B cmake.output.boost-no -Werror=dev -DBUILD_TESTING=Off -DUSE_BOOST=Off + cmake -S . -B cmake.output.boost-no -Werror=dev --warn-uninitialized -DBUILD_TESTING=Off -DUSE_BOOST=Off if grep -q '\-DHAVE_BOOST' ./cmake.output.boost-no/compile_commands.json; then exit 1 else @@ -400,7 +400,7 @@ jobs: - name: Run CMake on macOS (with Boost) run: | - cmake -S . -B cmake.output.boost -Werror=dev -DBUILD_TESTING=On -DCMAKE_DISABLE_PRECOMPILE_HEADERS=On -DCMAKE_COMPILE_WARNING_AS_ERROR=On -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache + cmake -S . -B cmake.output.boost -Werror=dev --warn-uninitialized -DBUILD_TESTING=On -DCMAKE_DISABLE_PRECOMPILE_HEADERS=On -DCMAKE_COMPILE_WARNING_AS_ERROR=On -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache grep -q '\-DHAVE_BOOST' ./cmake.output.boost/compile_commands.json - name: Build with CMake on macOS (with Boost) @@ -436,11 +436,13 @@ jobs: - name: Run CMake (without GUI) run: | export PATH=cmake-${{ env.CMAKE_VERSION_FULL }}-linux-x86_64/bin:$PATH + # FIXME: cannot use --warn-uninitialized here as it completely breaks the build cmake -S . -B cmake.output -Werror=dev -DHAVE_RULES=On -DBUILD_TESTING=On - name: Run CMake (with GUI) run: | export PATH=cmake-${{ env.CMAKE_VERSION_FULL }}-linux-x86_64/bin:$PATH + # FIXME: cannot use --warn-uninitialized here as it completely breaks the build cmake -S . -B cmake.output.gui -Werror=dev -DHAVE_RULES=On -DBUILD_TESTING=On -DBUILD_GUI=On -DWITH_QCHART=On -DBUILD_TRIAGE=On build: @@ -596,7 +598,7 @@ jobs: - name: Test Signalhandler run: | - cmake -S . -B build.cmake.signal -Werror=dev -DBUILD_TESTING=On -DCMAKE_COMPILE_WARNING_AS_ERROR=On + cmake -S . -B build.cmake.signal -Werror=dev --warn-uninitialized -DBUILD_TESTING=On -DCMAKE_COMPILE_WARNING_AS_ERROR=On cmake --build build.cmake.signal --target test-signalhandler -- -j$(nproc) # TODO: how to run this without copying the file? cp build.cmake.signal/bin/test-s* . @@ -607,7 +609,7 @@ jobs: - name: Test Stacktrace if: contains(matrix.os, 'ubuntu') run: | - cmake -S . -B build.cmake.stack -Werror=dev -DBUILD_TESTING=On -DCMAKE_COMPILE_WARNING_AS_ERROR=On + cmake -S . -B build.cmake.stack -Werror=dev --warn-uninitialized -DBUILD_TESTING=On -DCMAKE_COMPILE_WARNING_AS_ERROR=On cmake --build build.cmake.stack --target test-stacktrace -- -j$(nproc) # TODO: how to run this without copying the file? cp build.cmake.stack/bin/test-s* . @@ -734,7 +736,7 @@ jobs: - name: CMake run: | - cmake -S . -B cmake.output -Werror=dev -DHAVE_RULES=On -DBUILD_TESTING=On -DBUILD_GUI=On -DWITH_QCHART=On -DBUILD_TRIAGE=On -DUSE_MATCHCOMPILER=Verify -DENABLE_CHECK_INTERNAL=On -DCPPCHK_GLIBCXX_DEBUG=Off -DCMAKE_DISABLE_PRECOMPILE_HEADERS=On -DCMAKE_GLOBAL_AUTOGEN_TARGET=On -DDISABLE_DMAKE=On + cmake -S . -B cmake.output -Werror=dev --warn-uninitialized -DHAVE_RULES=On -DBUILD_TESTING=On -DBUILD_GUI=On -DWITH_QCHART=On -DBUILD_TRIAGE=On -DUSE_MATCHCOMPILER=Verify -DENABLE_CHECK_INTERNAL=On -DCPPCHK_GLIBCXX_DEBUG=Off -DCMAKE_DISABLE_PRECOMPILE_HEADERS=On -DCMAKE_GLOBAL_AUTOGEN_TARGET=On -DDISABLE_DMAKE=On - name: Generate dependencies run: | diff --git a/.github/workflows/CI-windows.yml b/.github/workflows/CI-windows.yml index a76997eb007..f9d108eefc9 100644 --- a/.github/workflows/CI-windows.yml +++ b/.github/workflows/CI-windows.yml @@ -52,7 +52,7 @@ jobs: run: | rem TODO: enable rules? rem specify Release build so matchcompiler is used - cmake -S . -B build -Werror=dev -DCMAKE_BUILD_TYPE=Release -DCMAKE_COMPILE_WARNING_AS_ERROR=On -DBUILD_TESTING=Off -DBUILD_GUI=On -DWITH_QCHART=On -DBUILD_TRIAGE=On -DBUILD_ONLINE_HELP=On -DCMAKE_INSTALL_PREFIX=cppcheck-cmake-install -DCMAKE_COMPILE_WARNING_AS_ERROR=On || exit /b !errorlevel! + cmake -S . -B build -Werror=dev --warn-uninitialized -DCMAKE_BUILD_TYPE=Release -DCMAKE_COMPILE_WARNING_AS_ERROR=On -DBUILD_TESTING=Off -DBUILD_GUI=On -DWITH_QCHART=On -DBUILD_TRIAGE=On -DBUILD_ONLINE_HELP=On -DCMAKE_INSTALL_PREFIX=cppcheck-cmake-install -DCMAKE_COMPILE_WARNING_AS_ERROR=On || exit /b !errorlevel! - name: Build GUI release run: | @@ -91,7 +91,7 @@ jobs: - name: Run CMake run: | - cmake -S . -B build.cxxstd -Werror=dev -A x64 -DCMAKE_CXX_STANDARD=${{ matrix.cxxstd }} -DCMAKE_BUILD_TYPE=Debug -DBUILD_TESTING=On -DCMAKE_COMPILE_WARNING_AS_ERROR=On || exit /b !errorlevel! + cmake -S . -B build.cxxstd -Werror=dev --warn-uninitialized -A x64 -DCMAKE_CXX_STANDARD=${{ matrix.cxxstd }} -DCMAKE_BUILD_TYPE=Debug -DBUILD_TESTING=On -DCMAKE_COMPILE_WARNING_AS_ERROR=On || exit /b !errorlevel! - name: Build run: | @@ -270,7 +270,7 @@ jobs: - name: Test SEH wrapper if: matrix.config == 'release' run: | - cmake -S . -B build.cmake.seh -Werror=dev -DBUILD_TESTING=On -DCMAKE_COMPILE_WARNING_AS_ERROR=On || exit /b !errorlevel! + cmake -S . -B build.cmake.seh -Werror=dev --warn-uninitialized -DBUILD_TESTING=On -DCMAKE_COMPILE_WARNING_AS_ERROR=On || exit /b !errorlevel! cmake --build build.cmake.seh --target test-sehwrapper || exit /b !errorlevel! :: TODO: how to run this without copying the file? copy build.cmake.seh\bin\Debug\test-sehwrapper.exe . || exit /b !errorlevel! diff --git a/.github/workflows/clang-tidy.yml b/.github/workflows/clang-tidy.yml index c4f8cc0cf6b..7a5b317693a 100644 --- a/.github/workflows/clang-tidy.yml +++ b/.github/workflows/clang-tidy.yml @@ -61,7 +61,7 @@ jobs: - name: Prepare CMake run: | - cmake -S . -B cmake.output -Werror=dev -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 -DCPPCHK_GLIBCXX_DEBUG=Off -DCMAKE_COMPILE_WARNING_AS_ERROR=On + cmake -S . -B cmake.output -Werror=dev --warn-uninitialized -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 -DCPPCHK_GLIBCXX_DEBUG=Off -DCMAKE_COMPILE_WARNING_AS_ERROR=On env: CC: clang-22 CXX: clang++-22 diff --git a/.github/workflows/iwyu.yml b/.github/workflows/iwyu.yml index 3b972dca443..de047b8d10a 100644 --- a/.github/workflows/iwyu.yml +++ b/.github/workflows/iwyu.yml @@ -126,7 +126,7 @@ jobs: - name: Prepare CMake run: | # 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++' }} + cmake -S . -B cmake.output -Werror=dev --warn-uninitialized -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++ @@ -234,7 +234,7 @@ jobs: - name: Prepare CMake run: | # 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 }} + cmake -S . -B cmake.output -Werror=dev --warn-uninitialized -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 diff --git a/.github/workflows/release-windows.yml b/.github/workflows/release-windows.yml index f59e77a2dca..8d09a55302e 100644 --- a/.github/workflows/release-windows.yml +++ b/.github/workflows/release-windows.yml @@ -85,7 +85,7 @@ jobs: run: | :: TODO: enable rules? :: specify Release build so matchcompiler is used - cmake -S . -B build -Werror=dev -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTING=Off -DBUILD_GUI=On -DWITH_QCHART=On -DBUILD_ONLINE_HELP=On -DUSE_BOOST=ON -DBOOST_INCLUDEDIR=%GITHUB_WORKSPACE%\boost -DCMAKE_COMPILE_WARNING_AS_ERROR=On || exit /b !errorlevel! + cmake -S . -B build -Werror=dev --warn-uninitialized -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTING=Off -DBUILD_GUI=On -DWITH_QCHART=On -DBUILD_ONLINE_HELP=On -DUSE_BOOST=ON -DBOOST_INCLUDEDIR=%GITHUB_WORKSPACE%\boost -DCMAKE_COMPILE_WARNING_AS_ERROR=On || exit /b !errorlevel! cmake --build build --target cppcheck-gui --config Release || exit /b !errorlevel! # TODO: package PDBs diff --git a/.github/workflows/sanitizers.yml b/.github/workflows/sanitizers.yml index d7ff31939d0..ea0a0276c99 100644 --- a/.github/workflows/sanitizers.yml +++ b/.github/workflows/sanitizers.yml @@ -96,7 +96,7 @@ jobs: - name: CMake run: | - cmake -S . -B cmake.output -Werror=dev -DCMAKE_BUILD_TYPE=RelWithDebInfo -DHAVE_RULES=On -DBUILD_TESTING=On -DBUILD_GUI=On -DWITH_QCHART=On -DBUILD_TRIAGE=On -DUSE_MATCHCOMPILER=Verify ${{ matrix.cmake_opts }} -DENABLE_CHECK_INTERNAL=On -DUSE_BOOST=On -DCPPCHK_GLIBCXX_DEBUG=Off -DCMAKE_DISABLE_PRECOMPILE_HEADERS=On -DCMAKE_GLOBAL_AUTOGEN_TARGET=On -DDISABLE_DMAKE=On -DFILESDIR= -DCMAKE_COMPILE_WARNING_AS_ERROR=On -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache + cmake -S . -B cmake.output -Werror=dev --warn-uninitialized -DCMAKE_BUILD_TYPE=RelWithDebInfo -DHAVE_RULES=On -DBUILD_TESTING=On -DBUILD_GUI=On -DWITH_QCHART=On -DBUILD_TRIAGE=On -DUSE_MATCHCOMPILER=Verify ${{ matrix.cmake_opts }} -DENABLE_CHECK_INTERNAL=On -DUSE_BOOST=On -DCPPCHK_GLIBCXX_DEBUG=Off -DCMAKE_DISABLE_PRECOMPILE_HEADERS=On -DCMAKE_GLOBAL_AUTOGEN_TARGET=On -DDISABLE_DMAKE=On -DFILESDIR= -DCMAKE_COMPILE_WARNING_AS_ERROR=On -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache env: CC: clang-22 CXX: clang++-22 diff --git a/.github/workflows/selfcheck.yml b/.github/workflows/selfcheck.yml index dcdf8bfbdd3..6bd87f9243f 100644 --- a/.github/workflows/selfcheck.yml +++ b/.github/workflows/selfcheck.yml @@ -64,7 +64,7 @@ jobs: # unusedFunction - start - name: CMake run: | - cmake -S . -B cmake.output -Werror=dev -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 -DCPPCHK_GLIBCXX_DEBUG=Off + cmake -S . -B cmake.output -Werror=dev --warn-uninitialized -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 -DCPPCHK_GLIBCXX_DEBUG=Off - name: Generate dependencies run: | @@ -90,7 +90,7 @@ jobs: # unusedFunction notest - start - name: CMake (no test) run: | - cmake -S . -B cmake.output.notest -Werror=dev -DHAVE_RULES=On -DBUILD_TESTING=Off -DBUILD_GUI=ON -DBUILD_TRIAGE=On -DWITH_QCHART=ON -DENABLE_CHECK_INTERNAL=On -DCMAKE_GLOBAL_AUTOGEN_TARGET=On -DDISABLE_DMAKE=On -DCPPCHK_GLIBCXX_DEBUG=Off + cmake -S . -B cmake.output.notest -Werror=dev --warn-uninitialized -DHAVE_RULES=On -DBUILD_TESTING=Off -DBUILD_GUI=ON -DBUILD_TRIAGE=On -DWITH_QCHART=ON -DENABLE_CHECK_INTERNAL=On -DCMAKE_GLOBAL_AUTOGEN_TARGET=On -DDISABLE_DMAKE=On -DCPPCHK_GLIBCXX_DEBUG=Off - name: Generate dependencies (no test) run: | @@ -112,7 +112,7 @@ jobs: # unusedFunction notest nogui - start - name: CMake (no test / no gui) run: | - cmake -S . -B cmake.output.notest_nogui -Werror=dev -DHAVE_RULES=On -DBUILD_TESTING=Off -DENABLE_CHECK_INTERNAL=On -DCPPCHK_GLIBCXX_DEBUG=Off + cmake -S . -B cmake.output.notest_nogui -Werror=dev --warn-uninitialized -DHAVE_RULES=On -DBUILD_TESTING=Off -DENABLE_CHECK_INTERNAL=On -DCPPCHK_GLIBCXX_DEBUG=Off - name: Generate dependencies (no test / no gui) run: | @@ -131,7 +131,7 @@ jobs: # unusedFunction notest nocli - start - name: CMake (no test / no cli) run: | - cmake -S . -B cmake.output.notest_nocli -Werror=dev -DHAVE_RULES=On -DBUILD_TESTING=Off -DBUILD_CLI=Off -DBUILD_GUI=ON -DWITH_QCHART=ON -DBUILD_TRIAGE=On -DENABLE_CHECK_INTERNAL=On -DCMAKE_GLOBAL_AUTOGEN_TARGET=On -DDISABLE_DMAKE=On -DCPPCHK_GLIBCXX_DEBUG=Off + cmake -S . -B cmake.output.notest_nocli -Werror=dev --warn-uninitialized -DHAVE_RULES=On -DBUILD_TESTING=Off -DBUILD_CLI=Off -DBUILD_GUI=ON -DWITH_QCHART=ON -DBUILD_TRIAGE=On -DENABLE_CHECK_INTERNAL=On -DCMAKE_GLOBAL_AUTOGEN_TARGET=On -DDISABLE_DMAKE=On -DCPPCHK_GLIBCXX_DEBUG=Off - name: Generate dependencies (no test / no cli) run: | @@ -154,7 +154,7 @@ jobs: # unusedFunction notest nocli nogui - start - name: CMake (no test / no cli / no gui) run: | - cmake -S . -B cmake.output.notest_nocli_nogui -Werror=dev -DHAVE_RULES=On -DBUILD_TESTING=Off -DBUILD_CLI=Off -DBUILD_GUI=Off -DENABLE_CHECK_INTERNAL=On -DCPPCHK_GLIBCXX_DEBUG=Off + cmake -S . -B cmake.output.notest_nocli_nogui -Werror=dev --warn-uninitialized -DHAVE_RULES=On -DBUILD_TESTING=Off -DBUILD_CLI=Off -DBUILD_GUI=Off -DENABLE_CHECK_INTERNAL=On -DCPPCHK_GLIBCXX_DEBUG=Off - name: Generate dependencies (no test / no cli / no gui) run: | diff --git a/cmake/options.cmake b/cmake/options.cmake index d640710e428..0fa27e4734b 100644 --- a/cmake/options.cmake +++ b/cmake/options.cmake @@ -145,7 +145,7 @@ string(LENGTH "${FILESDIR}" _filesdir_len) # override FILESDIR if it is set or empty if(FILESDIR OR ${_filesdir_len} EQUAL 0) # TODO: verify that it is an absolute path? - set(FILESDIR_DEF ${FILESDIR}) + set(FILESDIR_DEF "${FILESDIR}") else() set(FILESDIR_DEF ${CMAKE_INSTALL_PREFIX}/share/${PROJECT_NAME} CACHE STRING "Cppcheck files directory") endif() From 0d7884dad223e7f472b4af125e4e04fdc9d6bb02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Berder?= <18538310+francois-berder@users.noreply.github.com> Date: Wed, 17 Jun 2026 08:45:11 +0200 Subject: [PATCH 023/165] Fix #958: warn when feof() is used as a while loop condition (#8422) feof() only returns true after a read has already failed, causing the loop body to execute once more after the last successful read. Read errors also go undetected since feof() does not distinguish them from EOF. --------- Signed-off-by: Francois Berder --- lib/checkers.cpp | 1 + lib/checkio.cpp | 133 +++++++++++++++++++++++++++++++++ lib/checkio.h | 4 + man/checkers/wrongfeofUsage.md | 42 +++++++++++ releasenotes.txt | 2 +- test/cli/other_test.py | 8 +- test/testio.cpp | 50 +++++++++++++ 7 files changed, 235 insertions(+), 5 deletions(-) create mode 100644 man/checkers/wrongfeofUsage.md diff --git a/lib/checkers.cpp b/lib/checkers.cpp index 3b425926b9e..cc8c4054ea2 100644 --- a/lib/checkers.cpp +++ b/lib/checkers.cpp @@ -101,6 +101,7 @@ namespace checkers { {"CheckFunctions::useStandardLibrary","style"}, {"CheckIO::checkCoutCerrMisusage","c"}, {"CheckIO::checkFileUsage",""}, + {"CheckIO::checkWrongfeofUsage",""}, {"CheckIO::checkWrongPrintfScanfArguments",""}, {"CheckIO::invalidScanf",""}, {"CheckLeakAutoVar::check","notclang"}, diff --git a/lib/checkio.cpp b/lib/checkio.cpp index 8012d540898..f632ca99e9e 100644 --- a/lib/checkio.cpp +++ b/lib/checkio.cpp @@ -507,6 +507,137 @@ void CheckIOImpl::invalidScanfError(const Token *tok) CWE119, Certainty::normal); } +static const Token* findFileReadCall(const Token *start, const Token *end, int varid) +{ + const Token* found = Token::findmatch(start, "fgets|fgetc|getc|fread|fscanf (", end); + while (found) { + const std::vector args = getArguments(found); + if (!args.empty()) { + const bool match = (found->str() == "fscanf") + ? args.front()->varId() == varid + : args.back()->varId() == varid; + if (match) + return found; + } + found = Token::findmatch(found->next(), "fgets|fgetc|getc|fread|fscanf (", end); + } + return nullptr; +} + +void CheckIOImpl::checkWrongfeofUsage() +{ + const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase(); + + logChecker("CheckIO::checkWrongfeofUsage"); + + for (const Scope * scope : symbolDatabase->functionScopes) { + for (const Token *tok = scope->bodyStart->next(); tok != scope->bodyEnd; tok = tok->next()) { + // TODO: Handle for loops + if (!Token::Match(tok, "while ( ! feof ( %var% )")) + continue; + + // Bail out if we cannot identify file pointer + const int fpVarId = tok->tokAt(5)->varId(); + if (fpVarId == 0) + continue; + + const Token *endCond = tok->linkAt(1); + const Token *bodyStart; + const Token *bodyEnd; + + if (Token::simpleMatch(tok->previous(), "}") && tok->previous()->scope()->type == ScopeType::eDo) { + bodyEnd = tok->previous(); + bodyStart = bodyEnd->link(); + } else { + if (!Token::simpleMatch(endCond, ") {")) + continue; + bodyEnd = endCond->linkAt(1); + bodyStart = endCond->next(); + } + + // Bail out if the loop contains control flow (too complex to analyze) + if (Token::findmatch(bodyStart, "return|break|goto|continue|throw", bodyEnd)) + continue; + + // Bail out if fp is used outside of known file I/O functions. + // If it is passed to an unknown function, reads may occur there. + bool fpUsedElsewhere = false; + for (const Token *t = bodyStart->next(); t && t != bodyEnd; t = t->next()) { + if (t->varId() != fpVarId) + continue; + const Token *p = t->astParent(); + while (p && p->str() == ",") + p = p->astParent(); + if (!p || !Token::Match(p->astOperand1(), "fgets|fgetc|getc|fread|fscanf|fprintf|fwrite|fputs|fputc|putc")) { + fpUsedElsewhere = true; + break; + } + } + if (fpUsedElsewhere) + continue; + + // No file read call in the loop: feof can never become true inside it + const Token *loopFileReadCallTok = findFileReadCall(bodyStart, bodyEnd, fpVarId); + if (!loopFileReadCallTok) { + // TODO: Warn about infinite loop + continue; + } + + // Find last file read + const Token *lastLoopFileReadCallTok = loopFileReadCallTok; + while (loopFileReadCallTok) { + lastLoopFileReadCallTok = loopFileReadCallTok; + loopFileReadCallTok = findFileReadCall(lastLoopFileReadCallTok->next(), bodyEnd, fpVarId); + } + + // Warn if the destination of the last file read is used after the call before bodyEnd. + // If it is not, the stale buffer is never accessed on the extra iteration at EOF. + + if (lastLoopFileReadCallTok->str() == "fgetc" || lastLoopFileReadCallTok->str() == "getc") { + // Warn if the return value feeds into an expression (astParent of the call node) + if (lastLoopFileReadCallTok->astParent() && lastLoopFileReadCallTok->astParent()->astParent()) + wrongfeofUsage(getCondTok(tok)); + } else { + const std::vector args = getArguments(lastLoopFileReadCallTok); + // Collect destination varIds + std::vector destVarIds; + if (lastLoopFileReadCallTok->str() == "fscanf") { + // args[0]=fp, args[1]=format, args[2+]=destinations (typically &var) + for (std::size_t i = 2; i < args.size(); ++i) { + const Token *destTok = Token::Match(args[i], "& %var%") ? args[i]->next() : args[i]; + if (destTok->varId() != 0) + destVarIds.push_back(destTok->varId()); + } + } else { + // Handle fgets, fread + // First argument is the destination buffer + if (!args.empty() && args.front()->varId() != 0) + destVarIds.push_back(args.front()->varId()); + } + + // Search for any destination use between this call's ';' and endBody + const Token *semiColonTok = lastLoopFileReadCallTok->linkAt(1)->next(); + for (const Token *t = semiColonTok; t && t != bodyEnd; t = t->next()) { + if (std::find(destVarIds.begin(), destVarIds.end(), t->varId()) != destVarIds.end()) { + wrongfeofUsage(getCondTok(tok)); + break; + } + } + } + } + } +} + +void CheckIOImpl::wrongfeofUsage(const Token * tok) +{ + reportError(tok, Severity::warning, + "wrongfeofUsage", + "Using feof() as a loop condition causes the last line to be processed twice.\n" + "feof() returns true only after a read has failed due to end-of-file, so the loop " + "body executes once more after the last successful read. Check the return value of " + "the read function instead (e.g. fgets, fread, fscanf)."); +} + //--------------------------------------------------------------------------- // printf("%u", "xyz"); // Wrong argument type // printf("%u%s", 1); // Too few arguments @@ -2057,6 +2188,7 @@ void CheckIO::runChecks(const Tokenizer &tokenizer, ErrorLogger& errorLogger) checkIO.checkWrongPrintfScanfArguments(); checkIO.checkCoutCerrMisusage(); checkIO.checkFileUsage(); + checkIO.checkWrongfeofUsage(); checkIO.invalidScanf(); } @@ -2072,6 +2204,7 @@ void CheckIO::getErrorMessages(ErrorLogger& errorLogger, const Settings &setting c.fcloseInLoopConditionError(nullptr, "fp"); c.seekOnAppendedFileError(nullptr); c.incompatibleFileOpenError(nullptr, "tmp"); + c.wrongfeofUsage(nullptr); c.invalidScanfError(nullptr); c.wrongPrintfScanfArgumentsError(nullptr, "printf",3,2); c.invalidScanfArgTypeError_s(nullptr, 1, "s", nullptr); diff --git a/lib/checkio.h b/lib/checkio.h index 9f125e6bd7b..dff49006bab 100644 --- a/lib/checkio.h +++ b/lib/checkio.h @@ -82,6 +82,9 @@ class CPPCHECKLIB CheckIOImpl : public CheckImpl { /** @brief scanf can crash if width specifiers are not used */ void invalidScanf(); + /** @brief %Check wrong usage of feof */ + void checkWrongfeofUsage(); + /** @brief %Checks type and number of arguments given to functions like printf or scanf*/ void checkWrongPrintfScanfArguments(); @@ -127,6 +130,7 @@ class CPPCHECKLIB CheckIOImpl : public CheckImpl { void seekOnAppendedFileError(const Token *tok); void incompatibleFileOpenError(const Token *tok, const std::string &filename); void invalidScanfError(const Token *tok); + void wrongfeofUsage(const Token *tok); void wrongPrintfScanfArgumentsError(const Token* tok, const std::string &functionName, nonneg int numFormat, diff --git a/man/checkers/wrongfeofUsage.md b/man/checkers/wrongfeofUsage.md new file mode 100644 index 00000000000..9a3d0bbf5f6 --- /dev/null +++ b/man/checkers/wrongfeofUsage.md @@ -0,0 +1,42 @@ +# wrongfeofUsage + +**Message**: Using feof() as a loop condition causes the last line to be processed twice.
+**Category**: Correctness
+**Severity**: Warning
+**Language**: C/C++ + +## Description + +`feof()` returns non-zero only after a read operation has failed because the end of file was reached. When used as the sole condition of a loop, the loop body executes one extra time after the last successful read: the read fails silently (or returns partial data), and only then does `feof()` return true and terminate the loop. + +This checker matches `while (!feof(fp))` and `do { ... } while (!feof(fp))` loops and warns when all of the following are true: + +- The loop body contains at least one file-read call (`fgets`, `fgetc`, `getc`, `fread`, or `fscanf`) on the same file pointer. +- The destination (return value or output buffer) of the **last** file-read call in the loop is used after that call within the same loop iteration. + +The checker skips loops that contain a control-flow statement (`return`, `break`, `goto`, `continue`, `throw`) as those are too complex to analyze reliably, and loops where the file pointer appears in a context other than a recognised I/O function (`fgets`, `fgetc`, `getc`, `fread`, `fscanf`, `fprintf`, `fwrite`, `fputs`, `fputc`, `putc`). + +## How to fix + +Check the return value of the read function directly in the loop condition. + +Before: +```c +void process(FILE *fp) { + char line[256]; + while (!feof(fp)) { /* wrong: processes last line twice */ + fgets(line, sizeof(line), fp); + puts(line); + } +} +``` + +After: +```c +void process(FILE *fp) { + char line[256]; + while (fgets(line, sizeof(line), fp) != NULL) { + puts(line); + } +} +``` \ No newline at end of file diff --git a/releasenotes.txt b/releasenotes.txt index 185f06390e3..2141c34f001 100644 --- a/releasenotes.txt +++ b/releasenotes.txt @@ -5,7 +5,7 @@ Major bug fixes & crashes: - New checks: -- +- Warn when feof() is used as a while loop condition (wrongfeofUsage). C/C++ support: - diff --git a/test/cli/other_test.py b/test/cli/other_test.py index 243f600b5a6..f788a7d21c8 100644 --- a/test/cli/other_test.py +++ b/test/cli/other_test.py @@ -4318,25 +4318,25 @@ def __test_active_checkers(tmp_path, active_cnt, total_cnt, use_misra=False, use def test_active_unusedfunction_only(tmp_path): - __test_active_checkers(tmp_path, 1, 186, use_unusedfunction_only=True) + __test_active_checkers(tmp_path, 1, 187, use_unusedfunction_only=True) def test_active_unusedfunction_only_builddir(tmp_path): checkers_exp = [ 'CheckUnusedFunctions::check' ] - __test_active_checkers(tmp_path, 1, 186, use_unusedfunction_only=True, checkers_exp=checkers_exp) + __test_active_checkers(tmp_path, 1, 187, use_unusedfunction_only=True, checkers_exp=checkers_exp) def test_active_unusedfunction_only_misra(tmp_path): - __test_active_checkers(tmp_path, 1, 386, use_unusedfunction_only=True, use_misra=True) + __test_active_checkers(tmp_path, 1, 387, use_unusedfunction_only=True, use_misra=True) def test_active_unusedfunction_only_misra_builddir(tmp_path): checkers_exp = [ 'CheckUnusedFunctions::check' ] - __test_active_checkers(tmp_path, 1, 386, use_unusedfunction_only=True, use_misra=True, checkers_exp=checkers_exp) + __test_active_checkers(tmp_path, 1, 387, use_unusedfunction_only=True, use_misra=True, checkers_exp=checkers_exp) def test_analyzerinfo(tmp_path): diff --git a/test/testio.cpp b/test/testio.cpp index 15a65ef79c9..adfb6e31daf 100644 --- a/test/testio.cpp +++ b/test/testio.cpp @@ -45,6 +45,7 @@ class TestIO : public TestFixture { TEST_CASE(seekOnAppendedFile); TEST_CASE(fflushOnInputStream); TEST_CASE(incompatibleFileOpen); + TEST_CASE(testWrongfeofUsage); // #958 TEST_CASE(testScanf1); // Scanf without field limiters TEST_CASE(testScanf2); @@ -766,6 +767,55 @@ class TestIO : public TestFixture { ASSERT_EQUALS("[test.cpp:3:16]: (warning) The file '\"tmp\"' is opened for read and write access at the same time on different streams [incompatibleFileOpen]\n", errout_str()); } + void testWrongfeofUsage() { // ticket #958 + check("void foo(FILE * fp) {\n" + " while (!feof(fp)) \n" + " {\n" + " char line[100];\n" + " fgets(line, sizeof(line), fp);\n" + " dostuff(line);\n" + " }\n" + "}"); + ASSERT_EQUALS("[test.cpp:2:10]: (warning) Using feof() as a loop condition causes the last line to be processed twice. [wrongfeofUsage]\n", errout_str()); + + check("int foo(FILE *fp) {\n" + " char line[100];\n" + " while (fgets(line, sizeof(line), fp)) {}\n" + " if (!feof(fp))\n" + " return 1;\n" + " return 0;\n" + "}"); + ASSERT_EQUALS("", errout_str()); + + check("void foo(FILE *fp){\n" + " char line[100];\n" + " fgets(line, sizeof(line), fp);\n" + " while (!feof(fp)){\n" + " dostuff(line);\n" + " fgets(line, sizeof(line), fp);" + " }\n" + "}"); + ASSERT_EQUALS("", errout_str()); + + check("void foo(FILE *fp) {\n" + " char line[100];\n" + " do {\n" + " fgets(line, sizeof(line), fp);\n" + " dostuff(line);\n" + " } while (!feof(fp));\n" + "}"); + ASSERT_EQUALS("[test.cpp:6:12]: (warning) Using feof() as a loop condition causes the last line to be processed twice. [wrongfeofUsage]\n", errout_str()); + + check("void foo(FILE *fp) {\n" + " char line[100];\n" + " do {\n" + " dostuff(line);\n" + " fgets(line, sizeof(line), fp);\n" + " } while (!feof(fp));\n" + "}"); + ASSERT_EQUALS("", errout_str()); + } + void testScanf1() { check("void foo() {\n" From fec0f8daf8c4c5aed9750c84c7df764d436ca77e Mon Sep 17 00:00:00 2001 From: correctmost <134317971+correctmost@users.noreply.github.com> Date: Wed, 17 Jun 2026 02:46:06 -0400 Subject: [PATCH 024/165] gtk.cfg: Remove extra semicolons from g_return* macros (#8632) The extra semicolons caused unknownMacro errors when checking code like this: ```c if (hadj) g_return_if_fail (GTK_IS_ADJUSTMENT (hadj)); else hadj = GTK_ADJUSTMENT (...) ``` They were introduced in commit c0b530947, but they are not actually present in the upstream GLib macros. --- cfg/gtk.cfg | 8 ++++---- test/cfg/gtk.c | 40 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 4 deletions(-) diff --git a/cfg/gtk.cfg b/cfg/gtk.cfg index 14cd032945e..71d0f3dee05 100644 --- a/cfg/gtk.cfg +++ b/cfg/gtk.cfg @@ -4,10 +4,10 @@ - - - - + + + + diff --git a/test/cfg/gtk.c b/test/cfg/gtk.c index cab41ffa1cd..4accf7b63ec 100644 --- a/test/cfg/gtk.c +++ b/test/cfg/gtk.c @@ -596,3 +596,43 @@ void gtk_widget_destroy_test() { // cppcheck-suppress mismatchAllocDealloc g_object_unref(widget); } + +void g_return_if_fail_test(const char *s) { + // cppcheck-suppress valueFlowBailout + g_return_if_fail(s); + + if (*s) + // cppcheck-suppress valueFlowBailout + g_return_if_fail(*s == 'a'); + else + g_info("Test the else branch can be parsed"); +} + +int g_return_val_if_fail_test(const char *s) { + // cppcheck-suppress valueFlowBailout + g_return_val_if_fail(s, 1); + + if (*s) + // cppcheck-suppress valueFlowBailout + g_return_val_if_fail(*s == 'a', 1); + else + g_info("Test the else branch can be parsed"); + + return 0; +} + +void g_return_if_reached_test(const char *s) { + if (s) + g_return_if_reached(); + else + g_info("Test the else branch can be parsed"); +} + +int g_return_val_if_reached_test(const char *s) { + if (s) + g_return_val_if_reached(1); + else + g_info("Test the else branch can be parsed"); + + return 0; +} From be0052b65baf181d0ddd345878f4b577aa48a1c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20St=C3=B6neberg?= Date: Wed, 17 Jun 2026 09:50:52 +0200 Subject: [PATCH 025/165] refs #14345 - dropped some untranslatable strings (#8073) --- gui/applicationdialog.cpp | 2 +- gui/cppcheck_de.ts | 100 ++++++-------------------- gui/cppcheck_es.ts | 118 ++++-------------------------- gui/cppcheck_fi.ts | 128 +++------------------------------ gui/cppcheck_fr.ts | 144 ------------------------------------- gui/cppcheck_it.ts | 118 ++++-------------------------- gui/cppcheck_ja.ts | 94 +++++++----------------- gui/cppcheck_ka.ts | 100 ++++++-------------------- gui/cppcheck_ko.ts | 118 ++++-------------------------- gui/cppcheck_nl.ts | 128 +++------------------------------ gui/cppcheck_ru.ts | 110 +++++----------------------- gui/cppcheck_sr.ts | 118 ++++-------------------------- gui/cppcheck_sv.ts | 110 +++++----------------------- gui/cppcheck_zh_CN.ts | 116 ++++-------------------------- gui/cppcheck_zh_TW.ts | 104 ++++++--------------------- gui/fileviewdialog.cpp | 4 +- gui/helpdialog.cpp | 2 +- gui/librarydialog.cpp | 6 +- gui/mainwindow.cpp | 30 ++++---- gui/mainwindow.ui | 14 ++-- gui/platforms.cpp | 10 +-- gui/projectfile.ui | 4 +- gui/projectfiledialog.cpp | 4 +- gui/resultstree.cpp | 6 +- gui/resultsview.cpp | 4 +- gui/translationhandler.cpp | 2 +- 26 files changed, 249 insertions(+), 1445 deletions(-) diff --git a/gui/applicationdialog.cpp b/gui/applicationdialog.cpp index bc8804d6f97..bdf9a4f827e 100644 --- a/gui/applicationdialog.cpp +++ b/gui/applicationdialog.cpp @@ -80,7 +80,7 @@ void ApplicationDialog::ok() { if (mUI->mName->text().isEmpty() || mUI->mPath->text().isEmpty()) { QMessageBox msg(QMessageBox::Warning, - tr("Cppcheck"), + "Cppcheck", tr("You must specify a name, a path and optionally parameters for the application!"), QMessageBox::Ok, this); diff --git a/gui/cppcheck_de.ts b/gui/cppcheck_de.ts index 1361296b8ca..a9429aa1c94 100644 --- a/gui/cppcheck_de.ts +++ b/gui/cppcheck_de.ts @@ -107,9 +107,8 @@ Parameter: -l(line) (file) Anzeigeanwendung auswählen - Cppcheck - Cppcheck + Cppcheck @@ -176,10 +175,8 @@ Parameter: -l(line) (file) Konnte die Datei nicht finden: %1 - - Cppcheck - Cppcheck + Cppcheck @@ -210,9 +207,8 @@ Parameter: -l(line) (file) Hilfedatei '%1' nicht gefunden - Cppcheck - Cppcheck + Cppcheck @@ -332,11 +328,8 @@ Parameter: -l(line) (file) Bibliothek öffnen - - - Cppcheck - Cppcheck + Cppcheck @@ -482,23 +475,8 @@ Parameter: -l(line) (file) MainWindow - - - - - - - - - - - - - - - Cppcheck - Cppcheck + Cppcheck @@ -1006,29 +984,16 @@ Parameter: -l(line) (file) - Misra C - Misra C - - - - Misra C++ 2008 - + Misra C - Cert C - Cert C + Cert C - Cert C++ - Cert C++ - - - - Misra C++ 2023 - + Cert C++ @@ -1288,14 +1253,12 @@ Dies wurde vermutlich durch einen Wechsel der Cppcheck-Version hervorgerufen. Bi Compilerdatenbank - Visual Studio - Visual Studio + Visual Studio - Borland C++ Builder 6 - Borland C++-Builder 6 + Borland C++-Builder 6 @@ -1567,29 +1530,24 @@ Options: Nativ - Unix 32-bit - Unix 32-bit + Unix 32-bit - Unix 64-bit - Unix 64-bit + Unix 64-bit - Windows 32-bit ANSI - Windows 32-bit, ANSI + Windows 32-bit, ANSI - Windows 32-bit Unicode - Windows 32-bit, Unicode + Windows 32-bit, Unicode - Windows 64-bit - Windows 64-bit + Windows 64-bit @@ -1980,14 +1938,12 @@ Options: - Clang analyzer - Clang-Analyzer + Clang-Analyzer - Clang-tidy - Clang-Tidy + Clang-Tidy @@ -2028,9 +1984,8 @@ Options: Clang-tidy (nicht gefunden) - Visual Studio - Visual Studio + Visual Studio @@ -2038,9 +1993,8 @@ Options: Compilerdatenbank - Borland C++ Builder 6 - Borland C++-Builder 6 + Borland C++-Builder 6 @@ -2316,11 +2270,6 @@ Options: Tags - - - CWE - - QPlatformTheme @@ -2443,10 +2392,8 @@ Options: Kein Tag - - Cppcheck - Cppcheck + Cppcheck @@ -2534,10 +2481,8 @@ Bitte überprüfen Sie ob der Pfad und die Parameter der Anwendung richtig einge %p% (%1 von %2 Dateien geprüft) - - Cppcheck - Cppcheck + Cppcheck @@ -3210,9 +3155,8 @@ The user interface language has been reset to English. Open the Preferences-dial Die Sprache wurde auf Englisch zurückgesetzt. Öffnen Sie den Einstellungen-Dialog um eine verfügbare Sprache auszuwählen. - Cppcheck - Cppcheck + Cppcheck diff --git a/gui/cppcheck_es.ts b/gui/cppcheck_es.ts index bbe8bed24d5..fa03b4457cc 100644 --- a/gui/cppcheck_es.ts +++ b/gui/cppcheck_es.ts @@ -95,9 +95,8 @@ Parameters: -l(line) (file) Selecciona la aplicación para visualizar - Cppcheck - Cppcheck + Cppcheck @@ -113,10 +112,8 @@ Parameters: -l(line) (file) No se ha encontrado el fichero: %1 - - Cppcheck - Cppcheck + Cppcheck @@ -147,9 +144,8 @@ Parameters: -l(line) (file) - Cppcheck - Cppcheck + Cppcheck @@ -269,11 +265,8 @@ Parameters: -l(line) (file) Abrir archivo de biblioteca - - - Cppcheck - Cppcheck + Cppcheck @@ -411,23 +404,8 @@ Parameters: -l(line) (file) MainWindow - - - - - - - - - - - - - - - Cppcheck - Cppcheck + Cppcheck @@ -952,31 +930,6 @@ Parameters: -l(line) (file) Normal - - - Misra C - - - - - Misra C++ 2008 - - - - - Cert C - - - - - Cert C++ - - - - - Misra C++ 2023 - - Autosar @@ -1214,16 +1167,6 @@ Do you want to load this project file instead? Compile database - - - Visual Studio - - - - - Borland C++ Builder 6 - - Select files to analyze @@ -1482,29 +1425,24 @@ Options: - Unix 32-bit - Unix 32-bit + Unix 32-bit - Unix 64-bit - Unix 64-bit + Unix 64-bit - Windows 32-bit ANSI - Windows 32-bit ANSI + Windows 32-bit ANSI - Windows 32-bit Unicode - Windows 32-bit Unicode + Windows 32-bit Unicode - Windows 64-bit - Windows 64-bit + Windows 64-bit @@ -1892,16 +1830,6 @@ Options: Bug hunting (Premium) - - - Clang analyzer - - - - - Clang-tidy - - Defines: @@ -1940,21 +1868,11 @@ Options: Clang-tidy (not found) - - - Visual Studio - - Compile database - - - Borland C++ Builder 6 - - Import Project @@ -2230,11 +2148,6 @@ Options: Tags - - - CWE - - QPlatformTheme @@ -2371,10 +2284,8 @@ Options: - - Cppcheck - Cppcheck + Cppcheck @@ -2483,10 +2394,8 @@ Por favor comprueba que la ruta a la aplicación y los parámetros son correctos %p% (%1 of %2 archivos comprobados) - - Cppcheck - Cppcheck + Cppcheck @@ -3133,9 +3042,8 @@ The user interface language has been reset to English. Open the Preferences-dial El idioma de la interfaz gráfica ha sido cambiado a Inglés. Abra la ventana de Preferencias para seleccionar alguno de los idiomas disponibles. - Cppcheck - Cppcheck + Cppcheck diff --git a/gui/cppcheck_fi.ts b/gui/cppcheck_fi.ts index 517362d852b..bf379534998 100644 --- a/gui/cppcheck_fi.ts +++ b/gui/cppcheck_fi.ts @@ -96,9 +96,8 @@ Parameters: -l(line) (file) Valitse ohjelma jolla avata virhetiedosto - Cppcheck - Cppcheck + Cppcheck @@ -116,10 +115,8 @@ Parameters: -l(line) (file) Tiedostoa %1 ei löytynyt - - Cppcheck - Cppcheck + Cppcheck @@ -150,9 +147,8 @@ Parameters: -l(line) (file) - Cppcheck - Cppcheck + Cppcheck @@ -272,11 +268,8 @@ Parameters: -l(line) (file) - - - Cppcheck - Cppcheck + Cppcheck @@ -414,23 +407,8 @@ Parameters: -l(line) (file) MainWindow - - - - - - - - - - - - - - - Cppcheck - Cppcheck + Cppcheck @@ -942,31 +920,6 @@ Parameters: -l(line) (file) Normal - - - Misra C - - - - - Misra C++ 2008 - - - - - Cert C - - - - - Cert C++ - - - - - Misra C++ 2023 - - Autosar @@ -1214,16 +1167,6 @@ This is probably because the settings were changed between the Cppcheck versions Compile database - - - Visual Studio - - - - - Borland C++ Builder 6 - - Select files to analyze @@ -1475,31 +1418,6 @@ Options: Native - - - Unix 32-bit - - - - - Unix 64-bit - - - - - Windows 32-bit ANSI - - - - - Windows 32-bit Unicode - - - - - Windows 64-bit - - ProjectFile @@ -1886,16 +1804,6 @@ Options: Bug hunting (Premium) - - - Clang analyzer - - - - - Clang-tidy - - Defines: @@ -1934,21 +1842,11 @@ Options: Clang-tidy (not found) - - - Visual Studio - - Compile database - - - Borland C++ Builder 6 - - Import Project @@ -2226,11 +2124,6 @@ Options: Tags - - - CWE - - QPlatformTheme @@ -2349,10 +2242,8 @@ Options: - - Cppcheck - Cppcheck + Cppcheck @@ -2437,10 +2328,8 @@ Tarkista että ohjelman polku ja parametrit ovat oikeat. - - Cppcheck - Cppcheck + Cppcheck @@ -3102,9 +2991,8 @@ The user interface language has been reset to English. Open the Preferences-dial - Cppcheck - Cppcheck + Cppcheck diff --git a/gui/cppcheck_fr.ts b/gui/cppcheck_fr.ts index 7e8651d8ec3..6d464bc46af 100644 --- a/gui/cppcheck_fr.ts +++ b/gui/cppcheck_fr.ts @@ -65,11 +65,6 @@ General Public License version 3 Select viewer application Sélection de l'application - - - Cppcheck - - &Executable: @@ -123,12 +118,6 @@ Paramètres : -l(ligne) (fichier) Could not find the file: %1 Ne trouve pas le fichier : %1 - - - - Cppcheck - - Could not read the file: %1 @@ -157,11 +146,6 @@ Paramètres : -l(ligne) (fichier) Helpfile '%1' was not found - - - Cppcheck - - LibraryAddFunctionDialog @@ -279,13 +263,6 @@ Paramètres : -l(ligne) (fichier) Save as - - - - - Cppcheck - - Save the library as @@ -419,25 +396,6 @@ Paramètres : -l(ligne) (fichier) MainWindow - - - - - - - - - - - - - - - - - Cppcheck - - Checking for updates @@ -599,31 +557,6 @@ Paramètres : -l(ligne) (fichier) Normal - - - Misra C - - - - - Misra C++ 2008 - - - - - Cert C - - - - - Cert C++ - - - - - Misra C++ 2023 - - Autosar @@ -1407,16 +1340,6 @@ Do you want to stop the analysis and exit Cppcheck? Compile database - - - Visual Studio - - - - - Borland C++ Builder 6 - - Current results will be cleared. @@ -1461,31 +1384,6 @@ Do you want to proceed? Platforms - - - Unix 32-bit - - - - - Unix 64-bit - - - - - Windows 32-bit ANSI - - - - - Windows 32-bit Unicode - - - - - Windows 64-bit - - Native @@ -1691,16 +1589,6 @@ Do you want to proceed? Bug hunting - - - Clang analyzer - - - - - Clang-tidy - - @@ -1969,21 +1857,11 @@ Do you want to proceed? MISRA rule texts file (%1) - - - Visual Studio - - Compile database - - - Borland C++ Builder 6 - - QObject @@ -2212,11 +2090,6 @@ Do you want to proceed? Tags - - - CWE - - QPlatformTheme @@ -2259,12 +2132,6 @@ Do you want to proceed? Undefined file Fichier indéterminé - - - - Cppcheck - - Could not start %1 @@ -2427,12 +2294,6 @@ Please select the default editor application in preferences/Applications.Results Résultats - - - - Cppcheck - - No errors found. @@ -3101,11 +2962,6 @@ Pour configurer les erreurs affichées, ouvrez le menu d'affichage. - - - Cppcheck - - TxtReport diff --git a/gui/cppcheck_it.ts b/gui/cppcheck_it.ts index 2c19aa2e50b..65b31b59b1e 100644 --- a/gui/cppcheck_it.ts +++ b/gui/cppcheck_it.ts @@ -107,9 +107,8 @@ Parametri: -l(line) (file) Seleziona l'applicazione di lettura - Cppcheck - Cppcheck + Cppcheck @@ -125,10 +124,8 @@ Parametri: -l(line) (file) File non trovato: %1 - - Cppcheck - Cppcheck + Cppcheck @@ -159,9 +156,8 @@ Parametri: -l(line) (file) - Cppcheck - Cppcheck + Cppcheck @@ -281,11 +277,8 @@ Parametri: -l(line) (file) - - - Cppcheck - Cppcheck + Cppcheck @@ -423,23 +416,8 @@ Parametri: -l(line) (file) MainWindow - - - - - - - - - - - - - - - Cppcheck - Cppcheck + Cppcheck @@ -951,31 +929,6 @@ Parametri: -l(line) (file) Normal - - - Misra C - - - - - Misra C++ 2008 - - - - - Cert C - - - - - Cert C++ - - - - - Misra C++ 2023 - - Autosar @@ -1227,16 +1180,6 @@ Probabilmente ciò è avvenuto perché le impostazioni sono state modificate tra Compile database - - - Visual Studio - - - - - Borland C++ Builder 6 - - Select files to analyze @@ -1495,29 +1438,24 @@ Options: - Unix 32-bit - Unix 32-bit + Unix 32-bit - Unix 64-bit - Unix 64-bit + Unix 64-bit - Windows 32-bit ANSI - Windows 32-bit, ANSI + Windows 32-bit, ANSI - Windows 32-bit Unicode - Windows 32-bit, Unicode + Windows 32-bit, Unicode - Windows 64-bit - Windows 64-bit + Windows 64-bit @@ -1905,16 +1843,6 @@ Options: Bug hunting (Premium) - - - Clang analyzer - - - - - Clang-tidy - - Defines: @@ -1953,21 +1881,11 @@ Options: Clang-tidy (not found) - - - Visual Studio - - Compile database - - - Borland C++ Builder 6 - - Import Project @@ -2243,11 +2161,6 @@ Options: Tags - - - CWE - - QPlatformTheme @@ -2374,10 +2287,8 @@ Options: - - Cppcheck - Cppcheck + Cppcheck @@ -2469,10 +2380,8 @@ Per favore verifica che il percorso dell'applicazione e i parametri siano c %p% (%1 su %2 file scansionati) - - Cppcheck - Cppcheck + Cppcheck @@ -3145,9 +3054,8 @@ The user interface language has been reset to English. Open the Preferences-dial L'interfaccia utente è stata risettata in Inglese. Apri la finestra di dialogo Preferenze per selezionare una qualunque lingua a disposizione. - Cppcheck - Cppcheck + Cppcheck diff --git a/gui/cppcheck_ja.ts b/gui/cppcheck_ja.ts index 6c8269b4143..eedad8e9515 100644 --- a/gui/cppcheck_ja.ts +++ b/gui/cppcheck_ja.ts @@ -106,9 +106,8 @@ Parameters: -l(line) (file) 表示アプリケーションの選択 - Cppcheck - Cppcheck + Cppcheck @@ -179,10 +178,8 @@ Parameters: -l(line) (file) ファイル:%1 が見つかりません - - Cppcheck - Cppcheck + Cppcheck @@ -213,9 +210,8 @@ Parameters: -l(line) (file) ヘルプファイル '%1' が見つかりません - Cppcheck - Cppcheck + Cppcheck @@ -335,11 +331,8 @@ Parameters: -l(line) (file) ライブラリファイルを開く - - - Cppcheck - Cppcheck + Cppcheck @@ -488,23 +481,8 @@ Parameters: -l(line) (file) MainWindow - - - - - - - - - - - - - - - Cppcheck - Cppcheck + Cppcheck @@ -1048,29 +1026,24 @@ Parameters: -l(line) (file) ノーマル - Misra C - MISRA C + MISRA C - Misra C++ 2008 - MISRA C++ 2008 + MISRA C++ 2008 - Cert C - CERT C + CERT C - Cert C++ - Cert C++ + Cert C++ - Misra C++ 2023 - MISRA C++ 2023 + MISRA C++ 2023 @@ -1309,14 +1282,12 @@ Analysis is stopped. コンパイルデータベース - Visual Studio - Visual Studio + Visual Studio - Borland C++ Builder 6 - Borland C++ Builder 6 + Borland C++ Builder 6 @@ -1594,29 +1565,24 @@ Options: ネイティブ - Unix 32-bit - Unix 32-bit + Unix 32-bit - Unix 64-bit - Unix 64-bit + Unix 64-bit - Windows 32-bit ANSI - Windows 32-bit ANSIエンコード + Windows 32-bit ANSIエンコード - Windows 32-bit Unicode - Windows 32-bit Unicode + Windows 32-bit Unicode - Windows 64-bit - Windows 64-bit + Windows 64-bit @@ -2021,14 +1987,12 @@ Options: バグハント - Clang analyzer - Clang Analyzer + Clang Analyzer - Clang-tidy - Clang-tidy + Clang-tidy @@ -2069,9 +2033,8 @@ Options: Clang-tidy (みつかりません) - Visual Studio - Visual Studio + Visual Studio @@ -2079,9 +2042,8 @@ Options: コンパイルデータベース - Borland C++ Builder 6 - Borland C++ Builder 6 + Borland C++ Builder 6 @@ -2367,9 +2329,8 @@ Options: タグ - CWE - CWE + CWE @@ -2501,10 +2462,8 @@ Options: タグなし - - Cppcheck - Cppcheck + Cppcheck @@ -2631,10 +2590,8 @@ Please check the application path and parameters are correct. %p% (%1 / %2 :ファイル数) - - Cppcheck - Cppcheck + Cppcheck @@ -3283,9 +3240,8 @@ The user interface language has been reset to English. Open the Preferences-dial そのため言語を 英語にリセットします。設定ダイアログから利用可能な言語を選択してください。 - Cppcheck - Cppcheck + Cppcheck diff --git a/gui/cppcheck_ka.ts b/gui/cppcheck_ka.ts index 52c0657f646..00239743df0 100644 --- a/gui/cppcheck_ka.ts +++ b/gui/cppcheck_ka.ts @@ -96,9 +96,8 @@ Parameters: -l(line) (file) აირჩიეთ აპლიკაცია - Cppcheck - Cppcheck + Cppcheck @@ -167,10 +166,8 @@ Parameters: -l(line) (file) ვერ ვიპოვე ფაილი: %1 - - Cppcheck - Cppcheck + Cppcheck @@ -201,9 +198,8 @@ Parameters: -l(line) (file) დახმარების ფაილი '%1' ვერ ვიპოვე - Cppcheck - Cppcheck + Cppcheck @@ -323,11 +319,8 @@ Parameters: -l(line) (file) ბიბლიოთეკის ფაილის გახსნა - - - Cppcheck - Cppcheck + Cppcheck @@ -464,23 +457,8 @@ Parameters: -l(line) (file) MainWindow - - - - - - - - - - - - - - - Cppcheck - Cppcheck + Cppcheck @@ -993,29 +971,16 @@ Parameters: -l(line) (file) ნორმალური - Misra C - Misra C + Misra C - - Misra C++ 2008 - - - - Cert C - Cert C + Cert C - Cert C++ - Cert C++ - - - - Misra C++ 2023 - + Cert C++ @@ -1273,14 +1238,12 @@ This is probably because the settings were changed between the Cppcheck versions მონაცემთა ბაზის კომპილაცია - Visual Studio - Visual Studio + Visual Studio - Borland C++ Builder 6 - Borland C++ Builder 6 + Borland C++ Builder 6 @@ -1566,29 +1529,24 @@ Options: საკუთარი - Unix 32-bit - Unix 32-bit + Unix 32-bit - Unix 64-bit - Unix 64-bit + Unix 64-bit - Windows 32-bit ANSI - Windows 32-bit ANSI + Windows 32-bit ANSI - Windows 32-bit Unicode - Windows 32-bit Unicode + Windows 32-bit Unicode - Windows 64-bit - Windows 64-bit + Windows 64-bit @@ -1977,14 +1935,12 @@ Options: შეცდომებზე ნადირობა (ფასიანი) - Clang analyzer - Clang-ის ანალიზატორი + Clang-ის ანალიზატორი - Clang-tidy - Clang-tidy + Clang-tidy @@ -2025,9 +1981,8 @@ Options: Clang-tidy (ვერ ვიპოვე) - Visual Studio - Visual Studio + Visual Studio @@ -2035,9 +1990,8 @@ Options: მონაცემთა ბაზის კომპილაცია - Borland C++ Builder 6 - Borland C++ Builder 6 + Borland C++ Builder 6 @@ -2316,11 +2270,6 @@ Options: Tags - - - CWE - - QPlatformTheme @@ -2451,10 +2400,8 @@ Options: ჭდის გარეშე - - Cppcheck - Cppcheck + Cppcheck @@ -2555,10 +2502,8 @@ Please check the application path and parameters are correct. %p% (შემოწმებულია %1 ფაილი %2-დან) - - Cppcheck - Cppcheck + Cppcheck @@ -3236,9 +3181,8 @@ The user interface language has been reset to English. Open the Preferences-dial მომხმარებლის ინტერფეისი ინგლისურზე გადაირთო. გახსენით მორგების დიალოგი, რომ ხელმისაწვდომი ენებიდან სასურველი აირჩიოთ. - Cppcheck - Cppcheck + Cppcheck diff --git a/gui/cppcheck_ko.ts b/gui/cppcheck_ko.ts index 611eede0491..eef9ffac818 100644 --- a/gui/cppcheck_ko.ts +++ b/gui/cppcheck_ko.ts @@ -106,9 +106,8 @@ Kate로 파일을 열고, 해당 행으로 이동하는 예제: 뷰어 프로그램 선택 - Cppcheck - Cppcheck + Cppcheck @@ -124,10 +123,8 @@ Kate로 파일을 열고, 해당 행으로 이동하는 예제: 파일 찾기 실패: %1 - - Cppcheck - Cppcheck + Cppcheck @@ -158,9 +155,8 @@ Kate로 파일을 열고, 해당 행으로 이동하는 예제: - Cppcheck - Cppcheck + Cppcheck @@ -280,11 +276,8 @@ Kate로 파일을 열고, 해당 행으로 이동하는 예제: - - - Cppcheck - Cppcheck + Cppcheck @@ -420,23 +413,8 @@ Kate로 파일을 열고, 해당 행으로 이동하는 예제: MainWindow - - - - - - - - - - - - - - - Cppcheck - Cppcheck + Cppcheck @@ -710,31 +688,6 @@ Kate로 파일을 열고, 해당 행으로 이동하는 예제: Normal - - - Misra C - - - - - Misra C++ 2008 - - - - - Cert C - - - - - Cert C++ - - - - - Misra C++ 2023 - - Autosar @@ -1415,16 +1368,6 @@ Do you want to stop the analysis and exit Cppcheck? Compile database - - - Visual Studio - - - - - Borland C++ Builder 6 - - Current results will be cleared. @@ -1470,29 +1413,24 @@ Do you want to proceed? Platforms - Unix 32-bit - Unix 32-bit + Unix 32-bit - Unix 64-bit - Unix 64-bit + Unix 64-bit - Windows 32-bit ANSI - Windows 32-bit ANSI + Windows 32-bit ANSI - Windows 32-bit Unicode - Windows 32-bit Unicode + Windows 32-bit Unicode - Windows 64-bit - Windows 64-bit + Windows 64-bit @@ -1699,16 +1637,6 @@ Do you want to proceed? Bug hunting - - - Clang analyzer - - - - - Clang-tidy - - @@ -1977,21 +1905,11 @@ Do you want to proceed? MISRA rule texts file (%1) - - - Visual Studio - - Compile database - - - Borland C++ Builder 6 - - QObject @@ -2220,11 +2138,6 @@ Do you want to proceed? Tags - - - CWE - - QPlatformTheme @@ -2316,10 +2229,8 @@ Do you want to proceed? 숨기기 - - Cppcheck - Cppcheck + Cppcheck @@ -2443,10 +2354,8 @@ Please check the application path and parameters are correct. %p% (%2 중 %1 파일 검사됨) - - Cppcheck - Cppcheck + Cppcheck @@ -3118,9 +3027,8 @@ The user interface language has been reset to English. Open the Preferences-dial 언어가 영어로 초기화 됐습니다. 설정창을 열어서 설정 가능한 언어를 선택하세요. - Cppcheck - Cppcheck + Cppcheck diff --git a/gui/cppcheck_nl.ts b/gui/cppcheck_nl.ts index 7c58587662b..6a877a34909 100644 --- a/gui/cppcheck_nl.ts +++ b/gui/cppcheck_nl.ts @@ -106,9 +106,8 @@ Parameters: -l(lijn) (bestand) Selecteer applicatie - Cppcheck - Cppcheck + Cppcheck @@ -126,10 +125,8 @@ Parameters: -l(lijn) (bestand) Kon het bestand niet vinden: %1 - - Cppcheck - Cppcheck + Cppcheck @@ -160,9 +157,8 @@ Parameters: -l(lijn) (bestand) - Cppcheck - Cppcheck + Cppcheck @@ -282,11 +278,8 @@ Parameters: -l(lijn) (bestand) - - - Cppcheck - Cppcheck + Cppcheck @@ -424,23 +417,8 @@ Parameters: -l(lijn) (bestand) MainWindow - - - - - - - - - - - - - - - Cppcheck - Cppcheck + Cppcheck @@ -952,31 +930,6 @@ Parameters: -l(lijn) (bestand) Normal - - - Misra C - - - - - Misra C++ 2008 - - - - - Cert C - - - - - Cert C++ - - - - - Misra C++ 2023 - - Autosar @@ -1227,16 +1180,6 @@ Dit is waarschijnlijk omdat de instellingen zijn gewijzigd tussen de versies van Compile database - - - Visual Studio - - - - - Borland C++ Builder 6 - - Select files to analyze @@ -1493,31 +1436,6 @@ Options: Native - - - Unix 32-bit - - - - - Unix 64-bit - - - - - Windows 32-bit ANSI - - - - - Windows 32-bit Unicode - - - - - Windows 64-bit - - ProjectFile @@ -1904,16 +1822,6 @@ Options: Bug hunting (Premium) - - - Clang analyzer - - - - - Clang-tidy - - Defines: @@ -1952,21 +1860,11 @@ Options: Clang-tidy (not found) - - - Visual Studio - - Compile database - - - Borland C++ Builder 6 - - Import Project @@ -2244,11 +2142,6 @@ Options: Tags - - - CWE - - QPlatformTheme @@ -2375,10 +2268,8 @@ Options: - - Cppcheck - Cppcheck + Cppcheck @@ -2470,10 +2361,8 @@ Gelieve te controleren of de het pad en de parameters correct zijn.%p% (%1 van %2 bestanden gecontroleerd) - - Cppcheck - Cppcheck + Cppcheck @@ -3143,9 +3032,8 @@ The user interface language has been reset to English. Open the Preferences-dial De gebruikerstaal is gereset naar Engels. Open het dialoogvenster om een van de beschikbare talen te selecteren. - Cppcheck - Cppcheck + Cppcheck diff --git a/gui/cppcheck_ru.ts b/gui/cppcheck_ru.ts index a6608d90f7d..cd1a4c4d0ce 100644 --- a/gui/cppcheck_ru.ts +++ b/gui/cppcheck_ru.ts @@ -106,9 +106,8 @@ Parameters: -l(line) (file) Выберите приложение - Cppcheck - Cppcheck + Cppcheck @@ -126,10 +125,8 @@ Parameters: -l(line) (file) Невозможно найти файл: %1 - - Cppcheck - Cppcheck + Cppcheck @@ -160,9 +157,8 @@ Parameters: -l(line) (file) - Cppcheck - Cppcheck + Cppcheck @@ -282,11 +278,8 @@ Parameters: -l(line) (file) Открыть файл библиотеки - - - Cppcheck - Cppcheck + Cppcheck @@ -424,23 +417,8 @@ Parameters: -l(line) (file) MainWindow - - - - - - - - - - - - - - - Cppcheck - Cppcheck + Cppcheck @@ -952,31 +930,6 @@ Parameters: -l(line) (file) Normal - - - Misra C - - - - - Misra C++ 2008 - - - - - Cert C - - - - - Cert C++ - - - - - Misra C++ 2023 - - Autosar @@ -1235,14 +1188,12 @@ This is probably because the settings were changed between the Cppcheck versions - Visual Studio - Visual Studio + Visual Studio - Borland C++ Builder 6 - Borland C++ Builder 6 + Borland C++ Builder 6 @@ -1525,29 +1476,24 @@ Options: - Unix 32-bit - Unix 32-bit + Unix 32-bit - Unix 64-bit - Unix 64-bit + Unix 64-bit - Windows 32-bit ANSI - Windows 32-bit ANSI + Windows 32-bit ANSI - Windows 32-bit Unicode - Windows 32-bit Unicode + Windows 32-bit Unicode - Windows 64-bit - Windows 64-bit + Windows 64-bit @@ -1939,16 +1885,6 @@ Options: Bug hunting (Premium) - - - Clang analyzer - - - - - Clang-tidy - - Defines: @@ -1988,9 +1924,8 @@ Options: Clang-tidy (не найден) - Visual Studio - Visual Studio + Visual Studio @@ -1998,9 +1933,8 @@ Options: - Borland C++ Builder 6 - Borland C++ Builder 6 + Borland C++ Builder 6 @@ -2279,11 +2213,6 @@ Options: Tags - - - CWE - - QPlatformTheme @@ -2414,10 +2343,8 @@ Options: Тег отсутствует - - Cppcheck - Cppcheck + Cppcheck @@ -2515,10 +2442,8 @@ Please check the application path and parameters are correct. %p% (%1 из %2 файлов проверено) - - Cppcheck - Cppcheck + Cppcheck @@ -3192,9 +3117,8 @@ The user interface language has been reset to English. Open the Preferences-dial Язык пользовательского интерфейса был сброшен на английский. Откройте Настройки-диалог для выбора любого из доступных языков. - Cppcheck - Cppcheck + Cppcheck diff --git a/gui/cppcheck_sr.ts b/gui/cppcheck_sr.ts index 07e8059f724..ebfe46f5ced 100644 --- a/gui/cppcheck_sr.ts +++ b/gui/cppcheck_sr.ts @@ -96,9 +96,8 @@ Parameters: -l(line) (file) Select viewer application - Cppcheck - Cppcheck + Cppcheck @@ -114,10 +113,8 @@ Parameters: -l(line) (file) Could not find the file: %1 - - Cppcheck - Cppcheck + Cppcheck @@ -148,9 +145,8 @@ Parameters: -l(line) (file) - Cppcheck - Cppcheck + Cppcheck @@ -270,11 +266,8 @@ Parameters: -l(line) (file) - - - Cppcheck - Cppcheck + Cppcheck @@ -412,23 +405,8 @@ Parameters: -l(line) (file) MainWindow - - - - - - - - - - - - - - - Cppcheck - Cppcheck + Cppcheck @@ -940,31 +918,6 @@ Parameters: -l(line) (file) Normal - - - Misra C - - - - - Misra C++ 2008 - - - - - Cert C - - - - - Cert C++ - - - - - Misra C++ 2023 - - Autosar @@ -1212,16 +1165,6 @@ This is probably because the settings were changed between the Cppcheck versions Compile database - - - Visual Studio - - - - - Borland C++ Builder 6 - - Select files to analyze @@ -1474,29 +1417,24 @@ Options: - Unix 32-bit - Unix 32-bit + Unix 32-bit - Unix 64-bit - Unix 64-bit + Unix 64-bit - Windows 32-bit ANSI - Windows 32-bit ANSI + Windows 32-bit ANSI - Windows 32-bit Unicode - Windows 32-bit Unicode + Windows 32-bit Unicode - Windows 64-bit - Windows 64-bit + Windows 64-bit @@ -1884,16 +1822,6 @@ Options: Bug hunting (Premium) - - - Clang analyzer - - - - - Clang-tidy - - Defines: @@ -1932,21 +1860,11 @@ Options: Clang-tidy (not found) - - - Visual Studio - - Compile database - - - Borland C++ Builder 6 - - Import Project @@ -2222,11 +2140,6 @@ Options: Tags - - - CWE - - QPlatformTheme @@ -2345,10 +2258,8 @@ Options: - - Cppcheck - Cppcheck + Cppcheck @@ -2432,10 +2343,8 @@ Please check the application path and parameters are correct. - - Cppcheck - Cppcheck + Cppcheck @@ -3096,9 +3005,8 @@ The user interface language has been reset to English. Open the Preferences-dial - Cppcheck - Cppcheck + Cppcheck diff --git a/gui/cppcheck_sv.ts b/gui/cppcheck_sv.ts index 4b8164d7775..43d6886afc0 100644 --- a/gui/cppcheck_sv.ts +++ b/gui/cppcheck_sv.ts @@ -106,9 +106,8 @@ Parametrar: -l(line) (file) Välj program - Cppcheck - Cppcheck + Cppcheck @@ -126,10 +125,8 @@ Parametrar: -l(line) (file) Kunde inte hitta filen: %1 - - Cppcheck - Cppcheck + Cppcheck @@ -160,9 +157,8 @@ Parametrar: -l(line) (file) - Cppcheck - Cppcheck + Cppcheck @@ -282,11 +278,8 @@ Parametrar: -l(line) (file) Öppna Library fil - - - Cppcheck - Cppcheck + Cppcheck @@ -430,23 +423,8 @@ Exempel: MainWindow - - - - - - - - - - - - - - - Cppcheck - Cppcheck + Cppcheck @@ -959,31 +937,6 @@ Exempel: Normal - - - Misra C - - - - - Misra C++ 2008 - - - - - Cert C - - - - - Cert C++ - - - - - Misra C++ 2023 - - Autosar @@ -1242,14 +1195,8 @@ En trolig orsak är att inställningarna ändrats för olika Cppcheck versioner. - Visual Studio - Visual Studio - - - - Borland C++ Builder 6 - + Visual Studio @@ -1530,29 +1477,24 @@ Options: Native - Unix 32-bit - Unix 32-bit + Unix 32-bit - Unix 64-bit - Unix 64-bit + Unix 64-bit - Windows 32-bit ANSI - Windows 32-bit ANSI + Windows 32-bit ANSI - Windows 32-bit Unicode - Windows 32-bit Unicode + Windows 32-bit Unicode - Windows 64-bit - Windows 64-bit + Windows 64-bit @@ -1941,14 +1883,12 @@ Options: - Clang analyzer - Clang analyzer + Clang analyzer - Clang-tidy - Clang-tidy + Clang-tidy @@ -2025,20 +1965,14 @@ Options: Välj mapp att analysera - Visual Studio - Visual Studio + Visual Studio Compile database - - - Borland C++ Builder 6 - - Import Project @@ -2280,11 +2214,6 @@ Options: Tags - - - CWE - - QPlatformTheme @@ -2415,10 +2344,8 @@ Options: Ingen tag - - Cppcheck - Cppcheck + Cppcheck @@ -2519,10 +2446,8 @@ Kontrollera att sökvägen och parametrarna är korrekta. %p% (%1 av %2 filer analyserade) - - Cppcheck - Cppcheck + Cppcheck @@ -3196,9 +3121,8 @@ The user interface language has been reset to English. Open the Preferences-dial Språket har nollställts till Engelska. Öppna Preferences och välj något av de tillgängliga språken. - Cppcheck - Cppcheck + Cppcheck diff --git a/gui/cppcheck_zh_CN.ts b/gui/cppcheck_zh_CN.ts index 5860c842a16..5ecaa17a91b 100644 --- a/gui/cppcheck_zh_CN.ts +++ b/gui/cppcheck_zh_CN.ts @@ -105,9 +105,8 @@ Parameters: -l(line) (file) 选择查看应用程序 - Cppcheck - Cppcheck + Cppcheck @@ -123,10 +122,8 @@ Parameters: -l(line) (file) 无法找到文件: %1 - - Cppcheck - Cppcheck + Cppcheck @@ -157,9 +154,8 @@ Parameters: -l(line) (file) 帮助文件 '%1' 未找到 - Cppcheck - Cppcheck + Cppcheck @@ -279,11 +275,8 @@ Parameters: -l(line) (file) 打开库文件 - - - Cppcheck - Cppcheck + Cppcheck @@ -431,23 +424,8 @@ Parameters: -l(line) (file) MainWindow - - - - - - - - - - - - - - - Cppcheck - Cppcheck + Cppcheck @@ -990,31 +968,6 @@ Parameters: -l(line) (file) Normal 常规 - - - Misra C - - - - - Misra C++ 2008 - - - - - Cert C - - - - - Cert C++ - - - - - Misra C++ 2023 - - Autosar @@ -1242,14 +1195,12 @@ Analysis is stopped. Compile database - Visual Studio - Visual Studio + Visual Studio - Borland C++ Builder 6 - Borland C++ Builder 6 + Borland C++ Builder 6 @@ -1531,31 +1482,6 @@ Options: Native 本地 - - - Unix 32-bit - - - - - Unix 64-bit - - - - - Windows 32-bit ANSI - - - - - Windows 32-bit Unicode - - - - - Windows 64-bit - - ProjectFile @@ -1947,14 +1873,12 @@ Options: - Clang analyzer - Clang analyzer + Clang analyzer - Clang-tidy - Clang-tidy + Clang-tidy @@ -1995,9 +1919,8 @@ Options: Clang-tidy (未找到) - Visual Studio - Visual Studio + Visual Studio @@ -2005,9 +1928,8 @@ Options: Compile database - Borland C++ Builder 6 - Borland C++ Builder 6 + Borland C++ Builder 6 @@ -2284,11 +2206,6 @@ Options: Tags - - - CWE - - QPlatformTheme @@ -2419,10 +2336,8 @@ Options: 取消标记 - - Cppcheck - Cppcheck + Cppcheck @@ -2549,10 +2464,8 @@ Please check the application path and parameters are correct. %p% (%2 个文件已检查 %1 个) - - Cppcheck - Cppcheck + Cppcheck @@ -3204,9 +3117,8 @@ The user interface language has been reset to English. Open the Preferences-dial 用户界面语言已被重置为英语。打开“首选项”对话框,选择任何可用的语言。 - Cppcheck - Cppcheck + Cppcheck diff --git a/gui/cppcheck_zh_TW.ts b/gui/cppcheck_zh_TW.ts index 841650ba5b1..3c25925c207 100644 --- a/gui/cppcheck_zh_TW.ts +++ b/gui/cppcheck_zh_TW.ts @@ -95,9 +95,8 @@ Parameters: -l(line) (file) 選取檢視器應用程式 - Cppcheck - Cppcheck + Cppcheck @@ -128,10 +127,8 @@ Parameters: -l(line) (file) 無法找到檔案: %1 - - Cppcheck - Cppcheck + Cppcheck @@ -162,9 +159,8 @@ Parameters: -l(line) (file) 找不到幫助檔 '%1' - Cppcheck - Cppcheck + Cppcheck @@ -284,11 +280,8 @@ Parameters: -l(line) (file) 開啟程式庫檔案 - - - Cppcheck - Cppcheck + Cppcheck @@ -424,23 +417,8 @@ Parameters: -l(line) (file) MainWindow - - - - - - - - - - - - - - - Cppcheck - Cppcheck + Cppcheck @@ -974,29 +952,12 @@ Parameters: -l(line) (file) - - Misra C - - - - Misra C++ 2008 - Misra C++ 2008 - - - - Cert C - - - - - Cert C++ - + Misra C++ 2008 - Misra C++ 2023 - Misra C++ 2023 + Misra C++ 2023 @@ -1083,14 +1044,12 @@ This is probably because the settings were changed between the Cppcheck versions 編譯資料庫 - Visual Studio - Visual Studio + Visual Studio - Borland C++ Builder 6 - Borland C++ Builder 6 + Borland C++ Builder 6 @@ -1485,29 +1444,24 @@ Do you want to remove the file from the recently used projects -list? 原生 - Unix 32-bit - Unix 32 位元 + Unix 32 位元 - Unix 64-bit - Unix 64 位元 + Unix 64 位元 - Windows 32-bit ANSI - Windows 32 位元 ANSI + Windows 32 位元 ANSI - Windows 32-bit Unicode - Windows 32 位元 Unicode + Windows 32 位元 Unicode - Windows 64-bit - Windows 64 位元 + Windows 64 位元 @@ -1906,14 +1860,12 @@ Do you want to remove the file from the recently used projects -list? 外部工具 - Clang-tidy - Clang-tidy + Clang-tidy - Clang analyzer - Clang 分析器 + Clang 分析器 @@ -1939,9 +1891,8 @@ Do you want to remove the file from the recently used projects -list? 選取 Cppcheck 建置目錄 - Visual Studio - Visual Studio + Visual Studio @@ -1949,9 +1900,8 @@ Do you want to remove the file from the recently used projects -list? 編譯資料庫 - Borland C++ Builder 6 - Borland C++ Builder 6 + Borland C++ Builder 6 @@ -2237,11 +2187,6 @@ Do you want to remove the file from the recently used projects -list? Tags - - - CWE - - QPlatformTheme @@ -2362,10 +2307,8 @@ Do you want to remove the file from the recently used projects -list? 取消標記 - - Cppcheck - Cppcheck + Cppcheck @@ -2479,10 +2422,8 @@ Please check the application path and parameters are correct. - - Cppcheck - Cppcheck + Cppcheck @@ -3115,11 +3056,6 @@ To toggle what kind of errors are shown, open view menu. The user interface language has been reset to English. Open the Preferences-dialog to select any of the available languages. - - - Cppcheck - - TxtReport diff --git a/gui/fileviewdialog.cpp b/gui/fileviewdialog.cpp index 3f66f008678..9d453519450 100644 --- a/gui/fileviewdialog.cpp +++ b/gui/fileviewdialog.cpp @@ -54,7 +54,7 @@ void FileViewDialog::loadTextFile(const QString &filename, QTextEdit *edit) msg = msg.arg(filename); QMessageBox msgbox(QMessageBox::Critical, - tr("Cppcheck"), + "Cppcheck", msg, QMessageBox::Ok, this); @@ -68,7 +68,7 @@ void FileViewDialog::loadTextFile(const QString &filename, QTextEdit *edit) msg = msg.arg(filename); QMessageBox msgbox(QMessageBox::Critical, - tr("Cppcheck"), + "Cppcheck", msg, QMessageBox::Ok, this); diff --git a/gui/helpdialog.cpp b/gui/helpdialog.cpp index 78ac1e0e635..bef304c5471 100644 --- a/gui/helpdialog.cpp +++ b/gui/helpdialog.cpp @@ -84,7 +84,7 @@ HelpDialog::HelpDialog(QWidget *parent) : if (helpFile.isEmpty()) { const QString msg = tr("Helpfile '%1' was not found").arg("online-help.qhc"); QMessageBox msgBox(QMessageBox::Warning, - tr("Cppcheck"), + "Cppcheck", msg, QMessageBox::Ok, this); diff --git a/gui/librarydialog.cpp b/gui/librarydialog.cpp index 3199af9a975..147363a3a25 100644 --- a/gui/librarydialog.cpp +++ b/gui/librarydialog.cpp @@ -107,7 +107,7 @@ void LibraryDialog::openCfg() QFile file(selectedFile); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { QMessageBox msg(QMessageBox::Critical, - tr("Cppcheck"), + "Cppcheck", tr("Cannot open file %1.").arg(selectedFile), QMessageBox::Ok, this); @@ -119,7 +119,7 @@ void LibraryDialog::openCfg() const QString errmsg = tempdata.open(file); if (!errmsg.isNull()) { QMessageBox msg(QMessageBox::Critical, - tr("Cppcheck"), + "Cppcheck", tr("Failed to load %1. %2.").arg(selectedFile).arg(errmsg), QMessageBox::Ok, this); @@ -156,7 +156,7 @@ void LibraryDialog::saveCfg() mUi->buttonSave->setEnabled(false); } else { QMessageBox msg(QMessageBox::Critical, - tr("Cppcheck"), + "Cppcheck", tr("Cannot save file %1.").arg(mFileName), QMessageBox::Ok, this); diff --git a/gui/mainwindow.cpp b/gui/mainwindow.cpp index bf73828bed4..31f124bc5b0 100644 --- a/gui/mainwindow.cpp +++ b/gui/mainwindow.cpp @@ -456,7 +456,7 @@ void MainWindow::loadSettings() "Please check (and fix) the editor application settings, otherwise the editor " "program might not start correctly."); QMessageBox msgBox(QMessageBox::Warning, - tr("Cppcheck"), + "Cppcheck", msg, QMessageBox::Ok, this); @@ -666,7 +666,7 @@ void MainWindow::doAnalyzeFiles(const QStringList &files, const bool checkLib, c if (fileNames.isEmpty()) { QMessageBox msg(QMessageBox::Warning, - tr("Cppcheck"), + "Cppcheck", tr("No suitable files found to analyze!"), QMessageBox::Ok, this); @@ -751,7 +751,7 @@ QStringList MainWindow::selectFilesToAnalyze(QFileDialog::FileMode mode) { if (mProjectFile) { QMessageBox msgBox(this); - msgBox.setWindowTitle(tr("Cppcheck")); + msgBox.setWindowTitle("Cppcheck"); const QString msg(tr("You must close the project file before selecting new files or directories!")); msgBox.setText(msg); msgBox.setIcon(QMessageBox::Critical); @@ -768,8 +768,8 @@ QStringList MainWindow::selectFilesToAnalyze(QFileDialog::FileMode mode) QMap filters; filters[tr("C/C++ Source")] = FileList::getDefaultFilters().join(" "); filters[tr("Compile database")] = compile_commands_json; - filters[tr("Visual Studio")] = "*.sln *.slnx *.vcxproj"; - filters[tr("Borland C++ Builder 6")] = "*.bpr"; + filters["Visual Studio"] = "*.sln *.slnx *.vcxproj"; + filters["Borland C++ Builder 6"] = "*.bpr"; QString lastFilter = mSettings->value(SETTINGS_LAST_ANALYZE_FILES_FILTER).toString(); selected = QFileDialog::getOpenFileNames(this, tr("Select files to analyze"), @@ -857,7 +857,7 @@ void MainWindow::analyzeDirectory() if (projFiles.size() == 1) { // If one project file found, suggest loading it QMessageBox msgBox(this); - msgBox.setWindowTitle(tr("Cppcheck")); + msgBox.setWindowTitle("Cppcheck"); const QString msg(tr("Found project file: %1\n\nDo you want to " "load this project file instead?").arg(projFiles[0])); msgBox.setText(msg); @@ -879,7 +879,7 @@ void MainWindow::analyzeDirectory() // If multiple project files found inform that there are project // files also available. QMessageBox msgBox(this); - msgBox.setWindowTitle(tr("Cppcheck")); + msgBox.setWindowTitle("Cppcheck"); const QString msg(tr("Found project files from the directory.\n\n" "Do you want to proceed analysis without " "using any of these project files?")); @@ -1466,7 +1466,7 @@ void MainWindow::openResults() { if (mUI->mResults->hasResults()) { QMessageBox msgBox(this); - msgBox.setWindowTitle(tr("Cppcheck")); + msgBox.setWindowTitle("Cppcheck"); const QString msg(tr("Current results will be cleared.\n\n" "Opening a new XML file will clear current results.\n" "Do you want to proceed?")); @@ -1591,7 +1591,7 @@ void MainWindow::closeEvent(QCloseEvent *event) "Do you want to stop the analysis and exit Cppcheck?")); QMessageBox msg(QMessageBox::Warning, - tr("Cppcheck"), + "Cppcheck", text, QMessageBox::Yes | QMessageBox::No, this); @@ -1886,7 +1886,7 @@ void MainWindow::analyzeProject(const ProjectFile *projectFile, const QStringLis buildDir = inf.canonicalPath() + '/' + buildDir; if (!QDir(buildDir).exists()) { QMessageBox msg(QMessageBox::Question, - tr("Cppcheck"), + "Cppcheck", tr("Build dir '%1' does not exist, create it?").arg(buildDir), QMessageBox::Yes | QMessageBox::No, this); @@ -1894,7 +1894,7 @@ void MainWindow::analyzeProject(const ProjectFile *projectFile, const QStringLis QDir().mkpath(buildDir); } else if (!projectFile->getAddons().isEmpty()) { QMessageBox m(QMessageBox::Critical, - tr("Cppcheck"), + "Cppcheck", tr("To check the project using addons, you need a build directory."), QMessageBox::Ok, this); @@ -1949,7 +1949,7 @@ void MainWindow::analyzeProject(const ProjectFile *projectFile, const QStringLis if (!errorMessage.isEmpty()) { QMessageBox msg(QMessageBox::Critical, - tr("Cppcheck"), + "Cppcheck", tr("Failed to import '%1': %2\n\nAnalysis is stopped.").arg(prjfile).arg(errorMessage), QMessageBox::Ok, this); @@ -1958,7 +1958,7 @@ void MainWindow::analyzeProject(const ProjectFile *projectFile, const QStringLis } } catch (InternalError &e) { QMessageBox msg(QMessageBox::Critical, - tr("Cppcheck"), + "Cppcheck", tr("Failed to import '%1' (%2), analysis is stopped").arg(prjfile).arg(QString::fromStdString(e.errorMessage)), QMessageBox::Ok, this); @@ -2030,7 +2030,7 @@ void MainWindow::editProjectFile() { if (!mProjectFile) { QMessageBox msg(QMessageBox::Critical, - tr("Cppcheck"), + "Cppcheck", tr("No project file loaded"), QMessageBox::Ok, this); @@ -2118,7 +2118,7 @@ void MainWindow::openRecentProject() "used projects -list?").arg(project)); QMessageBox msg(QMessageBox::Warning, - tr("Cppcheck"), + "Cppcheck", text, QMessageBox::Yes | QMessageBox::No, this); diff --git a/gui/mainwindow.ui b/gui/mainwindow.ui index 1f66d1a582a..16577224874 100644 --- a/gui/mainwindow.ui +++ b/gui/mainwindow.ui @@ -23,7 +23,7 @@ - Cppcheck + Cppcheck @@ -684,7 +684,7 @@ :/cppcheck-gui.png:/cppcheck-gui.png - Cppcheck + Cppcheck Show Cppcheck results @@ -992,7 +992,7 @@ true - Misra C + Misra C @@ -1000,7 +1000,7 @@ true - Misra C++ 2008 + Misra C++ 2008 @@ -1008,7 +1008,7 @@ true - Cert C + Cert C @@ -1016,7 +1016,7 @@ true - Cert C++ + Cert C++ @@ -1024,7 +1024,7 @@ true - Misra C++ 2023 + Misra C++ 2023 diff --git a/gui/platforms.cpp b/gui/platforms.cpp index 77683a6ea09..27504006477 100644 --- a/gui/platforms.cpp +++ b/gui/platforms.cpp @@ -36,11 +36,11 @@ void Platforms::add(const QString &title, Platform::Type platform) void Platforms::init() { add(tr("Native"), Platform::Type::Native); - add(tr("Unix 32-bit"), Platform::Type::Unix32); - add(tr("Unix 64-bit"), Platform::Type::Unix64); - add(tr("Windows 32-bit ANSI"), Platform::Type::Win32A); - add(tr("Windows 32-bit Unicode"), Platform::Type::Win32W); - add(tr("Windows 64-bit"), Platform::Type::Win64); + add("Unix 32-bit", Platform::Type::Unix32); + add("Unix 64-bit", Platform::Type::Unix64); + add("Windows 32-bit ANSI", Platform::Type::Win32A); + add("Windows 32-bit Unicode", Platform::Type::Win32W); + add("Windows 64-bit", Platform::Type::Win64); } int Platforms::getCount() const diff --git a/gui/projectfile.ui b/gui/projectfile.ui index 84a1d6e40ec..9f7ad91fa8f 100644 --- a/gui/projectfile.ui +++ b/gui/projectfile.ui @@ -1010,14 +1010,14 @@ - Clang-tidy + Clang-Tidy - Clang analyzer + Clang Static Analyzer diff --git a/gui/projectfiledialog.cpp b/gui/projectfiledialog.cpp index e156f3dfe3b..72e3d651471 100644 --- a/gui/projectfiledialog.cpp +++ b/gui/projectfiledialog.cpp @@ -624,9 +624,9 @@ void ProjectFileDialog::browseImportProject() const QFileInfo inf(mProjectFile->getFilename()); const QDir &dir = inf.absoluteDir(); QMap filters; - filters[tr("Visual Studio")] = "*.sln *.slnx *.vcxproj"; + filters["Visual Studio"] = "*.sln *.slnx *.vcxproj"; filters[tr("Compile database")] = "compile_commands.json"; - filters[tr("Borland C++ Builder 6")] = "*.bpr"; + filters["Borland C++ Builder 6"] = "*.bpr"; QString fileName = QFileDialog::getOpenFileName(this, tr("Import Project"), dir.canonicalPath(), toFilterString(filters)); diff --git a/gui/resultstree.cpp b/gui/resultstree.cpp index fc70fdb84af..ed8b3c7412e 100644 --- a/gui/resultstree.cpp +++ b/gui/resultstree.cpp @@ -122,7 +122,7 @@ static QStringList getLabels() { QObject::tr("Rule"), QObject::tr("Since date"), QObject::tr("Tags"), - QObject::tr("CWE")}; + "CWE"}; } static Severity getSeverity(ReportType reportType, const ErrorItem& errorItem) { @@ -741,7 +741,7 @@ void ResultsTree::startApplication(const ResultItem *target, int application) //If there are no applications specified, tell the user about it if (mApplications->getApplicationCount() == 0) { QMessageBox msg(QMessageBox::Critical, - tr("Cppcheck"), + "Cppcheck", tr("No editor application configured.\n\n" "Configure the editor application for Cppcheck in preferences/Applications."), QMessageBox::Ok, @@ -755,7 +755,7 @@ void ResultsTree::startApplication(const ResultItem *target, int application) if (application == -1) { QMessageBox msg(QMessageBox::Critical, - tr("Cppcheck"), + "Cppcheck", tr("No default editor application selected.\n\n" "Please select the default editor application in preferences/Applications."), QMessageBox::Ok, diff --git a/gui/resultsview.cpp b/gui/resultsview.cpp index 496c0793157..55f673ab80c 100644 --- a/gui/resultsview.cpp +++ b/gui/resultsview.cpp @@ -345,7 +345,7 @@ void ResultsView::checkingFinished() //Tell user that we found no errors if (!hasResults()) { QMessageBox msg(QMessageBox::Information, - tr("Cppcheck"), + "Cppcheck", tr("No errors found."), QMessageBox::Ok, this); @@ -356,7 +356,7 @@ void ResultsView::checkingFinished() QString text = tr("Errors were found, but they are configured to be hidden.\n" \ "To toggle what kind of errors are shown, open view menu."); QMessageBox msg(QMessageBox::Information, - tr("Cppcheck"), + "Cppcheck", text, QMessageBox::Ok, this); diff --git a/gui/translationhandler.cpp b/gui/translationhandler.cpp index d8160525856..14faedc04a2 100644 --- a/gui/translationhandler.cpp +++ b/gui/translationhandler.cpp @@ -133,7 +133,7 @@ bool TranslationHandler::setLanguage(const QString &code) "the Preferences-dialog to select any of the available " "languages.").arg(error)); QMessageBox msgBox(QMessageBox::Warning, - tr("Cppcheck"), + "Cppcheck", msg, QMessageBox::Ok); msgBox.exec(); From 37b5e958a2bc9380594c9270620ee38adde1b0f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20St=C3=B6neberg?= Date: Wed, 17 Jun 2026 10:28:29 +0200 Subject: [PATCH 026/165] removed usage of `#file`/`#endfile` (#7951) --- lib/cppcheck.cpp | 8 --- test/cli/other_test.py | 111 ++++++++++++++++++++++++++++++++++++ test/testpreprocessor.cpp | 91 +++++++++++++---------------- test/testtokenize.cpp | 35 ++++++------ test/testunusedprivfunc.cpp | 39 ------------- 5 files changed, 168 insertions(+), 116 deletions(-) diff --git a/lib/cppcheck.cpp b/lib/cppcheck.cpp index da078e5eb20..b7ab1f99039 100644 --- a/lib/cppcheck.cpp +++ b/lib/cppcheck.cpp @@ -1136,15 +1136,7 @@ unsigned int CppCheck::checkInternal(const FileWithDetails& file, const std::str codeWithoutCfg = preprocessor.getcode(currentConfig, files, true); }); - if (startsWith(codeWithoutCfg,"#file")) - codeWithoutCfg.insert(0U, "//"); std::string::size_type pos = 0; - while ((pos = codeWithoutCfg.find("\n#file",pos)) != std::string::npos) - codeWithoutCfg.insert(pos+1U, "//"); - pos = 0; - while ((pos = codeWithoutCfg.find("\n#endfile",pos)) != std::string::npos) - codeWithoutCfg.insert(pos+1U, "//"); - pos = 0; while ((pos = codeWithoutCfg.find(Preprocessor::macroChar,pos)) != std::string::npos) codeWithoutCfg[pos] = ' '; mErrorLogger.reportOut(codeWithoutCfg, Color::Reset); diff --git a/test/cli/other_test.py b/test/cli/other_test.py index f788a7d21c8..c79fd0c8e50 100644 --- a/test/cli/other_test.py +++ b/test/cli/other_test.py @@ -4240,6 +4240,117 @@ def test_no_valid_configuration(tmp_path): ] +# The implementation for "A::a" is missing - so don't check if "A::b" is used or not +def test_unused_private_function_incomplete_impl(tmpdir): + test_inc = os.path.join(tmpdir, 'test.h') + with open(test_inc, 'wt') as f: + f.write( +""" +class A +{ +public: + A(); + void a(); +private: + void b(); +}; +""") + + test_file = os.path.join(tmpdir, 'test.cpp') + with open(test_file, 'wt') as f: + f.write( +""" +#include "test.h" + +A::A() { } +void A::b() { } +""") + + args = [ + '-q', + '--template=simple', + '--enable=style', + '--suppress=functionStatic', # we do not care about this - this was converted from TestUnusedPrivateFunction + test_file + ] + + ret, stdout, stderr = cppcheck(args) + assert stdout == '' + assert stderr.splitlines() == [] + assert ret == 0, stdout + + +def test_unused_private_function_multi_file(tmpdir): # ticket #2567 + test_inc = os.path.join(tmpdir, 'test.h') + with open(test_inc, 'wt') as f: + f.write( +""" +struct Fred +{ + Fred() + { + Init(); + } +private: + void Init(); +}; +""") + + test_file = os.path.join(tmpdir, 'test.cpp') + with open(test_file, 'wt') as f: + f.write( +""" +#include "test.h" + +void Fred::Init() +{ +} +""") + + args = [ + '-q', + '--template=simple', + '--enable=style', + '--suppress=functionStatic', # we do not care about this - this was converted from TestUnusedPrivateFunction + test_file + ] + + ret, stdout, stderr = cppcheck(args) + assert stdout == '' + assert stderr.splitlines() == [] + assert ret == 0, stdout + + +def test_missing_doublequote_include(tmpdir): + test_inc = os.path.join(tmpdir, 'abc.h') + with open(test_inc, 'wt') as f: + f.write( +''' +#define a +" +''') + + test_file = os.path.join(tmpdir, 'test.cpp') + with open(test_file, 'wt') as f: + f.write( +""" +#include "abc.h" +""") + + args = [ + '-q', + '--template=simple', + test_file + ] + + ret, stdout, stderr = cppcheck(args) + assert stdout == '' + assert stderr.splitlines() == [ + f"{test_inc}:3:1: error: No pair for character (\"). Can't process file. File is either invalid or unicode, which is currently not supported. [syntaxError]" + ] + assert ret == 0, stdout + + def test_no_valid_configuration_check_config(tmp_path): test_file = tmp_path / 'test.c' with open(test_file, "w") as f: diff --git a/test/testpreprocessor.cpp b/test/testpreprocessor.cpp index 7e01f6f233b..b90a879738d 100644 --- a/test/testpreprocessor.cpp +++ b/test/testpreprocessor.cpp @@ -50,13 +50,14 @@ class TestPreprocessor : public TestFixture { TestPreprocessor() : TestFixture("TestPreprocessor") {} private: + #define expandMacros(...) expandMacros_(__FILE__, __LINE__, __VA_ARGS__) template - std::string expandMacros(const char (&code)[size], ErrorLogger &errorLogger) const { + std::string expandMacros_(const char* file, int line, const char (&code)[size], ErrorLogger &errorLogger) const { simplecpp::OutputList outputList; std::vector files; simplecpp::TokenList tokens1 = simplecpp::TokenList(code, files, "file.cpp", &outputList); Preprocessor p(tokens1, settingsDefault, errorLogger, Path::identify(tokens1.getFiles()[0], false)); - ASSERT(p.loadFiles(files)); + ASSERT_LOC(p.loadFiles(files), file, line); simplecpp::TokenList tokens2 = p.preprocess("", files, outputList); (void)p.reportOutput(outputList, true); return tokens2.stringify(); @@ -140,7 +141,7 @@ class TestPreprocessor : public TestFixture { cfgs = preprocessor.getConfigs(); for (const std::string & config : cfgs) { try { - const bool writeLocations = (strstr(code, "#file") != nullptr) || (strstr(code, "#include") != nullptr); + const bool writeLocations = (strstr(code, "#include") != nullptr); cfgcode[config] = preprocessor.getcode(config, files, writeLocations); } catch (const simplecpp::Output &) { cfgcode[config] = ""; @@ -392,7 +393,7 @@ class TestPreprocessor : public TestFixture { std::vector files; simplecpp::OutputList outputList; simplecpp::TokenList tokens(code,files,"test.c",&outputList); - Preprocessor preprocessor(tokens, settings, *this, Standards::Language::C); // TODO: do we need to consider #file? + Preprocessor preprocessor(tokens, settings, *this, Standards::Language::C); ASSERT(preprocessor.loadFiles(files)); ASSERT(!preprocessor.reportOutput(outputList, true)); preprocessor.removeComments(); @@ -407,7 +408,7 @@ class TestPreprocessor : public TestFixture { std::size_t getHash(const char (&code)[size]) { std::vector files; simplecpp::TokenList tokens(code,files,"test.c"); - Preprocessor preprocessor(tokens, settingsDefault, *this, Standards::Language::C); // TODO: do we need to consider #file? + Preprocessor preprocessor(tokens, settingsDefault, *this, Standards::Language::C); ASSERT(preprocessor.loadFiles(files)); preprocessor.removeComments(); return preprocessor.calculateHash(""); @@ -472,16 +473,19 @@ class TestPreprocessor : public TestFixture { void error4() { // In included file { + ScopedFile header("ab.h", "#error hello world!\n"); const auto settings = dinit(Settings, $.userDefines = "TEST"); - const char code[] = "#file \"ab.h\"\n#error hello world!\n#endfile"; + const char code[] = "#include \"ab.h\""; (void)getcodeforcfg(settings, *this, code, "TEST", "test.c"); ASSERT_EQUALS("[ab.h:1:2]: (error) #error hello world! [preprocessorErrorDirective]\n", errout_str()); } // After including a file { + ScopedFile header("ab.h", ""); const auto settings = dinit(Settings, $.userDefines = "TEST"); - const char code[] = "#file \"ab.h\"\n\n#endfile\n#error aaa"; + const char code[] = "#include \"ab.h\"\n" + "#error aaa"; (void)getcodeforcfg(settings, *this, code, "TEST", "test.c"); ASSERT_EQUALS("[test.c:2:2]: (error) #error aaa [preprocessorErrorDirective]\n", errout_str()); } @@ -584,35 +588,35 @@ class TestPreprocessor : public TestFixture { } void includeguard1() { + ScopedFile header("abc.h", + "#ifndef abcH\n" + "#define abcH\n" + "#endif\n"); // Handling include guards.. - const char filedata[] = "#file \"abc.h\"\n" - "#ifndef abcH\n" - "#define abcH\n" - "#endif\n" - "#endfile\n" + const char filedata[] = "#include \"abc.h\"\n" "#ifdef ABC\n" "#endif"; ASSERT_EQUALS("\nABC=ABC\n", getConfigsStr(filedata)); } void includeguard2() { + ScopedFile header("abc.h", + "foo\n" + "#ifdef ABC\n" + "\n" + "#endif\n"); // Handling include guards.. - const char filedata[] = "#file \"abc.h\"\n" - "foo\n" - "#ifdef ABC\n" - "\n" - "#endif\n" - "#endfile\n"; + const char filedata[] = "#include \"abc.h\"\n"; ASSERT_EQUALS("\nABC=ABC\n", getConfigsStr(filedata)); } void ifdefwithfile() { + ScopedFile header("abc.h", "class A{};/*\n\n\n\n\n\n\n*/\n"); + // Handling include guards.. const char filedata[] = "#ifdef ABC\n" - "#file \"abc.h\"\n" - "class A{};/*\n\n\n\n\n\n\n*/\n" - "#endfile\n" + "#include \"abc.h\"\n" "#endif\n" "int main() {}\n"; @@ -1576,22 +1580,9 @@ class TestPreprocessor : public TestFixture { } { - const char filedata[] = "#file \"abc.h\"\n" - "#define a\n" - "\"\n" - "#endfile\n"; - - // expand macros.. - const std::string actual(expandMacros(filedata, *this)); - - ASSERT_EQUALS("", actual); - ASSERT_EQUALS("[abc.h:2:1]: (error) No pair for character (\"). Can't process file. File is either invalid or unicode, which is currently not supported. [syntaxError]\n", errout_str()); - } - - { - const char filedata[] = "#file \"abc.h\"\n" - "#define a\n" - "#endfile\n" + ScopedFile header("abc.h", + "#define a\n"); + const char filedata[] = "#include \"abc.h\"\n" "\"\n"; // expand macros.. @@ -2286,14 +2277,14 @@ class TestPreprocessor : public TestFixture { } void getConfigs7e() { + ScopedFile header("test.h", + "#ifndef test_h\n" + "#define test_h\n" + "#ifdef ABC\n" + "#endif\n" + "#endif\n"); const char filedata[] = "#ifdef ABC\n" - "#file \"test.h\"\n" - "#ifndef test_h\n" - "#define test_h\n" - "#ifdef ABC\n" - "#endif\n" - "#endif\n" - "#endfile\n" + "#include \"test.h\"\n" "#endif\n"; ASSERT_EQUALS("\nABC=ABC\n", getConfigsStr(filedata)); } @@ -2315,12 +2306,12 @@ class TestPreprocessor : public TestFixture { } void getConfigs11() { // #9832 - include guards - const char filedata[] = "#file \"test.h\"\n" - "#if !defined(test_h)\n" - "#define test_h\n" - "123\n" - "#endif\n" - "#endfile\n"; + ScopedFile header("test.h", + "#if !defined(test_h)\n" + "#define test_h\n" + "123\n" + "#endif\n"); + const char filedata[] = "#include \"test.h\"\n"; ASSERT_EQUALS("\n", getConfigsStr(filedata)); } diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp index b1e3e87cdcf..6e5ea0f785f 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -8848,14 +8848,11 @@ class TestTokenizer : public TestFixture { } void testDirectiveIncludeLocations() { + ScopedFile inc1("inc1.h", "#define macro2 val\n#include \"inc2.h\"\n#define macro4 val\n"); + ScopedFile inc2("inc2.h", "#define macro3 val\n"); + // TODO: preprocess? const char filedata[] = "#define macro1 val\n" - "#file \"inc1.h\"\n" - "#define macro2 val\n" - "#file \"inc2.h\"\n" - "#define macro3 val\n" - "#endfile\n" - "#define macro4 val\n" - "#endfile\n" + "#include \"inc1.h\"\n" "#define macro5 val\n"; const char dumpdata[] = " \n" " \n" @@ -8866,8 +8863,14 @@ class TestTokenizer : public TestFixture { " \n" " \n" " \n" - " \n" - " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" " \n" " \n" " \n" @@ -8877,14 +8880,8 @@ class TestTokenizer : public TestFixture { " \n" " \n" " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" + " \n" + " \n" " \n" " \n" " \n" @@ -8892,10 +8889,10 @@ class TestTokenizer : public TestFixture { " \n" " \n" " \n" - " \n" + " \n" " \n" " \n" - " \n" + " \n" " \n" " \n" " \n" diff --git a/test/testunusedprivfunc.cpp b/test/testunusedprivfunc.cpp index 4a2a6ca1894..09f8c21d102 100644 --- a/test/testunusedprivfunc.cpp +++ b/test/testunusedprivfunc.cpp @@ -58,7 +58,6 @@ class TestUnusedPrivateFunction : public TestFixture { TEST_CASE(classInClass); TEST_CASE(sameFunctionNames); - TEST_CASE(incompleteImplementation); TEST_CASE(derivedClass); // skip warning for derived classes. It might be a virtual function. @@ -76,7 +75,6 @@ class TestUnusedPrivateFunction : public TestFixture { TEST_CASE(testDoesNotIdentifyMethodAsMiddleFunctionArgument); TEST_CASE(testDoesNotIdentifyMethodAsLastFunctionArgument); - TEST_CASE(multiFile); TEST_CASE(unknownBaseTemplate); // ticket #2580 TEST_CASE(hierarchy_loop); // ticket 5590 @@ -482,24 +480,6 @@ class TestUnusedPrivateFunction : public TestFixture { ASSERT_EQUALS("", errout_str()); } - void incompleteImplementation() { - // The implementation for "A::a" is missing - so don't check if - // "A::b" is used or not - check("#file \"test.h\"\n" - "class A\n" - "{\n" - "public:\n" - " A();\n" - " void a();\n" - "private:\n" - " void b();\n" - "};\n" - "#endfile\n" - "A::A() { }\n" - "void A::b() { }"); - ASSERT_EQUALS("", errout_str()); - } - void derivedClass() { // skip warning in derived classes in case the base class is invisible check("class derived : public base\n" @@ -780,25 +760,6 @@ class TestUnusedPrivateFunction : public TestFixture { ASSERT_EQUALS("", errout_str()); } - void multiFile() { // ticket #2567 - check("#file \"test.h\"\n" - "struct Fred\n" - "{\n" - " Fred()\n" - " {\n" - " Init();\n" - " }\n" - "private:\n" - " void Init();\n" - "};\n" - "#endfile\n" - "void Fred::Init()\n" - "{\n" - "}"); - - ASSERT_EQUALS("", errout_str()); - } - void unknownBaseTemplate() { // ticket #2580 check("class Bla : public Base2 {\n" "public:\n" From 54b482c09bb9848343f6e30f6b0bd3814f9bcfcc Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Wed, 17 Jun 2026 11:24:55 +0200 Subject: [PATCH 027/165] Fix #14374 FP missingReturn with std::throw_with_nested() (#8638) --- cfg/std.cfg | 6 ++++++ test/cfg/std.cpp | 10 ++++++++++ 2 files changed, 16 insertions(+) diff --git a/cfg/std.cfg b/cfg/std.cfg index 245142c091d..4662d0a4632 100644 --- a/cfg/std.cfg +++ b/cfg/std.cfg @@ -8814,6 +8814,12 @@ initializer list (7) string& replace (const_iterator i1, const_iterator i2, init
+ + + + true + + malloc,std::malloc calloc,std::calloc diff --git a/test/cfg/std.cpp b/test/cfg/std.cpp index 77c9d99cd5d..850dd74b997 100644 --- a/test/cfg/std.cpp +++ b/test/cfg/std.cpp @@ -5379,3 +5379,13 @@ int containerOutOfBounds_std_initializer_list() { // #14340 int i = *x.end(); return i + containerOutOfBounds_std_initializer_list_access(x); } + +int* missingReturn_std_throw_with_nested() { // #14374 + try { + int* p = new int(); + return p; + } + catch (...) { + std::throw_with_nested(std::runtime_error("xyz")); + } +} From c903d68fdc7ca57da42ad0d0c1d33293f7d2d84b Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Wed, 17 Jun 2026 12:20:02 +0200 Subject: [PATCH 028/165] Fix #13855 useStlAlgorithm might lack column information (#8627) --- lib/tokenize.cpp | 1 + test/teststl.cpp | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 59da46a0b28..f97057ddb0f 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -7003,6 +7003,7 @@ Token *Tokenizer::simplifyAddBracesPair(Token *tok, bool commandWithCondition) tokAfterCondition->previous()->insertToken("{"); Token * tokOpenBrace=tokAfterCondition->previous(); + tokOpenBrace->column(tokAfterCondition->column()); tokEnd->insertToken("}"); Token * tokCloseBrace=tokEnd->next(); diff --git a/test/teststl.cpp b/test/teststl.cpp index 51fab0e6021..2060a5cfd2b 100644 --- a/test/teststl.cpp +++ b/test/teststl.cpp @@ -613,7 +613,7 @@ class TestStl : public TestFixture { " return i;\n" " return 0;\n" "}\n"); - ASSERT_EQUALS("[test.cpp:8:0]: style: Consider using std::find_if algorithm instead of a raw loop. [useStlAlgorithm]\n", errout_str()); + ASSERT_EQUALS("[test.cpp:8:13]: style: Consider using std::find_if algorithm instead of a raw loop. [useStlAlgorithm]\n", errout_str()); checkNormal("bool g();\n" "int f(int x) {\n" @@ -626,7 +626,7 @@ class TestStl : public TestFixture { " return i;\n" " return 0;\n" "}\n"); - ASSERT_EQUALS("[test.cpp:8:0]: style: Consider using std::find_if algorithm instead of a raw loop. [useStlAlgorithm]\n", errout_str()); + ASSERT_EQUALS("[test.cpp:8:13]: style: Consider using std::find_if algorithm instead of a raw loop. [useStlAlgorithm]\n", errout_str()); checkNormal("bool g();\n" "void f(int x) {\n" @@ -5260,7 +5260,7 @@ class TestStl : public TestFixture { " return s.erase(it);\n" " return s.end();\n" "}\n"); - ASSERT_EQUALS("[test.cpp:3:0]: (style) Consider using std::find_if algorithm instead of a raw loop. [useStlAlgorithm]\n", errout_str()); + ASSERT_EQUALS("[test.cpp:3:9]: (style) Consider using std::find_if algorithm instead of a raw loop. [useStlAlgorithm]\n", errout_str()); // #11381 check("int f(std::map& map) {\n" @@ -5953,7 +5953,7 @@ class TestStl : public TestFixture { " v1.erase(it1);\n" " }\n" "}\n"); - ASSERT_EQUALS("[test.cpp:9:0]: (style) Consider using std::find_if algorithm instead of a raw loop. [useStlAlgorithm]\n", errout_str()); + ASSERT_EQUALS("[test.cpp:9:17]: (style) Consider using std::find_if algorithm instead of a raw loop. [useStlAlgorithm]\n", errout_str()); check("bool f(const std::set& set, const std::string& f) {\n" // #11595 " for (const std::string& s : set) {\n" From 717566c1e2f262ddf266d54d3afaa42aed3a1022 Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Wed, 17 Jun 2026 12:21:05 +0200 Subject: [PATCH 029/165] Partial fix for #14810 FN constVariablePointer (cbegin() called on container) (#8619) Co-authored-by: chrchr-github --- lib/library.cpp | 2 ++ test/testother.cpp | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/lib/library.cpp b/lib/library.cpp index 7520944d8ad..2a198001d3c 100644 --- a/lib/library.cpp +++ b/lib/library.cpp @@ -1781,6 +1781,8 @@ bool Library::isFunctionConst(const Token *ftok) const const Yield yield = astContainerYield(ftok->astParent()->astOperand1(), *this); if (yield == Yield::EMPTY || yield == Yield::SIZE || yield == Yield::BUFFER_NT) return true; + if ((yield == Yield::START_ITERATOR || yield == Yield::END_ITERATOR) && ftok->str()[0] == 'c') + return true; } return false; } diff --git a/test/testother.cpp b/test/testother.cpp index c8a95c9882b..eb8f9dfe8ef 100644 --- a/test/testother.cpp +++ b/test/testother.cpp @@ -4867,6 +4867,11 @@ class TestOther : public TestFixture { ASSERT_EQUALS("[test.cpp:1:12]: (style) Parameter 'p' can be declared as pointer to const [constParameterPointer]\n" "[test.cpp:1:20]: (style) Parameter 'q' can be declared as pointer to const [constParameterPointer]\n", errout_str()); + + check("int f(std::vector* p) {\n" // #14810 + " return *p->cbegin();\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:1:25]: (style) Parameter 'p' can be declared as pointer to const [constParameterPointer]\n", errout_str()); } void constArray() { From af63e5fbad20993997279a9b73256c9dc2f3095d Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Wed, 17 Jun 2026 13:42:54 +0200 Subject: [PATCH 030/165] Fix #14783 / #14784 FN unusedVariable with templated type (default constructor, regression) (#8574) Co-authored-by: chrchr-github --- lib/checkunusedvar.cpp | 4 ---- test/testunusedvar.cpp | 19 +++++++++++++++++++ 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/lib/checkunusedvar.cpp b/lib/checkunusedvar.cpp index fcc8746c30e..8ed249f05e2 100644 --- a/lib/checkunusedvar.cpp +++ b/lib/checkunusedvar.cpp @@ -1155,10 +1155,6 @@ void CheckUnusedVarImpl::checkFunctionVariableUsage_iterateScopes(const Scope* c variables.read(tok2->varId(), tok); } } - } else if (tok->variable() && tok->variable()->isClass() && tok->variable()->type() && - (tok->variable()->type()->needInitialization == Type::NeedInitialization::False) && - tok->strAt(1) == ";") { - variables.write(tok->varId(), tok); } } } diff --git a/test/testunusedvar.cpp b/test/testunusedvar.cpp index 2efe658b52e..03ef0a14a83 100644 --- a/test/testunusedvar.cpp +++ b/test/testunusedvar.cpp @@ -7083,6 +7083,24 @@ class TestUnusedVar : public TestFixture { " S<0> s;\n" "}\n"); ASSERT_EQUALS("[test.cpp:6:10]: (style) Unused variable: s [unusedVariable]\n", errout_str()); + + functionVariableUsage("template \n" // #14783 + "struct A {\n" + " A() = default;\n" + "};\n" + "void f() {\n" + " A a;\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:6:12]: (style) Unused variable: a [unusedVariable]\n", errout_str()); + + functionVariableUsage("template \n" // #14784 + "struct A {\n" + " A() {}\n" + "};\n" + "void f() {\n" + " A a;\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:6:12]: (style) Unused variable: a [unusedVariable]\n", errout_str()); } void localvarFuncPtr() { @@ -7171,6 +7189,7 @@ class TestUnusedVar : public TestFixture { "void f() {\n" " Y y;\n" "}"); // #4695 + ASSERT_EQUALS("[test.cpp:6:7]: (style) Unused variable: y [unusedVariable]\n", errout_str()); } void crash3() { From 2538dcde482f91719b2c3e3ea7db508d6d3bf5a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Ramner=C3=B6?= Date: Wed, 17 Jun 2026 18:43:39 +0200 Subject: [PATCH 031/165] updated readme to direct vs code users to cppcheck official extension [skip ci] (#8657) --- readme.md | 66 ++----------------------------------------------------- 1 file changed, 2 insertions(+), 64 deletions(-) diff --git a/readme.md b/readme.md index 512a1ec1110..6671fdd4827 100644 --- a/readme.md +++ b/readme.md @@ -108,71 +108,9 @@ If you do not wish to use the Visual Studio IDE, you can compile Cppcheck from t msbuild cppcheck.sln ``` -### VS Code (on Windows) - -Install MSYS2 to get GNU toolchain with g++ and gdb (). -Create a `settings.json` file in the `.vscode` folder with the following content (adjust path as necessary): - -```json -{ - "terminal.integrated.shell.windows": "C:\\msys64\\usr\\bin\\bash.exe", - "terminal.integrated.shellArgs.windows": [ - "--login", - ], - "terminal.integrated.env.windows": { - "CHERE_INVOKING": "1", - "MSYSTEM": "MINGW64", - } -} -``` +### VS Code -Run `make` in the terminal to build Cppcheck. - -For debugging create a `launch.json` file in the `.vscode` folder with the following content, which covers configuration for debugging Cppcheck and `misra.py`: - -```json -{ - // Use IntelliSense to learn about possible attributes. - // Hover to view descriptions of existing attributes. - // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 - "version": "0.2.0", - "configurations": [ - { - "name": "cppcheck", - "type": "cppdbg", - "request": "launch", - "program": "${workspaceFolder}/cppcheck.exe", - "args": [ - "--dump", - "${workspaceFolder}/addons/test/misra/misra-test.c" - ], - "stopAtEntry": false, - "cwd": "${workspaceFolder}", - "environment": [], - "externalConsole": true, - "MIMode": "gdb", - "miDebuggerPath": "C:/msys64/mingw64/bin/gdb.exe", - "setupCommands": [ - { - "description": "Enable pretty-printing for gdb", - "text": "-enable-pretty-printing", - "ignoreFailures": true - } - ] - }, - { - "name": "misra.py", - "type": "python", - "request": "launch", - "program": "${workspaceFolder}/addons/misra.py", - "console": "integratedTerminal", - "args": [ - "${workspaceFolder}/addons/test/misra/misra-test.c.dump" - ] - } - ] -} -``` +Cppcheck Official is an extension officially supported by the cppcheck team allowing you to easily use cppcheck in VS Code. You can find it in VS Code Marketplace through the extension tab in your IDE. For instructions on how to set it up and use it, see the readme on the github page: ### Qt Creator + MinGW From 93bc25196f2b296b976bdf9a5ca1540ea97179b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Berder?= <18538310+francois-berder@users.noreply.github.com> Date: Thu, 18 Jun 2026 19:24:38 +0200 Subject: [PATCH 032/165] Fix #13628 FP: accessMoved with ternary (#8645) When std::move(x) is only in the true branch of a ternary operator, endOfFunctionCall was left pointing at the first token of the false branch, causing valueFlowForward to tag it as always-moved and report a spurious warning on the ? token. Fix by advancing past the entire false-branch subtree using nextAfterAstRightmostLeaf before starting propagation. --------- Signed-off-by: Francois Berder --- lib/valueflow.cpp | 7 +++++-- test/testother.cpp | 12 ++++++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index 68e989c0738..fb9f6dda7a1 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -3296,8 +3296,11 @@ static void valueFlowAfterMove(const TokenList& tokenlist, const SymbolDatabase& ternaryColon = ternaryColon->astParent(); if (Token::simpleMatch(ternaryColon, ":")) { endOfFunctionCall = ternaryColon->astOperand2(); - if (Token::simpleMatch(endOfFunctionCall, "(")) - endOfFunctionCall = endOfFunctionCall->link(); + Token* next = nextAfterAstRightmostLeaf(endOfFunctionCall); + if (next) + endOfFunctionCall = next; + else + endOfFunctionCall = endOfFunctionCall->next(); } } ValueFlow::Value value; diff --git a/test/testother.cpp b/test/testother.cpp index eb8f9dfe8ef..a24209fd4f1 100644 --- a/test/testother.cpp +++ b/test/testother.cpp @@ -12866,6 +12866,18 @@ class TestOther : public TestFixture { " h(b ? h(gA(5, std::move(s))) : h(gB(7, std::move(s))));\n" "}\n"); ASSERT_EQUALS("", errout_str()); + + check("int cb(std::string);\n" // #13628 + "void f(bool b, std::string s1) {\n" + " std::string s2 = b ? cb(std::move(s1)) : s1;\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + + check("int cb(std::string);\n" + "void f(bool b, std::string s1) {\n" + " std::string s2 = b ? cb(std::move(s1)) : s1 + s1;\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); } void movePointerAlias() From 3be9d35fb5d79c10cd0b591020e4f4f29dc9ee50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Fri, 19 Jun 2026 14:56:41 +0200 Subject: [PATCH 033/165] Fix #14863 (tokenizer: add token flag when braces are inserted during simplifications and publish in dumpfile) (#8664) --- lib/checkother.cpp | 4 ++-- lib/token.h | 19 ++++++++++++++----- lib/tokenize.cpp | 11 ++++++++--- test/testtokenize.cpp | 12 ++++++++++++ 4 files changed, 36 insertions(+), 10 deletions(-) diff --git a/lib/checkother.cpp b/lib/checkother.cpp index 551c3a47543..9b9d40a777e 100644 --- a/lib/checkother.cpp +++ b/lib/checkother.cpp @@ -1289,7 +1289,7 @@ void CheckOtherImpl::checkVariableScope() tok = tok->link(); // parse else if blocks.. - } else if (Token::simpleMatch(tok, "else { if (") && tok->next()->isSimplifiedScope() && Token::simpleMatch(tok->linkAt(3), ") {")) { + } else if (Token::simpleMatch(tok, "else { if (") && tok->next()->isInsertedBrace() && Token::simpleMatch(tok->linkAt(3), ") {")) { tok = tok->next(); } else if (tok->varId() == var->declarationId() || tok->str() == "goto") { reduce = false; @@ -1415,7 +1415,7 @@ bool CheckOtherImpl::checkInnerScope(const Token *tok, const Variable* var, bool if (scope->type == ScopeType::eSwitch) return false; // Used in outer switch scope - unsafe or impossible to reduce scope - if (scope->bodyStart && scope->bodyStart->isSimplifiedScope()) + if (scope->bodyStart && scope->bodyStart->isSimplifiedIfInitStmt()) return false; // simplified if/for/switch init statement } if (var->isArrayOrPointer()) { diff --git a/lib/token.h b/lib/token.h index ca945fcab22..3328af31fa0 100644 --- a/lib/token.h +++ b/lib/token.h @@ -732,11 +732,11 @@ class CPPCHECKLIB Token { setFlag(fIsTemplate, b); } - bool isSimplifiedScope() const { - return getFlag(fIsSimplifedScope); + bool isSimplifiedIfInitStmt() const { + return getFlag(fIsSimplifiedIfInitStmt); } - void isSimplifiedScope(bool b) { - setFlag(fIsSimplifedScope, b); + void isSimplifiedIfInitStmt(bool b) { + setFlag(fIsSimplifiedIfInitStmt, b); } bool isFinalType() const { @@ -767,6 +767,14 @@ class CPPCHECKLIB Token { setFlag(fIsAnonymous, b); } + bool isInsertedBrace() const { + return getFlag(fIsInsertedBrace); + } + Token* isInsertedBrace(bool b) { + setFlag(fIsInsertedBrace, b); + return this; + } + // cppcheck-suppress unusedFunction bool isBitfield() const { return mImpl->mBits >= 0; @@ -1498,7 +1506,7 @@ class CPPCHECKLIB Token { fIsImplicitInt = (1ULL << 33), // Is "int" token implicitly added? fIsInline = (1ULL << 34), // Is this a inline type fIsTemplate = (1ULL << 35), - fIsSimplifedScope = (1ULL << 36), // scope added when simplifying e.g. if (int i = ...; ...) + fIsSimplifiedIfInitStmt = (1ULL << 36), // simplified if/switch/while init statement e.g. if (int i = ...; ...) => { int i = ...; if (..) .. } fIsRemovedVoidParameter = (1ULL << 37), // A void function parameter has been removed fIsIncompleteConstant = (1ULL << 38), fIsRestrict = (1ULL << 39), // Is this a restrict pointer type @@ -1508,6 +1516,7 @@ class CPPCHECKLIB Token { fIsInitComma = (1ULL << 43), // Is this comma located inside some {..}. i.e: {1,2,3,4} fIsInitBracket = (1ULL << 44), // Is this bracket used as a part of variable initialization i.e: int a{5}, b(2); fIsAnonymous = (1ULL << 45), // Is this a token added for an unnamed member + fIsInsertedBrace = (1ULL << 46), // brace added when simplifying e.g. if (x) f(); => if (x) { f(); } }; enum : std::uint8_t { diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index f97057ddb0f..a8f675bbc97 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -6218,6 +6218,8 @@ void Tokenizer::dump(std::ostream &out) const } if (tok->isRemovedVoidParameter()) outs += " isRemovedVoidParameter=\"true\""; + if (tok->isInsertedBrace()) + outs += " isInsertedBrace=\"true\""; if (tok->isSplittedVarDeclComma()) outs += " isSplittedVarDeclComma=\"true\""; if (tok->isSplittedVarDeclEq()) @@ -7004,10 +7006,12 @@ Token *Tokenizer::simplifyAddBracesPair(Token *tok, bool commandWithCondition) tokAfterCondition->previous()->insertToken("{"); Token * tokOpenBrace=tokAfterCondition->previous(); tokOpenBrace->column(tokAfterCondition->column()); + tokOpenBrace->isInsertedBrace(true); tokEnd->insertToken("}"); Token * tokCloseBrace=tokEnd->next(); tokCloseBrace->column(tokEnd->column()); + tokCloseBrace->isInsertedBrace(true); Token::createMutualLinks(tokOpenBrace,tokCloseBrace); tokBracesEnd=tokCloseBrace; @@ -8038,8 +8042,8 @@ void Tokenizer::elseif() if (Token::Match(tok2, "}|;")) { if (tok2->next() && tok2->strAt(1) != "else") { - tok->insertToken("{")->isSimplifiedScope(true); - tok2->insertToken("}")->isSimplifiedScope(true); + tok->insertToken("{")->isInsertedBrace(true); + tok2->insertToken("}")->isInsertedBrace(true); Token::createMutualLinks(tok->next(), tok2->next()); break; } @@ -8105,7 +8109,8 @@ void Tokenizer::simplifyIfSwitchForInit() tok->str("{"); endscope->insertToken("}"); Token::createMutualLinks(tok, endscope->next()); - tok->isSimplifiedScope(true); + tok->isInsertedBrace(true); + tok->isSimplifiedIfInitStmt(true); } } diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp index 6e5ea0f785f..e56ffa3d8bb 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -140,6 +140,7 @@ class TestTokenizer : public TestFixture { TEST_CASE(whileAddBraces); TEST_CASE(whileAddBracesLabels); + TEST_CASE(whileAddBracesDump); TEST_CASE(doWhileAddBraces); TEST_CASE(doWhileAddBracesLabels); @@ -1532,6 +1533,17 @@ class TestTokenizer : public TestFixture { ASSERT_EQUALS("", filter_valueflow(errout_str())); } + void whileAddBracesDump() { + const char code[] = "void f(){while(a);}"; + SimpleTokenizer tokenizer(settingsDefault, *this, false); + ASSERT(tokenizer.tokenize(code)); + ASSERT(Token::simpleMatch(tokenizer.tokens(), "void f ( ) { while ( a ) { ; } }")); + std::ostringstream ostr; + tokenizer.dump(ostr); + const std::string dump = ostr.str(); + ASSERT(dump.find("isInsertedBrace=\"true\"") != std::string::npos); + } + void doWhileAddBraces() { { const char code[] = "{do ; while (0);}"; From d45d90792b2414ff7e3ec0a3069fac1d6bd3c89f Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Fri, 19 Jun 2026 19:15:05 +0200 Subject: [PATCH 034/165] Fix #14853 FP funcArgNamesDifferentUnnamed with function pointer argument (#8655) Co-authored-by: chrchr-github --- lib/checkother.cpp | 2 +- test/testother.cpp | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/checkother.cpp b/lib/checkother.cpp index 9b9d40a777e..d69cfa7830a 100644 --- a/lib/checkother.cpp +++ b/lib/checkother.cpp @@ -4052,7 +4052,7 @@ void CheckOtherImpl::checkFuncArgNamesDifferent() break; } // skip over templates and arrays - if (decl->link() && !Token::Match(decl, "[()]")) + if (decl->link() && precedes(decl, decl->link()) && !Token::Match(decl, "( [*&]")) decl = decl->link(); else if (decl->varId()) declarations[j] = decl; diff --git a/test/testother.cpp b/test/testother.cpp index a24209fd4f1..4215a3b3449 100644 --- a/test/testother.cpp +++ b/test/testother.cpp @@ -12976,6 +12976,10 @@ class TestOther : public TestFixture { check("void f(void (*fp)(), int x);\n" // #14847 "void f(void (*fp)(), int x) {}\n"); ASSERT_EQUALS("", errout_str()); + + check("void f(void (*fp)(int a, int b), int b);\n" // #14853 + "void f(void (*fp)(int a, int b), int b) {}\n"); + ASSERT_EQUALS("", errout_str()); } void funcArgOrderDifferent() { From fb388e69bcfd9117e77289e8386daaaab9be9fea Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Fri, 19 Jun 2026 19:39:29 +0200 Subject: [PATCH 035/165] Fix #14812 FN useStlAlgorithm with std::set (#8629) Co-authored-by: chrchr-github --- gui/checkstatistics.cpp | 10 +++++----- lib/checkother.cpp | 1 + lib/checkstl.cpp | 9 ++++----- lib/symboldatabase.cpp | 4 ++-- lib/templatesimplifier.cpp | 1 + test/cfg/boost.cpp | 1 + test/teststl.cpp | 8 ++++++++ tools/dmake/dmake.cpp | 1 + 8 files changed, 23 insertions(+), 12 deletions(-) diff --git a/gui/checkstatistics.cpp b/gui/checkstatistics.cpp index 612e79da63b..830f5eb6b4e 100644 --- a/gui/checkstatistics.cpp +++ b/gui/checkstatistics.cpp @@ -109,10 +109,10 @@ unsigned CheckStatistics::getCount(const QString &tool, ShowTypes::ShowType type QStringList CheckStatistics::getTools() const { QSet ret; - for (const QString& tool: mStyle.keys()) ret.insert(tool); - for (const QString& tool: mWarning.keys()) ret.insert(tool); - for (const QString& tool: mPerformance.keys()) ret.insert(tool); - for (const QString& tool: mPortability.keys()) ret.insert(tool); - for (const QString& tool: mError.keys()) ret.insert(tool); + std::copy(mStyle.keyBegin(), mStyle.keyEnd(), std::inserter(ret, ret.end())); + std::copy(mWarning.keyBegin(), mWarning.keyEnd(), std::inserter(ret, ret.end())); + std::copy(mPerformance.keyBegin(), mPerformance.keyEnd(), std::inserter(ret, ret.end())); + std::copy(mPortability.keyBegin(), mPortability.keyEnd(), std::inserter(ret, ret.end())); + std::copy(mError.keyBegin(), mError.keyEnd(), std::inserter(ret, ret.end())); return ret.values(); } diff --git a/lib/checkother.cpp b/lib/checkother.cpp index d69cfa7830a..a45dfdf672e 100644 --- a/lib/checkother.cpp +++ b/lib/checkother.cpp @@ -4586,6 +4586,7 @@ void CheckOtherImpl::checkUnionZeroInit() std::unordered_map unionsByScopeId; const std::vector unions = parseUnions(*symbolDatabase, mSettings); for (const Union &u : unions) { + // cppcheck-suppress useStlAlgorithm - std::transform is cumbersome unionsByScopeId.emplace(u.scope, u); } diff --git a/lib/checkstl.cpp b/lib/checkstl.cpp index c8fcca48f1a..f499bb03b91 100644 --- a/lib/checkstl.cpp +++ b/lib/checkstl.cpp @@ -3116,19 +3116,18 @@ void CheckStlImpl::useStlAlgorithm() bool useLoopVarInMemCall; const Token *memberAccessTok = singleMemberCallInScope(bodyTok, loopVar->varId(), useLoopVarInMemCall, mSettings); if (memberAccessTok && loopType == LoopType::RANGE) { - const Token *memberCallTok = memberAccessTok->astOperand2(); const int contVarId = memberAccessTok->astOperand1()->varId(); if (contVarId == loopVar->varId()) continue; - if (memberCallTok->str() == "push_back" || - memberCallTok->str() == "push_front" || - memberCallTok->str() == "emplace_back") { + using Action = Library::Container::Action; + const auto action = astContainerAction(memberAccessTok->astOperand1(), mSettings.library); + if (contains({Action::PUSH, Action::INSERT}, action)) { std::string algo; if (useLoopVarInMemCall) algo = "std::copy"; else algo = "std::transform"; - useStlAlgorithmError(memberCallTok, algo); + useStlAlgorithmError(memberAccessTok->astOperand2(), algo); } continue; } diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index 4b923a328ca..ba5c31d1f47 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -1246,6 +1246,7 @@ void SymbolDatabase::createSymbolDatabaseSetTypePointers() { std::unordered_set typenames; for (const Type &t : typeList) { + // cppcheck-suppress useStlAlgorithm - std::transform is cumbersome typenames.insert(t.name()); } @@ -4599,8 +4600,7 @@ void SymbolDatabase::printXml(std::ostream &out) const } // Variables.. - for (const Variable *var : mVariableList) - variables.insert(var); + std::copy(mVariableList.begin(), mVariableList.end(), std::inserter(variables, variables.end())); outs += " \n"; for (const Variable *var : variables) { if (!var) diff --git a/lib/templatesimplifier.cpp b/lib/templatesimplifier.cpp index 9c8c8fdde9a..2672e66c263 100644 --- a/lib/templatesimplifier.cpp +++ b/lib/templatesimplifier.cpp @@ -3916,6 +3916,7 @@ void TemplateSimplifier::simplifyTemplates(const std::time_t maxtime) std::unordered_map nameOrdinal; int ordinal = 0; for (const auto& decl : mTemplateDeclarations) { + // cppcheck-suppress useStlAlgorithm - std::transform is cumbersome nameOrdinal.emplace(decl.fullName(), ordinal++); } diff --git a/test/cfg/boost.cpp b/test/cfg/boost.cpp index 2cc4b288cce..27fae71b499 100644 --- a/test/cfg/boost.cpp +++ b/test/cfg/boost.cpp @@ -157,6 +157,7 @@ void test_BOOST_FOREACH_5() { std::set data; BOOST_FOREACH(const int& i, get_data()) + // cppcheck-suppress useStlAlgorithm data.insert(i); } diff --git a/test/teststl.cpp b/test/teststl.cpp index 2060a5cfd2b..b7a29b2a11a 100644 --- a/test/teststl.cpp +++ b/test/teststl.cpp @@ -5661,6 +5661,14 @@ class TestStl : public TestFixture { "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); + + check("void f(const std::vector& v) {\n" // #14812 + " std::set s;\n" + " for (const std::string& a : v) {\n" + " s.insert(a);\n" + " }\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:4:11]: (style) Consider using std::copy algorithm instead of a raw loop. [useStlAlgorithm]\n", errout_str()); } void loopAlgoIncrement() { diff --git a/tools/dmake/dmake.cpp b/tools/dmake/dmake.cpp index a434c710631..eaf0a727646 100644 --- a/tools/dmake/dmake.cpp +++ b/tools/dmake/dmake.cpp @@ -297,6 +297,7 @@ static std::vector prioritizelib(const std::vector& li std::map priorities; std::size_t prio = libfiles.size(); for (const auto &l : libfiles) { + // cppcheck-suppress useStlAlgorithm - std::transform is cumbersome priorities.emplace(l, prio--); } priorities["lib/valueflow.cpp"] = 1000; From 731ef86c9e1034336854ab858986c400941a9f0f Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Fri, 19 Jun 2026 19:46:54 +0200 Subject: [PATCH 036/165] Fix #11861 Syntax Error: AST broken for C++20 ranges (#8644) Co-authored-by: chrchr-github --- lib/tokenlist.cpp | 2 ++ test/testtokenize.cpp | 1 + 2 files changed, 3 insertions(+) diff --git a/lib/tokenlist.cpp b/lib/tokenlist.cpp index f98335badb7..5921621fed2 100644 --- a/lib/tokenlist.cpp +++ b/lib/tokenlist.cpp @@ -1696,6 +1696,8 @@ static Token * createAstAtToken(Token *tok) tok->next()->astOperand1(tok); tok->next()->astOperand2(colon); + createAstAtTokenInner(colon, tok->linkAt(1), cpp); + return decl; } } diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp index e56ffa3d8bb..8a6a9353707 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -6701,6 +6701,7 @@ class TestTokenizer : public TestFixture { ASSERT_EQUALS("foria:( asize.(", testAst("for(decltype(a.size()) i:a);")); ASSERT_EQUALS("forec0{([,(:( fb.return", testAst("for (auto e : c(0, [](auto f) { return f->b; }));")); // #10802 ASSERT_EQUALS("forvar1{;;(", testAst("for(int var{1};;)")); // #12867 + ASSERT_EQUALS("forxg{([(:( si.return", testAst("for (auto [x] : g([](S s) { return s.i; })) {}")); // #11861 // for with initializer (c++20) ASSERT_EQUALS("forab=ca:;(", testAst("for(a=b;int c:a)")); From bf099d1d152456e3372e9301e2d4a821689b0ff3 Mon Sep 17 00:00:00 2001 From: Jonny Date: Sat, 20 Jun 2026 15:00:03 +0100 Subject: [PATCH 037/165] Fix #14854 (import project: Handle forced include files from compilation database projects) (#8641) --- .github/workflows/selfcheck.yml | 2 +- lib/cppcheck.cpp | 1 + lib/filesettings.h | 1 + lib/importproject.cpp | 5 +++++ test/testimportproject.cpp | 19 +++++++++++++++++++ 5 files changed, 27 insertions(+), 1 deletion(-) diff --git a/.github/workflows/selfcheck.yml b/.github/workflows/selfcheck.yml index 6bd87f9243f..6d100c4ddc8 100644 --- a/.github/workflows/selfcheck.yml +++ b/.github/workflows/selfcheck.yml @@ -121,7 +121,7 @@ jobs: - name: Self check (unusedFunction / no test / no gui) run: | - supprs="--suppress=unusedFunction:lib/errorlogger.h:197 --suppress=unusedFunction:lib/importproject.cpp:1666 --suppress=unusedFunction:lib/importproject.cpp:1690" + supprs="--suppress=unusedFunction:lib/errorlogger.h:197 --suppress=unusedFunction:lib/importproject.cpp:1671 --suppress=unusedFunction:lib/importproject.cpp:1695" ./cppcheck -q --template=selfcheck --error-exitcode=1 --library=cppcheck-lib -D__CPPCHECK__ -D__GNUC__ --enable=unusedFunction,information --exception-handling -rp=. --project=cmake.output.notest_nogui/compile_commands.json --suppressions-list=.selfcheck_unused_suppressions --inline-suppr $supprs env: DISABLE_VALUEFLOW: 1 diff --git a/lib/cppcheck.cpp b/lib/cppcheck.cpp index b7ab1f99039..9a3e2e2a053 100644 --- a/lib/cppcheck.cpp +++ b/lib/cppcheck.cpp @@ -825,6 +825,7 @@ unsigned int CppCheck::check(const FileSettings &fs) else tempSettings.userDefines += fs.cppcheckDefines(); tempSettings.includePaths = fs.includePaths; + tempSettings.userIncludes.insert(tempSettings.userIncludes.end(), fs.forcedIncludes.cbegin(), fs.forcedIncludes.cend()); tempSettings.userUndefs.insert(fs.undefs.cbegin(), fs.undefs.cend()); if (fs.standard.find("++") != std::string::npos) tempSettings.standards.setCPP(fs.standard); diff --git a/lib/filesettings.h b/lib/filesettings.h index 183e38708fd..0b4f15dd7e1 100644 --- a/lib/filesettings.h +++ b/lib/filesettings.h @@ -148,6 +148,7 @@ struct CPPCHECKLIB FileSettings { } std::set undefs; std::list includePaths; + std::list forcedIncludes; // only used by clang mode std::list systemIncludePaths; std::string standard; diff --git a/lib/importproject.cpp b/lib/importproject.cpp index 0bcda5a43bf..2d63fa8bbb7 100644 --- a/lib/importproject.cpp +++ b/lib/importproject.cpp @@ -149,6 +149,11 @@ void ImportProject::parseArgs(FileSettings &fs, const std::vector & continue; } + if (!(optArg = getOptArg({ "-include", "/FI", "-FI" }, i)).empty()) { + fs.forcedIncludes.push_back(std::move(optArg)); + continue; + } + if (!(optArg = getOptArg({ "-D", "/D" }, i)).empty()) { defs += optArg + ";"; continue; diff --git a/test/testimportproject.cpp b/test/testimportproject.cpp index 88ca2fe75b7..c9889445c3c 100644 --- a/test/testimportproject.cpp +++ b/test/testimportproject.cpp @@ -73,6 +73,7 @@ class TestImportProject : public TestFixture { TEST_CASE(importCompileCommands13); // #13333: duplicate file entries TEST_CASE(importCompileCommands14); // #14156 TEST_CASE(importCompileCommands15); // #14306 + TEST_CASE(importCompileCommandsForcedInclude); // -include / /FI force-include TEST_CASE(importCompileCommandsArgumentsSection); // Handle arguments section TEST_CASE(importCompileCommandsNoCommandSection); // gracefully handles malformed json TEST_CASE(importCompileCommandsDirectoryMissing); // 'directory' field missing @@ -436,6 +437,24 @@ class TestImportProject : public TestFixture { ASSERT_EQUALS("C:/Users/abcd/efg/hijk/path/123/", fs.includePaths.front()); } + void importCompileCommandsForcedInclude() const { // -include / /FI force-include + REDIRECT; + constexpr char json[] = + R"([{ + "file": "/x/a.c", + "directory": "/x", + "command": "cc -include prefix.h /FIplatform.h -c a.c" + }])"; + std::istringstream istr(json); + TestImporter importer; + ASSERT_EQUALS(true, importer.importCompileCommands(istr)); + ASSERT_EQUALS(1, importer.fileSettings.size()); + const FileSettings &fs = importer.fileSettings.front(); + ASSERT_EQUALS(2, fs.forcedIncludes.size()); + ASSERT_EQUALS("prefix.h", fs.forcedIncludes.front()); // gcc/clang -include + ASSERT_EQUALS("platform.h", fs.forcedIncludes.back()); // MSVC/clang-cl /FI + } + void importCompileCommandsArgumentsSection() const { REDIRECT; constexpr char json[] = "[ { \"directory\": \"/tmp/\"," From 30ec6e1970b3f113de2bc95865cf02ba5c2d8535 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Sat, 20 Jun 2026 16:02:10 +0200 Subject: [PATCH 038/165] AUTHORS: Add JonnyPtn [skip ci] (#8666) --- AUTHORS | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS b/AUTHORS index 874ff59748b..b505b682708 100644 --- a/AUTHORS +++ b/AUTHORS @@ -206,6 +206,7 @@ Jonathan Clohessy Jonathan Haehne Jonathan Neuschäfer Jonathan Thackray +Jonny Paton José Martins Jose Roquette Joshua Beck From 907f9a46060151139eb909abf1bc414a336390cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Sat, 20 Jun 2026 18:44:08 +0200 Subject: [PATCH 039/165] Fix #14850 (Compilation fails on oraclelinux:8 (g++ 8.5.0 released in 2021)) (#8654) --- lib/checks.h | 2 +- lib/settings.cpp | 4 ++-- lib/settings.h | 14 ++++++++++++-- 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/lib/checks.h b/lib/checks.h index ec4a78c2008..9c053b81405 100644 --- a/lib/checks.h +++ b/lib/checks.h @@ -29,6 +29,6 @@ namespace CheckInstances { /** List of registered check classes. This is used by Cppcheck to run checks and generate documentation */ CPPCHECKLIB const std::list& get(); -}; +} #endif // checksH diff --git a/lib/settings.cpp b/lib/settings.cpp index 95d4c4e953b..c0539bbeaba 100644 --- a/lib/settings.cpp +++ b/lib/settings.cpp @@ -79,8 +79,8 @@ Settings::~Settings() = default; Settings::Settings(const Settings&) = default; Settings & Settings::operator=(const Settings &) = default; -Settings::Settings(Settings&&) noexcept = default; -Settings & Settings::operator=(Settings &&) noexcept = default; +Settings::Settings(Settings&&) CPPCHECK_NOEXCEPT = default; +Settings & Settings::operator=(Settings &&) CPPCHECK_NOEXCEPT = default; std::string Settings::loadCppcheckCfg(Settings& settings, Suppressions& suppressions, bool debug) { diff --git a/lib/settings.h b/lib/settings.h index 04ddb9adb9a..4a73f35039b 100644 --- a/lib/settings.h +++ b/lib/settings.h @@ -94,6 +94,16 @@ class SimpleEnableGroup { }; +#if defined(__GNUC__) && !defined(__clang__) && __GNUC__ <= 9 +// Hack to workaround GCC bug. +// Details: https://trac.cppcheck.net/ticket/14850 +// seen on g++ before 10.x +#define CPPCHECK_NOEXCEPT +#else +#define CPPCHECK_NOEXCEPT noexcept +#endif + + /** * @brief This is just a container for general settings so that we don't need * to pass individual values to functions or constructors now or in the @@ -113,8 +123,8 @@ class CPPCHECKLIB WARN_UNUSED Settings { Settings(const Settings&); Settings& operator=(const Settings&); - Settings(Settings&&) noexcept; - Settings& operator=(Settings&&) noexcept; + Settings(Settings&&) CPPCHECK_NOEXCEPT; + Settings& operator=(Settings&&) CPPCHECK_NOEXCEPT; static std::string loadCppcheckCfg(Settings& settings, Suppressions& suppressions, bool debug = false); From 31222058d3a70f824c08f3b9f92381874800ffd8 Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Sat, 20 Jun 2026 19:25:43 +0200 Subject: [PATCH 040/165] Refs #9173: Fix FN bufferAccessOutOfBounds (memset on array, &a[0]) (#8656) --- lib/checkbufferoverrun.cpp | 10 +++++++++- test/testbufferoverrun.cpp | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/lib/checkbufferoverrun.cpp b/lib/checkbufferoverrun.cpp index d278208fcc3..8be9b508849 100644 --- a/lib/checkbufferoverrun.cpp +++ b/lib/checkbufferoverrun.cpp @@ -556,8 +556,16 @@ ValueFlow::Value CheckBufferOverrunImpl::getBufferSize(const Token *bufTok) cons { if (!bufTok->valueType()) return ValueFlow::Value(-1); - if (bufTok->isUnaryOp("&")) + + if (bufTok->isUnaryOp("&")) { bufTok = bufTok->astOperand1(); + if (Token::simpleMatch(bufTok, "[")) { + const Token* index = bufTok->astOperand2(); + if (!(index && index->hasKnownIntValue() && index->getKnownIntValue() == 0)) + return ValueFlow::Value(-1); + bufTok = bufTok->astOperand1(); + } + } const Variable *var = bufTok->variable(); if (!var || var->dimensions().empty()) { diff --git a/test/testbufferoverrun.cpp b/test/testbufferoverrun.cpp index 23e55748ce6..1a03ca336f8 100644 --- a/test/testbufferoverrun.cpp +++ b/test/testbufferoverrun.cpp @@ -227,6 +227,7 @@ class TestBufferOverrun : public TestFixture { TEST_CASE(buffer_overrun_35); //#2304 TEST_CASE(buffer_overrun_36); TEST_CASE(buffer_overrun_37); + TEST_CASE(buffer_overrun_38); TEST_CASE(buffer_overrun_errorpath); TEST_CASE(buffer_overrun_bailoutIfSwitch); // ticket #2378 : bailoutIfSwitch TEST_CASE(buffer_overrun_function_array_argument); @@ -3507,6 +3508,39 @@ class TestBufferOverrun : public TestFixture { ASSERT_EQUALS("", errout_str()); } + void buffer_overrun_38() { // #9173 + check("void f() {\n" + " int a[10];\n" + " memset(&a[0], 0, 20 * sizeof(int));\n" + "}\n" + "void g() {\n" + " int a[10];\n" + " memset(&a[0], 0, 10 * sizeof(int));\n" + "}\n" + "void h() {\n" + " int a[10];\n" + " memset(&a[5], 0, 5 * sizeof(int));\n" + "}\n" + "void i() {\n" + " int a[10][10];\n" + " memset(&a[0][0], 0, 100 * sizeof(int));\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:3:12]: (error) Buffer is accessed out of bounds: &a[0] [bufferAccessOutOfBounds]\n", errout_str()); + + check("void f() {\n" + " int a[10];\n" + " memset(&a[5], 0, 10 * sizeof(int));\n" + "}\n" + "void g() {\n" + " int a[1][1];\n" + " memset(&a[0][0], 0, 10 * sizeof(int));\n" + "}\n"); + TODO_ASSERT_EQUALS("[test.cpp:3:12]: (error) Buffer is accessed out of bounds: &a[5] [bufferAccessOutOfBounds]\n" + "[test.cpp:7:12]: (error) Buffer is accessed out of bounds: &a[0][0] [bufferAccessOutOfBounds]\n", + "", + errout_str()); + } + void buffer_overrun_errorpath() { setMultiline(); Settings s = settings0; From 49f7cd2853f9bc2f1d2c964a4c19addfdb776bf9 Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Sat, 20 Jun 2026 19:26:39 +0200 Subject: [PATCH 041/165] Fix #14848 FP compareValueOutOfTypeRangeError and knownConditionTrueFalse with unsigned arithmetic (#8658) Co-authored-by: chrchr-github --- lib/vf_settokenvalue.cpp | 2 +- test/testvalueflow.cpp | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/vf_settokenvalue.cpp b/lib/vf_settokenvalue.cpp index fe94225083b..315f4a40129 100644 --- a/lib/vf_settokenvalue.cpp +++ b/lib/vf_settokenvalue.cpp @@ -613,7 +613,7 @@ namespace ValueFlow } // unary minus - else if (parent->isUnaryOp("-")) { + else if (parent->isUnaryOp("-") && !astIsUnsigned(parent)) { for (const Value &val : tok->values()) { if (!val.isIntValue() && !val.isFloatValue()) continue; diff --git a/test/testvalueflow.cpp b/test/testvalueflow.cpp index 247d2ae6012..8305a63bc56 100644 --- a/test/testvalueflow.cpp +++ b/test/testvalueflow.cpp @@ -1269,6 +1269,12 @@ class TestValueFlow : public TestFixture { ASSERT_EQUALS(1U, values.size()); ASSERT_EQUALS(-10, values.back().intvalue); + code = "bool f(unsigned a) {\n" // #14848 + " bool x = -a < 1;\n" + " return x;\n" + "}"; + ASSERT_EQUALS(false, testValueOfXKnown(code, 3U, 1)); + // Logical and code = "void f(bool b) {\n" " bool x = false && b;\n" From d7bcdb595797b6f31504ad805a7dd795b6e52bb4 Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Mon, 22 Jun 2026 12:53:33 +0200 Subject: [PATCH 042/165] Fix #14809 FP syntaxError for typedef involving std::size_t (#8618) `size_t` is a platform type and will be simplified anyway, this is tested here: https://github.com/cppcheck-opensource/cppcheck/blob/e1053dba3b0988dc828d7a9c4b2a8f6c9866035b/test/testtokenize.cpp#L9012 --------- Co-authored-by: chrchr-github --- lib/token.cpp | 1 - test/testtoken.cpp | 17 ----------------- test/testtokenize.cpp | 2 ++ test/testvarid.cpp | 2 +- 4 files changed, 3 insertions(+), 19 deletions(-) diff --git a/lib/token.cpp b/lib/token.cpp index 2b30419b9df..7e19106e1b0 100644 --- a/lib/token.cpp +++ b/lib/token.cpp @@ -204,7 +204,6 @@ static const std::unordered_set stdTypes = { "bool" , "int" , "long" , "short" - , "size_t" , "void" , "wchar_t" , "signed" diff --git a/test/testtoken.cpp b/test/testtoken.cpp index 83a514eb963..92c111c810c 100644 --- a/test/testtoken.cpp +++ b/test/testtoken.cpp @@ -1059,7 +1059,6 @@ class TestToken : public TestFixture { standard_types.emplace_back("long"); standard_types.emplace_back("float"); standard_types.emplace_back("double"); - standard_types.emplace_back("size_t"); for (auto test_op = standard_types.cbegin(); test_op != standard_types.cend(); ++test_op) { auto tokensFrontBack = std::make_shared(); @@ -1484,13 +1483,6 @@ class TestToken : public TestFixture { tok.str("char"); // not treated as keyword in TokenList::isKeyword() assert_tok(&tok, Token::Type::eType, /*l=*/ false, /*std=*/ true); } - { - TokenList list_c{settingsDefault, Standards::Language::C}; - auto tokensFrontBack = std::make_shared(); - Token tok(list_c, std::move(tokensFrontBack)); - tok.str("size_t"); // not treated as keyword in TokenList::isKeyword() - assert_tok(&tok, Token::Type::eType, /*l=*/ false, /*std=*/ true); - } } void update_property_info_etype_cpp() const @@ -1502,21 +1494,12 @@ class TestToken : public TestFixture { tok.str("bool"); // not treated as keyword in TokenList::isKeyword() assert_tok(&tok, Token::Type::eType, /*l=*/ false, /*std=*/ true); } - { - TokenList list_cpp{settingsDefault, Standards::Language::CPP}; - auto tokensFrontBack = std::make_shared(); - Token tok(list_cpp, std::move(tokensFrontBack)); - tok.str("size_t"); - assert_tok(&tok, Token::Type::eType, /*l=*/ false, /*std=*/ true); - } } void update_property_info_replace() const // #13743 { auto tokensFrontBack = std::make_shared(); Token tok(list, std::move(tokensFrontBack)); - tok.str("size_t"); - assert_tok(&tok, Token::Type::eType, false, true); tok.str("long"); assert_tok(&tok, Token::Type::eType, false, true); } diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp index 8a6a9353707..167d5411553 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -7893,6 +7893,8 @@ class TestTokenizer : public TestFixture { "}\n")); ignore_errout(); + + ASSERT_EQUALS(";", tokenizeAndStringify("typedef std::size_t size_t;\n")); // #14809 } diff --git a/test/testvarid.cpp b/test/testvarid.cpp index 941b5812678..c8d16bc89a5 100644 --- a/test/testvarid.cpp +++ b/test/testvarid.cpp @@ -2841,7 +2841,7 @@ class TestVarID : public TestFixture { void varid_using() { // #3648 const char code[] = "using std::size_t;"; - const char expected[] = "1: using unsigned long ;\n"; + const char expected[] = "1: ;\n"; ASSERT_EQUALS(expected, tokenize(code)); } From d833b6b276af306ffdef18eda4199589ac26bb10 Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Mon, 22 Jun 2026 13:44:36 +0200 Subject: [PATCH 043/165] Fix #12520 FN mismatchingContainers/iterators3 with temporary containers and erase (#8665) --- lib/checkstl.cpp | 6 ++++-- test/teststl.cpp | 9 +++++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/lib/checkstl.cpp b/lib/checkstl.cpp index f499bb03b91..3e08fe04ed6 100644 --- a/lib/checkstl.cpp +++ b/lib/checkstl.cpp @@ -637,12 +637,14 @@ void CheckStlImpl::iterators() void CheckStlImpl::mismatchingContainerIteratorError(const Token* containerTok, const Token* iterTok, const Token* containerTok2) { const std::string container(containerTok ? containerTok->expressionString() : std::string("v1")); + const std::string containerTemp(isTemporary(containerTok, &mSettings.library) ? " temporary " : " "); const std::string container2(containerTok2 ? containerTok2->expressionString() : std::string("v2")); + const std::string containerTemp2(isTemporary(containerTok2, &mSettings.library) ? " temporary " : " "); const std::string iter(iterTok ? iterTok->expressionString() : std::string("it")); reportError(containerTok, Severity::error, "mismatchingContainerIterator", - "Iterator '" + iter + "' referring to container '" + container2 + "' is used with container '" + container + "'.", + "Iterator '" + iter + "' referring to" + containerTemp2 + "container '" + container2 + "' is used with" + containerTemp + "container '" + container + "'.", CWE664, Certainty::normal); } @@ -884,7 +886,7 @@ void CheckStlImpl::mismatchingContainerIterator() const std::vector args = getArguments(ftok); const Library::Container * c = tok->valueType()->container; - const Library::Container::Action action = c->getAction(tok->strAt(2)); + const Library::Container::Action action = c->getAction(ftok->str()); const Token* iterTok = nullptr; if (action == Library::Container::Action::INSERT && args.size() == 2) { // Skip if iterator pair diff --git a/test/teststl.cpp b/test/teststl.cpp index b7a29b2a11a..35941f6422c 100644 --- a/test/teststl.cpp +++ b/test/teststl.cpp @@ -2345,6 +2345,15 @@ class TestStl : public TestFixture { " } \n" "}\n"); ASSERT_EQUALS("", errout_str()); + + check("std::string g1();\n" // #12520 + "const std::string& g2();\n" + "void f() {\n" + " g1().erase(g1().begin());\n" + " g2().erase(g2().begin());\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:4:7]: (error) Iterator 'g1().begin()' referring to temporary container 'g1()' is used with temporary container 'g1()'. [mismatchingContainerIterator]\n", + errout_str()); } void eraseIteratorOutOfBounds() { From ed596da1dc32b29d19573cae722e8fcb730c56c6 Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Mon, 22 Jun 2026 14:19:55 +0200 Subject: [PATCH 044/165] Fix #14817 FN constParameterPointer for constructor initializing array (regression) , add test for #11471 (#8637) Co-authored-by: chrchr-github --- lib/astutils.cpp | 2 ++ test/testother.cpp | 22 ++++++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/lib/astutils.cpp b/lib/astutils.cpp index 8dfd03596d3..7af806508fd 100644 --- a/lib/astutils.cpp +++ b/lib/astutils.cpp @@ -2592,6 +2592,8 @@ bool isVariableChangedByFunctionCall(const Token *tok, int indirect, const Setti if (const Variable* var = tok->variable()) { if (tok == var->nameToken() && (!var->isReference() || (var->isConst() && var->type() == tok1->type())) && (!var->isClass() || (var->valueType() && var->valueType()->container))) // const ref or passed to (copy) ctor return false; + if (var->isArray() && var->valueType() && var->valueType()->pointer == 0 && var->valueType()->isPrimitive()) + return false; } std::vector args = getArgumentVars(tok, argnr); diff --git a/test/testother.cpp b/test/testother.cpp index 4215a3b3449..1d69cf6763e 100644 --- a/test/testother.cpp +++ b/test/testother.cpp @@ -4872,6 +4872,28 @@ class TestOther : public TestFixture { " return *p->cbegin();\n" "}\n"); ASSERT_EQUALS("[test.cpp:1:25]: (style) Parameter 'p' can be declared as pointer to const [constParameterPointer]\n", errout_str()); + + check("struct S {\n" // #14817 + " explicit S(int *a) : m{ a[0], a[1] } {}\n" + " int m[2];\n" + "}" + "struct T {\n" + " explicit T(int *a) : m{ &a[0], &a[1] } {}\n" + " int* m[2];\n" + "};\n"); + ASSERT_EQUALS("[test.cpp:2:21]: (style) Parameter 'a' can be declared as pointer to const [constParameterPointer]\n", + errout_str()); + + check("class A {\n" // #11471 + "public:\n" + " A(const int& i, int) : m_i(&i) {}\n" + " const int* m_i;\n" + "};\n" + "A f(int& s) {\n" + " return A(s, 0);\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:6:10]: (style) Parameter 's' can be declared as reference to const [constParameterReference]\n", + errout_str()); } void constArray() { From a709c8664ee156fd0f3c5b286cc0eb58a3c15de9 Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Mon, 22 Jun 2026 14:39:23 +0200 Subject: [PATCH 045/165] Fix #14860 FP sizeofwithsilentarraypointer with std::array (#8661) --- lib/checksizeof.cpp | 2 +- test/testsizeof.cpp | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/lib/checksizeof.cpp b/lib/checksizeof.cpp index b9c495733e0..2d9012078a6 100644 --- a/lib/checksizeof.cpp +++ b/lib/checksizeof.cpp @@ -87,7 +87,7 @@ void CheckSizeofImpl::checkSizeofForArrayParameter() } const Variable *var = varTok->variable(); - if (var && var->isArray() && var->isArgument() && !var->isReference()) + if (var && var->isArray() && var->isArgument() && !var->isReference() && !(var->isStlType() && var->getTypeName() == "std::array")) sizeofForArrayParameterError(tok); } } diff --git a/test/testsizeof.cpp b/test/testsizeof.cpp index 9337252f92c..f955242019f 100644 --- a/test/testsizeof.cpp +++ b/test/testsizeof.cpp @@ -334,6 +334,14 @@ class TestSizeof : public TestFixture { "}"); ASSERT_EQUALS("", errout_str()); + check("int f(std::array a) {\n" // #14860 + " return sizeof(a);\n" + "}\n" + "int g(std::string a[2]) {\n" + " return sizeof(a);\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:5:12]: (warning) Using 'sizeof' on array given as function argument returns size of a pointer. [sizeofwithsilentarraypointer]\n", + errout_str()); } void sizeofForNumericParameter() { From e0014e1b023442e9c0e15609658a910c41436356 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20St=C3=B6neberg?= Date: Tue, 23 Jun 2026 08:58:20 +0200 Subject: [PATCH 046/165] fixed some `-Wsign-compare` compiler warnings (#8280) --- lib/analyzerinfo.cpp | 2 +- lib/analyzerinfo.h | 2 +- lib/check64bit.cpp | 12 ++++++------ lib/checkbufferoverrun.cpp | 4 ++-- lib/checkclass.cpp | 6 +++--- lib/checkfunctions.cpp | 2 +- lib/checkleakautovar.cpp | 2 +- lib/checknullpointer.cpp | 6 +++--- lib/checkother.cpp | 12 ++++++------ lib/checkother.h | 2 +- lib/checkstl.cpp | 8 ++++---- lib/clangimport.cpp | 10 +++++----- lib/ctu.cpp | 18 +++++++++--------- lib/ctu.h | 10 +++++----- lib/errorlogger.h | 2 +- lib/fwdanalysis.cpp | 4 ++-- lib/programmemory.cpp | 2 +- lib/reverseanalyzer.cpp | 2 +- lib/symboldatabase.cpp | 18 +++++++++--------- lib/symboldatabase.h | 12 ++++++------ lib/templatesimplifier.cpp | 6 +++--- lib/token.cpp | 6 +++--- lib/valueflow.cpp | 4 ++-- 23 files changed, 76 insertions(+), 76 deletions(-) diff --git a/lib/analyzerinfo.cpp b/lib/analyzerinfo.cpp index 6f919ec3651..36803b897b1 100644 --- a/lib/analyzerinfo.cpp +++ b/lib/analyzerinfo.cpp @@ -126,7 +126,7 @@ std::string AnalyzerInformation::skipAnalysis(const tinyxml2::XMLDocument &analy return ""; } -std::string AnalyzerInformation::getAnalyzerInfoFileFromFilesTxt(std::istream& filesTxt, const std::string &sourcefile, const std::string &cfg, int fsFileId) +std::string AnalyzerInformation::getAnalyzerInfoFileFromFilesTxt(std::istream& filesTxt, const std::string &sourcefile, const std::string &cfg, size_t fsFileId) { std::string line; while (std::getline(filesTxt,line)) { diff --git a/lib/analyzerinfo.h b/lib/analyzerinfo.h index d2a83c747c3..75674a22f82 100644 --- a/lib/analyzerinfo.h +++ b/lib/analyzerinfo.h @@ -87,7 +87,7 @@ class CPPCHECKLIB AnalyzerInformation { protected: static std::string getFilesTxt(const std::list &sourcefiles, const std::list &fileSettings); - static std::string getAnalyzerInfoFileFromFilesTxt(std::istream& filesTxt, const std::string &sourcefile, const std::string &cfg, int fsFileId); + static std::string getAnalyzerInfoFileFromFilesTxt(std::istream& filesTxt, const std::string &sourcefile, const std::string &cfg, size_t fsFileId); static std::string skipAnalysis(const tinyxml2::XMLDocument &analyzerInfoDoc, std::size_t hash, std::list &errors); diff --git a/lib/check64bit.cpp b/lib/check64bit.cpp index 345d66d9846..174237eef5a 100644 --- a/lib/check64bit.cpp +++ b/lib/check64bit.cpp @@ -90,11 +90,11 @@ void Check64BitPortabilityImpl::pointerassignment() if (!returnType) continue; - if (retPointer && !returnType->typeScope && returnType->pointer == 0U) + if (retPointer && !returnType->typeScope && returnType->pointer == 0) returnIntegerError(tok); if (!retPointer) { - bool warn = returnType->pointer >= 1U; + bool warn = returnType->pointer >= 1; if (!warn) { const Token* tok2 = tok->astOperand1(); while (tok2 && tok2->isCast()) @@ -119,17 +119,17 @@ void Check64BitPortabilityImpl::pointerassignment() continue; // Assign integer to pointer.. - if (lhstype->pointer >= 1U && + if (lhstype->pointer >= 1 && !tok->astOperand2()->isNumber() && - rhstype->pointer == 0U && + rhstype->pointer == 0 && rhstype->originalTypeName.empty() && rhstype->type == ValueType::Type::INT && !isFunctionPointer(tok->astOperand1())) assignmentIntegerToAddressError(tok); // Assign pointer to integer.. - if (rhstype->pointer >= 1U && - lhstype->pointer == 0U && + if (rhstype->pointer >= 1 && + lhstype->pointer == 0 && lhstype->originalTypeName.empty() && lhstype->isIntegral() && lhstype->type >= ValueType::Type::CHAR && diff --git a/lib/checkbufferoverrun.cpp b/lib/checkbufferoverrun.cpp index 8be9b508849..879ade5f21f 100644 --- a/lib/checkbufferoverrun.cpp +++ b/lib/checkbufferoverrun.cpp @@ -654,7 +654,7 @@ void CheckBufferOverrunImpl::bufferOverflow() if (!mSettings.library.hasminsize(tok)) continue; const std::vector args = getArguments(tok); - for (int argnr = 0; argnr < args.size(); ++argnr) { + for (size_t argnr = 0; argnr < args.size(); ++argnr) { if (!args[argnr]->valueType() || args[argnr]->valueType()->pointer == 0) continue; const std::vector *minsizes = mSettings.library.argminsizes(tok, argnr + 1); @@ -846,7 +846,7 @@ void CheckBufferOverrunImpl::argumentSize() // If argument is '%type% a[num]' then check bounds against num const Function *callfunc = tok->function(); const std::vector callargs = getArguments(tok); - for (nonneg int paramIndex = 0; paramIndex < callargs.size() && paramIndex < callfunc->argCount(); ++paramIndex) { + for (size_t paramIndex = 0; paramIndex < callargs.size() && paramIndex < callfunc->argCount(); ++paramIndex) { const Variable* const argument = callfunc->getArgumentVar(paramIndex); if (!argument || !argument->nameToken() || !argument->isArray()) continue; diff --git a/lib/checkclass.cpp b/lib/checkclass.cpp index 7d3fa5c51ec..ce96849ca27 100644 --- a/lib/checkclass.cpp +++ b/lib/checkclass.cpp @@ -2414,7 +2414,7 @@ bool CheckClassImpl::isMemberFunc(const Scope *scope, const Token *tok) for (const Function &func : scope->functionList) { if (func.name() == tok->str()) { const Token* tok2 = tok->tokAt(2); - int argsPassed = tok2->str() == ")" ? 0 : 1; + size_t argsPassed = tok2->str() == ")" ? 0 : 1; for (;;) { tok2 = tok2->nextArgument(); if (tok2) @@ -2511,9 +2511,9 @@ bool CheckClassImpl::checkConstFunc(const Scope *scope, const Function *func, Me if (const Function* f = funcTok->function()) { // check known function const std::vector args = getArguments(funcTok); - const auto argMax = std::min(args.size(), f->argCount()); + const auto argMax = std::min(args.size(), f->argCount()); - for (nonneg int argIndex = 0; argIndex < argMax; ++argIndex) { + for (size_t argIndex = 0; argIndex < argMax; ++argIndex) { const Variable* const argVar = f->getArgumentVar(argIndex); if (!argVar || ((argVar->isArrayOrPointer() || argVar->isReference()) && !(argVar->valueType() && argVar->valueType()->isConst(argVar->valueType()->pointer)))) { // argument might be modified diff --git a/lib/checkfunctions.cpp b/lib/checkfunctions.cpp index d04f9d9cc1d..23db248816d 100644 --- a/lib/checkfunctions.cpp +++ b/lib/checkfunctions.cpp @@ -116,7 +116,7 @@ void CheckFunctionsImpl::invalidFunctionUsage() continue; const Token * const functionToken = tok; const std::vector arguments = getArguments(tok); - for (int argnr = 1; argnr <= arguments.size(); ++argnr) { + for (size_t argnr = 1; argnr <= arguments.size(); ++argnr) { const Token * const argtok = arguments[argnr-1]; // check ... diff --git a/lib/checkleakautovar.cpp b/lib/checkleakautovar.cpp index 2fd16e85eaa..9049d56e7ff 100644 --- a/lib/checkleakautovar.cpp +++ b/lib/checkleakautovar.cpp @@ -392,7 +392,7 @@ bool CheckLeakAutoVarImpl::checkScope(const Token * const startToken, }); }); if (hasOutParam) { - for (int i = 0; i < args.size(); i++) { + for (size_t i = 0; i < args.size(); i++) { if (!argChecks.count(i + 1)) continue; const ArgumentChecks argCheck = argChecks.at(i + 1); diff --git a/lib/checknullpointer.cpp b/lib/checknullpointer.cpp index 9790f7f2724..ac56f19eb09 100644 --- a/lib/checknullpointer.cpp +++ b/lib/checknullpointer.cpp @@ -49,7 +49,7 @@ static const CWE CWE_INCORRECT_CALCULATION(682U); //--------------------------------------------------------------------------- -static bool checkNullpointerFunctionCallPlausibility(const Function* func, unsigned int arg) +static bool checkNullpointerFunctionCallPlausibility(const Function* func, size_t arg) { return !func || (func->argCount() >= arg && func->getArgumentVar(arg - 1) && func->getArgumentVar(arg - 1)->isPointer()); } @@ -61,7 +61,7 @@ std::list CheckNullPointerImpl::parseFunctionCall(const Token &tok const std::vector args = getArguments(&tok); std::list var; - for (int argnr = 1; argnr <= args.size(); ++argnr) { + for (size_t argnr = 1; argnr <= args.size(); ++argnr) { const Token *param = args[argnr - 1]; if ((!checkNullArg || library.isnullargbad(&tok, argnr)) && checkNullpointerFunctionCallPlausibility(tok.function(), argnr)) var.push_back(param); @@ -370,7 +370,7 @@ void CheckNullPointerImpl::nullConstantDereference() else if (Token::Match(tok->previous(), "::|. %name% (")) { const std::vector &args = getArguments(tok); - for (int argnr = 0; argnr < args.size(); ++argnr) { + for (size_t argnr = 0; argnr < args.size(); ++argnr) { const Token *argtok = args[argnr]; if (!argtok->hasKnownIntValue()) continue; diff --git a/lib/checkother.cpp b/lib/checkother.cpp index a45dfdf672e..5ed3473c8a7 100644 --- a/lib/checkother.cpp +++ b/lib/checkother.cpp @@ -3313,7 +3313,7 @@ static bool constructorTakesReference(const Scope * const classScope) { return std::any_of(classScope->functionList.begin(), classScope->functionList.end(), [&](const Function& constructor) { if (constructor.isConstructor()) { - for (int argnr = 0U; argnr < constructor.argCount(); argnr++) { + for (size_t argnr = 0U; argnr < constructor.argCount(); argnr++) { const Variable * const argVar = constructor.getArgumentVar(argnr); if (argVar && argVar->isReference()) { return true; @@ -4036,7 +4036,7 @@ void CheckOtherImpl::checkFuncArgNamesDifferent() std::vector declarations(function->argCount()); std::vector definitions(function->argCount()); const Token * decl = function->argDef->next(); - for (int j = 0; j < function->argCount(); ++j) { + for (size_t j = 0; j < function->argCount(); ++j) { // get the definition const Variable * variable = function->getArgumentVar(j); if (variable) { @@ -4064,11 +4064,11 @@ void CheckOtherImpl::checkFuncArgNamesDifferent() // check for different argument order if (warning) { bool order_different = false; - for (int j = 0; j < function->argCount(); ++j) { + for (size_t j = 0; j < function->argCount(); ++j) { if (!declarations[j] || !definitions[j] || declarations[j]->str() == definitions[j]->str()) continue; - for (int k = 0; k < function->argCount(); ++k) { + for (size_t k = 0; k < function->argCount(); ++k) { if (j != k && definitions[k] && declarations[j]->str() == definitions[k]->str()) { order_different = true; break; @@ -4082,7 +4082,7 @@ void CheckOtherImpl::checkFuncArgNamesDifferent() } // check for different argument names if (style && inconclusive) { - for (int j = 0; j < function->argCount(); ++j) { + for (size_t j = 0; j < function->argCount(); ++j) { const bool warn = (declarations[j] != nullptr) != (definitions[j] != nullptr) || (declarations[j] && definitions[j] && declarations[j]->str() != definitions[j]->str()); if (warn) @@ -4092,7 +4092,7 @@ void CheckOtherImpl::checkFuncArgNamesDifferent() } } -void CheckOtherImpl::funcArgNamesDifferent(const std::string & functionName, nonneg int index, +void CheckOtherImpl::funcArgNamesDifferent(const std::string & functionName, size_t index, const Token* declaration, const Token* definition) { std::list tokens = { declaration,definition }; diff --git a/lib/checkother.h b/lib/checkother.h index 7f21ffc00f8..759a4d23e7b 100644 --- a/lib/checkother.h +++ b/lib/checkother.h @@ -316,7 +316,7 @@ class CPPCHECKLIB CheckOtherImpl : public CheckImpl { void unusedLabelError(const Token* tok, bool inSwitch, bool hasIfdef); void unknownEvaluationOrder(const Token* tok, bool isUnspecifiedBehavior = false); void accessMovedError(const Token *tok, const std::string &varname, const ValueFlow::Value *value, bool inconclusive); - void funcArgNamesDifferent(const std::string & functionName, nonneg int index, const Token* declaration, const Token* definition); + void funcArgNamesDifferent(const std::string & functionName, size_t index, const Token* declaration, const Token* definition); void funcArgOrderDifferent(const std::string & functionName, const Token * declaration, const Token * definition, const std::vector & declarations, const std::vector & definitions); void shadowError(const Token *shadows, const std::string &shadowsType, const Token *shadowed, const std::string &shadowedType); void knownArgumentError(const Token *tok, const Token *ftok, const ValueFlow::Value *value, const std::string &varexpr, bool isVariableExpressionHidden); diff --git a/lib/checkstl.cpp b/lib/checkstl.cpp index 3e08fe04ed6..6c4e5a7a22c 100644 --- a/lib/checkstl.cpp +++ b/lib/checkstl.cpp @@ -830,7 +830,7 @@ void CheckStlImpl::mismatchingContainers() // Group args together by container std::map> containers; - for (int argnr = 1; argnr <= args.size(); ++argnr) { + for (size_t argnr = 1; argnr <= args.size(); ++argnr) { const Library::ArgumentChecks::IteratorInfo *i = mSettings.library.getArgIteratorInfo(ftok, argnr); if (!i) continue; @@ -1435,7 +1435,7 @@ void CheckStlImpl::eraseCheckLoopVar(const Scope &scope, const Variable *var) if (Token::Match(tok->astParent(), "=|return")) continue; // Iterator is invalid.. - int indentlevel = 0U; + int indentlevel = 0; const Token *tok2 = tok->link(); for (; tok2 != scope.bodyEnd; tok2 = tok2->next()) { if (tok2->str() == "{") { @@ -1443,7 +1443,7 @@ void CheckStlImpl::eraseCheckLoopVar(const Scope &scope, const Variable *var) continue; } if (tok2->str() == "}") { - if (indentlevel > 0U) + if (indentlevel > 0) --indentlevel; else if (Token::simpleMatch(tok2, "} else {")) tok2 = tok2->linkAt(2); @@ -3295,7 +3295,7 @@ void CheckStlImpl::knownEmptyContainer() if (args.empty()) continue; - for (int argnr = 1; argnr <= args.size(); ++argnr) { + for (size_t argnr = 1; argnr <= args.size(); ++argnr) { const Library::ArgumentChecks::IteratorInfo *i = mSettings.library.getArgIteratorInfo(tok, argnr); if (!i) continue; diff --git a/lib/clangimport.cpp b/lib/clangimport.cpp index 417e94e8798..98c0e700d83 100644 --- a/lib/clangimport.cpp +++ b/lib/clangimport.cpp @@ -140,7 +140,7 @@ static std::vector splitString(const std::string &line) pos2 = line.find('\"', pos1+1); else if (line[pos1] == '\'') { pos2 = line.find('\'', pos1+1); - if (pos2 < static_cast(line.size()) - 3 && line.compare(pos2, 3, "\':\'", 0, 3) == 0) + if (pos2 < line.size() - 3 && line.compare(pos2, 3, "\':\'", 0, 3) == 0) pos2 = line.find('\'', pos2 + 3); } else { pos2 = pos1; @@ -357,7 +357,7 @@ namespace clangimport { /** * @throws InternalError thrown if index is out of bounds */ - AstNodePtr getChild(int c) { + AstNodePtr getChild(size_t c) { if (c >= children.size()) { std::ostringstream err; err << "ClangImport: AstNodePtr::getChild(" << c << ") out of bounds. children.size=" << children.size() << " " << nodeType; @@ -509,7 +509,7 @@ void clangimport::AstNode::dumpAst(int num, int indent) const for (const auto& tok: mExtTokens) std::cout << " " << tok; std::cout << std::endl; - for (int c = 0; c < children.size(); ++c) { + for (size_t c = 0; c < children.size(); ++c) { if (children[c]) children[c]->dumpAst(c, indent + 2); else @@ -1432,7 +1432,7 @@ void clangimport::AstNode::createTokensFunctionDecl(TokenList &tokenList) function->nestedIn = nestedIn; function->argDef = par1; // Function arguments - for (int i = 0; i < children.size(); ++i) { + for (size_t i = 0; i < children.size(); ++i) { AstNodePtr child = children[i]; if (child->nodeType != ParmVarDecl) continue; @@ -1657,7 +1657,7 @@ void clangimport::parseClangAstDump(Tokenizer &tokenizer, std::istream &f) continue; } - const int level = (pos1 - 1) / 2; + const size_t level = (pos1 - 1) / 2; if (level == 0 || level > tree.size()) continue; diff --git a/lib/ctu.cpp b/lib/ctu.cpp index fee3acb85ae..feef065d3ac 100644 --- a/lib/ctu.cpp +++ b/lib/ctu.cpp @@ -280,11 +280,11 @@ std::list CTU::loadUnsafeUsageListFromXml(const tiny return ret; } -static int isCallFunction(const Scope *scope, int argnr, const Token *&tok) +static size_t isCallFunction(const Scope *scope, size_t argnr, const Token *&tok) { const Variable * const argvar = scope->function->getArgumentVar(argnr); if (!argvar->isPointer()) - return -1; + return 0; for (const Token *tok2 = scope->bodyStart; tok2 != scope->bodyEnd; tok2 = tok2->next()) { if (tok2->variable() != argvar) continue; @@ -306,7 +306,7 @@ static int isCallFunction(const Scope *scope, int argnr, const Token *&tok) tok = prev->previous(); return argnr2; } - return -1; + return 0; } @@ -330,7 +330,7 @@ const CTU::FileInfo *CTU::getFileInfo(const Tokenizer &tokenizer) if (!tokFunction) continue; const std::vector args(getArguments(tok->previous())); - for (int argnr = 0; argnr < args.size(); ++argnr) { + for (size_t argnr = 0; argnr < args.size(); ++argnr) { const Token *argtok = args[argnr]; if (!argtok) continue; @@ -427,9 +427,9 @@ const CTU::FileInfo *CTU::getFileInfo(const Tokenizer &tokenizer) } // Nested function calls - for (int argnr = 0; argnr < scopeFunction->argCount(); ++argnr) { + for (size_t argnr = 0; argnr < scopeFunction->argCount(); ++argnr) { const Token *tok; - const int argnr2 = isCallFunction(&scope, argnr, tok); + const size_t argnr2 = isCallFunction(&scope, argnr, tok); if (argnr2 > 0) { FileInfo::NestedCall nestedCall(tokenizer, scopeFunction, tok); nestedCall.myArgNr = argnr + 1; @@ -442,7 +442,7 @@ const CTU::FileInfo *CTU::getFileInfo(const Tokenizer &tokenizer) return fileInfo; } -static std::vector> getUnsafeFunction(const Settings &settings, const Scope *scope, int argnr, bool (*isUnsafeUsage)(const Settings &settings, const Token *argtok, CTU::FileInfo::Value *value)) +static std::vector> getUnsafeFunction(const Settings &settings, const Scope *scope, size_t argnr, bool (*isUnsafeUsage)(const Settings &settings, const Token *argtok, CTU::FileInfo::Value *value)) { std::vector> ret; const Variable * const argvar = scope->function->getArgumentVar(argnr); @@ -487,7 +487,7 @@ std::list CTU::getUnsafeUsage(const Tokenizer &token const Function *const function = scope.function; // "Unsafe" functions unconditionally reads data before it is written.. - for (int argnr = 0; argnr < function->argCount(); ++argnr) { + for (size_t argnr = 0; argnr < function->argCount(); ++argnr) { for (const std::pair &v : getUnsafeFunction(settings, &scope, argnr, isUnsafeUsage)) { const Token *tok = v.first; const MathLib::bigint val = v.second.value; @@ -500,7 +500,7 @@ std::list CTU::getUnsafeUsage(const Tokenizer &token } static bool findPath(const std::string &callId, - nonneg int callArgNr, + size_t callArgNr, MathLib::bigint unsafeValue, CTU::FileInfo::InvalidValueType invalidValue, const std::map> &callsMap, diff --git a/lib/ctu.h b/lib/ctu.h index 60120064284..76baff21b9f 100644 --- a/lib/ctu.h +++ b/lib/ctu.h @@ -79,14 +79,14 @@ namespace CTU { struct UnsafeUsage { UnsafeUsage() = default; - UnsafeUsage(std::string myId, nonneg int myArgNr, std::string myArgumentName, Location location, MathLib::bigint value) + UnsafeUsage(std::string myId, size_t myArgNr, std::string myArgumentName, Location location, MathLib::bigint value) : myId(std::move(myId)) , myArgNr(myArgNr) , myArgumentName(std::move(myArgumentName)) , location(std::move(location)) , value(value) {} std::string myId; - nonneg int myArgNr{}; + size_t myArgNr{}; std::string myArgumentName; Location location; MathLib::bigint value{}; @@ -96,14 +96,14 @@ namespace CTU { class CallBase { public: CallBase() = default; - CallBase(std::string callId, int callArgNr, std::string callFunctionName, Location loc) + CallBase(std::string callId, size_t callArgNr, std::string callFunctionName, Location loc) : callId(std::move(callId)), callArgNr(callArgNr), callFunctionName(std::move(callFunctionName)), location(std::move(loc)) {} CallBase(const Tokenizer &tokenizer, const Token *callToken); virtual ~CallBase() = default; CallBase(const CallBase&) = default; std::string callId; - int callArgNr{}; + size_t callArgNr{}; std::string callFunctionName; Location location; protected: @@ -138,7 +138,7 @@ namespace CTU { bool loadFromXml(const tinyxml2::XMLElement *xmlElement); std::string myId; - nonneg int myArgNr{}; + size_t myArgNr{}; }; std::list functionCalls; diff --git a/lib/errorlogger.h b/lib/errorlogger.h index d739cb3fbf9..daf683bd0a3 100644 --- a/lib/errorlogger.h +++ b/lib/errorlogger.h @@ -88,7 +88,7 @@ class CPPCHECKLIB ErrorMessage { std::string stringify(bool addcolumn = false) const; unsigned int fileIndex; - int line; // negative value means "no line" + int line; // negative value means "no line" - TODO: actually 0 means no line - lines from simplecpp are unsigned unsigned int column; const std::string& getinfo() const { diff --git a/lib/fwdanalysis.cpp b/lib/fwdanalysis.cpp index ddcbbbd1fa9..07ba7cc2e59 100644 --- a/lib/fwdanalysis.cpp +++ b/lib/fwdanalysis.cpp @@ -289,7 +289,7 @@ FwdAnalysis::Result FwdAnalysis::checkRecursive(const Token *expr, const Token * ftok = ftok->astParent(); if (ftok && Token::Match(ftok->previous(), "%name% (")) { const std::vector args = getArguments(ftok); - int argnr = 0; + size_t argnr = 0; while (argnr < args.size() && args[argnr] != parent) argnr++; if (argnr < args.size()) { @@ -469,7 +469,7 @@ bool FwdAnalysis::possiblyAliased(const Token *expr, const Token *startToken) co if (Token::Match(tok, "%name% (") && !Token::Match(tok, "if|while|for")) { // Is argument passed by reference? const std::vector args = getArguments(tok); - for (int argnr = 0; argnr < args.size(); ++argnr) { + for (size_t argnr = 0; argnr < args.size(); ++argnr) { if (!Token::Match(args[argnr], "%name%|.|::")) continue; if (tok->function() && tok->function()->getArgumentVar(argnr) && !tok->function()->getArgumentVar(argnr)->isReference() && !tok->function()->isConst()) diff --git a/lib/programmemory.cpp b/lib/programmemory.cpp index e1f40de277e..b86ca2d8812 100644 --- a/lib/programmemory.cpp +++ b/lib/programmemory.cpp @@ -1552,7 +1552,7 @@ namespace { return unknown(); const MathLib::bigint index = rhs.intvalue; if (index >= 0 && index < strValue.size()) - return ValueFlow::Value{strValue[static_cast(index)]}; + return ValueFlow::Value{strValue[index]}; if (index == strValue.size()) return ValueFlow::Value{}; } else if (Token::Match(expr, "%cop%") && expr->astOperand1() && expr->astOperand2()) { diff --git a/lib/reverseanalyzer.cpp b/lib/reverseanalyzer.cpp index 4afd2556a24..38aea656bf0 100644 --- a/lib/reverseanalyzer.cpp +++ b/lib/reverseanalyzer.cpp @@ -204,7 +204,7 @@ namespace { void traverse(Token* start, const Token* end = nullptr) { if (start == end) return; - std::size_t i = start->index(); + nonneg int i = start->index(); for (Token* tok = start->previous(); succeeds(tok, end); tok = tok->previous()) { if (tok->index() >= i) throw InternalError(tok, "Cyclic reverse analysis."); diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index ba5c31d1f47..14fc1b7cdf2 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -2174,7 +2174,7 @@ namespace { { if (const Scope* scope = var->nameToken()->scope()) { auto it = std::find_if(scope->functionList.begin(), scope->functionList.end(), [&](const Function& function) { - for (nonneg int arg = 0; arg < function.argCount(); ++arg) { + for (size_t arg = 0; arg < function.argCount(); ++arg) { if (var == function.getArgumentVar(arg)) return true; } @@ -4537,7 +4537,7 @@ void SymbolDatabase::printXml(std::ostream &out) const outs += "/>\n"; else { outs += ">\n"; - for (unsigned int argnr = 0; argnr < function->argCount(); ++argnr) { + for (size_t argnr = 0; argnr < function->argCount(); ++argnr) { const Variable *arg = function->getArgumentVar(argnr); outs += " & matches) const +void Scope::findFunctionInBase(const Token* tok, size_t args, std::vector & matches) const { if (isClassOrStruct() && definedType && !definedType->derivedFrom.empty()) { const std::vector &derivedFrom = definedType->derivedFrom; @@ -7049,7 +7049,7 @@ void SymbolDatabase::setValueType(Token* tok, const ValueType& valuetype, const return; } - if (parent->str() == "[" && (!parent->isCpp() || parent->astOperand1() == tok) && valuetype.pointer > 0U && !Token::Match(parent->previous(), "[{,]")) { + if (parent->str() == "[" && (!parent->isCpp() || parent->astOperand1() == tok) && valuetype.pointer > 0 && !Token::Match(parent->previous(), "[{,]")) { const Token *op1 = parent->astOperand1(); while (op1 && op1->str() == "[") op1 = op1->astOperand1(); @@ -7061,7 +7061,7 @@ void SymbolDatabase::setValueType(Token* tok, const ValueType& valuetype, const setValueType(parent, vt); return; } - if (Token::Match(parent->tokAt(-1), "%name% (") && !parent->tokAt(-1)->isKeyword() && parent->astOperand1() == tok && valuetype.pointer > 0U) { + if (Token::Match(parent->tokAt(-1), "%name% (") && !parent->tokAt(-1)->isKeyword() && parent->astOperand1() == tok && valuetype.pointer > 0) { ValueType vt(valuetype); vt.pointer -= 1U; setValueType(parent, vt); @@ -7074,7 +7074,7 @@ void SymbolDatabase::setValueType(Token* tok, const ValueType& valuetype, const setValueType(parent, vt); return; } - if (parent->str() == "*" && !parent->astOperand2() && valuetype.pointer > 0U) { + if (parent->str() == "*" && !parent->astOperand2() && valuetype.pointer > 0) { ValueType vt(valuetype); vt.pointer -= 1U; setValueType(parent, vt); @@ -7107,7 +7107,7 @@ void SymbolDatabase::setValueType(Token* tok, const ValueType& valuetype, const return; } } - if (parent->str() == "*" && Token::simpleMatch(parent->astOperand2(), "[") && valuetype.pointer > 0U) { + if (parent->str() == "*" && Token::simpleMatch(parent->astOperand2(), "[") && valuetype.pointer > 0) { const Token *op1 = parent->astOperand2()->astOperand1(); while (op1 && op1->str() == "[") op1 = op1->astOperand1(); @@ -8714,7 +8714,7 @@ std::string ValueType::str() const } else if (type == ValueType::Type::SMART_POINTER && smartPointer) { ret += " smart-pointer(" + smartPointer->name + ")"; } - for (unsigned int p = 0; p < pointer; p++) { + for (nonneg int p = 0; p < pointer; p++) { ret += " *"; if (constness & (2 << p)) ret += " const"; diff --git a/lib/symboldatabase.h b/lib/symboldatabase.h index a4a07fd2083..166f228ad99 100644 --- a/lib/symboldatabase.h +++ b/lib/symboldatabase.h @@ -767,14 +767,14 @@ class CPPCHECKLIB Function { std::string fullName() const; - nonneg int argCount() const { + size_t argCount() const { return argumentList.size(); } - nonneg int minArgCount() const { + size_t minArgCount() const { return argumentList.size() - initArgCount; } - const Variable* getArgumentVar(nonneg int num) const; - nonneg int initializedArgCount() const { + const Variable* getArgumentVar(size_t num) const; + size_t initializedArgCount() const { return initArgCount; } /** @@ -928,7 +928,7 @@ class CPPCHECKLIB Function { const Scope* functionScope{}; ///< scope of function body const Scope* nestedIn{}; ///< Scope the function is declared in std::list argumentList; ///< argument list, must remain list due to clangimport usage! - nonneg int initArgCount{}; ///< number of args with default values + size_t initArgCount{}; ///< number of args with default values FunctionType type = FunctionType::eFunction; ///< constructor, destructor, ... const Token* noexceptArg{}; ///< noexcept token const Token* throwArg{}; ///< throw token @@ -1209,7 +1209,7 @@ class CPPCHECKLIB Scope { */ bool isVariableDeclaration(const Token* tok, const Token*& vartok, const Token*& typetok) const; - void findFunctionInBase(const Token* tok, nonneg int args, std::vector & matches) const; + void findFunctionInBase(const Token* tok, size_t args, std::vector & matches) const; /** @brief initialize varlist */ void getVariableList(const Token *start, const Token *end); diff --git a/lib/templatesimplifier.cpp b/lib/templatesimplifier.cpp index 2672e66c263..4051b05c204 100644 --- a/lib/templatesimplifier.cpp +++ b/lib/templatesimplifier.cpp @@ -2258,7 +2258,7 @@ void TemplateSimplifier::expandTemplate( Token::Match(tok3->next()->findClosingBracket(), ">|>>")) { const Token *closingBracket = tok3->next()->findClosingBracket(); if (Token::simpleMatch(closingBracket->next(), "&")) { - int num = 0; + size_t num = 0; const Token *par = tok3->next(); while (num < typeParametersInDeclaration.size() && par != closingBracket) { const std::string pattern("[<,] " + typeParametersInDeclaration[num]->str() + " [,>]"); @@ -3041,7 +3041,7 @@ bool TemplateSimplifier::matchSpecialization( declToken->isSigned() != instToken->isSigned() || declToken->isUnsigned() != instToken->isUnsigned() || declToken->isLong() != instToken->isLong()) { - int nr = 0; + size_t nr = 0; while (nr < templateParameters.size() && templateParameters[nr]->str() != declToken->str()) ++nr; @@ -3139,7 +3139,7 @@ bool TemplateSimplifier::simplifyTemplateInstantiations( // locate template usage.. std::string::size_type numberOfTemplateInstantiations = mTemplateInstantiations.size(); - unsigned int recursiveCount = 0; + int recursiveCount = 0; bool instantiated = false; diff --git a/lib/token.cpp b/lib/token.cpp index 7e19106e1b0..d8b438c5073 100644 --- a/lib/token.cpp +++ b/lib/token.cpp @@ -1330,10 +1330,10 @@ std::string Token::stringifyList(const stringifyOptions& options, const std::vec std::string ret; - unsigned int lineNumber = mImpl->mLineNumber - (options.linenumbers ? 1U : 0U); + nonneg int lineNumber = mImpl->mLineNumber - (options.linenumbers ? 1 : 0); // cppcheck-suppress shadowFunction - TODO: fix this - unsigned int fileIndex = options.files ? ~0U : mImpl->mFileIndex; - std::map lineNumbers; + nonneg int fileIndex = options.files ? ~0U : mImpl->mFileIndex; + std::map lineNumbers; for (const Token *tok = this; tok != end; tok = tok->next()) { assert(tok && "end precedes token"); if (!tok) diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index fb9f6dda7a1..9ff54a5c244 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -2459,7 +2459,7 @@ static void valueFlowLifetimeFunction(Token *tok, const TokenList &tokenlist, Er const int returnContainer = settings.library.returnValueContainer(tok); if (returnContainer >= 0) { std::vector args = getArguments(tok); - for (int argnr = 1; argnr <= args.size(); ++argnr) { + for (size_t argnr = 1; argnr <= args.size(); ++argnr) { const Library::ArgumentChecks::IteratorInfo *i = settings.library.getArgIteratorInfo(tok, argnr); if (!i) continue; @@ -5758,7 +5758,7 @@ static void valueFlowFunctionDefaultParameter(const TokenList& tokenlist, const const Function* function = scope->function; if (!function) continue; - for (nonneg int arg = function->minArgCount(); arg < function->argCount(); arg++) { + for (size_t arg = function->minArgCount(); arg < function->argCount(); arg++) { const Variable* var = function->getArgumentVar(arg); if (var && var->hasDefault() && Token::Match(var->nameToken(), "%var% = %num%|%str%|%char%|%name% [,)]")) { const std::list &values = var->nameToken()->tokAt(2)->values(); From b587c7cf10ca5c1de8cdc00b8a55495fac1bda98 Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Wed, 24 Jun 2026 08:19:23 +0200 Subject: [PATCH 047/165] Fix #14866 FP bufferAccessOutOfBounds with vector and gethostname() (#8667) Co-authored-by: chrchr-github --- lib/checkbufferoverrun.cpp | 2 +- test/testbufferoverrun.cpp | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/checkbufferoverrun.cpp b/lib/checkbufferoverrun.cpp index 879ade5f21f..a98ba73429c 100644 --- a/lib/checkbufferoverrun.cpp +++ b/lib/checkbufferoverrun.cpp @@ -574,7 +574,7 @@ ValueFlow::Value CheckBufferOverrunImpl::getBufferSize(const Token *bufTok) cons return *value; } - if (!var || var->isPointer()) + if (!var || var->isPointer() || (astIsContainer(bufTok) && var->getTypeName() != "std::array")) return ValueFlow::Value(-1); const MathLib::bigint dim = std::accumulate(var->dimensions().cbegin(), var->dimensions().cend(), MathLib::bigint(1), [](MathLib::bigint i1, const Dimension &dim) { diff --git a/test/testbufferoverrun.cpp b/test/testbufferoverrun.cpp index 1a03ca336f8..e1da77ccbfb 100644 --- a/test/testbufferoverrun.cpp +++ b/test/testbufferoverrun.cpp @@ -3539,6 +3539,12 @@ class TestBufferOverrun : public TestFixture { "[test.cpp:7:12]: (error) Buffer is accessed out of bounds: &a[0][0] [bufferAccessOutOfBounds]\n", "", errout_str()); + + check("void f() {\n" // #14866 + " std::vector buf(25);\n" + " std::memset(&buf[0], 0, 25);\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); } void buffer_overrun_errorpath() { From 6640a7ce56cd57a046907360fbbe320d2b1f5704 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20St=C3=B6neberg?= Date: Wed, 24 Jun 2026 10:35:13 +0200 Subject: [PATCH 048/165] enabled `-Wshorten-64-to-32` Clang compiler warning (#8670) --- cmake/compileroptions.cmake | 1 - 1 file changed, 1 deletion(-) diff --git a/cmake/compileroptions.cmake b/cmake/compileroptions.cmake index aa7deb8552c..6343a8a5102 100644 --- a/cmake/compileroptions.cmake +++ b/cmake/compileroptions.cmake @@ -134,7 +134,6 @@ elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang") # TODO: fix and enable these warnings - or move to suppression list below add_compile_options_safe(-Wno-sign-conversion) add_compile_options_safe(-Wno-shadow-field-in-constructor) - add_compile_options_safe(-Wno-shorten-64-to-32) add_compile_options_safe(-Wno-implicit-int-conversion) add_compile_options_safe(-Wno-double-promotion) add_compile_options_safe(-Wno-shadow-field) From 887b5d2ff53031cc53ec76881caf27a6c74da005 Mon Sep 17 00:00:00 2001 From: Paul Fultz II Date: Thu, 25 Jun 2026 01:18:17 -0500 Subject: [PATCH 049/165] Fix issue 13682: false negative: nullPointerRedundantCheck (multiple conditions, regression) (#8669) Co-authored-by: Your Name --- .selfcheck_suppressions | 1 + lib/astutils.cpp | 4 -- lib/checkclass.cpp | 11 +++- lib/checkcondition.cpp | 2 +- lib/checkstl.cpp | 2 +- lib/forwardanalyzer.cpp | 2 +- lib/reverseanalyzer.cpp | 3 - lib/symboldatabase.cpp | 6 +- lib/tokenize.cpp | 2 +- lib/vf_analyzers.cpp | 30 +++++++-- test/testnullpointer.cpp | 134 +++++++++++++++++++++++++++++++++++++++ 11 files changed, 175 insertions(+), 22 deletions(-) diff --git a/.selfcheck_suppressions b/.selfcheck_suppressions index f21492e783a..402fdbeb75d 100644 --- a/.selfcheck_suppressions +++ b/.selfcheck_suppressions @@ -79,3 +79,4 @@ useStlAlgorithm:externals/simplecpp/simplecpp.cpp funcArgNamesDifferentUnnamed:externals/simplecpp/simplecpp.h missingMemberCopy:externals/simplecpp/simplecpp.h shadowFunction:externals/simplecpp/simplecpp.h +knownConditionTrueFalse:externals/simplecpp/simplecpp.cpp \ No newline at end of file diff --git a/lib/astutils.cpp b/lib/astutils.cpp index 7af806508fd..8700d2d2cd9 100644 --- a/lib/astutils.cpp +++ b/lib/astutils.cpp @@ -495,8 +495,6 @@ bool isTemporary(const Token* tok, const Library* library, bool unknown) } return unknown; } - if (tok->isCast()) - return false; // Currying a function is unknown in cppcheck if (Token::simpleMatch(tok, "(") && Token::simpleMatch(tok->astOperand1(), "(")) return unknown; @@ -1543,8 +1541,6 @@ bool isUsedAsBool(const Token* const tok, const Settings& settings) return true; if (parent->isCast()) return !Token::simpleMatch(parent->astOperand1(), "dynamic_cast") && isUsedAsBool(parent, settings); - if (parent->isUnaryOp("*")) - return isUsedAsBool(parent, settings); if (Token::Match(parent, "==|!=") && tok->valueType() && tok->valueType()->pointer && tok->astSibling()->hasKnownIntValue() && tok->astSibling()->getKnownIntValue() == 0) return true; diff --git a/lib/checkclass.cpp b/lib/checkclass.cpp index ce96849ca27..b610e963d76 100644 --- a/lib/checkclass.cpp +++ b/lib/checkclass.cpp @@ -3452,9 +3452,14 @@ void CheckClassImpl::checkUselessOverride() if (isSameCode) { // bailout for shadowed members - if (!classScope->definedType || - !getDuplInheritedMembersRecursive(classScope->definedType, classScope->definedType, /*skipPrivate*/ false).empty() || - !getDuplInheritedMemberFunctionsRecursive(classScope->definedType, classScope->definedType, /*skipPrivate*/ false).empty()) + if (!getDuplInheritedMembersRecursive(classScope->definedType, + classScope->definedType, + /*skipPrivate*/ false) + .empty() || + !getDuplInheritedMemberFunctionsRecursive(classScope->definedType, + classScope->definedType, + /*skipPrivate*/ false) + .empty()) continue; uselessOverrideError(baseFunc, &func, true); continue; diff --git a/lib/checkcondition.cpp b/lib/checkcondition.cpp index 72b61fd68b9..e77641f89e7 100644 --- a/lib/checkcondition.cpp +++ b/lib/checkcondition.cpp @@ -455,7 +455,7 @@ bool CheckConditionImpl::isOverlappingCond(const Token * const cond1, const Toke if (!num1->isNumber() || MathLib::isNegative(num1->str())) return false; - if (!Token::Match(cond2, "&|==") || !cond2->astOperand1() || !cond2->astOperand2()) + if (!Token::Match(cond2, "&|==") || !cond2->astOperand1()) return false; const Token *expr2 = cond2->astOperand1(); const Token *num2 = cond2->astOperand2(); diff --git a/lib/checkstl.cpp b/lib/checkstl.cpp index 6c4e5a7a22c..6d97dffe3d2 100644 --- a/lib/checkstl.cpp +++ b/lib/checkstl.cpp @@ -549,7 +549,7 @@ void CheckStlImpl::iterators() } // Not different containers if a reference is used.. - if (containerToken && containerToken->variable() && containerToken->variable()->isReference()) { + if (containerToken->variable() && containerToken->variable()->isReference()) { const Token *nameToken = containerToken->variable()->nameToken(); if (Token::Match(nameToken, "%name% =")) { const Token *name1 = nameToken->tokAt(2); diff --git a/lib/forwardanalyzer.cpp b/lib/forwardanalyzer.cpp index 0999a08d908..670db0b1090 100644 --- a/lib/forwardanalyzer.cpp +++ b/lib/forwardanalyzer.cpp @@ -782,7 +782,7 @@ namespace { } else if (thenBranch.check) { return Break(); } else { - if (analyzer->isConditional() && stopUpdates()) + if (stopOnCondition(condTok) && stopUpdates()) return Break(Analyzer::Terminate::Conditional); analyzer->assume(condTok, false); } diff --git a/lib/reverseanalyzer.cpp b/lib/reverseanalyzer.cpp index 38aea656bf0..0c3c966f2b2 100644 --- a/lib/reverseanalyzer.cpp +++ b/lib/reverseanalyzer.cpp @@ -340,9 +340,6 @@ namespace { valueFlowGenericForward(condTok, analyzer, tokenlist, errorLogger, settings); else if (condAction.isRead()) break; - // If the condition modifies the variable then bail - if (condAction.isModified()) - break; tok = jumpToStart(tok->link()); continue; } diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index 14fc1b7cdf2..231a8ce009c 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -1043,10 +1043,8 @@ void SymbolDatabase::createSymbolDatabaseNeedInitialization() scope.definedType->needInitialization = Type::NeedInitialization::True; else if (!unknown) scope.definedType->needInitialization = Type::NeedInitialization::False; - else { - if (scope.definedType->needInitialization == Type::NeedInitialization::Unknown) - unknowns++; - } + else + unknowns++; } } else if (scope.type == ScopeType::eUnion && scope.definedType->needInitialization == Type::NeedInitialization::Unknown) scope.definedType->needInitialization = Type::NeedInitialization::True; diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index a8f675bbc97..7379957804f 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -2711,7 +2711,7 @@ namespace { { Token *tok1 = tok; - if (tok1 && tok1->str() != nameToken->str()) + if (!tok1 || tok1->str() != nameToken->str()) return false; // skip this using diff --git a/lib/vf_analyzers.cpp b/lib/vf_analyzers.cpp index a50a3b1d4a4..10efc6d6f39 100644 --- a/lib/vf_analyzers.cpp +++ b/lib/vf_analyzers.cpp @@ -1198,18 +1198,40 @@ struct SingleValueFlowAnalyzer : ValueFlowAnalyzer { bool stopOnCondition(const Token* condTok) const override { - if (value.isNonValue()) - return false; if (value.isImpossible()) return false; - if (isConditional() && !value.isKnown()) + // lifetime values must keep flowing to properly track aliases + if (value.isLifetimeValue()) + return false; + // 'conditional' flag (uninit, or lowered after a modifying branch): may depend on a + // condition that doesn't mention the variable -> stop + if (value.conditional && !value.isKnown()) return true; - if (value.isSymbolicValue()) + if (value.isNonValue()) return false; + if (value.isSymbolicValue()) + return isConditional() && !value.isKnown(); + // conditional via the originating 'condition' (e.g. possible null after 'if (p && ...)'): only flow + // if the condition references the value, else a correlation we can't follow (e.g. + // 'bool ok = (p != nullptr); if (!ok)') could make a later deref safe -> stop + if (value.condition && !value.isKnown() && !conditionReferencesValue(condTok)) + return true; ConditionState cs = analyzeCondition(condTok); return cs.isUnknownDependent(); } + // Does the condition mention the tracked value, either directly or through a symbolic alias? + bool conditionReferencesValue(const Token* condTok) const + { + return findAstNode(condTok, [&](const Token* tok) { + if (match(tok)) + return true; + return std::any_of(tok->values().cbegin(), tok->values().cend(), [&](const ValueFlow::Value& v) { + return v.isSymbolicValue() && !v.isImpossible() && v.tokvalue && match(v.tokvalue); + }); + }) != nullptr; + } + bool updateScope(const Token* endBlock, bool /*modified*/) const override { const Scope* scope = endBlock->scope(); if (!scope) diff --git a/test/testnullpointer.cpp b/test/testnullpointer.cpp index 99ece1c57fc..369c04a2101 100644 --- a/test/testnullpointer.cpp +++ b/test/testnullpointer.cpp @@ -143,6 +143,8 @@ class TestNullPointer : public TestFixture { TEST_CASE(nullpointer103); TEST_CASE(nullpointer104); // #13881 TEST_CASE(nullpointer105); // #13861 + TEST_CASE(nullpointer106); // #13682 + TEST_CASE(nullpointer107); // #13682 (FP/FN cases around guards that depend on the pointer indirectly) TEST_CASE(nullpointer_addressOf); // address of TEST_CASE(nullpointerSwitch); // #2626 TEST_CASE(nullpointer_cast); // #4692 @@ -2966,6 +2968,138 @@ class TestNullPointer : public TestFixture { ASSERT_EQUALS("", errout_str()); } + void nullpointer106() // #13682 + { + // An unrelated condition between the null check and the dereference must not stop the analysis + check("struct S {\n" + " bool b;\n" + " bool f() const;\n" + "};\n" + "void f(const S* p, const S* o) {\n" + " const S* p1 = p;\n" + " if (p1 && p1->f())\n" + " return;\n" + " if (p == o)\n" + " return;\n" + " if (p1->b) {}\n" + "}\n"); + ASSERT_EQUALS( + "[test.cpp:7:9] -> [test.cpp:11:9]: (warning) Either the condition 'p1' is redundant or there is possible null pointer dereference: p1. [nullPointerRedundantCheck]\n", + errout_str()); + } + + void nullpointer107() // #13682 - guards that depend on the pointer indirectly + { + // cached null-check 'ok'; guard 'if (!ok)' is safe -> no FP + check("struct S { void g(); bool f() const; };\n" + "void f(S* p) {\n" + " bool ok = (p != nullptr);\n" + " if (p && p->f())\n" + " return;\n" + " if (!ok)\n" + " return;\n" + " p->g();\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + + // unrelated bool guard -> conservative, no FP + check("struct S { void g(); bool f() const; };\n" + "void f(S* p, bool valid) {\n" + " S* p1 = p;\n" + " if (p1 && p1->f())\n" + " return;\n" + " if (!valid)\n" + " return;\n" + " p1->g();\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + + // guard on a different pointer -> no FP + check("struct S { void g(); bool f() const; };\n" + "void f(S* p, S* q) {\n" + " S* p1 = p;\n" + " if (p1 && p1->f())\n" + " return;\n" + " if (!q)\n" + " return;\n" + " p1->g();\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + + // direct null guard on the alias -> no FP + check("struct S { void g(); bool f() const; };\n" + "void f(S* p) {\n" + " S* p1 = p;\n" + " if (p1 && p1->f())\n" + " return;\n" + " if (!p)\n" + " return;\n" + " p1->g();\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + + // FN: 'if (ok)' => survivor has p==nullptr, but the cached 'ok' is not followed -> should warn + check("struct S { void g(); bool f() const; };\n" + "void f(S* p) {\n" + " bool ok = (p != nullptr);\n" + " if (p && p->f())\n" + " return;\n" + " if (ok)\n" + " return;\n" + " p->g();\n" + "}\n"); + TODO_ASSERT_EQUALS( + "[test.cpp:4:9] -> [test.cpp:8:5]: (warning) Either the condition 'p' is redundant or there is possible null pointer dereference: p. [nullPointerRedundantCheck]\n", + "", + errout_str()); + + // FN: sink(q) drops the q==p symbolic, so guard 'if (q)' is no longer seen to relate to p -> should warn + check("struct S { void g(); bool f() const; };\n" + "void sink(S*&);\n" + "void f(S* p) {\n" + " S* q = p;\n" + " if (p && p->f())\n" + " return;\n" + " sink(q);\n" + " if (q)\n" + " return;\n" + " p->g();\n" + "}\n"); + TODO_ASSERT_EQUALS( + "[test.cpp:5:9] -> [test.cpp:10:5]: (warning) Either the condition 'p' is redundant or there is possible null pointer dereference: p. [nullPointerRedundantCheck]\n", + "", + errout_str()); + + // a conditional modification makes ProgramMemory drop the guard (FP-prone) -> must stay quiet: + // alias 'q==p' re-assigned to p under a condition + check("struct S { void g(); bool f() const; };\n" + "void f(S* p, bool c) {\n" + " S* q = p;\n" + " if (p && p->f())\n" + " return;\n" + " if (c)\n" + " q = p;\n" + " if (!q)\n" + " return;\n" + " p->g();\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + + // cached 'ok' refreshed under a condition + check("struct S { void g(); bool f() const; };\n" + "void f(S* p, bool c) {\n" + " bool ok = (p != nullptr);\n" + " if (p && p->f())\n" + " return;\n" + " if (c)\n" + " ok = (p != nullptr);\n" + " if (!ok)\n" + " return;\n" + " p->g();\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + } + void nullpointer_addressOf() { // address of check("void f() {\n" " struct X *x = 0;\n" From d8eaa524f24c9269bab520ad187decdc6a58c5a9 Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Thu, 25 Jun 2026 13:15:49 +0200 Subject: [PATCH 050/165] Fix #13678 FN constParameterPointer (calling const function on struct member) (#8624) --- lib/checkother.cpp | 13 ++++++++----- lib/checkunusedvar.cpp | 4 ++-- test/testother.cpp | 12 ++++++++++++ 3 files changed, 22 insertions(+), 7 deletions(-) diff --git a/lib/checkother.cpp b/lib/checkother.cpp index 5ed3473c8a7..21657cfd9fd 100644 --- a/lib/checkother.cpp +++ b/lib/checkother.cpp @@ -1945,13 +1945,16 @@ void CheckOtherImpl::checkConstPointer() if (deref == MEMBER) { if (!gparent) continue; - if (parent->astOperand2()) { - if (parent->astOperand2()->function() && parent->astOperand2()->function()->isConst()) + const Token* funcParent = parent; + while (Token::simpleMatch(funcParent->astParent(), ".")) + funcParent = funcParent->astParent(); + if (funcParent->astOperand2()) { + if (funcParent->astOperand2()->function() && funcParent->astOperand2()->function()->isConst()) continue; - if (mSettings.library.isFunctionConst(parent->astOperand2())) + if (mSettings.library.isFunctionConst(funcParent->astOperand2())) continue; - if (parent->astOperand2()->varId()) { - if (gparent->str() == "?" && astIsLHS(parent)) + if (funcParent->astOperand2()->varId()) { + if (gparent->str() == "?" && astIsLHS(funcParent)) continue; } } diff --git a/lib/checkunusedvar.cpp b/lib/checkunusedvar.cpp index 8ed249f05e2..fe85260fc8d 100644 --- a/lib/checkunusedvar.cpp +++ b/lib/checkunusedvar.cpp @@ -249,7 +249,7 @@ void Variables::clearAliases(nonneg int varid) void Variables::eraseAliases(nonneg int varid) { - VariableUsage *usage = find(varid); + const VariableUsage *usage = find(varid); if (usage) { for (auto aliases = usage->_aliases.cbegin(); aliases != usage->_aliases.cend(); ++aliases) @@ -329,7 +329,7 @@ void Variables::write(nonneg int varid, const Token* tok) void Variables::writeAliases(nonneg int varid, const Token* tok) { - VariableUsage *usage = find(varid); + const VariableUsage *usage = find(varid); if (usage) { for (auto aliases = usage->_aliases.cbegin(); aliases != usage->_aliases.cend(); ++aliases) { diff --git a/test/testother.cpp b/test/testother.cpp index 1d69cf6763e..b8134623a37 100644 --- a/test/testother.cpp +++ b/test/testother.cpp @@ -4894,6 +4894,18 @@ class TestOther : public TestFixture { "}\n"); ASSERT_EQUALS("[test.cpp:6:10]: (style) Parameter 's' can be declared as reference to const [constParameterReference]\n", errout_str()); + + check("struct S { std::string a; };\n" // #13678 + "struct T { S s; };\n" + "bool f(S* s) {\n" + " return s->a.empty();\n" + "}\n" + "bool g(T* t) {\n" + " return t->s.a.empty();\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:3:11]: (style) Parameter 's' can be declared as pointer to const [constParameterPointer]\n" + "[test.cpp:6:11]: (style) Parameter 't' can be declared as pointer to const [constParameterPointer]\n", + errout_str()); } void constArray() { From b37e6b85e5b1655a6b379d0f76446fd940be4371 Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Thu, 25 Jun 2026 16:49:13 +0200 Subject: [PATCH 051/165] Add test for #13099 (#8674) --- test/testother.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/testother.cpp b/test/testother.cpp index b8134623a37..60323b3395b 100644 --- a/test/testother.cpp +++ b/test/testother.cpp @@ -4906,6 +4906,14 @@ class TestOther : public TestFixture { ASSERT_EQUALS("[test.cpp:3:11]: (style) Parameter 's' can be declared as pointer to const [constParameterPointer]\n" "[test.cpp:6:11]: (style) Parameter 't' can be declared as pointer to const [constParameterPointer]\n", errout_str()); + + check("struct S { int i; };\n" // #13099 + "double f(S * s, int n, int a, int b, double* p) {\n" + " return (s + (n * (a + 1) + b))->i / *(p + b);\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:2:14]: (style) Parameter 's' can be declared as pointer to const [constParameterPointer]\n" + "[test.cpp:2:46]: (style) Parameter 'p' can be declared as pointer to const [constParameterPointer]\n", + errout_str()); } void constArray() { From 86f4c91741690386cd5917ccd8120624d9473ad5 Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Fri, 26 Jun 2026 08:32:09 +0200 Subject: [PATCH 052/165] Fix #14864 FN knownConditionTrueFalse with default initialized user type pointer (#8672) --- lib/valueflow.cpp | 2 ++ test/testvalueflow.cpp | 12 ++++++++++++ 2 files changed, 14 insertions(+) diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index 9ff54a5c244..f934d8496d6 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -4099,6 +4099,8 @@ static bool isVariableInit(const Token *tok) return false; if (var->nameToken() != tok->astOperand1()) return false; + if (var->isPointer()) + return true; const ValueType* vt = var->valueType(); if (!vt) return false; diff --git a/test/testvalueflow.cpp b/test/testvalueflow.cpp index 8305a63bc56..7fa28855eb1 100644 --- a/test/testvalueflow.cpp +++ b/test/testvalueflow.cpp @@ -3188,6 +3188,18 @@ class TestValueFlow : public TestFixture { " return x;\n" "}\n"; ASSERT_EQUALS(true, testValueOfXKnown(code, 3U, -1)); + + code = "A* f() {\n" // #14864 + " A* x{};\n" + " return x;\n" + "}\n"; + ASSERT_EQUALS(true, testValueOfXKnown(code, 3U, 0)); + + code = "A* f() {\n" + " A* x{ nullptr };\n" + " return x;\n" + "}\n"; + ASSERT_EQUALS(true, testValueOfXKnown(code, 3U, 0)); } void valueFlowAfterSwap() From 7d5a54cc6e62c86fc38ae57e1834f45cce9709a3 Mon Sep 17 00:00:00 2001 From: Gilmar Santos Jr Date: Tue, 30 Jun 2026 13:30:12 -0300 Subject: [PATCH 053/165] Fix #14877: heap-use-after-free in Tokenizer::simplifyUsing() (#8679) In a large codebase, constructs like `using C = struct C { C() {} };` lead to errors such as `Code.cpp:0:0: error: Bailing out from analysis: Checking file failed: out of memory [internalError]`. When compiling cppcheck using clang 22's address sanitizer, the analysis terminates with the following messages: ``` ================================================================= ==1390963==ERROR: AddressSanitizer: heap-use-after-free on address 0x7c985f8ff900 at pc 0x55dcbe530972 bp 0x7ffd79cf5010 sp 0x7ffd79cf5008 READ of size 8 at 0x7c985f8ff900 thread T0 #0 0x55dcbe530971 in std::__cxx11::basic_string, std::allocator>::size() const /usr/include/c++/bits/basic_string.h:1165:19 #1 0x55dcbe53c624 in std::__cxx11::basic_string, std::allocator>::length() const /usr/include/c++/bits/basic_string.h:1176:16 #2 0x55dcbe54f8d6 in std::__cxx11::basic_string, std::allocator>::_M_assign(std::__cxx11::basic_string, std::allocator> const&) /usr/include/c++/bits/basic_string.tcc:313:36 #3 0x55dcbe54f7f0 in std::__cxx11::basic_string, std::allocator>::assign(std::__cxx11::basic_string, std::allocator> const&) /usr/include/c++/bits/basic_string.h:1771:8 #4 0x55dcbe54f7bc in std::__cxx11::basic_string, std::allocator>::operator=(std::__cxx11::basic_string, std::allocator> const&) /usr/include/c++/bits/basic_string.h:906:15 #5 0x55dcbe635d19 in Tokenizer::simplifyUsing() ./src/cppcheck/lib/tokenize.cpp:3214:32 #6 0x55dcbe6470b3 in Tokenizer::simplifyTokenList1(char const*) ./src/cppcheck/lib/tokenize.cpp:5910:12 #7 0x55dcbe643cb8 in Tokenizer::simplifyTokens1(std::__cxx11::basic_string, std::allocator> const&, int) ./src/cppcheck/lib/tokenize.cpp:3527:14 #8 0x55dcbedb37e7 in CppCheck::checkInternal(FileWithDetails const&, std::__cxx11::basic_string, std::allocator> const&, std::function, std::allocator>, std::allocator, std::allocator>>>&, std::__cxx11::list>*)> const&) ./src/cppcheck/lib/cppcheck.cpp:1203:32 #9 0x55dcbeda7bf4 in CppCheck::checkFile(FileWithDetails const&, std::__cxx11::basic_string, std::allocator> const&) ./src/cppcheck/lib/cppcheck.cpp:898:12 #10 0x55dcbeda7862 in CppCheck::check(FileWithDetails const&) ./src/cppcheck/lib/cppcheck.cpp:802:23 #11 0x55dcbf294ce0 in SingleExecutor::check() ./src/cppcheck/cli/singleexecutor.cpp:52:29 #12 0x55dcbf23cf66 in CppCheckExecutor::check_internal(Settings const&, Suppressions&) const ./src/cppcheck/cli/cppcheckexecutor.cpp:453:32 #13 0x55dcbf23c4fc in CppCheckExecutor::check_wrapper(Settings const&, Suppressions&) ./src/cppcheck/cli/cppcheckexecutor.cpp:295:12 #14 0x55dcbf23c1af in CppCheckExecutor::check(int, char const* const*) ./src/cppcheck/cli/cppcheckexecutor.cpp:280:21 #15 0x55dcbf23b67d in main ./src/cppcheck/cli/main.cpp:71:17 #16 0x7fe8606517e4 in __libc_start_main (/lib64/libc.so.6+0x3a7e4) (BuildId: b81415c1738806b536fb1599d7af2d15bf6a86b7) #17 0x55dcbe317bed in _start (./src/cppcheck/build/bin/cppcheck+0x4bbbed) 0x7c985f8ff900 is located 32 bytes inside of 112-byte region [0x7c985f8ff8e0,0x7c985f8ff950) freed by thread T0 here: #0 0x55dcbe4642ba in operator delete(void*) /usr/local/src/conda/compiler-rt-packages-22.1.8/compiler-rt/lib/asan/asan_new_delete.cpp:177:44 #1 0x55dcbf144bd0 in Token::deleteNext(int) ./src/cppcheck/lib/token.cpp:281:9 #2 0x55dcbf145e2d in Token::deleteThis() ./src/cppcheck/lib/token.cpp:360:9 #3 0x55dcbe634c84 in Tokenizer::simplifyUsing() ./src/cppcheck/lib/tokenize.cpp:3086:18 #4 0x55dcbe6470b3 in Tokenizer::simplifyTokenList1(char const*) ./src/cppcheck/lib/tokenize.cpp:5910:12 #5 0x55dcbe643cb8 in Tokenizer::simplifyTokens1(std::__cxx11::basic_string, std::allocator> const&, int) ./src/cppcheck/lib/tokenize.cpp:3527:14 #6 0x55dcbedb37e7 in CppCheck::checkInternal(FileWithDetails const&, std::__cxx11::basic_string, std::allocator> const&, std::function, std::allocator>, std::allocator, std::allocator>>>&, std::__cxx11::list>*)> const&) ./src/cppcheck/lib/cppcheck.cpp:1203:32 #7 0x55dcbeda7bf4 in CppCheck::checkFile(FileWithDetails const&, std::__cxx11::basic_string, std::allocator> const&) ./src/cppcheck/lib/cppcheck.cpp:898:12 #8 0x55dcbeda7862 in CppCheck::check(FileWithDetails const&) ./src/cppcheck/lib/cppcheck.cpp:802:23 #9 0x55dcbf294ce0 in SingleExecutor::check() ./src/cppcheck/cli/singleexecutor.cpp:52:29 #10 0x55dcbf23cf66 in CppCheckExecutor::check_internal(Settings const&, Suppressions&) const ./src/cppcheck/cli/cppcheckexecutor.cpp:453:32 #11 0x55dcbf23c4fc in CppCheckExecutor::check_wrapper(Settings const&, Suppressions&) ./src/cppcheck/cli/cppcheckexecutor.cpp:295:12 #12 0x55dcbf23c1af in CppCheckExecutor::check(int, char const* const*) ./src/cppcheck/cli/cppcheckexecutor.cpp:280:21 #13 0x55dcbf23b67d in main ./src/cppcheck/cli/main.cpp:71:17 #14 0x7fe8606517e4 in __libc_start_main (/lib64/libc.so.6+0x3a7e4) (BuildId: b81415c1738806b536fb1599d7af2d15bf6a86b7) previously allocated by thread T0 here: #0 0x55dcbe4638aa in operator new(unsigned long) /usr/local/src/conda/compiler-rt-packages-22.1.8/compiler-rt/lib/asan/asan_new_delete.cpp:109:35 #1 0x55dcbf14fb4a in Token::insertToken(std::__cxx11::basic_string, std::allocator> const&, bool) ./src/cppcheck/lib/token.cpp:1069:20 #2 0x55dcbe758b2e in Token::insertToken(std::__cxx11::basic_string, std::allocator> const&) ./src/cppcheck/lib/token.h:991:16 #3 0x55dcbf18de6e in TokenList::createTokens(simplecpp::TokenList&&) ./src/cppcheck/lib/tokenlist.cpp:392:37 #4 0x55dcbedc8c03 in CppCheck::checkInternal(FileWithDetails const&, std::__cxx11::basic_string, std::allocator> const&, std::function, std::allocator>, std::allocator, std::allocator>>>&, std::__cxx11::list>*)> const&)::$_2::operator()() const ./src/cppcheck/lib/cppcheck.cpp:1157:35 #5 0x55dcbedb9322 in void Timer::run, std::allocator> const&, std::function, std::allocator>, std::allocator, std::allocator>>>&, std::__cxx11::list>*)> const&)::$_2>(std::__cxx11::basic_string, std::allocator>, TimerResultsIntf*, CppCheck::checkInternal(FileWithDetails const&, std::__cxx11::basic_string, std::allocator> const&, std::function, std::allocator>, std::allocator, std::allocator>>>&, std::__cxx11::list>*)> const&)::$_2 const&) ./src/cppcheck/lib/timer.h:77:9 #6 0x55dcbedb2f65 in CppCheck::checkInternal(FileWithDetails const&, std::__cxx11::basic_string, std::allocator> const&, std::function, std::allocator>, std::allocator, std::allocator>>>&, std::__cxx11::list>*)> const&) ./src/cppcheck/lib/cppcheck.cpp:1152:17 #7 0x55dcbeda7bf4 in CppCheck::checkFile(FileWithDetails const&, std::__cxx11::basic_string, std::allocator> const&) ./src/cppcheck/lib/cppcheck.cpp:898:12 #8 0x55dcbeda7862 in CppCheck::check(FileWithDetails const&) ./src/cppcheck/lib/cppcheck.cpp:802:23 #9 0x55dcbf294ce0 in SingleExecutor::check() ./src/cppcheck/cli/singleexecutor.cpp:52:29 #10 0x55dcbf23cf66 in CppCheckExecutor::check_internal(Settings const&, Suppressions&) const ./src/cppcheck/cli/cppcheckexecutor.cpp:453:32 #11 0x55dcbf23c4fc in CppCheckExecutor::check_wrapper(Settings const&, Suppressions&) ./src/cppcheck/cli/cppcheckexecutor.cpp:295:12 #12 0x55dcbf23c1af in CppCheckExecutor::check(int, char const* const*) ./src/cppcheck/cli/cppcheckexecutor.cpp:280:21 #13 0x55dcbf23b67d in main ./src/cppcheck/cli/main.cpp:71:17 #14 0x7fe8606517e4 in __libc_start_main (/lib64/libc.so.6+0x3a7e4) (BuildId: b81415c1738806b536fb1599d7af2d15bf6a86b7) SUMMARY: AddressSanitizer: heap-use-after-free ./src/cppcheck/lib/tokenize.cpp:3214:32 in Tokenizer::simplifyUsing() Shadow bytes around the buggy address: 0x7c985f8ff680: fd fa fa fa fa fa fa fa fa fa fd fd fd fd fd fd 0x7c985f8ff700: fd fd fd fd fd fd fd fa fa fa fa fa fa fa fa fa 0x7c985f8ff780: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 fa fa 0x7c985f8ff800: fa fa fa fa fa fa 00 00 00 00 00 00 00 00 00 00 0x7c985f8ff880: 00 00 00 fa fa fa fa fa fa fa fa fa fd fd fd fd =>0x7c985f8ff900:[fd]fd fd fd fd fd fd fd fd fd fa fa fa fa fa fa 0x7c985f8ff980: fa fa fd fd fd fd fd fd fd fd fd fd fd fd fd fd 0x7c985f8ffa00: fa fa fa fa fa fa fa fa fd fd fd fd fd fd fd fd 0x7c985f8ffa80: fd fd fd fd fd fd fa fa fa fa fa fa fa fa 00 00 0x7c985f8ffb00: 00 00 00 00 00 00 00 00 00 00 00 00 fa fa fa fa 0x7c985f8ffb80: fa fa fa fa 00 00 00 00 00 00 00 00 00 00 00 00 Shadow byte legend (one shadow byte represents 8 application bytes): Addressable: 00 Partially addressable: 01 02 03 04 05 06 07 Heap left redzone: fa Freed heap region: fd Stack left redzone: f1 Stack mid redzone: f2 Stack right redzone: f3 Stack after return: f5 Stack use after scope: f8 Global redzone: f9 Global init order: f6 Poisoned by user: f7 Container overflow: fc Array cookie: ac Intra object redzone: bb ASan internal: fe Left alloca redzone: ca Right alloca redzone: cb ==1390963==ABORTING ``` The proposed fix avoids storing a reference to a memory area that will eventually be deallocated before the reference is used. --- AUTHORS | 1 + lib/tokenize.cpp | 5 ++--- test/testsimplifyusing.cpp | 7 +++++++ 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/AUTHORS b/AUTHORS index b505b682708..19cbe734d2e 100644 --- a/AUTHORS +++ b/AUTHORS @@ -156,6 +156,7 @@ Gerhard Zlabinger Gerik Rhoden Gianfranco Costamagna Gianluca Scacco +Gilmar Santos Jr Gleydson Soares Goncalo Mao-Cheia Goran Džaferi diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 7379957804f..2d248f2cbd2 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -3015,7 +3015,6 @@ bool Tokenizer::simplifyUsing() Token::Match(tok->linkAt(2), "] ] = ::| %name%"))))) continue; - const std::string& name = tok->strAt(1); const Token *nameToken = tok->next(); std::string scope = currentScope->fullName; Token *usingStart = tok; @@ -3064,7 +3063,7 @@ bool Tokenizer::simplifyUsing() if (!hasName) { std::string newName; if (structEnd->strAt(2) == ";") - newName = name; + newName = nameToken->str(); else newName = "Unnamed" + std::to_string(mUnnamedCount++); TokenList::copyTokens(structEnd->next(), tok, start); @@ -3211,7 +3210,7 @@ bool Tokenizer::simplifyUsing() if (!isTypedefInfoAdded && Token::Match(tok1, "%name% (")) { isTypedefInfoAdded = true; TypedefInfo usingInfo; - usingInfo.name = name; + usingInfo.name = nameToken->str(); usingInfo.filename = list.file(nameToken); usingInfo.lineNumber = nameToken->linenr(); usingInfo.column = nameToken->column(); diff --git a/test/testsimplifyusing.cpp b/test/testsimplifyusing.cpp index 7359613510f..0d09fa37b12 100644 --- a/test/testsimplifyusing.cpp +++ b/test/testsimplifyusing.cpp @@ -98,6 +98,7 @@ class TestSimplifyUsing : public TestFixture { TEST_CASE(simplifyUsing10335); TEST_CASE(simplifyUsing10720); TEST_CASE(simplifyUsing13873); // function declaration + TEST_CASE(simplifyUsing14877); TEST_CASE(scopeInfo1); TEST_CASE(scopeInfo2); @@ -1667,6 +1668,12 @@ class TestSimplifyUsing : public TestFixture { ASSERT_EQUALS("namespace NS1 { void * f ( ) ; }", tok(code3)); } + void simplifyUsing14877() { + const char code[] = "using C = struct C { C() {} };"; + const char expected[] = "struct C { C ( ) { } } ;"; + ASSERT_EQUALS(expected, tok(code)); + } + void scopeInfo1() { const char code[] = "struct A {\n" " enum class Mode { UNKNOWN, ENABLED, NONE, };\n" From 7d0d721d489d0380ce5aefd67f3e64f5af8d9e2a Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Wed, 1 Jul 2026 08:25:30 +0200 Subject: [PATCH 054/165] Fix #14876 Nullptr dereference in usingMatch() (#8678) Root cause is here: https://github.com/cppcheck-opensource/cppcheck/blob/86f4c91741690386cd5917ccd8120624d9473ad5/lib/tokenize.cpp#L3108 Co-authored-by: chrchr-github --- lib/tokenize.cpp | 3 +++ test/testsimplifyusing.cpp | 8 ++++++++ 2 files changed, 11 insertions(+) diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 2d248f2cbd2..b29e807b8b5 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -2720,6 +2720,9 @@ namespace { return false; } + if (!tok->tokAt(-1)) + return false; + // skip other using with this name if (tok1->strAt(-1) == "using") { // fixme: this is wrong diff --git a/test/testsimplifyusing.cpp b/test/testsimplifyusing.cpp index 0d09fa37b12..160f80762a8 100644 --- a/test/testsimplifyusing.cpp +++ b/test/testsimplifyusing.cpp @@ -77,6 +77,7 @@ class TestSimplifyUsing : public TestFixture { TEST_CASE(simplifyUsing37); TEST_CASE(simplifyUsing38); TEST_CASE(simplifyUsing39); + TEST_CASE(simplifyUsing40); TEST_CASE(simplifyUsing8970); TEST_CASE(simplifyUsing8971); @@ -940,6 +941,13 @@ class TestSimplifyUsing : public TestFixture { ASSERT_EQUALS("", errout_str()); } + void simplifyUsing40() { + const char code[] = "uint8_t f();\n" // #14876 + "using ::std::uint8_t;"; + const char expected[] = "uint8_t f ( ) ;"; + ASSERT_EQUALS(expected, tok(code)); + } + void simplifyUsing8970() { const char code[] = "using V = std::vector;\n" "struct A {\n" From 186a7a9eeccc2968d9730aa0b5bc2d189b9b953d Mon Sep 17 00:00:00 2001 From: William Jakobsson <50847546+wjakobsson@users.noreply.github.com> Date: Wed, 1 Jul 2026 15:01:54 +0200 Subject: [PATCH 055/165] Fix --premium-license CLI parsing problem with space in path (#8683) --- cli/cmdlineparser.cpp | 5 ++++- test/testcmdlineparser.cpp | 9 +++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/cli/cmdlineparser.cpp b/cli/cmdlineparser.cpp index 1ad0863d96d..f2d2254f833 100644 --- a/cli/cmdlineparser.cpp +++ b/cli/cmdlineparser.cpp @@ -1159,7 +1159,10 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a if (!parseNumberArg(argv[i], 31, tmp, true)) return Result::Fail; } - mSettings.premiumArgs += "--" + p; + if (p.find(' ') != std::string::npos) + mSettings.premiumArgs += "\"--" + p + "\""; + else + mSettings.premiumArgs += "--" + p; if (isCodingStandard) { // All checkers related to the coding standard should be enabled. The coding standards // do not all undefined behavior or portability issues. diff --git a/test/testcmdlineparser.cpp b/test/testcmdlineparser.cpp index 3b88e050f82..326b7ad613d 100644 --- a/test/testcmdlineparser.cpp +++ b/test/testcmdlineparser.cpp @@ -262,6 +262,7 @@ class TestCmdlineParser : public TestFixture { TEST_CASE(premiumOptionsMetrics); TEST_CASE(premiumOptionsCertCIntPrecision); TEST_CASE(premiumOptionsLicenseFile); + TEST_CASE(premiumOptionsLicenseFilePathWithSpace); TEST_CASE(premiumOptionsInvalid1); TEST_CASE(premiumOptionsInvalid2); TEST_CASE(premiumSafety); @@ -1642,6 +1643,14 @@ class TestCmdlineParser : public TestFixture { ASSERT_EQUALS("--license-file=file.lic", settings->premiumArgs); } + void premiumOptionsLicenseFilePathWithSpace() { + REDIRECT; + asPremium(); + const char * const argv[] = {"cppcheck", "--premium-license-file=license folder/file.lic", "file.c"}; + ASSERT_EQUALS_ENUM(CmdLineParser::Result::Success, parseFromArgs(argv)); + ASSERT_EQUALS("\"--license-file=license folder/file.lic\"", settings->premiumArgs); + } + void premiumOptionsInvalid1() { REDIRECT; asPremium(); From 47d4f68f5e9a1c2c86f48f9f06b430233cb9476f Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Wed, 1 Jul 2026 22:21:59 +0200 Subject: [PATCH 056/165] Fix #12428 FN objectIndex when accessing struct member (#8676) --- lib/checkbufferoverrun.cpp | 6 ++++-- test/testbufferoverrun.cpp | 4 +++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/lib/checkbufferoverrun.cpp b/lib/checkbufferoverrun.cpp index a98ba73429c..496ca6905a1 100644 --- a/lib/checkbufferoverrun.cpp +++ b/lib/checkbufferoverrun.cpp @@ -1086,9 +1086,11 @@ void CheckBufferOverrunImpl::objectIndex() std::vector values = ValueFlow::getLifetimeObjValues(obj, false, -1); for (const ValueFlow::Value& v:values) { - if (v.lifetimeKind != ValueFlow::Value::LifetimeKind::Address) + if (v.lifetimeKind != ValueFlow::Value::LifetimeKind::Address && v.lifetimeKind != ValueFlow::Value::LifetimeKind::Object) continue; - const Variable *var = v.tokvalue->variable(); + const Token* varTok = nextAfterAstRightmostLeaf(v.tokvalue->astParent()); + varTok = varTok ? varTok->previous() : nullptr; + const Variable *var = varTok ? varTok->variable() : nullptr; if (!var) continue; if (var->isReference()) diff --git a/test/testbufferoverrun.cpp b/test/testbufferoverrun.cpp index e1da77ccbfb..e51a1708389 100644 --- a/test/testbufferoverrun.cpp +++ b/test/testbufferoverrun.cpp @@ -5857,7 +5857,9 @@ class TestBufferOverrun : public TestFixture { " (void)y[1];\n" " (void)y[2];\n" "}\n"); - TODO_ASSERT_EQUALS("error", "", errout_str()); + ASSERT_EQUALS("[test.cpp:7:20] -> [test.cpp:9:12]: (error) The address of variable 's.a' is accessed at non-zero index. [objectIndex]\n" + "[test.cpp:7:20] -> [test.cpp:10:12]: (error) The address of variable 's.a' is accessed at non-zero index. [objectIndex]\n", + errout_str()); } void checkPipeParameterSize() { // #3521 From 56a055d5ab0d28a47f65bd14893f8155f2735fa4 Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Wed, 1 Jul 2026 22:26:45 +0200 Subject: [PATCH 057/165] Refs #14859: Fix sizeof calculation for std::array (#8671) Co-authored-by: chrchr-github --- lib/symboldatabase.cpp | 14 +++++++++----- lib/vf_common.cpp | 10 ++++++++-- test/testvalueflow.cpp | 14 ++++++++++++++ 3 files changed, 31 insertions(+), 7 deletions(-) diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index 231a8ce009c..bbf6cc8ce52 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -8476,7 +8476,7 @@ namespace { } template -static Result accumulateStructMembers(const Scope* scope, F f, ValueType::Accuracy accuracy) +static Result accumulateStructMembers(const Scope* scope, F f, ValueType::Accuracy accuracy, const Settings& settings) { size_t total = 0; std::set anonScopes; @@ -8495,6 +8495,10 @@ static Result accumulateStructMembers(const Scope* scope, F f, ValueType::Accura if (ret.second) total = f(total, *vt, dim, bits); } + else if (vt->container && vt->container->startPattern == "std :: array <") { + const ValueType vtElement = ValueType::parseDecl(vt->containerTypeToken, settings); + total = f(total, vtElement, dim, bits); + } else total = f(total, *vt, dim, bits); } @@ -8534,12 +8538,12 @@ static size_t getAlignOf(const ValueType& vt, const Settings& settings, ValueTyp size_t a = getAlignOf(vt2, settings, accuracy, ValueType::SizeOf::Pointer, ++maxRecursion); return std::max(max, a); }; - Result result = accumulateStructMembers(vt.typeScope, accHelper, accuracy); + Result result = accumulateStructMembers(vt.typeScope, accHelper, accuracy, settings); size_t total = result.total; if (const Type* dt = vt.typeScope->definedType) { total = std::accumulate(dt->derivedFrom.begin(), dt->derivedFrom.end(), total, [&](size_t v, const Type::BaseInfo& bi) { if (bi.type && bi.type->classScope) - v += accumulateStructMembers(bi.type->classScope, accHelper, accuracy).total; + v += accumulateStructMembers(bi.type->classScope, accHelper, accuracy, settings).total; return v; }); } @@ -8627,14 +8631,14 @@ size_t ValueType::getSizeOf( const Settings& settings, Accuracy accuracy, SizeOf } return typeScope->type == ScopeType::eUnion ? std::max(total, n) : total + padding + n; }; - Result result = accumulateStructMembers(typeScope, accHelper, accuracy); + Result result = accumulateStructMembers(typeScope, accHelper, accuracy, settings); size_t total = result.total; if (currentBitCount > 0) total += currentBitfieldAlloc; if (const ::Type* dt = typeScope->definedType) { total = std::accumulate(dt->derivedFrom.begin(), dt->derivedFrom.end(), total, [&](size_t v, const ::Type::BaseInfo& bi) { if (bi.type && bi.type->classScope) - v += accumulateStructMembers(bi.type->classScope, accHelper, accuracy).total; + v += accumulateStructMembers(bi.type->classScope, accHelper, accuracy, settings).total; return v; }); } diff --git a/lib/vf_common.cpp b/lib/vf_common.cpp index 56f928bcbd8..b4bd756d05e 100644 --- a/lib/vf_common.cpp +++ b/lib/vf_common.cpp @@ -165,7 +165,8 @@ namespace ValueFlow 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 + !obj->valueType()->isEnum() && // <- TODO this is a bailout, handle enum with non-int types + !(obj->valueType()->container && obj->valueType()->container->startPattern == "std :: array <")) { 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) { @@ -246,7 +247,12 @@ namespace ValueFlow if (var->type()->classScope && var->type()->classScope->enumType) size = getSizeOfType(var->type()->classScope->enumType, settings); } else if (var->valueType()) { - size = var->valueType()->getSizeOf(settings, ValueType::Accuracy::ExactOrZero, ValueType::SizeOf::Pointer); + if (var->valueType()->container && var->valueType()->container->startPattern == "std :: array <") { + const ValueType vtElement = ValueType::parseDecl(var->valueType()->containerTypeToken, settings); + size = vtElement.getSizeOf(settings, ValueType::Accuracy::ExactOrZero, ValueType::SizeOf::Pointer); + } + else + size = var->valueType()->getSizeOf(settings, ValueType::Accuracy::ExactOrZero, ValueType::SizeOf::Pointer); } else if (!var->type()) { size = getSizeOfType(var->typeStartToken(), settings); } diff --git a/test/testvalueflow.cpp b/test/testvalueflow.cpp index 7fa28855eb1..c015664554a 100644 --- a/test/testvalueflow.cpp +++ b/test/testvalueflow.cpp @@ -1812,6 +1812,20 @@ class TestValueFlow : public TestFixture { ASSERT_EQUALS(1U, values.size()); ASSERT_EQUALS(2 * settings.platform.sizeof_pointer, values.back().intvalue); ASSERT_EQUALS_ENUM(ValueFlow::Value::ValueKind::Known, values.back().valueKind); + + code = "struct S { std::array a; };\n" + "x = sizeof(S);\n"; + values = tokenValues(code, "( S"); + ASSERT_EQUALS(1U, values.size()); + ASSERT_EQUALS(3 * settings.platform.sizeof_int, values.back().intvalue); + ASSERT_EQUALS_ENUM(ValueFlow::Value::ValueKind::Known, values.back().valueKind); + + code = "std::array a;\n" + "x = sizeof(a);\n"; + values = tokenValues(code, "( a"); + ASSERT_EQUALS(1U, values.size()); + ASSERT_EQUALS(3 * settings.platform.sizeof_int, values.back().intvalue); + ASSERT_EQUALS_ENUM(ValueFlow::Value::ValueKind::Known, values.back().valueKind); } void valueFlowComma() From 9162aa7fb9d54b79e5abc0f3ebd441a2dfa7e7e5 Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Thu, 2 Jul 2026 08:25:18 +0200 Subject: [PATCH 058/165] Fix #14878 fuzzing crash (null-pointer-use) in Tokenizer::simplifyUsing() (#8682) --- lib/tokenize.cpp | 2 ++ .../fuzz-crash/crash-42dad53b40278386e4ebd224813e26541cc725f1 | 1 + 2 files changed, 3 insertions(+) create mode 100644 test/cli/fuzz-crash/crash-42dad53b40278386e4ebd224813e26541cc725f1 diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index b29e807b8b5..61719f5291d 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -3470,6 +3470,8 @@ bool Tokenizer::simplifyUsing() skip = true; simplifyUsingError(usingStart, usingEnd); } + if (!after) + syntaxError(tok1); tok1 = after->previous(); } diff --git a/test/cli/fuzz-crash/crash-42dad53b40278386e4ebd224813e26541cc725f1 b/test/cli/fuzz-crash/crash-42dad53b40278386e4ebd224813e26541cc725f1 new file mode 100644 index 00000000000..3a9abbf229f --- /dev/null +++ b/test/cli/fuzz-crash/crash-42dad53b40278386e4ebd224813e26541cc725f1 @@ -0,0 +1 @@ +using C=C*;C{{}} From 449ee2413ae26b1c31c28752efa7b2e1636ac8a5 Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Thu, 2 Jul 2026 08:28:11 +0200 Subject: [PATCH 059/165] Fix #13944 FN constParameterPointer in method in derived class (#8673) https://github.com/cppcheck-opensource/cppcheck/pull/8240 seems to have stalled. Co-authored-by: ceJce --------- Co-authored-by: chrchr-github --- lib/checkother.cpp | 18 +++++++++++++----- lib/checkother.h | 2 +- test/testother.cpp | 12 ++++++++++++ 3 files changed, 26 insertions(+), 6 deletions(-) diff --git a/lib/checkother.cpp b/lib/checkother.cpp index 21657cfd9fd..9dee8df7810 100644 --- a/lib/checkother.cpp +++ b/lib/checkother.cpp @@ -2033,8 +2033,11 @@ void CheckOtherImpl::checkConstPointer() nonConstPointers.emplace(var); } for (const Variable *p: pointers) { + bool foundAllBaseClasses = true; if (p->isArgument()) { - if (!p->scope() || !p->scope()->function || p->scope()->function->isImplicitlyVirtual(true) || p->scope()->function->hasVirtualSpecifier()) + if (!p->scope() || !p->scope()->function || p->scope()->function->hasVirtualSpecifier()) + continue; + if (p->scope()->function->isImplicitlyVirtual(true, &foundAllBaseClasses) && foundAllBaseClasses) continue; if (p->isMaybeUnused()) continue; @@ -2051,12 +2054,12 @@ void CheckOtherImpl::checkConstPointer() continue; if (p->typeStartToken() && p->typeStartToken()->isSimplifiedTypedef() && !(Token::simpleMatch(p->typeEndToken(), "*") && !p->typeEndToken()->isSimplifiedTypedef())) continue; - constVariableError(p, p->isArgument() ? p->scope()->function : nullptr); + constVariableError(p, p->isArgument() ? p->scope()->function : nullptr, foundAllBaseClasses); } } } -void CheckOtherImpl::constVariableError(const Variable *var, const Function *function) +void CheckOtherImpl::constVariableError(const Variable *var, const Function *function, bool foundAllBaseClasses) { if (!var) { reportError(nullptr, Severity::style, "constParameter", "Parameter 'x' can be declared with const"); @@ -2069,13 +2072,18 @@ void CheckOtherImpl::constVariableError(const Variable *var, const Function *fun return; } - const std::string vartype(var->isArgument() ? "Parameter" : "Variable"); + std::string vartype(var->isArgument() ? "Parameter" : "Variable"); const std::string& varname(var->name()); const std::string ptrRefArray = var->isArray() ? "const array" : (var->isPointer() ? "pointer to const" : "reference to const"); ErrorPath errorPath; std::string id = "const" + vartype; - std::string message = "$symbol:" + varname + "\n" + vartype + " '$symbol' can be declared as " + ptrRefArray; + std::string message = "$symbol:" + varname + "\n"; + if (!foundAllBaseClasses) { + message += "Either there is a missing override/final keyword, or the "; + vartype[0] = std::tolower(vartype[0]); + } + message += vartype + " '$symbol' can be declared as " + ptrRefArray; errorPath.emplace_back(var->nameToken(), message); if (var->isArgument() && function && function->functionPointerUsage) { errorPath.emplace_front(function->functionPointerUsage, "You might need to cast the function pointer here"); diff --git a/lib/checkother.h b/lib/checkother.h index 759a4d23e7b..caf9f4a9e57 100644 --- a/lib/checkother.h +++ b/lib/checkother.h @@ -275,7 +275,7 @@ class CPPCHECKLIB CheckOtherImpl : public CheckImpl { void suspiciousFloatingPointCastError(const Token *tok); void invalidPointerCastError(const Token* tok, const std::string& from, const std::string& to, bool inconclusive, bool toIsInt); void passedByValueError(const Variable* var, bool inconclusive, bool isRangeBasedFor = false); - void constVariableError(const Variable *var, const Function *function); + void constVariableError(const Variable *var, const Function *function, bool foundAllBaseClasses = true); void constStatementError(const Token *tok, const std::string &type, bool inconclusive); void signedCharArrayIndexError(const Token *tok); void unknownSignCharArrayIndexError(const Token *tok); diff --git a/test/testother.cpp b/test/testother.cpp index 60323b3395b..fa6899cf543 100644 --- a/test/testother.cpp +++ b/test/testother.cpp @@ -4914,6 +4914,18 @@ class TestOther : public TestFixture { ASSERT_EQUALS("[test.cpp:2:14]: (style) Parameter 's' can be declared as pointer to const [constParameterPointer]\n" "[test.cpp:2:46]: (style) Parameter 'p' can be declared as pointer to const [constParameterPointer]\n", errout_str()); + + check("struct S : U {\n" // #13944 + " void f(int* p) const {\n" + " if (m == p) {}\n" + " }\n" + " void g(int* p) final {\n" + " if (m == p) {}\n" + " }\n" + " int* m;\n" + "};\n"); + ASSERT_EQUALS("[test.cpp:2:17]: (style) Either there is a missing override/final keyword, or the parameter 'p' can be declared as pointer to const [constParameterPointer]\n", + errout_str()); } void constArray() { From 161dcc1bb1161d28884ad054819cc79f9bdb5d09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20St=C3=B6neberg?= Date: Thu, 2 Jul 2026 08:57:39 +0200 Subject: [PATCH 060/165] checkstl.cpp: small `LoopAnalyzer` cleanup (#8659) - pass `Settings` by reference - cleaned up `LoopAnalyzer` access - removed unnessary condition from `LoopAnalyzer::findAlgo()` - small `LoopAnalyzer::findAlgo()` cleanup --- lib/checkstl.cpp | 97 +++++++++++++++++++++++------------------------- 1 file changed, 47 insertions(+), 50 deletions(-) diff --git a/lib/checkstl.cpp b/lib/checkstl.cpp index 6d97dffe3d2..4c3b51ac5db 100644 --- a/lib/checkstl.cpp +++ b/lib/checkstl.cpp @@ -2869,26 +2869,25 @@ static bool isTernaryAssignment(const Token* assignTok, nonneg int loopVarId, no namespace { struct LoopAnalyzer { - const Token* bodyTok = nullptr; - const Token* loopVar = nullptr; - const Settings* settings = nullptr; - std::set varsChanged; - - explicit LoopAnalyzer(const Token* tok, const Settings* psettings) - : bodyTok(tok->linkAt(1)->next()), settings(psettings) + private: + const Token* mBodyTok; + const Token* mLoopVar{}; + const Settings& mSettings; + std::set mVarsChanged; + + public: + explicit LoopAnalyzer(const Token* tok, const Settings& settings) + : mBodyTok(tok->linkAt(1)->next()), mSettings(settings) { const Token* splitTok = tok->next()->astOperand2(); if (Token::simpleMatch(splitTok, ":") && splitTok->previous()->varId() != 0) { - loopVar = splitTok->previous(); + mLoopVar = splitTok->previous(); } if (valid()) { findChangedVariables(); } } - bool isLoopVarChanged() const { - return varsChanged.count(loopVar->varId()) > 0; - } - + private: bool isModified(const Token* tok) const { if (tok->variable() && tok->variable()->isConst()) @@ -2896,11 +2895,11 @@ namespace { int n = 1 + (astIsPointer(tok) ? 1 : 0); for (int i = 0; i < n; i++) { bool inconclusive = false; - if (isVariableChangedByFunctionCall(tok, i, *settings, &inconclusive)) + if (isVariableChangedByFunctionCall(tok, i, mSettings, &inconclusive)) return true; if (inconclusive) return true; - if (isVariableChanged(tok, i, *settings)) + if (isVariableChanged(tok, i, mSettings)) return true; } return false; @@ -2909,7 +2908,7 @@ namespace { template void findTokens(Predicate pred, F f) const { - for (const Token* tok = bodyTok; precedes(tok, bodyTok->link()); tok = tok->next()) { + for (const Token* tok = mBodyTok; precedes(tok, mBodyTok->link()); tok = tok->next()) { if (pred(tok)) f(tok); } @@ -2918,7 +2917,7 @@ namespace { template const Token* findToken(Predicate pred) const { - for (const Token* tok = bodyTok; precedes(tok, bodyTok->link()); tok = tok->next()) { + for (const Token* tok = mBodyTok; precedes(tok, mBodyTok->link()); tok = tok->next()) { if (pred(tok)) return tok; } @@ -2933,58 +2932,56 @@ namespace { } bool valid() const { - return bodyTok && loopVar; + return mBodyTok && mLoopVar; } + public: std::string findAlgo() const { if (!valid()) return ""; - bool loopVarChanged = isLoopVarChanged(); - if (!loopVarChanged && varsChanged.empty()) { - if (hasGotoOrBreak()) - return ""; - bool alwaysTrue = true; - bool alwaysFalse = true; - auto hasReturn = [](const Token* tok) { - return Token::simpleMatch(tok, "return"); - }; - findTokens(hasReturn, [&](const Token* tok) { - const Token* returnTok = tok->astOperand1(); - if (!returnTok || !returnTok->hasKnownIntValue() || !astIsBool(returnTok)) { - alwaysTrue = false; - alwaysFalse = false; - return; - } - (returnTok->getKnownIntValue() ? alwaysTrue : alwaysFalse) &= true; - (returnTok->getKnownIntValue() ? alwaysFalse : alwaysTrue) &= false; - }); - if (alwaysTrue == alwaysFalse) - return ""; - if (alwaysTrue) - return "std::any_of"; - return "std::all_of or std::none_of"; - } - return ""; + if (!mVarsChanged.empty()) + return ""; + if (hasGotoOrBreak()) + return ""; + bool alwaysTrue = true; + bool alwaysFalse = true; + const auto hasReturn = [](const Token* tok) { + return Token::simpleMatch(tok, "return"); + }; + findTokens(hasReturn, [&](const Token* tok) { + const Token* returnTok = tok->astOperand1(); + if (!returnTok || !returnTok->hasKnownIntValue() || !astIsBool(returnTok)) { + alwaysTrue = false; + alwaysFalse = false; + return; + } + (returnTok->getKnownIntValue() ? alwaysTrue : alwaysFalse) &= true; + (returnTok->getKnownIntValue() ? alwaysFalse : alwaysTrue) &= false; + }); + if (alwaysTrue == alwaysFalse) + return ""; + if (alwaysTrue) + return "std::any_of"; + return "std::all_of or std::none_of"; } - + private: bool isLocalVar(const Variable* var) const { if (!var) return false; if (var->isPointer() || var->isReference()) return false; - if (var->declarationId() == loopVar->varId()) + if (var->declarationId() == mLoopVar->varId()) return false; const Scope* scope = var->scope(); - return scope && scope->isNestedIn(bodyTok->scope()); + return scope && scope->isNestedIn(mBodyTok->scope()); } - private: void findChangedVariables() { std::set vars; - for (const Token* tok = bodyTok; precedes(tok, bodyTok->link()); tok = tok->next()) { + for (const Token* tok = mBodyTok; precedes(tok, mBodyTok->link()); tok = tok->next()) { if (tok->varId() == 0) continue; if (vars.count(tok->varId()) > 0) @@ -2995,7 +2992,7 @@ namespace { } if (!isModified(tok)) continue; - varsChanged.insert(tok->varId()); + mVarsChanged.insert(tok->varId()); vars.insert(tok->varId()); } } @@ -3046,7 +3043,7 @@ void CheckStlImpl::useStlAlgorithm() continue; if (!Token::simpleMatch(tok->linkAt(1), ") {")) continue; - LoopAnalyzer a{tok, &mSettings}; + LoopAnalyzer a{tok, mSettings}; std::string algoName = a.findAlgo(); if (!algoName.empty()) { useStlAlgorithmError(tok, algoName); From ac061dac8a68c811300cf3c5201886a3c085e15f Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Thu, 2 Jul 2026 14:36:20 +0200 Subject: [PATCH 061/165] Fix #14886 fuzzing crash (null-pointer-use) in SymbolDatabase::createSymbolDatabaseIncompleteVars() (#8685) --- lib/symboldatabase.cpp | 2 +- .../fuzz-crash/crash-60d6b7bc43d21f6a8ad8eb8cca551e45c31c6a32 | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 test/cli/fuzz-crash/crash-60d6b7bc43d21f6a8ad8eb8cca551e45c31c6a32 diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index bbf6cc8ce52..b687c9f77a4 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -1491,7 +1491,7 @@ void SymbolDatabase::createSymbolDatabaseEnums() void SymbolDatabase::createSymbolDatabaseIncompleteVars() { - for (Token* tok = mTokenizer.list.front(); tok != mTokenizer.list.back(); tok = tok->next()) { + for (Token* tok = mTokenizer.list.front(); precedes(tok, mTokenizer.list.back()); tok = tok->next()) { const Scope * scope = tok->scope(); if (!scope) continue; diff --git a/test/cli/fuzz-crash/crash-60d6b7bc43d21f6a8ad8eb8cca551e45c31c6a32 b/test/cli/fuzz-crash/crash-60d6b7bc43d21f6a8ad8eb8cca551e45c31c6a32 new file mode 100644 index 00000000000..4a60eb05b88 --- /dev/null +++ b/test/cli/fuzz-crash/crash-60d6b7bc43d21f6a8ad8eb8cca551e45c31c6a32 @@ -0,0 +1 @@ +ti(){using S}; From 3f2d60c4b72b5ab28ded6fc980341348643cc817 Mon Sep 17 00:00:00 2001 From: metsw24-max Date: Fri, 3 Jul 2026 12:52:50 +0530 Subject: [PATCH 062/165] Fix #14885 Shift by negative value in TemplateSimplifier::simplifyNumericalCalculations() (#8639) the value shift operators only reject a count >= bigint_bits, so MathLib::value::shiftLeft still left-shifts a negative value and both shiftLeft and shiftRight still shift by a negative count, which is undefined behaviour. it is reachable when folding a template argument like 0x8000000000000000 << 1 in simplifyNumericCalculations, since MathLib::isNegative only checks for a leading minus while a large hex literal parses to a negative bigint and the guard there lets it through. mirror the negative-operand check calculate.h already uses and return the operand unchanged, as is already done for oversized counts. ubsan flags the left shift at mathlib.cpp:272 on that input. --- AUTHORS | 1 + lib/mathlib.cpp | 4 ++-- test/testsimplifytemplate.cpp | 17 +++++++++++++++++ 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/AUTHORS b/AUTHORS index 19cbe734d2e..1a7543b0d93 100644 --- a/AUTHORS +++ b/AUTHORS @@ -369,6 +369,7 @@ Samuel Degrande Samuel Poláček Sandeep Dutta Savvas Etairidis +Sayed Kaif Scott Ehlert Scott Furry Seafarix Ltd. diff --git a/lib/mathlib.cpp b/lib/mathlib.cpp index 403662f4df2..c7c055899fd 100644 --- a/lib/mathlib.cpp +++ b/lib/mathlib.cpp @@ -266,7 +266,7 @@ MathLib::value MathLib::value::shiftLeft(const MathLib::value &v) const if (!isInt() || !v.isInt()) throw InternalError(nullptr, "Shift operand is not integer"); MathLib::value ret(*this); - if (v.mIntValue >= MathLib::bigint_bits) { + if (v.mIntValue < 0 || v.mIntValue >= MathLib::bigint_bits || ret.mIntValue < 0) { return ret; } ret.mIntValue <<= v.mIntValue; @@ -278,7 +278,7 @@ MathLib::value MathLib::value::shiftRight(const MathLib::value &v) const if (!isInt() || !v.isInt()) throw InternalError(nullptr, "Shift operand is not integer"); MathLib::value ret(*this); - if (v.mIntValue >= MathLib::bigint_bits) { + if (v.mIntValue < 0 || v.mIntValue >= MathLib::bigint_bits) { return ret; } ret.mIntValue >>= v.mIntValue; diff --git a/test/testsimplifytemplate.cpp b/test/testsimplifytemplate.cpp index b28bc503869..6960b791426 100644 --- a/test/testsimplifytemplate.cpp +++ b/test/testsimplifytemplate.cpp @@ -320,6 +320,8 @@ class TestSimplifyTemplate : public TestFixture { TEST_CASE(templateArgPreserveType); // #13882 - type of template argument + TEST_CASE(template_shift_negative); // shift folding with a negative operand + TEST_CASE(dumpTemplateArgFrom); } @@ -6715,6 +6717,21 @@ class TestSimplifyTemplate : public TestFixture { tok(code)); } + void template_shift_negative() { + // a large hex literal is not negative as a string but parses to a negative + // bigint, so folding the shift in simplifyNumericCalculations would left-shift + // a negative value / shift by a negative count, both UB. the operand must be + // returned unchanged. parentheses are needed so the numeric folding is reached. + const char code[] = "template struct S { };\n" + "S<(0x8000000000000000 << 1)> s1;\n" + "S<(1 << 0x8000000000000000)> s2;\n" + "S<(1 >> 0x8000000000000000)> s3;"; + const char expected[] = "struct S<9223372036854775808U> ; struct S<1> ; " + "S<9223372036854775808U> s1 ; S<1> s2 ; S<1> s3 ; " + "struct S<9223372036854775808U> { } ; struct S<1> { } ;"; + ASSERT_EQUALS(expected, tok(code)); + } + void dumpTemplateArgFrom() { const char code[] = "template void foo(T t) {}\n" "foo(23);"; From ddab07631d6ef3ccff5dc4c93ae5ba8d3dd57c1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Berder?= <18538310+francois-berder@users.noreply.github.com> Date: Fri, 3 Jul 2026 11:42:45 +0200 Subject: [PATCH 063/165] Fix #14826 valueflow: forward lifetimes through array and member subobjects (#8636) Signed-off-by: Francois Berder --- lib/valueflow.cpp | 39 ++++++++++++---- test/testautovariables.cpp | 93 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 124 insertions(+), 8 deletions(-) diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index f934d8496d6..7d25166bf99 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -1952,6 +1952,35 @@ const Token* ValueFlow::getEndOfExprScope(const Token* tok, const Scope* default return end; } +static void getLhsLifetimeParentsImpl(const Token* lhs, const Library& library, std::vector& result) +{ + if (!lhs) + return; + + if (Token::simpleMatch(lhs, "[")) { + getLhsLifetimeParentsImpl(lhs->astOperand1(), library, result); + } else if (Token::simpleMatch(lhs, ".") && lhs->originalName() != "->") { + const Token* obj = lhs->astOperand1(); + if (Token::simpleMatch(obj, "[") && obj->exprId() > 0) + result.push_back(obj); + getLhsLifetimeParentsImpl(obj, library, result); + } else { + const Token* tok = getParentLifetime(lhs, library); + if (tok && tok->exprId() > 0) { + const Variable* var = tok->variable(); + if (!var || var->isLocal() || var->isArgument()) + result.push_back(tok); + } + } +} + +static std::vector getLhsLifetimeParents(const Token* lhs, const Library& library) +{ + std::vector result; + getLhsLifetimeParentsImpl(lhs, library, result); + return result; +} + static void valueFlowForwardLifetime(Token * tok, const TokenList &tokenlist, ErrorLogger &errorLogger, const Settings &settings) { // Forward lifetimes to constructed variable @@ -2004,14 +2033,8 @@ static void valueFlowForwardLifetime(Token * tok, const TokenList &tokenlist, Er if (val.lifetimeKind == ValueFlow::Value::LifetimeKind::Address) val.lifetimeKind = ValueFlow::Value::LifetimeKind::SubObject; } - // TODO: handle `[` - if (Token::simpleMatch(parent->astOperand1(), ".")) { - const Token* parentLifetime = - getParentLifetime(parent->astOperand1()->astOperand2(), settings.library); - if (parentLifetime && parentLifetime->exprId() > 0) { - valueFlowForward(nextExpression, endOfVarScope, parentLifetime, std::move(values), tokenlist, errorLogger, settings); - } - } + for (const Token *p : getLhsLifetimeParents(parent->astOperand1(), settings.library)) + valueFlowForward(nextExpression, endOfVarScope, p, values, tokenlist, errorLogger, settings); } // Constructor } else if (Token::simpleMatch(parent, "{") && !isScopeBracket(parent)) { diff --git a/test/testautovariables.cpp b/test/testautovariables.cpp index 9fe3e126660..2867f147d81 100644 --- a/test/testautovariables.cpp +++ b/test/testautovariables.cpp @@ -4452,6 +4452,99 @@ class TestAutoVariables : public TestFixture { "}\n"); ASSERT_EQUALS("[test.cpp:5:14] -> [test.cpp:5:18] -> [test.cpp:6:7]: (error) Using pointer that is a temporary. [danglingTemporaryLifetime]\n", errout_str()); + + check("struct A { const int* data[2]; };\n" + "A g() {\n" + " int x = 0;\n" + " A a;\n" + " a.data[0] = &x;\n" + " return a;\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:5:17] -> [test.cpp:3:9] -> [test.cpp:6:12]: (error) Returning object that points to local variable 'x' that will be invalid when returning. [returnDanglingLifetime]\n", + errout_str()); + + check("struct A { const int* data[2]; };\n" + "A g() {\n" + " int x = 0;\n" + " A a[2];\n" + " a[0].data[0] = &x;\n" + " return a[0];\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:5:20] -> [test.cpp:3:9] -> [test.cpp:6:13]: (error) Returning object that points to local variable 'x' that will be invalid when returning. [returnDanglingLifetime]\n", + errout_str()); + + check("struct A { const int* data[2]; };\n" + "A* g() {\n" + " int x = 0;\n" + " static A arr[2];\n" + " arr[0].data[0] = &x;\n" + " return arr;\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:5:22] -> [test.cpp:3:9] -> [test.cpp:6:12]: (error) Returning pointer to local variable 'x' that will be invalid when returning. [returnDanglingLifetime]\n", + errout_str()); + + check("struct A { const int* p; };\n" + "A g(int i) {\n" + " int x = 0;\n" + " A arr[2];\n" + " arr[i].p = &x;\n" + " return arr[i];\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:5:16] -> [test.cpp:3:9] -> [test.cpp:6:15]: (error) Returning object that points to local variable 'x' that will be invalid when returning. [returnDanglingLifetime]\n", + errout_str()); + + check("struct A { const int* p; };\n" + "A* g(int i) {\n" + " int x = 0;\n" + " static A arr[2];\n" + " arr[i].p = &x;\n" + " return arr;\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:5:16] -> [test.cpp:3:9] -> [test.cpp:6:12]: (error) Returning pointer to local variable 'x' that will be invalid when returning. [returnDanglingLifetime]\n", + errout_str()); + + check("struct A { const int* p; };\n" + "struct B { A arr[2]; };\n" + "B g(int i) {\n" + " int x = 0;\n" + " B b;\n" + " b.arr[i].p = &x;\n" + " return b;\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:6:18] -> [test.cpp:4:9] -> [test.cpp:7:12]: (error) Returning object that points to local variable 'x' that will be invalid when returning. [returnDanglingLifetime]\n", + errout_str()); + + check("struct A { const int* p; };\n" + "A* g() {\n" + " int x = 0;\n" + " static A a;\n" + " A* ap = &a;\n" + " ap->p = &x;\n" + " (*ap).p = &x;\n" + " return ap;\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + + check("struct A { int* a; int* b; };\n" + "static A g;\n" + "int* f() {\n" + " int x = 0;\n" + " g.a = &x;\n" + " return g.b;\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:5:11] -> [test.cpp:4:9] -> [test.cpp:5:6]: (error) Non-local variable 'g.a' will use pointer to local variable 'x'. [danglingLifetime]\n", + errout_str()); + + check("struct A { int* a; int* b; };\n" + "static A g;\n" + "int* f() {\n" + " int x = 0;\n" + " g.a = &x;\n" + " return g.a;\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:5:11] -> [test.cpp:4:9] -> [test.cpp:5:6]: (error) Non-local variable 'g.a' will use pointer to local variable 'x'. [danglingLifetime]\n" + "[test.cpp:5:11] -> [test.cpp:4:9] -> [test.cpp:6:13]: (error) Returning pointer to local variable 'x' that will be invalid when returning. [returnDanglingLifetime]\n", + errout_str()); } void danglingLifetimeClassMemberFunctions() From 04091bd597b5ec8bd2ee56f018cd628f9885d7c9 Mon Sep 17 00:00:00 2001 From: Robert Morin Date: Fri, 3 Jul 2026 05:48:23 -0400 Subject: [PATCH 064/165] Fix #14743 (New check: ftell() result is unspecified when file is opened in mode "t") (#8360) --- .gitignore | 1 + lib/checkio.cpp | 20 +++++++++++ lib/checkio.h | 1 + man/checkers/ftellTextModeFile.md | 56 +++++++++++++++++++++++++++++++ releasenotes.txt | 1 + test/testio.cpp | 17 ++++++++++ 6 files changed, 96 insertions(+) create mode 100644 man/checkers/ftellTextModeFile.md diff --git a/.gitignore b/.gitignore index 434203fe2a9..a821204bf2d 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ *.gcno *.gch *.o +*.a *.pyc /cppcheck /cppcheck.exe diff --git a/lib/checkio.cpp b/lib/checkio.cpp index f632ca99e9e..c753dd80739 100644 --- a/lib/checkio.cpp +++ b/lib/checkio.cpp @@ -48,6 +48,7 @@ // CVE ID used: static const CWE CWE119(119U); // Improper Restriction of Operations within the Bounds of a Memory Buffer static const CWE CWE398(398U); // Indicator of Poor Code Quality +static const CWE CWE474(474U); // Use of Function with Inconsistent Implementations static const CWE CWE664(664U); // Improper Control of a Resource Through its Lifetime static const CWE CWE685(685U); // Function Call With Incorrect Number of Arguments static const CWE CWE686(686U); // Function Call With Incorrect Argument Type @@ -111,6 +112,8 @@ namespace { nonneg int op_indent{}; enum class AppendMode : std::uint8_t { UNKNOWN_AM, APPEND, APPEND_EX }; AppendMode append_mode = AppendMode::UNKNOWN_AM; + enum class ReadMode : std::uint8_t { READ_TEXT, READ_BIN }; + ReadMode read_mode = ReadMode::READ_BIN; std::string filename; explicit Filepointer(OpenMode mode_ = OpenMode::UNKNOWN_OM) : mode(mode_) {} @@ -183,6 +186,7 @@ void CheckIOImpl::checkFileUsage() } } else if (Token::Match(tok, "%name% (") && tok->previous() && (!tok->previous()->isName() || Token::Match(tok->previous(), "return|throw"))) { std::string mode; + bool isftell = false; const Token* fileTok = nullptr; const Token* fileNameTok = nullptr; Filepointer::Operation operation = Filepointer::Operation::NONE; @@ -266,6 +270,9 @@ void CheckIOImpl::checkFileUsage() fileTok = tok->tokAt(2); if ((tok->str() == "ungetc" || tok->str() == "ungetwc") && fileTok) fileTok = fileTok->nextArgument(); + else if (tok->str() == "ftell") { + isftell = true; + } operation = Filepointer::Operation::UNIMPORTANT; } else if (!Token::Match(tok, "if|for|while|catch|switch") && !mSettings.library.isFunctionConst(tok->str(), true)) { const Token* const end2 = tok->linkAt(1); @@ -321,10 +328,15 @@ void CheckIOImpl::checkFileUsage() f.append_mode = Filepointer::AppendMode::APPEND_EX; else f.append_mode = Filepointer::AppendMode::APPEND; + } + else if (mode.find('r') != std::string::npos && + mode.find('t') != std::string::npos) { + f.read_mode = Filepointer::ReadMode::READ_TEXT; } else f.append_mode = Filepointer::AppendMode::UNKNOWN_AM; f.mode_indent = indent; break; + case Filepointer::Operation::POSITIONING: if (f.mode == OpenMode::CLOSED) useClosedFileError(tok); @@ -357,6 +369,8 @@ void CheckIOImpl::checkFileUsage() case Filepointer::Operation::UNIMPORTANT: if (f.mode == OpenMode::CLOSED) useClosedFileError(tok); + if (isftell && f.read_mode == Filepointer::ReadMode::READ_TEXT && printPortability) + ftellFileError(tok); break; case Filepointer::Operation::UNKNOWN_OP: f.mode = OpenMode::UNKNOWN_OM; @@ -424,6 +438,12 @@ void CheckIOImpl::seekOnAppendedFileError(const Token *tok) "seekOnAppendedFile", "Repositioning operation performed on a file opened in append mode has no effect.", CWE398, Certainty::normal); } +void CheckIOImpl::ftellFileError(const Token *tok) +{ + reportError(tok, Severity::portability, + "ftellTextModeFile", "ftell() result is unspecified when file is opened in mode \"t\"", CWE474, Certainty::normal); +} + void CheckIOImpl::incompatibleFileOpenError(const Token *tok, const std::string &filename) { reportError(tok, Severity::warning, diff --git a/lib/checkio.h b/lib/checkio.h index dff49006bab..ae0ea242dab 100644 --- a/lib/checkio.h +++ b/lib/checkio.h @@ -128,6 +128,7 @@ class CPPCHECKLIB CheckIOImpl : public CheckImpl { void useClosedFileError(const Token *tok); void fcloseInLoopConditionError(const Token *tok, const std::string &varname); void seekOnAppendedFileError(const Token *tok); + void ftellFileError(const Token *tok); void incompatibleFileOpenError(const Token *tok, const std::string &filename); void invalidScanfError(const Token *tok); void wrongfeofUsage(const Token *tok); diff --git a/man/checkers/ftellTextModeFile.md b/man/checkers/ftellTextModeFile.md new file mode 100644 index 00000000000..6ca6653a6f2 --- /dev/null +++ b/man/checkers/ftellTextModeFile.md @@ -0,0 +1,56 @@ +# ftellModeTextFile + +**Message**: ftell() result is unspecified when file is opened in mode "t".
+**Category**: Portability
+**Severity**: Style
+**Language**: C/C++ + +## Description + +This checker detects the use of ftell() on a file open in text (or translate) mode. The text mode is not consistent + in between Linux and Windows system and may cause ftell() to return the wrong offset inside a text file. + +See section 7.21.9.4p2 of the C11 standard regarding the ftell function states for a text stream: + +- For a text stream, its file position indicator contains unspecified information, usable by the fseek function for returning the file position indicator for the stream to its position at the time of the ftell call; the difference between two such return values is not necessarily a meaningful measure of the number of characters written or read. + +This warning helps improve code quality by: +- Making the intent clear that the use of ftell() in "t" mode may cause portability problem. + +## Motivation + +This checker improves portability accross system. + +## How to fix + +According to C11, the file must be opened in binary mode 'b' to prevent this problem. + +Before: +```cpp + FILE *f = fopen("Example.txt", "rt"); + if (f) + { + fseek(f, 0, SEEK_END); + printf( "File size %d\n", ftell(f)); + fclose(f); + } + +``` + +After: +```cpp + + FILE *f = fopen("Example.txt", "rb"); + if (f) + { + fseek(f, 0, SEEK_END); + printf( "File size %d\n", ftell(f)); + fclose(f); + } + +``` + +## Notes + +See https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/fopen-wfopen?view=msvc-170 + diff --git a/releasenotes.txt b/releasenotes.txt index 2141c34f001..0ca26f2374a 100644 --- a/releasenotes.txt +++ b/releasenotes.txt @@ -6,6 +6,7 @@ Major bug fixes & crashes: New checks: - Warn when feof() is used as a while loop condition (wrongfeofUsage). +- ftell() result is unspecified when file is opened in mode "t". C/C++ support: - diff --git a/test/testio.cpp b/test/testio.cpp index adfb6e31daf..f90773d4cf4 100644 --- a/test/testio.cpp +++ b/test/testio.cpp @@ -44,6 +44,7 @@ class TestIO : public TestFixture { TEST_CASE(fileIOwithoutPositioning); TEST_CASE(seekOnAppendedFile); TEST_CASE(fflushOnInputStream); + TEST_CASE(ftellCompatibility); TEST_CASE(incompatibleFileOpen); TEST_CASE(testWrongfeofUsage); // #958 @@ -728,6 +729,22 @@ class TestIO : public TestFixture { ASSERT_EQUALS("", errout_str()); // #6566 } + void ftellCompatibility() { + + check("void foo() {\n" + " FILE *f = fopen(\"\", \"rt\");\n" + " if (f)\n" + " {\n" + " extern long position;\n" + " fseek(f, 0, SEEK_END);\n" + " position = ftell(f);\n" + " fclose(f);\n" + " }\n" + "}\n", dinit(CheckOptions, $.portability = true)); + ASSERT_EQUALS("[test.cpp:7:21]: (portability) ftell() result is unspecified when file is opened in mode \"t\" [ftellTextModeFile]\n", errout_str()); + } + + void fflushOnInputStream() { check("void foo()\n" "{\n" From c1644448468b6e406b3c2c6c7864a105e7aeae54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20St=C3=B6neberg?= Date: Fri, 3 Jul 2026 13:44:08 +0200 Subject: [PATCH 065/165] pass `Library` instead of `Settings` (#8660) --- lib/astutils.cpp | 26 +++++++++++++------------- lib/astutils.h | 10 +++++----- lib/checkautovariables.cpp | 22 +++++++++++----------- lib/checkbufferoverrun.cpp | 2 +- lib/checkclass.cpp | 2 +- lib/checkio.cpp | 6 +++--- lib/checkio.h | 3 ++- lib/checkleakautovar.cpp | 14 +++++++------- lib/checknullpointer.cpp | 12 ++++++------ lib/checknullpointer.h | 2 +- lib/checkother.cpp | 8 ++++---- lib/checkstl.cpp | 4 ++-- lib/checkuninitvar.cpp | 4 ++-- lib/checkunusedfunctions.cpp | 30 +++++++++++++++--------------- lib/checkunusedfunctions.h | 5 +++-- lib/cppcheck.cpp | 10 +++++----- lib/valueflow.cpp | 8 ++++---- lib/vf_analyzers.cpp | 4 ++-- lib/vf_common.cpp | 8 ++++---- lib/vf_common.h | 3 ++- test/testastutils.cpp | 2 +- test/testunusedfunctions.cpp | 12 ++++++------ 22 files changed, 100 insertions(+), 97 deletions(-) diff --git a/lib/astutils.cpp b/lib/astutils.cpp index 8700d2d2cd9..a6fe2573f08 100644 --- a/lib/astutils.cpp +++ b/lib/astutils.cpp @@ -2334,14 +2334,14 @@ bool isWithinScope(const Token* tok, const Variable* var, ScopeType type) return false; } -bool isVariableChangedByFunctionCall(const Token *tok, int indirect, nonneg int varid, const Settings &settings, bool *inconclusive) +bool isVariableChangedByFunctionCall(const Token *tok, int indirect, nonneg int varid, const Library &library, bool *inconclusive) { if (!tok) return false; if (tok->varId() == varid) - return isVariableChangedByFunctionCall(tok, indirect, settings, inconclusive); - return isVariableChangedByFunctionCall(tok->astOperand1(), indirect, varid, settings, inconclusive) || - isVariableChangedByFunctionCall(tok->astOperand2(), indirect, varid, settings, inconclusive); + return isVariableChangedByFunctionCall(tok, indirect, library, inconclusive); + return isVariableChangedByFunctionCall(tok->astOperand1(), indirect, varid, library, inconclusive) || + isVariableChangedByFunctionCall(tok->astOperand2(), indirect, varid, library, inconclusive); } bool isScopeBracket(const Token* tok) @@ -2522,7 +2522,7 @@ bool isMutableExpression(const Token* tok) return true; } -bool isVariableChangedByFunctionCall(const Token *tok, int indirect, const Settings &settings, bool *inconclusive) +bool isVariableChangedByFunctionCall(const Token *tok, int indirect, const Library &library, bool *inconclusive) { if (!tok) return false; @@ -2562,13 +2562,13 @@ bool isVariableChangedByFunctionCall(const Token *tok, int indirect, const Setti if (!tok->function() && !tok->variable() && tok->isName()) { // Check if direction (in, out, inout) is specified in the library configuration and use that - const Library::ArgumentChecks::Direction argDirection = settings.library.getArgDirection(tok, 1 + argnr, indirect); + const Library::ArgumentChecks::Direction argDirection = library.getArgDirection(tok, 1 + argnr, indirect); if (argDirection == Library::ArgumentChecks::Direction::DIR_IN) return false; if (argDirection == Library::ArgumentChecks::Direction::DIR_OUT || argDirection == Library::ArgumentChecks::Direction::DIR_INOUT) return true; - const bool requireNonNull = settings.library.isnullargbad(tok, 1 + argnr); + const bool requireNonNull = library.isnullargbad(tok, 1 + argnr); if (Token::simpleMatch(tok->tokAt(-2), "std :: tie")) return true; // if the library says 0 is invalid @@ -2796,7 +2796,7 @@ bool isVariableChanged(const Token *tok, int indirect, const Settings &settings, if (indirect == 0 && astIsLHS(tok2) && Token::Match(ptok, ". %var%") && astIsPointer(ptok->next())) pindirect = 1; bool inconclusive = false; - bool isChanged = isVariableChangedByFunctionCall(ptok, pindirect, settings, &inconclusive); + bool isChanged = isVariableChangedByFunctionCall(ptok, pindirect, settings.library, &inconclusive); isChanged |= inconclusive; if (isChanged) return true; @@ -3421,7 +3421,7 @@ bool isConstVarExpression(const Token *tok, const std::functionastParent() && tok->astParent()->isUnaryOp("&"); @@ -3483,14 +3483,14 @@ static ExprUsage getFunctionUsage(const Token* tok, int indirect, const Settings } else if (ftok->str() == "{") { return indirect == 0 ? ExprUsage::Used : ExprUsage::Inconclusive; } else { - const bool isnullbad = settings.library.isnullargbad(ftok, argnr + 1); + const bool isnullbad = library.isnullargbad(ftok, argnr + 1); if (indirect == 0 && astIsPointer(tok) && !addressOf && isnullbad) return ExprUsage::Used; bool hasIndirect = false; - const bool isuninitbad = settings.library.isuninitargbad(ftok, argnr + 1, indirect, &hasIndirect); + const bool isuninitbad = library.isuninitargbad(ftok, argnr + 1, indirect, &hasIndirect); if (isuninitbad && (!addressOf || isnullbad)) return ExprUsage::Used; - const Library::ArgumentChecks::Direction argDirection = settings.library.getArgDirection(ftok, argnr + 1, indirect); + const Library::ArgumentChecks::Direction argDirection = library.getArgDirection(ftok, argnr + 1, indirect); if (argDirection == Library::ArgumentChecks::Direction::DIR_IN) // TODO: DIR_INOUT? return ExprUsage::Used; if (argDirection == Library::ArgumentChecks::Direction::DIR_OUT) @@ -3560,7 +3560,7 @@ ExprUsage getExprUsage(const Token* tok, int indirect, const Settings& settings) (astIsLHS(tok) || Token::simpleMatch(parent, "( )"))) return ExprUsage::Used; } - return getFunctionUsage(tok, indirect, settings); + return getFunctionUsage(tok, indirect, settings.library); } static void getLHSVariablesRecursive(std::vector& vars, const Token* tok) diff --git a/lib/astutils.h b/lib/astutils.h index 617e01f0415..2c6650068b5 100644 --- a/lib/astutils.h +++ b/lib/astutils.h @@ -327,20 +327,20 @@ bool isMutableExpression(const Token* tok); * * @param tok ast tree * @param varid Variable Id - * @param settings program settings + * @param library library configurations * @param inconclusive pointer to output variable which indicates that the answer of the question is inconclusive */ -bool isVariableChangedByFunctionCall(const Token *tok, int indirect, nonneg int varid, const Settings &settings, bool *inconclusive); +bool isVariableChangedByFunctionCall(const Token *tok, int indirect, nonneg int varid, const Library &library, bool *inconclusive); /** Is variable changed by function call? * In case the answer of the question is inconclusive, e.g. because the function declaration is not known * the return value is false and the output parameter inconclusive is set to true * - * @param tok token of variable in function call - * @param settings program settings + * @param tok token of variable in function call + * @param library library configurations * @param inconclusive pointer to output variable which indicates that the answer of the question is inconclusive */ -CPPCHECKLIB bool isVariableChangedByFunctionCall(const Token *tok, int indirect, const Settings &settings, bool *inconclusive); +CPPCHECKLIB bool isVariableChangedByFunctionCall(const Token *tok, int indirect, const Library &library, bool *inconclusive); /** Is variable changed in block of code? */ CPPCHECKLIB bool isVariableChanged(const Token *start, const Token *end, nonneg int exprid, bool globalvar, const Settings &settings, int depth = 20); diff --git a/lib/checkautovariables.cpp b/lib/checkautovariables.cpp index b848928ebf4..de70772a279 100644 --- a/lib/checkautovariables.cpp +++ b/lib/checkautovariables.cpp @@ -139,14 +139,14 @@ static bool isAutoVarArray(const Token *tok) return false; } -static bool isLocalContainerBuffer(const Token* tok, const Settings& settings) +static bool isLocalContainerBuffer(const Token* tok, const Library& library) { if (!tok) return false; // x+y if (tok->str() == "+") - return isLocalContainerBuffer(tok->astOperand1(), settings) || isLocalContainerBuffer(tok->astOperand2(), settings); + return isLocalContainerBuffer(tok->astOperand1(), library) || isLocalContainerBuffer(tok->astOperand2(), library); if (tok->str() != "(" || !Token::simpleMatch(tok->astOperand1(), ".")) return false; @@ -157,7 +157,7 @@ static bool isLocalContainerBuffer(const Token* tok, const Settings& settings) if (!var || !var->isLocal() || var->isStatic()) return false; - const Library::Container::Yield yield = astContainerYield(tok, settings.library); + const Library::Container::Yield yield = astContainerYield(tok, library); return yield == Library::Container::Yield::BUFFER || yield == Library::Container::Yield::BUFFER_NT; } @@ -233,8 +233,8 @@ void CheckAutoVariablesImpl::assignFunctionArg() } } -static bool isAutoVariableRHS(const Token* tok, const Settings& settings) { - return isAddressOfLocalVariable(tok) || isAutoVarArray(tok) || isLocalContainerBuffer(tok, settings); +static bool isAutoVariableRHS(const Token* tok, const Library& library) { + return isAddressOfLocalVariable(tok) || isAutoVarArray(tok) || isLocalContainerBuffer(tok, library); } static bool hasOverloadedAssignment(const Token* tok, bool& inconclusive) @@ -257,7 +257,7 @@ static bool hasOverloadedAssignment(const Token* tok, bool& inconclusive) return true; } -static bool isMemberAssignment(const Token* tok, const Token*& rhs, const Settings& settings) +static bool isMemberAssignment(const Token* tok, const Token*& rhs, const Library& library) { const Token *endBracket = nullptr; if (!Token::Match(tok, "[;{}] %var% . %var%")) { @@ -274,7 +274,7 @@ static bool isMemberAssignment(const Token* tok, const Token*& rhs, const Settin assign = assign->astParent(); if (!Token::simpleMatch(assign, "=")) return false; - if (!isAutoVariableRHS(assign->astOperand2(), settings)) + if (!isAutoVariableRHS(assign->astOperand2(), library)) return false; rhs = assign->astOperand2(); return true; @@ -295,15 +295,15 @@ void CheckAutoVariablesImpl::autoVariables() } // Critical assignment const Token* rhs{}; - if (Token::Match(tok, "[;{}] %var% =") && isRefPtrArg(tok->next()) && isAutoVariableRHS(tok->tokAt(2)->astOperand2(), mSettings)) { + if (Token::Match(tok, "[;{}] %var% =") && isRefPtrArg(tok->next()) && isAutoVariableRHS(tok->tokAt(2)->astOperand2(), mSettings.library)) { checkAutoVariableAssignment(tok->next(), false); - } else if (Token::Match(tok, "[;{}] * %var% =") && isPtrArg(tok->tokAt(2)) && isAutoVariableRHS(tok->tokAt(3)->astOperand2(), mSettings)) { + } else if (Token::Match(tok, "[;{}] * %var% =") && isPtrArg(tok->tokAt(2)) && isAutoVariableRHS(tok->tokAt(3)->astOperand2(), mSettings.library)) { const Token* lhs = tok->tokAt(2); bool inconclusive = false; if (!hasOverloadedAssignment(lhs, inconclusive) || (printInconclusive && inconclusive)) checkAutoVariableAssignment(tok->next(), inconclusive); tok = tok->tokAt(4); - } else if (isMemberAssignment(tok, rhs, mSettings)) { + } else if (isMemberAssignment(tok, rhs, mSettings.library)) { const Token* lhs = tok->tokAt(3); bool inconclusive = false; if (!hasOverloadedAssignment(lhs, inconclusive) || (printInconclusive && inconclusive)) @@ -311,7 +311,7 @@ void CheckAutoVariablesImpl::autoVariables() tok = rhs; } else if (Token::Match(tok, "[;{}] %var% [") && Token::simpleMatch(tok->linkAt(2), "] =") && (isPtrArg(tok->next()) || isArrayArg(tok->next(), mSettings)) && - isAutoVariableRHS(tok->linkAt(2)->next()->astOperand2(), mSettings)) { + isAutoVariableRHS(tok->linkAt(2)->next()->astOperand2(), mSettings.library)) { errorAutoVariableAssignment(tok->next(), false); } // Invalid pointer deallocation diff --git a/lib/checkbufferoverrun.cpp b/lib/checkbufferoverrun.cpp index 496ca6905a1..81b6653d348 100644 --- a/lib/checkbufferoverrun.cpp +++ b/lib/checkbufferoverrun.cpp @@ -133,7 +133,7 @@ static int getMinFormatStringOutputLength(const std::vector ¶m case 's': parameterLength = 0; if (inputArgNr < parameters.size()) - parameterLength = ValueFlow::valueFlowGetStrLength(parameters[inputArgNr], settings); + parameterLength = ValueFlow::valueFlowGetStrLength(parameters[inputArgNr], settings.library); handleNextParameter = true; break; diff --git a/lib/checkclass.cpp b/lib/checkclass.cpp index b610e963d76..e04df8b5748 100644 --- a/lib/checkclass.cpp +++ b/lib/checkclass.cpp @@ -1059,7 +1059,7 @@ void CheckClassImpl::initializeVarList(const Function &func, std::listnext(); if (tok2->str() == "&") tok2 = tok2->next(); - if (isVariableChangedByFunctionCall(tok2, tok2->strAt(-1) == "&", tok2->varId(), mSettings, nullptr)) + if (isVariableChangedByFunctionCall(tok2, tok2->strAt(-1) == "&", tok2->varId(), mSettings.library, nullptr)) assignVar(usage, tok2->varId()); } } diff --git a/lib/checkio.cpp b/lib/checkio.cpp index c753dd80739..3d82bdb796a 100644 --- a/lib/checkio.cpp +++ b/lib/checkio.cpp @@ -875,7 +875,7 @@ void CheckIOImpl::checkFormatString(const Token * const tok, // Perform type checks ArgumentInfo argInfo(argListTok, mSettings, mTokenizer->isCPP()); - if ((argInfo.typeToken && !argInfo.isLibraryType(mSettings)) || *i == ']') { + if ((argInfo.typeToken && !argInfo.isLibraryType(mSettings.library)) || *i == ']') { if (scan) { std::string specifier; bool done = false; @@ -1877,9 +1877,9 @@ bool CheckIOImpl::ArgumentInfo::isKnownType() const return typeToken->isStandardType() || Token::Match(typeToken, "std :: string|wstring"); } -bool CheckIOImpl::ArgumentInfo::isLibraryType(const Settings &settings) const +bool CheckIOImpl::ArgumentInfo::isLibraryType(const Library &library) const { - return typeToken && typeToken->isStandardType() && settings.library.podtype(typeToken->str()); + return typeToken && typeToken->isStandardType() && library.podtype(typeToken->str()); } void CheckIOImpl::wrongPrintfScanfArgumentsError(const Token* tok, diff --git a/lib/checkio.h b/lib/checkio.h index ae0ea242dab..06c6d8d973b 100644 --- a/lib/checkio.h +++ b/lib/checkio.h @@ -35,6 +35,7 @@ class Token; class Variable; class ErrorLogger; class Tokenizer; +class Library; enum class Severity : std::uint8_t; /// @addtogroup Checks @@ -101,7 +102,7 @@ class CPPCHECKLIB CheckIOImpl : public CheckImpl { bool isKnownType() const; bool isStdVectorOrString(); bool isStdContainer(const Token *tok); - bool isLibraryType(const Settings &settings) const; + bool isLibraryType(const Library &library) const; const Variable* variableInfo{}; const Token* typeToken{}; diff --git a/lib/checkleakautovar.cpp b/lib/checkleakautovar.cpp index 9049d56e7ff..e8271f9eed0 100644 --- a/lib/checkleakautovar.cpp +++ b/lib/checkleakautovar.cpp @@ -267,7 +267,7 @@ static const Token * isFunctionCall(const Token * nameToken) return nullptr; } -static const Token* getOutparamAllocation(const Token* tok, const Settings& settings) +static const Token* getOutparamAllocation(const Token* tok, const Library& library) { if (!tok) return nullptr; @@ -275,16 +275,16 @@ static const Token* getOutparamAllocation(const Token* tok, const Settings& sett const Token* ftok = getTokenArgumentFunction(tok, argn); if (!ftok) return nullptr; - if (const Library::AllocFunc* allocFunc = settings.library.getAllocFuncInfo(ftok)) { + if (const Library::AllocFunc* allocFunc = library.getAllocFuncInfo(ftok)) { if (allocFunc->arg == argn + 1) return ftok; } return nullptr; } -static const Token* getReturnValueFromOutparamAlloc(const Token* alloc, const Settings& settings) +static const Token* getReturnValueFromOutparamAlloc(const Token* alloc, const Library& library) { - if (const Token* ftok = getOutparamAllocation(alloc, settings)) { + if (const Token* ftok = getOutparamAllocation(alloc, library)) { if (Token::simpleMatch(ftok->astParent()->astParent(), "=")) return ftok->next()->astParent()->astOperand1(); } @@ -623,7 +623,7 @@ bool CheckLeakAutoVarImpl::checkScope(const Token * const startToken, if (std::any_of(varInfo1.alloctype.begin(), varInfo1.alloctype.end(), [&](const std::pair& info) { if (info.second.status != VarInfo::ALLOC) return false; - const Token* ret = getReturnValueFromOutparamAlloc(info.second.allocTok, mSettings); + const Token* ret = getReturnValueFromOutparamAlloc(info.second.allocTok, mSettings.library); return ret && vartok && ret->varId() && ret->varId() == vartok->varId(); })) { varInfo1.clear(); @@ -896,7 +896,7 @@ const Token * CheckLeakAutoVarImpl::checkTokenInsideExpression(const Token * con if (var != varInfo.alloctype.end()) { bool unknown = false; if (var->second.status == VarInfo::DEALLOC && tok->valueType() && tok->valueType()->pointer && - CheckNullPointerImpl::isPointerDeRef(tok, unknown, mSettings, /*checkNullArg*/ false) && !unknown) { + CheckNullPointerImpl::isPointerDeRef(tok, unknown, mSettings.library, /*checkNullArg*/ false) && !unknown) { deallocUseError(tok, tok->str()); } else if (Token::simpleMatch(tok->tokAt(-2), "= &")) { varInfo.erase(tok->varId()); @@ -1232,7 +1232,7 @@ void CheckLeakAutoVarImpl::ret(const Token *tok, VarInfo &varInfo, const bool is // don't warn when returning after checking return value of outparam allocation const Token* outparamFunc{}; if ((tok->scope()->type == ScopeType::eIf || tok->scope()->type== ScopeType::eElse) && - (outparamFunc = getOutparamAllocation(it->second.allocTok, mSettings))) { + (outparamFunc = getOutparamAllocation(it->second.allocTok, mSettings.library))) { const Scope* scope = tok->scope(); if (scope->type == ScopeType::eElse) { scope = scope->bodyStart->tokAt(-2)->scope(); diff --git a/lib/checknullpointer.cpp b/lib/checknullpointer.cpp index ac56f19eb09..5c2e64e9a6c 100644 --- a/lib/checknullpointer.cpp +++ b/lib/checknullpointer.cpp @@ -130,10 +130,10 @@ namespace { bool CheckNullPointerImpl::isPointerDeRef(const Token *tok, bool &unknown) const { - return isPointerDeRef(tok, unknown, mSettings); + return isPointerDeRef(tok, unknown, mSettings.library); } -bool CheckNullPointerImpl::isPointerDeRef(const Token *tok, bool &unknown, const Settings &settings, bool checkNullArg) +bool CheckNullPointerImpl::isPointerDeRef(const Token *tok, bool &unknown, const Library &library, bool checkNullArg) { unknown = false; @@ -146,7 +146,7 @@ bool CheckNullPointerImpl::isPointerDeRef(const Token *tok, bool &unknown, const ftok = ftok->previous(); } if (ftok && ftok->previous()) { - const std::list varlist = CheckNullPointerImpl::parseFunctionCall(*ftok->previous(), settings.library, checkNullArg); + const std::list varlist = CheckNullPointerImpl::parseFunctionCall(*ftok->previous(), library, checkNullArg); if (std::find(varlist.cbegin(), varlist.cend(), tok) != varlist.cend()) { return true; } @@ -161,7 +161,7 @@ bool CheckNullPointerImpl::isPointerDeRef(const Token *tok, bool &unknown, const return false; const bool addressOf = parent->astParent() && parent->astParent()->str() == "&"; if (parent->str() == "." && astIsRHS(tok)) - return isPointerDeRef(parent, unknown, settings); + return isPointerDeRef(parent, unknown, library); const bool firstOperand = parent->astOperand1() == tok; parent = astParentSkipParens(tok); if (!parent) @@ -298,7 +298,7 @@ void CheckNullPointerImpl::nullPointerByDeRefAndCheck() // Pointer dereference. bool unknown = false; - if (!CheckNullPointerImpl::isPointerDeRef(tok, unknown, mSettings)) { + if (!CheckNullPointerImpl::isPointerDeRef(tok, unknown, mSettings.library)) { if (unknown) nullPointerError(tok, tok->expressionString(), value, true); continue; @@ -578,7 +578,7 @@ static bool isUnsafeUsage(const Settings &settings, const Token *vartok, CTU::Fi { (void)value; bool unknown = false; - return CheckNullPointerImpl::isPointerDeRef(vartok, unknown, settings); + return CheckNullPointerImpl::isPointerDeRef(vartok, unknown, settings.library); } // a Clang-built executable will crash when using the anonymous MyFileInfo later on - so put it in a unique namespace for now diff --git a/lib/checknullpointer.h b/lib/checknullpointer.h index bc494dad70f..ed6a617d81a 100644 --- a/lib/checknullpointer.h +++ b/lib/checknullpointer.h @@ -92,7 +92,7 @@ class CPPCHECKLIB CheckNullPointerImpl : public CheckImpl { */ bool isPointerDeRef(const Token *tok, bool &unknown) const; - static bool isPointerDeRef(const Token *tok, bool &unknown, const Settings &settings, bool checkNullArg = true); + static bool isPointerDeRef(const Token *tok, bool &unknown, const Library &library, bool checkNullArg = true); /** * @brief parse a function call and extract information about variable usage diff --git a/lib/checkother.cpp b/lib/checkother.cpp index 9dee8df7810..51124c45d1c 100644 --- a/lib/checkother.cpp +++ b/lib/checkother.cpp @@ -1793,7 +1793,7 @@ void CheckOtherImpl::checkConstVariable() continue; } else if (const Token* ftok = getTokenArgumentFunction(tok, argn)) { bool inconclusive{}; - if (var->valueType() && !isVariableChangedByFunctionCall(ftok, var->valueType()->pointer, var->declarationId(), mSettings, &inconclusive) && !inconclusive) + if (var->valueType() && !isVariableChangedByFunctionCall(ftok, var->valueType()->pointer, var->declarationId(), mSettings.library, &inconclusive) && !inconclusive) continue; } usedInAssignment = true; @@ -1989,7 +1989,7 @@ void CheckOtherImpl::checkConstPointer() continue; else if (const Token* ftok = getTokenArgumentFunction(parent, argn)) { bool inconclusive{}; - if (!isVariableChangedByFunctionCall(ftok->next(), vt->pointer, var->declarationId(), mSettings, &inconclusive) && !inconclusive) + if (!isVariableChangedByFunctionCall(ftok->next(), vt->pointer, var->declarationId(), mSettings.library, &inconclusive) && !inconclusive) continue; } } else { @@ -2014,7 +2014,7 @@ void CheckOtherImpl::checkConstPointer() const Variable* argVar = ftok->function()->getArgumentVar(argn); if (argVar && argVar->valueType() && argVar->valueType()->isConst(vt->pointer)) { bool inconclusive{}; - if (!isVariableChangedByFunctionCall(ftok, vt->pointer, var->declarationId(), mSettings, &inconclusive) && !inconclusive) + if (!isVariableChangedByFunctionCall(ftok, vt->pointer, var->declarationId(), mSettings.library, &inconclusive) && !inconclusive) continue; } } @@ -3981,7 +3981,7 @@ void CheckOtherImpl::checkAccessOfMovedVariable() if (usage == ExprUsage::Used) accessOfMoved = true; if (usage == ExprUsage::PassedByReference) - accessOfMoved = !isVariableChangedByFunctionCall(tok, 0, mSettings, &inconclusive); + accessOfMoved = !isVariableChangedByFunctionCall(tok, 0, mSettings.library, &inconclusive); else if (usage == ExprUsage::Inconclusive) inconclusive = true; } diff --git a/lib/checkstl.cpp b/lib/checkstl.cpp index 4c3b51ac5db..743ac8a3cb4 100644 --- a/lib/checkstl.cpp +++ b/lib/checkstl.cpp @@ -2552,7 +2552,7 @@ void CheckStlImpl::checkDereferenceInvalidIterator2() emptyAdvance = tok->astParent(); } } - if (!CheckNullPointerImpl::isPointerDeRef(tok, unknown, mSettings) && !isInvalidIterator && !emptyAdvance) { + if (!CheckNullPointerImpl::isPointerDeRef(tok, unknown, mSettings.library) && !isInvalidIterator && !emptyAdvance) { if (!unknown) continue; inconclusive = true; @@ -2895,7 +2895,7 @@ namespace { int n = 1 + (astIsPointer(tok) ? 1 : 0); for (int i = 0; i < n; i++) { bool inconclusive = false; - if (isVariableChangedByFunctionCall(tok, i, mSettings, &inconclusive)) + if (isVariableChangedByFunctionCall(tok, i, mSettings.library, &inconclusive)) return true; if (inconclusive) return true; diff --git a/lib/checkuninitvar.cpp b/lib/checkuninitvar.cpp index 6bc2a86b8a5..d05ea3fbd28 100644 --- a/lib/checkuninitvar.cpp +++ b/lib/checkuninitvar.cpp @@ -1664,7 +1664,7 @@ void CheckUninitVarImpl::valueFlowUninit() if (yield != Library::Container::Yield::AT_INDEX && yield != Library::Container::Yield::ITEM) continue; } - const bool deref = CheckNullPointerImpl::isPointerDeRef(tok, unknown, mSettings); + const bool deref = CheckNullPointerImpl::isPointerDeRef(tok, unknown, mSettings.library); uninitderef = deref && v->indirect == 0; const bool isleaf = isLeafDot(tok) || uninitderef; if (!isleaf && Token::Match(tok->astParent(), ". %name%") && @@ -1681,7 +1681,7 @@ void CheckUninitVarImpl::valueFlowUninit() isVariableChanged(tok, v->indirect, mSettings)) continue; bool inconclusive = false; - if (isVariableChangedByFunctionCall(tok, v->indirect, mSettings, &inconclusive) || inconclusive) + if (isVariableChangedByFunctionCall(tok, v->indirect, mSettings.library, &inconclusive) || inconclusive) continue; } uninitvarError(tok, *v); diff --git a/lib/checkunusedfunctions.cpp b/lib/checkunusedfunctions.cpp index 5965de1aada..4177a13a013 100644 --- a/lib/checkunusedfunctions.cpp +++ b/lib/checkunusedfunctions.cpp @@ -65,11 +65,11 @@ static bool isRecursiveCall(const Token* ftok) return ftok->function() && ftok->function() == Scope::nestedInFunction(ftok->scope()); } -void CheckUnusedFunctions::parseTokens(const Tokenizer &tokenizer, const Settings &settings) +void CheckUnusedFunctions::parseTokens(const Tokenizer &tokenizer, const Library &library) { const char * const FileName = tokenizer.list.getFiles().front().c_str(); - const bool doMarkup = settings.library.markupFile(FileName); + const bool doMarkup = library.markupFile(FileName); // Function declarations.. if (!doMarkup) { @@ -139,8 +139,8 @@ void CheckUnusedFunctions::parseTokens(const Tokenizer &tokenizer, const Setting lambdaEndToken = findLambdaEndToken(tok); // parsing of library code to find called functions - if (settings.library.isexecutableblock(FileName, tok->str())) { - const Token * markupVarToken = tok->tokAt(settings.library.blockstartoffset(FileName)); + if (library.isexecutableblock(FileName, tok->str())) { + const Token * markupVarToken = tok->tokAt(library.blockstartoffset(FileName)); // not found if (!markupVarToken) continue; @@ -148,12 +148,12 @@ void CheckUnusedFunctions::parseTokens(const Tokenizer &tokenizer, const Setting bool start = true; // find all function calls in library code (starts with '(', not if or while etc) while ((scope || start) && markupVarToken) { - if (markupVarToken->str() == settings.library.blockstart(FileName)) { + if (markupVarToken->str() == library.blockstart(FileName)) { scope++; start = false; - } else if (markupVarToken->str() == settings.library.blockend(FileName)) + } else if (markupVarToken->str() == library.blockend(FileName)) scope--; - else if (!settings.library.iskeyword(FileName, markupVarToken->str())) { + else if (!library.iskeyword(FileName, markupVarToken->str())) { mFunctionCalls.insert(markupVarToken->str()); if (mFunctions.find(markupVarToken->str()) != mFunctions.end()) mFunctions[markupVarToken->str()].usedOtherFile = true; @@ -171,10 +171,10 @@ void CheckUnusedFunctions::parseTokens(const Tokenizer &tokenizer, const Setting } if (!doMarkup // only check source files - && settings.library.isexporter(tok->str()) && tok->next() != nullptr) { + && library.isexporter(tok->str()) && tok->next() != nullptr) { const Token * propToken = tok->next(); while (propToken && propToken->str() != ")") { - if (settings.library.isexportedprefix(tok->str(), propToken->str())) { + if (library.isexportedprefix(tok->str(), propToken->str())) { const Token* nextPropToken = propToken->next(); const std::string& value = nextPropToken->str(); if (mFunctions.find(value) != mFunctions.end()) { @@ -182,7 +182,7 @@ void CheckUnusedFunctions::parseTokens(const Tokenizer &tokenizer, const Setting } mFunctionCalls.insert(value); } - if (settings.library.isexportedsuffix(tok->str(), propToken->str())) { + if (library.isexportedsuffix(tok->str(), propToken->str())) { const Token* prevPropToken = propToken->previous(); const std::string& value = prevPropToken->str(); if (value != ")" && mFunctions.find(value) != mFunctions.end()) { @@ -194,7 +194,7 @@ void CheckUnusedFunctions::parseTokens(const Tokenizer &tokenizer, const Setting } } - if (doMarkup && settings.library.isimporter(FileName, tok->str()) && tok->next()) { + if (doMarkup && library.isimporter(FileName, tok->str()) && tok->next()) { const Token * propToken = tok->next(); if (propToken->next()) { propToken = propToken->next(); @@ -210,8 +210,8 @@ void CheckUnusedFunctions::parseTokens(const Tokenizer &tokenizer, const Setting } } - if (settings.library.isreflection(tok->str())) { - const int argIndex = settings.library.reflectionArgument(tok->str()); + if (library.isreflection(tok->str())) { + const int argIndex = library.reflectionArgument(tok->str()); if (argIndex >= 0) { const Token * funcToken = tok->next(); int index = 0; @@ -366,7 +366,7 @@ void CheckUnusedFunctions::staticFunctionError(ErrorLogger& errorLogger, errorLogger.reportErr(errmsg); \ } while (false) -bool CheckUnusedFunctions::check(const Settings& settings, ErrorLogger& errorLogger) const +bool CheckUnusedFunctions::check(const Library& library, ErrorLogger& errorLogger) const { logChecker("CheckUnusedFunctions::check"); // unusedFunction @@ -379,7 +379,7 @@ bool CheckUnusedFunctions::check(const Settings& settings, ErrorLogger& errorLog const FunctionUsage &func = it->second; if (func.usedOtherFile || func.filename.empty()) continue; - if (settings.library.isentrypoint(it->first)) + if (library.isentrypoint(it->first)) continue; if (!func.usedSameFile) { if (isOperatorFunction(it->first)) diff --git a/lib/checkunusedfunctions.h b/lib/checkunusedfunctions.h index 5c5b369c194..1b560cfb7cb 100644 --- a/lib/checkunusedfunctions.h +++ b/lib/checkunusedfunctions.h @@ -33,6 +33,7 @@ class ErrorLogger; class Function; class Settings; class Tokenizer; +class Library; /** @brief Check for functions never called */ /// @{ @@ -44,7 +45,7 @@ class CPPCHECKLIB CheckUnusedFunctions { // Parse current tokens and determine.. // * Check what functions are used // * What functions are declared - void parseTokens(const Tokenizer &tokenizer, const Settings &settings); + void parseTokens(const Tokenizer &tokenizer, const Library &library); std::string analyzerInfo(const Tokenizer &tokenizer) const; @@ -56,7 +57,7 @@ class CPPCHECKLIB CheckUnusedFunctions { } // Return true if an error is reported. - bool check(const Settings& settings, ErrorLogger& errorLogger) const; + bool check(const Library& library, ErrorLogger& errorLogger) const; void updateFunctionData(const CheckUnusedFunctions& checkUnusedFunctions); diff --git a/lib/cppcheck.cpp b/lib/cppcheck.cpp index 9a3e2e2a053..50f7fa36e80 100644 --- a/lib/cppcheck.cpp +++ b/lib/cppcheck.cpp @@ -977,7 +977,7 @@ unsigned int CppCheck::checkInternal(const FileWithDetails& file, const std::str tokenlist.createTokens(std::move(tokens)); // this is not a real source file - we just want to tokenize it. treat it as C anyways as the language needs to be determined. Tokenizer tokenizer(std::move(tokenlist), mErrorLogger); - mUnusedFunctionsCheck->parseTokens(tokenizer, mSettings); + mUnusedFunctionsCheck->parseTokens(tokenizer, mSettings.library); if (analyzerInformation) { mLogger->setAnalyzerInfo(nullptr); @@ -1358,10 +1358,10 @@ void CppCheck::checkNormalTokens(const Tokenizer &tokenizer, AnalyzerInformation } if (mSettings.checks.isEnabled(Checks::unusedFunction) && !mSettings.buildDir.empty()) { - unusedFunctionsChecker.parseTokens(tokenizer, mSettings); + unusedFunctionsChecker.parseTokens(tokenizer, mSettings.library); } if (mUnusedFunctionsCheck && mSettings.useSingleJob() && mSettings.buildDir.empty()) { - mUnusedFunctionsCheck->parseTokens(tokenizer, mSettings); + mUnusedFunctionsCheck->parseTokens(tokenizer, mSettings.library); } if (mSettings.clang) { @@ -1830,7 +1830,7 @@ bool CppCheck::analyseWholeProgram() } if (mUnusedFunctionsCheck) - errors |= mUnusedFunctionsCheck->check(mSettings, mErrorLogger); + errors |= mUnusedFunctionsCheck->check(mSettings.library, mErrorLogger); return errors && (mLogger->exitcode() > 0); } @@ -1841,7 +1841,7 @@ unsigned int CppCheck::analyseWholeProgram(const std::string &buildDir, const st CheckUnusedFunctions::analyseWholeProgram(mSettings, mErrorLogger, buildDir); if (mUnusedFunctionsCheck) - mUnusedFunctionsCheck->check(mSettings, mErrorLogger); + mUnusedFunctionsCheck->check(mSettings.library, mErrorLogger); if (Settings::unusedFunctionOnly()) return mLogger->exitcode(); diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index 7d25166bf99..ef81fc772ac 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -6183,7 +6183,7 @@ static bool isContainerSizeChangedByFunction(const Token* tok, } bool inconclusive = false; - const bool isChanged = isVariableChangedByFunctionCall(tok, indirect, settings, &inconclusive); + const bool isChanged = isVariableChangedByFunctionCall(tok, indirect, settings.library, &inconclusive); return (isChanged || inconclusive); } @@ -6850,17 +6850,17 @@ static void valueFlowContainerSize(const TokenList& tokenlist, } else if (tok->str() == "+=" && astIsContainer(tok->astOperand1())) { const Token* containerTok = tok->astOperand1(); const Token* valueTok = tok->astOperand2(); - const MathLib::bigint size = ValueFlow::valueFlowGetStrLength(valueTok, settings); + const MathLib::bigint size = ValueFlow::valueFlowGetStrLength(valueTok, settings.library); forwardMinimumContainerSize(size, tok, containerTok); } else if (tok->str() == "=" && Token::simpleMatch(tok->astOperand2(), "+") && astIsContainerString(tok)) { const Token* tok2 = tok->astOperand2(); MathLib::bigint size = 0; while (Token::simpleMatch(tok2, "+") && tok2->astOperand2()) { - size += ValueFlow::valueFlowGetStrLength(tok2->astOperand2(), settings); + size += ValueFlow::valueFlowGetStrLength(tok2->astOperand2(), settings.library); tok2 = tok2->astOperand1(); } - size += ValueFlow::valueFlowGetStrLength(tok2, settings); + size += ValueFlow::valueFlowGetStrLength(tok2, settings.library); forwardMinimumContainerSize(size, tok, tok->astOperand1()); } } diff --git a/lib/vf_analyzers.cpp b/lib/vf_analyzers.cpp index 10efc6d6f39..44c86cbc2b7 100644 --- a/lib/vf_analyzers.cpp +++ b/lib/vf_analyzers.cpp @@ -222,7 +222,7 @@ struct ValueFlowAnalyzer : Analyzer { return Action::Read; } bool inconclusive = false; - if (isVariableChangedByFunctionCall(tok, getIndirect(tok), getSettings(), &inconclusive)) + if (isVariableChangedByFunctionCall(tok, getIndirect(tok), getSettings().library, &inconclusive)) return Action::Read | Action::Invalid; if (inconclusive) return Action::Read | Action::Inconclusive; @@ -1569,7 +1569,7 @@ struct ContainerExpressionAnalyzer : ExpressionAnalyzer { case Library::Container::Action::APPEND: { std::vector args = getArguments(tok->astParent()->tokAt(2)); if (args.size() == 1) // TODO: handle overloads - n = ValueFlow::valueFlowGetStrLength(tok->astParent()->tokAt(3), settings); + n = ValueFlow::valueFlowGetStrLength(tok->astParent()->tokAt(3), settings.library); if (n == 0) // TODO: handle known empty append val->setPossible(); break; diff --git a/lib/vf_common.cpp b/lib/vf_common.cpp index b4bd756d05e..ef48423f38a 100644 --- a/lib/vf_common.cpp +++ b/lib/vf_common.cpp @@ -398,7 +398,7 @@ namespace ValueFlow v.debugPath.emplace_back(tok, std::move(s)); } - MathLib::bigint valueFlowGetStrLength(const Token* tok, const Settings& settings) + MathLib::bigint valueFlowGetStrLength(const Token* tok, const Library& library) { if (tok->tokType() == Token::eString) return Token::getStrLength(tok); @@ -408,10 +408,10 @@ namespace ValueFlow return v->intvalue; if (const Value* v = tok->getKnownValue(Value::ValueType::TOK)) { if (v->tokvalue != tok) - return valueFlowGetStrLength(v->tokvalue, settings); + return valueFlowGetStrLength(v->tokvalue, library); } - if (const Token* cont = settings.library.getContainerFromYield(tok, Library::Container::Yield::BUFFER_NT)) - return valueFlowGetStrLength(cont, settings); + if (const Token* cont = library.getContainerFromYield(tok, Library::Container::Yield::BUFFER_NT)) + return valueFlowGetStrLength(cont, library); return 0; } } diff --git a/lib/vf_common.h b/lib/vf_common.h index 9859955cbfe..aca438a0dff 100644 --- a/lib/vf_common.h +++ b/lib/vf_common.h @@ -30,6 +30,7 @@ class Token; class Settings; class Platform; +class Library; namespace ValueFlow { @@ -53,7 +54,7 @@ namespace ValueFlow const Token* tok, SourceLocation local = SourceLocation::current()); - MathLib::bigint valueFlowGetStrLength(const Token* tok, const Settings& settings); + MathLib::bigint valueFlowGetStrLength(const Token* tok, const Library& library); } #endif // vfCommonH diff --git a/test/testastutils.cpp b/test/testastutils.cpp index 904ea92b466..6a6e0624587 100644 --- a/test/testastutils.cpp +++ b/test/testastutils.cpp @@ -259,7 +259,7 @@ class TestAstUtils : public TestFixture { const Token * const argtok = Token::findmatch(tokenizer.tokens(), pattern); ASSERT_LOC(argtok, file, line); int indirect = (argtok->variable() && argtok->variable()->isArray()); - return (isVariableChangedByFunctionCall)(argtok, indirect, settingsDefault, inconclusive); + return (isVariableChangedByFunctionCall)(argtok, indirect, settingsDefault.library, inconclusive); } void isVariableChangedByFunctionCallTest() { diff --git a/test/testunusedfunctions.cpp b/test/testunusedfunctions.cpp index 3e78b119012..938a1394394 100644 --- a/test/testunusedfunctions.cpp +++ b/test/testunusedfunctions.cpp @@ -111,8 +111,8 @@ class TestUnusedFunctions : public TestFixture { // Check for unused functions.. CheckUnusedFunctions checkUnusedFunctions; - checkUnusedFunctions.parseTokens(tokenizer, settings1); - (checkUnusedFunctions.check)(settings1, *this); // TODO: check result + checkUnusedFunctions.parseTokens(tokenizer, settings1.library); + (checkUnusedFunctions.check)(settings1.library, *this); // TODO: check result } // TODO: get rid of this @@ -123,8 +123,8 @@ class TestUnusedFunctions : public TestFixture { // Check for unused functions.. CheckUnusedFunctions checkUnusedFunctions; - checkUnusedFunctions.parseTokens(tokenizer, settings); - (checkUnusedFunctions.check)(settings, *this); // TODO: check result + checkUnusedFunctions.parseTokens(tokenizer, settings.library); + (checkUnusedFunctions.check)(settings.library, *this); // TODO: check result } void incondition() { @@ -602,11 +602,11 @@ class TestUnusedFunctions : public TestFixture { SimpleTokenizer tokenizer{settings, *this, fname}; ASSERT(tokenizer.tokenize(code)); - c.parseTokens(tokenizer, settings); + c.parseTokens(tokenizer, settings.library); } // Check for unused functions.. - (c.check)(settings, *this); // TODO: check result + (c.check)(settings.library, *this); // TODO: check result ASSERT_EQUALS("[test1.cpp:1:13]: (style) The function 'f' is never used. [unusedFunction]\n", errout_str()); } From e039c081179b135089469c40ba78ef9d9b37c523 Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Fri, 3 Jul 2026 18:45:31 +0200 Subject: [PATCH 066/165] Fix #14887 FP objectIndex with pointer to array member (#8689) --- lib/checkbufferoverrun.cpp | 8 ++++++-- test/testbufferoverrun.cpp | 20 ++++++++++++++++++++ 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/lib/checkbufferoverrun.cpp b/lib/checkbufferoverrun.cpp index 81b6653d348..c72db22a68c 100644 --- a/lib/checkbufferoverrun.cpp +++ b/lib/checkbufferoverrun.cpp @@ -1088,8 +1088,12 @@ void CheckBufferOverrunImpl::objectIndex() for (const ValueFlow::Value& v:values) { if (v.lifetimeKind != ValueFlow::Value::LifetimeKind::Address && v.lifetimeKind != ValueFlow::Value::LifetimeKind::Object) continue; - const Token* varTok = nextAfterAstRightmostLeaf(v.tokvalue->astParent()); - varTok = varTok ? varTok->previous() : nullptr; + const Token* varTok = v.tokvalue; + if (Token::simpleMatch(varTok->astParent(), ".")) { + varTok = varTok->astParent(); + while (Token::simpleMatch(varTok, ".")) + varTok = varTok->astOperand2(); + } const Variable *var = varTok ? varTok->variable() : nullptr; if (!var) continue; diff --git a/test/testbufferoverrun.cpp b/test/testbufferoverrun.cpp index e51a1708389..387a0eeea8a 100644 --- a/test/testbufferoverrun.cpp +++ b/test/testbufferoverrun.cpp @@ -5860,6 +5860,26 @@ class TestBufferOverrun : public TestFixture { ASSERT_EQUALS("[test.cpp:7:20] -> [test.cpp:9:12]: (error) The address of variable 's.a' is accessed at non-zero index. [objectIndex]\n" "[test.cpp:7:20] -> [test.cpp:10:12]: (error) The address of variable 's.a' is accessed at non-zero index. [objectIndex]\n", errout_str()); + + check("const int N = 12;\n" // #14887 + "struct S {\n" + " void f() const;\n" + " int a[N];\n" + "};\n" + "struct T {\n" + " void f() const;\n" + " S s;\n" + "};\n" + "int g(const int* p) { return p[5]; }\n" + "void S::f() const {\n" + " const int* q = a;\n" + " g(q);\n" + "}\n" + "void T::f() const {\n" + " const int* q = s.a;\n" + " g(q);\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); } void checkPipeParameterSize() { // #3521 From bcd74c735e745f7b1bd8d5362e91dd748acbe2b3 Mon Sep 17 00:00:00 2001 From: Paul Fultz II Date: Sat, 4 Jul 2026 06:29:46 -0500 Subject: [PATCH 067/165] Partial fix for 9049: False negative: uninitialized variable with nested ifs (#8680) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This fixes the case for this: ```cpp unsigned int g(); void f(bool a) { unsigned int dimensions = 0; bool mightBeLarger; if (a) { dimensions = g(); if (dimensions >= 1) mightBeLarger = false; } else { mightBeLarger = false; } if (dimensions == 1) return; if (!mightBeLarger) {} } ``` Which doesnt use a compund condition `dimensions >= 1 && b)` and it also requires complete variables and functions. The compund condition could be handled in the future by forking within the condition, so `if(a && b) { ... }` can be treated as `if(a) { if(b) { ... }}`. Here is a summary of the changes: 1. Fork-based condition handling — lib/forwardanalyzer.cpp (the largest change) - When a condition can't be resolved, the traversal now forks: the then-branch is walked by a separate ForwardTraversal, in analyze-only mode when the value can't actually flow into it (opaque/correlated conditions like if (f(x))), so the branch's effect is tracked but nothing is reported there. - Branch breaks are deferred: if the else kills the value on the main path, the then-fork can still carry it forward. - Escapes the traversal didn't flag (e.g. unknown noreturn calls) are detected via isEscapeScope, and exit/abort are now recognized as escape functions (lib/astutils.cpp). 2. Program-state anchoring at block boundaries — lib/vf_analyzers.cpp + lib/analyzer.h - assume() now anchors the assumed state at the block's end (not the condition) when control is leaving an already-traversed branch. This keeps an assumption on a variable modified inside the block (e.g. a nested if narrowing a value computed there) from being discarded as "modified" once control leaves the block. - New Assume::Pending flag marks the pre-traversal assume (branch walked separately) so it doesn't record premature boundary state. - ProgramMemoryState::assume gained an optional origin parameter so the anchor point can be overridden. 3. vars-aware execute — lib/programmemory.cpp / .h - execute/conditionIsTrue/conditionIsFalse now take the tracked values (vars). A tracked value is the authoritative current value of its expression (returned and written back into the program memory), and any cached compound that depends on a tracked value is re-evaluated instead of served stale (getTrackedValue / dependsOnTrackedValue). - The per-assignment substitution was removed from fillProgramMemoryFromAssignments and now lives entirely in execute so it can be used for all executions. --------- Co-authored-by: Your Name --- lib/analyzer.h | 10 +- lib/astutils.cpp | 2 + lib/forwardanalyzer.cpp | 225 ++++++++++++++++++++----------------- lib/programmemory.cpp | 209 +++++++++++++++++++++++----------- lib/programmemory.h | 38 ++++++- lib/settings.cpp | 4 + lib/settings.h | 9 ++ lib/vf_analyzers.cpp | 61 ++++++---- test/testautovariables.cpp | 4 +- test/testcondition.cpp | 24 ++++ test/testnullpointer.cpp | 5 + test/testother.cpp | 5 +- test/teststl.cpp | 4 +- test/testuninitvar.cpp | 46 +++++++- test/testvalueflow.cpp | 75 ++++++++++++- 15 files changed, 514 insertions(+), 207 deletions(-) diff --git a/lib/analyzer.h b/lib/analyzer.h index a4546eb7dc4..9b87310530f 100644 --- a/lib/analyzer.h +++ b/lib/analyzer.h @@ -153,9 +153,13 @@ struct Analyzer { struct Assume { enum Flags : std::uint8_t { None = 0, - Quiet = (1 << 0), - Absolute = (1 << 1), - ContainerEmpty = (1 << 2), + Quiet = (1u << 0), + Absolute = (1u << 1), + ContainerEmpty = (1u << 2), + // The branch this condition guards is not traversed yet (a separate path walks it), so + // the assume must not record the program state at the branch boundaries - they would be + // premature. When unset, the branch has been traversed and control is leaving it. + Pending = (1u << 3), }; }; diff --git a/lib/astutils.cpp b/lib/astutils.cpp index a6fe2573f08..c433036cfcc 100644 --- a/lib/astutils.cpp +++ b/lib/astutils.cpp @@ -2230,6 +2230,8 @@ bool isEscapeFunction(const Token* ftok, const Library& library) { if (!Token::Match(ftok, "%name% (")) return false; + if (Token::Match(ftok, "exit|abort")) + return true; const Function* function = ftok->function(); if (function) { if (function->isEscapeFunction()) diff --git a/lib/forwardanalyzer.cpp b/lib/forwardanalyzer.cpp index 670db0b1090..727c64b076d 100644 --- a/lib/forwardanalyzer.cpp +++ b/lib/forwardanalyzer.cpp @@ -59,6 +59,10 @@ namespace { Analyzer::Terminate terminate = Analyzer::Terminate::None; std::vector loopEnds; int branchCount = 0; + // Nested condition-fork depth on this lineage (copied by fork()); bounds the fan-out. + int forkDepth = 0; + // Total forks of the traversal (shared via the fork() copy); backstop past the depth bound. + std::shared_ptr forkBudget = std::make_shared(0); Progress Break(Analyzer::Terminate t = Analyzer::Terminate::None) { if ((!analyzeOnly || analyzeTerminate) && t != Analyzer::Terminate::None) @@ -73,7 +77,6 @@ namespace { bool check = false; bool escape = false; bool escapeUnknown = false; - bool active = false; bool isEscape() const { return escape || escapeUnknown; } @@ -89,6 +92,9 @@ namespace { bool isDead() const { return action.isModified() || action.isInconclusive() || isEscape(); } + bool hasGoto() const { + return endBlock ? ForwardTraversal::hasGoto(endBlock) : false; + } }; bool stopUpdates() { @@ -348,18 +354,6 @@ namespace { return Token::findmatch(endBlock->link(), "goto|break", endBlock); } - bool hasInnerReturnScope(const Token* start, const Token* end) const { - for (const Token* tok=start; tok != end; tok = tok->previous()) { - if (Token::simpleMatch(tok, "}")) { - const Token* ftok = nullptr; - const bool r = isReturnScope(tok, settings.library, &ftok); - if (r) - return true; - } - } - return false; - } - bool isEscapeScope(const Token* endBlock, bool& unknown) const { const Token* ftok = nullptr; const bool r = isReturnScope(endBlock, settings.library, &ftok); @@ -383,30 +377,34 @@ namespace { return a; } - bool checkBranch(Branch& branch) const { - Analyzer::Action a = analyzeScope(branch.endBlock); - branch.action = a; - std::vector ft1 = tryForkUpdateScope(branch.endBlock, a.isModified()); - const bool bail = hasGoto(branch.endBlock); - if (!a.isModified() && !bail) { - if (ft1.empty()) { - // Traverse into the branch to see if there is a conditional escape - if (!branch.escape && hasInnerReturnScope(branch.endBlock->previous(), branch.endBlock->link())) { - ForwardTraversal ft2 = fork(true); - ft2.updateScope(branch.endBlock); - if (ft2.terminate == Analyzer::Terminate::Escape) { - branch.escape = true; - branch.escapeUnknown = false; - } - } - } else { - if (ft1.front().terminate == Analyzer::Terminate::Escape) { - branch.escape = true; - branch.escapeUnknown = false; - } + Progress updateBranch(Branch& branch, int depth) + { + // Save and reset actions + Analyzer::Action prevActions = actions; + actions = Analyzer::Action::None; + Progress p = updateRange(branch.endBlock->link(), branch.endBlock, depth); + branch.action |= actions; + // Restore actions + actions |= prevActions; + + if (terminate == Analyzer::Terminate::Escape) { + branch.escape = true; + // The traversal followed an escaping path, but if the scope does not structurally + // always escape then another path (e.g. a modified fork) falls through, so the escape + // is only conditional - keep isModified() meaningful by not treating it as conclusive. + bool structuralUnknown = false; + const bool structuralEscape = isEscapeScope(branch.endBlock, structuralUnknown); + branch.escapeUnknown = !structuralEscape || structuralUnknown; + } else { + // Detect an escape the traversal did not flag (e.g. an unknown noreturn call); + // escapeUnknown reports a possible (unknown) escape. + branch.escape = isEscapeScope(branch.endBlock, branch.escapeUnknown); + if (terminate != Analyzer::Terminate::None && terminate != Analyzer::Terminate::Modified) { + branch.action |= analyzeScope(branch.endBlock); } } - return bail; + + return p; } bool reentersLoop(Token* endBlock, const Token* condTok, const Token* stepTok) const { @@ -529,14 +527,12 @@ namespace { forkContinue = false; } - if (allAnalysis.isModified() || !forkContinue) { - // TODO: Don't bail on missing condition - if (!condTok) - return Break(Analyzer::Terminate::Bail); - if (analyzer->isConditional() && stopUpdates()) - return Break(Analyzer::Terminate::Conditional); - analyzer->assume(condTok, false); - } + // TODO: Don't bail on missing condition + if (!condTok) + return Break(Analyzer::Terminate::Bail); + if (analyzer->isConditional() && stopUpdates()) + return Break(Analyzer::Terminate::Conditional); + analyzer->assume(condTok, false); if (forkContinue) { for (ForwardTraversal& ft : ftv) { if (!ft.actions.isIncremental()) @@ -646,11 +642,20 @@ namespace { const bool inElse = scope->type == ScopeType::eElse; const bool inDoWhile = scope->type == ScopeType::eDo; const bool inLoop = contains({ScopeType::eDo, ScopeType::eFor, ScopeType::eWhile}, scope->type); + const bool hasElse = Token::simpleMatch(tok, "} else {"); Token* condTok = getCondTokFromEnd(tok); if (!condTok) return Break(); + // When the 'else' branch escapes (e.g. returns), control can only continue + // here via the 'then' branch, so the value established there is still + // definite - keep it known instead of lowering to possible. + bool elseEscape = false; + if (!inLoop && !inElse && hasElse) { + bool unknownEscape = false; + elseEscape = isEscapeScope(tok->linkAt(2), unknownEscape); + } if (!condTok->hasKnownIntValue() || inLoop) { - if (!analyzer->lowerToPossible()) + if (!elseEscape && !analyzer->lowerToPossible()) return Break(Analyzer::Terminate::Bail); } else if (condTok->getKnownIntValue() == inElse) { return Break(); @@ -675,7 +680,7 @@ namespace { } analyzer->assume(condTok, !inElse, Analyzer::Assume::Quiet); assert(!inDoWhile || Token::simpleMatch(tok, "} while (")); - if (Token::simpleMatch(tok, "} else {") || inDoWhile) + if (hasElse || inDoWhile) tok = tok->linkAt(2); } else if (contains({ScopeType::eTry, ScopeType::eCatch}, scope->type)) { if (!analyzer->lowerToPossible()) @@ -731,71 +736,83 @@ namespace { if (!thenBranch.check && !elseBranch.check && stopOnCondition(condTok) && stopUpdates()) return Break(Analyzer::Terminate::Conditional); const bool hasElse = Token::simpleMatch(endBlock, "} else {"); - bool bail = false; - - // Traverse then block - thenBranch.escape = isEscapeScope(endBlock, thenBranch.escapeUnknown); + tok = hasElse ? endBlock->linkAt(2) : endBlock; if (thenBranch.check) { - thenBranch.active = true; - if (updateScope(endBlock, depth - 1) == Progress::Break) + // The condition is only "known" because of an earlier assumption, so the + // skipped else block could still modify the value -> lower to possible + if (!condTok->hasKnownIntValue() && hasElse && + analyzeScope(elseBranch.endBlock).isModified() && !analyzer->lowerToPossible()) + return Break(Analyzer::Terminate::Bail); + if (updateScope(thenBranch.endBlock, depth - 1) == Progress::Break) + return Break(); + } else if (elseBranch.check) { + // Likewise the skipped then block could still modify the value + if (!condTok->hasKnownIntValue() && analyzeScope(thenBranch.endBlock).isModified() && + !analyzer->lowerToPossible()) + return Break(Analyzer::Terminate::Bail); + if (elseBranch.endBlock && updateScope(elseBranch.endBlock, depth - 1) == Progress::Break) return Break(); - } else if (!elseBranch.check) { - thenBranch.active = true; - if (checkBranch(thenBranch)) - bail = true; - } - // Traverse else block - if (hasElse) { - elseBranch.escape = isEscapeScope(endBlock->linkAt(2), elseBranch.escapeUnknown); - if (elseBranch.check) { - elseBranch.active = true; - const Progress result = updateScope(endBlock->linkAt(2), depth - 1); - if (result == Progress::Break) - return Break(); - } else if (!thenBranch.check) { - elseBranch.active = true; - if (checkBranch(elseBranch)) - bail = true; - } - tok = endBlock->linkAt(2); } else { - tok = endBlock; - } - if (thenBranch.active) + const bool conditional = stopOnCondition(condTok); + // The value only flows into the then-branch when the condition can split + // it; for an opaque or correlated condition (e.g. 'if (f(x))') it does + // not, so fork in analyze-only mode: the branch's effect is still tracked + // but nothing is reported in it. + ForwardTraversal ft = fork(!analyzer->updateScope(thenBranch.endBlock, false)); + // The branch is traversed below, so don't record its boundary state here. + ft.analyzer->assume(condTok, true, Analyzer::Assume::Pending); + Progress pThen = ft.updateBranch(thenBranch, depth - 1); + // Merge the fork's actions so a modification in the then-branch bubbles up + // to the enclosing branch's isModified(). actions |= thenBranch.action; - if (elseBranch.active) - actions |= elseBranch.action; - if (bail) - return Break(Analyzer::Terminate::Bail); - if (thenBranch.isDead() && elseBranch.isDead()) { - if (thenBranch.isModified() && elseBranch.isModified()) - return Break(Analyzer::Terminate::Modified); - if (thenBranch.isConclusiveEscape() && elseBranch.isConclusiveEscape()) - return Break(Analyzer::Terminate::Escape); - return Break(Analyzer::Terminate::Bail); - } - // Conditional return - if (thenBranch.active && thenBranch.isEscape() && !hasElse) { - if (!thenBranch.isConclusiveEscape()) { - if (!analyzer->lowerToInconclusive()) - return Break(Analyzer::Terminate::Bail); - } else if (thenBranch.check) { - return Break(); - } else { - if (stopOnCondition(condTok) && stopUpdates()) - return Break(Analyzer::Terminate::Conditional); - analyzer->assume(condTok, false); + + // Commit the condition as false on the main path only when the then-branch + // is dead. The else block, if any, is traversed separately (Pending); with + // no else the false path continues past the closing brace, so record the + // assumed state there (None). + if (thenBranch.isDead()) + analyzer->assume(condTok, + false, + hasElse ? Analyzer::Assume::Pending : Analyzer::Assume::None); + // The else block is traversed on the main path. If it kills the value + // (modified) the main path stops, but the then-fork may still carry the + // value forward, so defer the break until after the fork continues. + Progress pElse = Progress::Continue; + if (hasElse) + pElse = updateBranch(elseBranch, depth - 1); + if (thenBranch.isDead() || elseBranch.isDead()) { + if (conditional && stopUpdates()) + pElse = Break(Analyzer::Terminate::Conditional); } - } - if (thenBranch.isInconclusive() || elseBranch.isInconclusive()) { - if (!analyzer->lowerToInconclusive()) - return Break(Analyzer::Terminate::Bail); - } else if (thenBranch.isModified() || elseBranch.isModified()) { - if (!hasElse && analyzer->isConditional() && stopUpdates()) - return Break(Analyzer::Terminate::Conditional); - if (!analyzer->lowerToPossible()) + if (thenBranch.isModified() || elseBranch.isModified()) { + if (!ft.analyzer->lowerToPossible()) + pThen = Progress::Break; + if (pElse != Progress::Break && !analyzer->lowerToPossible()) + pElse = Break(Analyzer::Terminate::Bail); + } + if (thenBranch.isInconclusive() || elseBranch.isInconclusive()) { + if (!ft.analyzer->lowerToInconclusive()) + pThen = Progress::Break; + if (pElse != Progress::Break && !analyzer->lowerToInconclusive()) + pElse = Break(Analyzer::Terminate::Bail); + } + if (thenBranch.hasGoto() || elseBranch.hasGoto()) { return Break(Analyzer::Terminate::Bail); - analyzer->assume(condTok, elseBranch.isModified()); + } + // Carry the then-fork forward, unless a limit is hit - then only the linear main + // path continues (no bail). forkDepth bounds nesting, forkBudget total. <0 = off. + assert(forkBudget != nullptr); + const int forkDepthLimit = settings.vfOptions.maxForwardConditionForkDepth; + const int forkBudgetLimit = settings.vfOptions.maxForwardConditionForks; + const bool depthOk = forkDepthLimit < 0 || forkDepth < forkDepthLimit; + const bool budgetOk = forkBudgetLimit < 0 || *forkBudget < forkBudgetLimit; + if (pThen != Progress::Break && !thenBranch.isEscape() && depthOk && budgetOk) { + ++(*forkBudget); + ++ft.forkDepth; + ft.updateRange(thenBranch.endBlock, end, depth - 1); + } + if (pElse == Progress::Break) + return Break(); } } } else if (Token::simpleMatch(tok, "try {")) { diff --git a/lib/programmemory.cpp b/lib/programmemory.cpp index b86ca2d8812..013906d00ae 100644 --- a/lib/programmemory.cpp +++ b/lib/programmemory.cpp @@ -262,26 +262,33 @@ ProgramMemory::Map::iterator ProgramMemory::find(nonneg int exprid) return mValues->find(ExprIdToken::create(exprid)); } -static ValueFlow::Value execute(const Token* expr, ProgramMemory& pm, const Settings& settings); - -static bool evaluateCondition(MathLib::bigint r, const Token* condition, ProgramMemory& pm, const Settings& settings) +static ValueFlow::Value execute(const Token* expr, + ProgramMemory& pm, + const Settings& settings, + const ProgramMemory::Map& vars = {}); + +static bool evaluateCondition(MathLib::bigint r, + const Token* condition, + ProgramMemory& pm, + const Settings& settings, + const ProgramMemory::Map& vars = {}) { if (!condition) return false; MathLib::bigint result = 0; bool error = false; - execute(condition, pm, &result, &error, settings); + execute(condition, pm, &result, &error, settings, vars); return !error && result == r; } -bool conditionIsFalse(const Token* condition, ProgramMemory pm, const Settings& settings) +bool conditionIsFalse(const Token* condition, ProgramMemory pm, const Settings& settings, const ProgramMemory::Map& vars) { - return evaluateCondition(0, condition, pm, settings); + return evaluateCondition(0, condition, pm, settings, vars); } -bool conditionIsTrue(const Token* condition, ProgramMemory pm, const Settings& settings) +bool conditionIsTrue(const Token* condition, ProgramMemory pm, const Settings& settings, const ProgramMemory::Map& vars) { - return evaluateCondition(1, condition, pm, settings); + return evaluateCondition(1, condition, pm, settings, vars); } static bool frontIs(const std::vector& v, bool i) @@ -337,7 +344,13 @@ static bool isBasicForLoop(const Token* tok) return true; } -static void programMemoryParseCondition(ProgramMemory& pm, const Token* tok, const Token* endTok, const Settings& settings, bool then) +// findChanged: optional cached findExpressionChanged (see ProgramMemoryState::FindChangedFn). +static void programMemoryParseCondition(ProgramMemory& pm, + const Token* tok, + const Token* endTok, + const Settings& settings, + bool then, + const ProgramMemoryState::FindChangedFn& findChanged = {}) { auto eval = [&](const Token* t) -> std::vector { if (!t) @@ -351,6 +364,10 @@ static void programMemoryParseCondition(ProgramMemory& pm, const Token* tok, con return {result}; return std::vector{}; }; + // Use the cached closure if given, else compute directly. + auto changed = [&](const Token* e, const Token* s, const Token* en) -> const Token* { + return findChanged ? findChanged(e, s, en) : findExpressionChanged(e, s, en, settings); + }; if (Token::Match(tok, "==|>=|<=|<|>|!=")) { ValueFlow::Value truevalue; ValueFlow::Value falsevalue; @@ -361,7 +378,7 @@ static void programMemoryParseCondition(ProgramMemory& pm, const Token* tok, con return; if (!truevalue.isIntValue()) return; - if (endTok && findExpressionChanged(vartok, tok->next(), endTok, settings)) + if (endTok && changed(vartok, tok->next(), endTok)) return; const bool impossible = (tok->str() == "==" && !then) || (tok->str() == "!=" && then); const ValueFlow::Value& v = then ? truevalue : falsevalue; @@ -370,26 +387,26 @@ static void programMemoryParseCondition(ProgramMemory& pm, const Token* tok, con if (containerTok) pm.setContainerSizeValue(containerTok, v.intvalue, !impossible); } else if (Token::simpleMatch(tok, "!")) { - programMemoryParseCondition(pm, tok->astOperand1(), endTok, settings, !then); + programMemoryParseCondition(pm, tok->astOperand1(), endTok, settings, !then, findChanged); } else if (then && Token::simpleMatch(tok, "&&")) { - programMemoryParseCondition(pm, tok->astOperand1(), endTok, settings, then); - programMemoryParseCondition(pm, tok->astOperand2(), endTok, settings, then); + programMemoryParseCondition(pm, tok->astOperand1(), endTok, settings, then, findChanged); + programMemoryParseCondition(pm, tok->astOperand2(), endTok, settings, then, findChanged); } else if (!then && Token::simpleMatch(tok, "||")) { - programMemoryParseCondition(pm, tok->astOperand1(), endTok, settings, then); - programMemoryParseCondition(pm, tok->astOperand2(), endTok, settings, then); + programMemoryParseCondition(pm, tok->astOperand1(), endTok, settings, then, findChanged); + programMemoryParseCondition(pm, tok->astOperand2(), endTok, settings, then, findChanged); } else if (Token::Match(tok, "&&|%oror%")) { std::vector lhs = eval(tok->astOperand1()); std::vector rhs = eval(tok->astOperand2()); if (lhs.empty() || rhs.empty()) { if (frontIs(lhs, !then)) - programMemoryParseCondition(pm, tok->astOperand2(), endTok, settings, then); + programMemoryParseCondition(pm, tok->astOperand2(), endTok, settings, then, findChanged); else if (frontIs(rhs, !then)) - programMemoryParseCondition(pm, tok->astOperand1(), endTok, settings, then); + programMemoryParseCondition(pm, tok->astOperand1(), endTok, settings, then, findChanged); else pm.setIntValue(tok, 0, then); } } else if (tok && tok->exprId() > 0) { - if (endTok && findExpressionChanged(tok, tok->next(), endTok, settings)) + if (endTok && changed(tok, tok->next(), endTok)) return; pm.setIntValue(tok, 0, then); const Token* containerTok = settings.library.getContainerFromYield(tok, Library::Container::Yield::EMPTY); @@ -398,14 +415,18 @@ static void programMemoryParseCondition(ProgramMemory& pm, const Token* tok, con } } -static void fillProgramMemoryFromConditions(ProgramMemory& pm, const Scope* scope, const Token* endTok, const Settings& settings) +static void fillProgramMemoryFromConditions(ProgramMemory& pm, + const Scope* scope, + const Token* endTok, + const Settings& settings, + const ProgramMemoryState::FindChangedFn& findChanged) { if (!scope) return; if (!scope->isLocal()) return; assert(scope != scope->nestedIn); - fillProgramMemoryFromConditions(pm, scope->nestedIn, endTok, settings); + fillProgramMemoryFromConditions(pm, scope->nestedIn, endTok, settings, findChanged); if (scope->type == ScopeType::eIf || scope->type == ScopeType::eWhile || scope->type == ScopeType::eElse || scope->type == ScopeType::eFor) { const Token* condTok = getCondTokFromEnd(scope->bodyEnd); if (!condTok) @@ -414,13 +435,16 @@ static void fillProgramMemoryFromConditions(ProgramMemory& pm, const Scope* scop bool error = false; execute(condTok, pm, &result, &error, settings); if (error) - programMemoryParseCondition(pm, condTok, endTok, settings, scope->type != ScopeType::eElse); + programMemoryParseCondition(pm, condTok, endTok, settings, scope->type != ScopeType::eElse, findChanged); } } -static void fillProgramMemoryFromConditions(ProgramMemory& pm, const Token* tok, const Settings& settings) +static void fillProgramMemoryFromConditions(ProgramMemory& pm, + const Token* tok, + const Settings& settings, + const ProgramMemoryState::FindChangedFn& findChanged = {}) { - fillProgramMemoryFromConditions(pm, tok->scope(), tok, settings); + fillProgramMemoryFromConditions(pm, tok->scope(), tok, settings, findChanged); } static void fillProgramMemoryFromAssignments(ProgramMemory& pm, const Token* tok, const Settings& settings, const ProgramMemory& state, const ProgramMemory::Map& vars) @@ -429,22 +453,12 @@ static void fillProgramMemoryFromAssignments(ProgramMemory& pm, const Token* tok for (const Token *tok2 = tok; tok2; tok2 = tok2->previous()) { if ((Token::simpleMatch(tok2, "=") || Token::Match(tok2->previous(), "%var% (|{")) && tok2->astOperand1() && tok2->astOperand2()) { - bool setvar = false; const Token* vartok = tok2->astOperand1(); - for (const auto& p:vars) { - if (p.first.getExpressionId() != vartok->exprId()) - continue; - if (vartok == tok) - continue; - pm.setValue(vartok, p.second); - setvar = true; - } - if (!setvar) { - if (!pm.hasValue(vartok->exprId())) { - const Token* valuetok = tok2->astOperand2(); - ProgramMemory local = state; - pm.setValue(vartok, execute(valuetok, local, settings)); - } + if (!pm.hasValue(vartok->exprId())) { + const Token* valuetok = tok2->astOperand2(); + ProgramMemory local = state; + // Tracked values are substituted by execute() when the expression is evaluated. + pm.setValue(vartok, execute(valuetok, local, settings, vars)); } } else if (Token::simpleMatch(tok2, ")") && tok2->link() && Token::Match(tok2->link()->previous(), "assert|ASSERT ( !!)")) { @@ -516,7 +530,7 @@ static ProgramMemory getInitialProgramState(const Token* tok, return pm; } -ProgramMemoryState::ProgramMemoryState(const Settings& s) : settings(s) +ProgramMemoryState::ProgramMemoryState(const Settings& s) : settings(s), changedCache(std::make_shared()) {} void ProgramMemoryState::replace(ProgramMemory pm, const Token* origin) @@ -539,7 +553,7 @@ void ProgramMemoryState::addState(const Token* tok, const ProgramMemory::Map& va { ProgramMemory local = state; addVars(local, vars); - fillProgramMemoryFromConditions(local, tok, settings); + fillProgramMemoryFromConditions(local, tok, settings, getCachedFindExpressionChanged(/*skipDeadCode*/ false)); ProgramMemory pm; fillProgramMemoryFromAssignments(pm, tok, settings, local, vars); local.replace(std::move(pm)); @@ -547,44 +561,73 @@ void ProgramMemoryState::addState(const Token* tok, const ProgramMemory::Map& va replace(std::move(local), tok); } -void ProgramMemoryState::assume(const Token* tok, bool b, bool isEmpty) +void ProgramMemoryState::assume(const Token* tok, bool b, bool isEmpty, const Token* origin) { ProgramMemory pm = state; if (isEmpty) pm.setContainerSizeValue(tok, 0, b); else programMemoryParseCondition(pm, tok, nullptr, settings, b); - const Token* origin = tok; - const Token* top = tok->astTop(); - if (Token::Match(top->previous(), "for|while|if (") && !Token::simpleMatch(tok->astParent(), "?")) { - origin = top->link()->next(); - if (!b && origin->link()) { - origin = origin->link(); + if (!origin) { + origin = tok; + const Token* top = tok->astTop(); + if (Token::Match(top->previous(), "for|while|if (") && !Token::simpleMatch(tok->astParent(), "?")) { + origin = top->link()->next(); + if (!b && origin->link()) { + origin = origin->link(); + } } } replace(std::move(pm), origin); } -void ProgramMemoryState::removeModifiedVars(const Token* tok) +ProgramMemoryState::FindChangedFn ProgramMemoryState::getCachedFindExpressionChanged(bool skipDeadCode) const { - const ProgramMemory& pm = state; - auto eval = [&](const Token* cond) -> std::vector { - ProgramMemory pm2 = pm; - auto result = execute(cond, pm2, settings); - if (isTrue(result)) - return {1}; - if (isFalse(result)) - return {0}; - return {}; + // Structural findExpressionChanged() is pure, so memoize it in changedCache (never invalidated). + // skipDeadCode adds the dead-code walk; it evaluates guards against a fixed state snapshot (so every + // variable follows the same path) and memoizes those evals in evalCache for the closure's lifetime. + using EvalCache = std::map>; + const std::shared_ptr cache = changedCache; + const Settings* const sp = &settings; + ProgramMemory snapshot = state; + const std::shared_ptr evalCache = skipDeadCode ? std::make_shared() : nullptr; + return [cache, sp, snapshot, skipDeadCode, evalCache](const Token* expr, + const Token* start, + const Token* end) -> const Token* { + const auto key = std::make_tuple(expr, start, end); + const auto it = cache->find(key); + const Token* modified = (it != cache->end()) + ? it->second + : cache->emplace(key, findExpressionChanged(expr, start, end, *sp)).first->second; + if (!skipDeadCode || !modified) + return modified; + auto eval = [&](const Token* cond) -> std::vector { + const auto cit = evalCache->find(cond); + if (cit != evalCache->end()) + return cit->second; + ProgramMemory pm2 = snapshot; + const auto result = execute(cond, pm2, *sp); + std::vector r; + if (isTrue(result)) + r = {1}; + else if (isFalse(result)) + r = {0}; + return evalCache->emplace(cond, std::move(r)).first->second; + }; + return findExpressionChangedSkipDeadCode(expr, start, end, *sp, eval); }; +} + +void ProgramMemoryState::removeModifiedVars(const Token* tok) +{ + const auto findChanged = getCachedFindExpressionChanged(/*skipDeadCode*/ true); state.erase_if([&](const ExprIdToken& e) { const Token* start = origins[e.getExpressionId()]; const Token* expr = e.tok; - if (!expr || findExpressionChangedSkipDeadCode(expr, start, tok, settings, eval)) { + const bool changed = !expr || findChanged(expr, start, tok); + if (changed) origins.erase(e.getExpressionId()); - return true; - } - return false; + return changed; }); } @@ -1316,6 +1359,9 @@ namespace { struct Executor { ProgramMemory* pm; const Settings& settings; + // Values tracked by the forward/reverse analysis. A tracked value is the authoritative + // current value of its expression and takes precedence over the program memory. + const ProgramMemory::Map* vars = nullptr; int fdepth = 4; int depth = 10; @@ -1324,6 +1370,26 @@ namespace { assert(pm != nullptr); } + // Is the tracked value for this expression available? + const ValueFlow::Value* getTrackedValue(const Token* expr) const + { + if (!vars || expr->exprId() == 0) + return nullptr; + const auto it = vars->find(ExprIdToken::create(expr->exprId())); + return it == vars->end() ? nullptr : &it->second; + } + + // Does the expression read a tracked value? If so, any value cached for it may be stale + // (the tracked value may have changed since), so it must be re-evaluated, not served cached. + bool dependsOnTrackedValue(const Token* expr) const + { + if (!vars || vars->empty()) + return false; + return findAstNode(expr, [&](const Token* tok) { + return getTrackedValue(tok) != nullptr; + }) != nullptr; + } + static ValueFlow::Value unknown() { return ValueFlow::Value::unknown(); } @@ -1622,7 +1688,15 @@ namespace { } return execute(expr->astOperand1()); } - if (expr->exprId() > 0 && pm->hasValue(expr->exprId())) { + // Return the tracked value and write it back when it differs, so later reads see the + // same value (as fillProgramMemoryFromAssignments used to do). + if (const ValueFlow::Value* tracked = getTrackedValue(expr)) { + const ValueFlow::Value* stored = pm->getValue(expr->exprId(), /*impossible*/ true); + if (!stored || *stored != *tracked) + pm->setValue(expr, *tracked); + return *tracked; + } + if (expr->exprId() > 0 && pm->hasValue(expr->exprId()) && !dependsOnTrackedValue(expr)) { ValueFlow::Value result = utils::as_const(*pm).at(expr->exprId()); if (result.isImpossible() && result.isIntValue() && result.intvalue == 0 && isUsedAsBool(expr, settings)) { result.intvalue = !result.intvalue; @@ -1815,9 +1889,13 @@ namespace { }; } // namespace -static ValueFlow::Value execute(const Token* expr, ProgramMemory& pm, const Settings& settings) +static ValueFlow::Value execute(const Token* expr, + ProgramMemory& pm, + const Settings& settings, + const ProgramMemory::Map& vars) { Executor ex{&pm, settings}; + ex.vars = &vars; return ex.execute(expr); } @@ -1907,9 +1985,10 @@ void execute(const Token* expr, ProgramMemory& programMemory, MathLib::bigint* result, bool* error, - const Settings& settings) + const Settings& settings, + const ProgramMemory::Map& vars) { - ValueFlow::Value v = execute(expr, programMemory, settings); + ValueFlow::Value v = execute(expr, programMemory, settings, vars); if (!v.isIntValue() || v.isImpossible()) { if (error) *error = true; diff --git a/lib/programmemory.h b/lib/programmemory.h index ec24c0df59f..de81d0bc901 100644 --- a/lib/programmemory.h +++ b/lib/programmemory.h @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -161,9 +162,26 @@ struct CPPCHECKLIB ProgramMemory { }; struct ProgramMemoryState { + struct ChangedKeyHash { + std::size_t operator()(const std::tuple& t) const + { + const std::hash h; + std::size_t seed = h(std::get<0>(t)); + seed ^= h(std::get<1>(t)) + 0x9e3779b9 + (seed << 6) + (seed >> 2); + seed ^= h(std::get<2>(t)) + 0x9e3779b9 + (seed << 6) + (seed >> 2); + return seed; + } + }; + using ChangedCache = + std::unordered_map, const Token*, ChangedKeyHash>; + // The token modifying expr between start and end, or nullptr. + using FindChangedFn = std::function; + ProgramMemory state; std::map origins; const Settings& settings; + // Memoized findExpressionChanged() pre-filter; structural, so never invalidated. + std::shared_ptr changedCache; explicit ProgramMemoryState(const Settings& s); @@ -171,10 +189,13 @@ struct ProgramMemoryState { void addState(const Token* tok, const ProgramMemory::Map& vars); - void assume(const Token* tok, bool b, bool isEmpty = false); + void assume(const Token* tok, bool b, bool isEmpty = false, const Token* origin = nullptr); void removeModifiedVars(const Token* tok); + // A findExpressionChanged() closure memoized in changedCache + FindChangedFn getCachedFindExpressionChanged(bool skipDeadCode) const; + ProgramMemory get(const Token* tok, const Token* ctx, const ProgramMemory::Map& vars) const; }; @@ -184,21 +205,30 @@ void execute(const Token* expr, ProgramMemory& programMemory, MathLib::bigint* result, bool* error, - const Settings& settings); + const Settings& settings, + const ProgramMemory::Map& vars = {}); /** * Is condition always false when variable has given value? * \param condition top ast token in condition * \param pm program memory + * \param vars optional tracked values that take precedence over the program memory */ -bool conditionIsFalse(const Token* condition, ProgramMemory pm, const Settings& settings); +bool conditionIsFalse(const Token* condition, + ProgramMemory pm, + const Settings& settings, + const ProgramMemory::Map& vars = {}); /** * Is condition always true when variable has given value? * \param condition top ast token in condition * \param pm program memory + * \param vars optional tracked values that take precedence over the program memory */ -bool conditionIsTrue(const Token* condition, ProgramMemory pm, const Settings& settings); +bool conditionIsTrue(const Token* condition, + ProgramMemory pm, + const Settings& settings, + const ProgramMemory::Map& vars = {}); /** * Get program memory by looking backwards from given token. diff --git a/lib/settings.cpp b/lib/settings.cpp index c0539bbeaba..479346208e3 100644 --- a/lib/settings.cpp +++ b/lib/settings.cpp @@ -335,6 +335,7 @@ void Settings::setCheckLevel(CheckLevel level) vfOptions.maxIfCount = 100; vfOptions.doConditionExpressionAnalysis = false; vfOptions.maxForwardBranches = 4; + vfOptions.maxForwardConditionForkDepth = 0; vfOptions.maxIterations = 1; } else if (level == CheckLevel::normal) { @@ -344,6 +345,7 @@ void Settings::setCheckLevel(CheckLevel level) vfOptions.maxIfCount = 100; vfOptions.doConditionExpressionAnalysis = false; vfOptions.maxForwardBranches = 4; + vfOptions.maxForwardConditionForkDepth = 1; } else if (level == CheckLevel::exhaustive) { // Checking can take a little while. ~ 10 times slower than normal analysis is OK. @@ -352,6 +354,8 @@ void Settings::setCheckLevel(CheckLevel level) vfOptions.maxSubFunctionArgs = 256; vfOptions.doConditionExpressionAnalysis = true; vfOptions.maxForwardBranches = -1; + vfOptions.maxForwardConditionForkDepth = 4; + vfOptions.maxForwardConditionForks = 256; } } diff --git a/lib/settings.h b/lib/settings.h index 4a73f35039b..ce4a32e1690 100644 --- a/lib/settings.h +++ b/lib/settings.h @@ -512,6 +512,15 @@ class CPPCHECKLIB WARN_UNUSED Settings { /** @brief Maximum performed forward branches */ int maxForwardBranches = -1; + /** @brief Maximum depth of nested condition-fork continuations in the forward analyzer. + Bounds the exponential fan-out of carrying condition state forward at exhaustive level (where + maxForwardBranches is unlimited); past it the forward analysis continues on a single linear path + without skipping any branch. 0 disables forking (linear); a negative value means unlimited. */ + int maxForwardConditionForkDepth = 4; + + /** @brief Maximum total condition-fork continuations in one forward traversal. */ + int maxForwardConditionForks = 256; + /** @brief Maximum performed alignof recursion */ int maxAlignOfRecursion = 100; diff --git a/lib/vf_analyzers.cpp b/lib/vf_analyzers.cpp index 44c86cbc2b7..cfba7d5f970 100644 --- a/lib/vf_analyzers.cpp +++ b/lib/vf_analyzers.cpp @@ -678,16 +678,20 @@ struct ValueFlowAnalyzer : Analyzer { if (const ValueFlow::Value* v = tok->getKnownValue(ValueFlow::Value::ValueType::INT)) return {v->intvalue}; std::vector result; - ProgramMemory pm = getProgramMemoryFunc(); + // Pass the tracked values so a cached program-memory value that depends on one (e.g. 'h(p)' + // after 'p' was reassigned) is re-evaluated rather than served stale. The memory is built + // from the same state, so compute it once and hand it to the builder. + const ProgramState vars = getProgramState(); + ProgramMemory pm = getProgramMemoryFunc(vars); if (Token::Match(tok, "&&|%oror%")) { - if (conditionIsTrue(tok, pm, getSettings())) + if (conditionIsTrue(tok, pm, getSettings(), vars)) result.push_back(1); - if (conditionIsFalse(tok, std::move(pm), getSettings())) + if (conditionIsFalse(tok, std::move(pm), getSettings(), vars)) result.push_back(0); } else { MathLib::bigint out = 0; bool error = false; - execute(tok, pm, &out, &error, getSettings()); + execute(tok, pm, &out, &error, getSettings(), vars); if (!error) result.push_back(out); } @@ -696,16 +700,16 @@ struct ValueFlowAnalyzer : Analyzer { std::vector evaluateInt(const Token* tok) const { - return evaluateInt(tok, [&] { - return ProgramMemory{getProgramState()}; + return evaluateInt(tok, [](const ProgramState& vars) { + return ProgramMemory{vars}; }); } std::vector evaluate(Evaluate e, const Token* tok, const Token* ctx = nullptr) const override { if (e == Evaluate::Integral) { - return evaluateInt(tok, [&] { - return pms.get(tok, ctx, getProgramState()); + return evaluateInt(tok, [&](const ProgramState& vars) { + return pms.get(tok, ctx, vars); }); } if (e == Evaluate::ContainerEmpty) { @@ -723,30 +727,43 @@ struct ValueFlowAnalyzer : Analyzer { return {}; } - void assume(const Token* tok, bool state, unsigned int flags) override { - // Update program state - pms.removeModifiedVars(tok); - pms.addState(tok, getProgramState()); - pms.assume(tok, state, flags & Assume::ContainerEmpty); - + void assume(const Token* tok, bool state, unsigned int flags) override + { bool isCondBlock = false; const Token* parent = tok->astParent(); if (parent) { isCondBlock = Token::Match(parent->previous(), "if|while ("); } + const Token* endBlock = nullptr; if (isCondBlock) { const Token* startBlock = parent->link()->next(); if (Token::simpleMatch(startBlock, ";") && Token::simpleMatch(parent->tokAt(-2), "} while (")) startBlock = parent->linkAt(-2); - const Token* endBlock = startBlock->link(); - if (state) { - pms.removeModifiedVars(endBlock); - pms.addState(endBlock->previous(), getProgramState()); - } else { - if (Token::simpleMatch(endBlock, "} else {")) - pms.addState(endBlock->linkAt(2)->previous(), getProgramState()); - } + endBlock = startBlock->link(); + } + + // Without Pending the 'then' block has been traversed and control is leaving it, so anchor + // the assumed state at the block end instead of the condition. That keeps assumptions on + // variables modified inside the block (e.g. an 'if' narrowing a value computed there) from + // being discarded as "modified" once control leaves the block. + const bool scopeEnd = !(flags & Assume::Pending) && state && endBlock; + const Token* anchor = scopeEnd ? endBlock : tok; + const Token* origin = scopeEnd ? endBlock : nullptr; + + // Update program state + pms.removeModifiedVars(anchor); + pms.addState(anchor, getProgramState()); + pms.assume(tok, state, flags & Assume::ContainerEmpty, origin); + + // The false path (the true path uses scopeEnd above): record the assumed state where control + // continues - the end of the else block, or the closing brace when there is no else - so it + // reaches the enclosing scope. + if (isCondBlock && !(flags & Assume::Pending) && !state) { + if (Token::simpleMatch(endBlock, "} else {")) + pms.addState(endBlock->linkAt(2)->previous(), getProgramState()); + else + pms.addState(endBlock, getProgramState()); } if (!(flags & Assume::Quiet)) { diff --git a/test/testautovariables.cpp b/test/testautovariables.cpp index 2867f147d81..df421d6879c 100644 --- a/test/testautovariables.cpp +++ b/test/testautovariables.cpp @@ -4941,7 +4941,9 @@ class TestAutoVariables : public TestFixture { " return *iPtr;\n" " return 0;\n" "}"); - ASSERT_EQUALS("[test.cpp:5:16] -> [test.cpp:4:13] -> [test.cpp:8:17]: (error) Using pointer to local variable 'x' that is out of scope. [invalidLifetime]\n", errout_str()); + ASSERT_EQUALS( + "[test.cpp:5:16] -> [test.cpp:7:10] -> [test.cpp:4:13] -> [test.cpp:8:17]: (error) Using pointer to local variable 'x' that is out of scope. [invalidLifetime]\n", + errout_str()); // #11753 check("int main(int argc, const char *argv[]) {\n" diff --git a/test/testcondition.cpp b/test/testcondition.cpp index 3143b6eb201..837cd4e78ba 100644 --- a/test/testcondition.cpp +++ b/test/testcondition.cpp @@ -4911,6 +4911,30 @@ class TestCondition : public TestFixture { ASSERT_EQUALS("[test.cpp:3:10]: (style) Condition 'b()' is always false [knownConditionTrueFalse]\n" "[test.cpp:4:9]: (style) Condition '!b()' is always true [knownConditionTrueFalse]\n", errout_str()); + + check("int g();\n" // a value modified inside a nested branch must be lowered to possible + "void f(int outer, int inner) {\n" + " int bits = 0;\n" + " if (outer) {\n" + " if (inner == 1)\n" + " bits = g();\n" + " }\n" + " if (bits > 0) {}\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + + check("int g();\n" // the modifying branch has an escaping sibling - still must be lowered + "void f(int t, int u) {\n" + " int v = 0;\n" + " if (t) {\n" + " if (u == 2)\n" + " v = g();\n" + " else\n" + " return;\n" + " }\n" + " if (v > 0) {}\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); } void alwaysTrueSymbolic() diff --git a/test/testnullpointer.cpp b/test/testnullpointer.cpp index 369c04a2101..2483a967947 100644 --- a/test/testnullpointer.cpp +++ b/test/testnullpointer.cpp @@ -2450,6 +2450,9 @@ class TestNullPointer : public TestFixture { void nullpointer77() { + // No warning: 'i' is passed to the unknown function 'h' in the same condition that guards the + // dereference. 'h' may validate the pointer (e.g. return false for null), so '*i' can be safe + // - this is the common "if (check(p) && p->...)" pattern, so we must not assume 'i' is null. check("bool h(int*);\n" "void f(int* i) {\n" " int* i = nullptr;\n" @@ -2465,6 +2468,8 @@ class TestNullPointer : public TestFixture { "}\n"); ASSERT_EQUALS("", errout_str()); + // Likewise here, even though 'i' is null when the first 'h(i)' was true: the second 'h(i)' is an + // independent call that may validate 'i', so '*i' is not necessarily a null dereference. check("bool h(int*);\n" "void f(int* x) {\n" " int* i = x;\n" diff --git a/test/testother.cpp b/test/testother.cpp index fa6899cf543..02418df5627 100644 --- a/test/testother.cpp +++ b/test/testother.cpp @@ -11511,8 +11511,9 @@ class TestOther : public TestFixture { " x = a + b;\n" " return x;\n" "}\n"); - ASSERT_EQUALS("[test.cpp:2:11] -> [test.cpp:4:9]: (style) Variable 'x' is assigned an expression that holds the same value. [redundantAssignment]\n", - errout_str()); + ASSERT_EQUALS( + "[test.cpp:2:11] -> [test.cpp:3:9] -> [test.cpp:4:9]: (style) Variable 'x' is assigned an expression that holds the same value. [redundantAssignment]\n", + errout_str()); } void varFuncNullUB() { // #4482 diff --git a/test/teststl.cpp b/test/teststl.cpp index 35941f6422c..93b53b43671 100644 --- a/test/teststl.cpp +++ b/test/teststl.cpp @@ -368,7 +368,9 @@ class TestStl : public TestFixture { " if(b) ++x;\n" " return s[x];\n" "}"); - ASSERT_EQUALS("[test.cpp:5:13]: error: Out of bounds access in 's[x]', if 's' size is 6 and 'x' is 6 [containerOutOfBounds]\n", errout_str()); + ASSERT_EQUALS( + "[test.cpp:5:13]: error: Out of bounds access in 's[x]', if 's' size is 6 and 'x' is 7 [containerOutOfBounds]\n", + errout_str()); checkNormal("void f() {\n" " static const int N = 4;\n" diff --git a/test/testuninitvar.cpp b/test/testuninitvar.cpp index e0c5512f1fd..6a43493cd0d 100644 --- a/test/testuninitvar.cpp +++ b/test/testuninitvar.cpp @@ -4265,7 +4265,7 @@ class TestUninitVar : public TestFixture { " else {}\n" " return y;\n" "}"); - TODO_ASSERT_EQUALS("", "[test.cpp:5:9] -> [test.cpp:7:12]: (warning) Uninitialized variable: y [uninitvar]\n", errout_str()); + ASSERT_EQUALS("", errout_str()); // #4560: escaping else keeps x known, so x is true and y is initialized valueFlowUninit("int f(int a) {\n" // #6583 " int x;\n" @@ -4284,7 +4284,8 @@ class TestUninitVar : public TestFixture { " else y = 123;\n" // <- y is always initialized " return y;\n" "}"); - TODO_ASSERT_EQUALS("", "[test.cpp:5:9] -> [test.cpp:7:12]: (warning) Uninitialized variable: y [uninitvar]\n", errout_str()); + ASSERT_EQUALS("", + errout_str()); // #4560: fork-based condition analysis tracks x==0 -> else branch -> y initialized valueFlowUninit("void f(int x) {\n" // #3948 " int value;\n" @@ -5614,6 +5615,47 @@ class TestUninitVar : public TestFixture { "}"); ASSERT_EQUALS("[test.cpp:18:9] -> [test.cpp:12:13] -> [test.cpp:8:15]: (warning) Uninitialized variable: s->flag [uninitvar]\n", errout_str()); + // A value narrowed by a nested condition (dimensions < 1 here) must survive the enclosing + // 'if' so a later correlated condition can be resolved: dimensions == 1 is then false, the + // function does not return, and the uninitialized read is reached. + valueFlowUninit("unsigned int g();\n" + "void f(bool a) {\n" + " unsigned int dimensions = 0;\n" + " bool mightBeLarger;\n" + " if (a) {\n" + " dimensions = g();\n" + " if (dimensions >= 1)\n" + " mightBeLarger = false;\n" + " } else {\n" + " mightBeLarger = false;\n" + " }\n" + " if (dimensions == 1)\n" + " return;\n" + " if (!mightBeLarger) {}\n" + "}"); + ASSERT_EQUALS( + "[test.cpp:5:9] -> [test.cpp:7:24] -> [test.cpp:14:10]: (warning) Uninitialized variable: mightBeLarger [uninitvar]\n", + errout_str()); + + // Same shape, but the later condition (dimensions == 0) is implied by the narrowing, so the + // early return fires on the uninitialized path and there must be no warning. + valueFlowUninit("unsigned int g();\n" + "void f(bool a) {\n" + " unsigned int dimensions = 0;\n" + " bool mightBeLarger;\n" + " if (a) {\n" + " dimensions = g();\n" + " if (dimensions >= 1)\n" + " mightBeLarger = false;\n" + " } else {\n" + " mightBeLarger = false;\n" + " }\n" + " if (dimensions == 0)\n" + " return;\n" + " if (!mightBeLarger) {}\n" + "}"); + ASSERT_EQUALS("", errout_str()); + // Ticket #2207 - False negative valueFlowUninit("void foo() {\n" " int a;\n" diff --git a/test/testvalueflow.cpp b/test/testvalueflow.cpp index c015664554a..888710ce57d 100644 --- a/test/testvalueflow.cpp +++ b/test/testvalueflow.cpp @@ -6123,9 +6123,9 @@ class TestValueFlow : public TestFixture { " c++;\n" "}\n"; values = tokenValues(code, "c ++ ; }"); - TODO_ASSERT_EQUALS(true, false, values.size() == 2); - // ASSERT_EQUALS(true, values.front().isUninitValue() || values.back().isUninitValue()); - // ASSERT_EQUALS(true, values.front().isPossible() || values.back().isPossible()); + ASSERT_EQUALS(true, values.size() == 2); + ASSERT_EQUALS(true, values.front().isUninitValue() || values.back().isUninitValue()); + ASSERT_EQUALS(true, values.front().isPossible() || values.back().isPossible()); // ASSERT_EQUALS(true, values.front().intvalue == 0 || values.back().intvalue == 0); code = "void b(bool d, bool e) {\n" @@ -8446,6 +8446,75 @@ class TestValueFlow : public TestFixture { " static T f[64];\n" "};\n"; (void)valueOfTok(code, "("); + + // fork explosion on many opaque conditions; bounded by maxForwardConditionForks + code = "int g(int);\n" + "bool h(int);\n" + "void f() {\n" + " int x = 0;\n" + " if (h(0)) g(x);\n" + " if (h(1)) g(x);\n" + " if (h(2)) g(x);\n" + " if (h(3)) g(x);\n" + " if (h(4)) g(x);\n" + " if (h(5)) g(x);\n" + " if (h(6)) g(x);\n" + " if (h(7)) g(x);\n" + " if (h(8)) g(x);\n" + " if (h(9)) g(x);\n" + " if (h(10)) g(x);\n" + " if (h(11)) g(x);\n" + " if (h(12)) g(x);\n" + " if (h(13)) g(x);\n" + " if (h(14)) g(x);\n" + " if (h(15)) g(x);\n" + " if (h(16)) g(x);\n" + " if (h(17)) g(x);\n" + " if (h(18)) g(x);\n" + " if (h(19)) g(x);\n" + " if (h(20)) g(x);\n" + " if (h(21)) g(x);\n" + " if (h(22)) g(x);\n" + " if (h(23)) g(x);\n" + " if (h(24)) g(x);\n" + " if (h(25)) g(x);\n" + " if (h(26)) g(x);\n" + " if (h(27)) g(x);\n" + " if (h(28)) g(x);\n" + " if (h(29)) g(x);\n" + " if (h(30)) g(x);\n" + " if (h(31)) g(x);\n" + " if (h(32)) g(x);\n" + " if (h(33)) g(x);\n" + " if (h(34)) g(x);\n" + " if (h(35)) g(x);\n" + " if (h(36)) g(x);\n" + " if (h(37)) g(x);\n" + " if (h(38)) g(x);\n" + " if (h(39)) g(x);\n" + " if (h(40)) g(x);\n" + " if (h(41)) g(x);\n" + " if (h(42)) g(x);\n" + " if (h(43)) g(x);\n" + " if (h(44)) g(x);\n" + " if (h(45)) g(x);\n" + " if (h(46)) g(x);\n" + " if (h(47)) g(x);\n" + " if (h(48)) g(x);\n" + " if (h(49)) g(x);\n" + " if (h(50)) g(x);\n" + " if (h(51)) g(x);\n" + " if (h(52)) g(x);\n" + " if (h(53)) g(x);\n" + " if (h(54)) g(x);\n" + " if (h(55)) g(x);\n" + " if (h(56)) g(x);\n" + " if (h(57)) g(x);\n" + " if (h(58)) g(x);\n" + " if (h(59)) g(x);\n" + " (void)x;\n" + "}\n"; + (void)valueOfTok(code, "x"); } void valueFlowCrashConstructorInitialization() { // #9577 From 1e1bc87e2b424512af04e071840f59512c3453f9 Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Mon, 6 Jul 2026 08:34:42 +0200 Subject: [PATCH 068/165] Fix #14884 fuzzing timeout (hang) in TemplateSimplifier::expandTemplate() (#8691) --- lib/templatesimplifier.cpp | 8 ++++++-- .../timeout-5225c0e6e895cdd05a15c388547d13a78a2574e2 | 1 + 2 files changed, 7 insertions(+), 2 deletions(-) create mode 100644 test/cli/fuzz-timeout/timeout-5225c0e6e895cdd05a15c388547d13a78a2574e2 diff --git a/lib/templatesimplifier.cpp b/lib/templatesimplifier.cpp index 4051b05c204..6fdd423628b 100644 --- a/lib/templatesimplifier.cpp +++ b/lib/templatesimplifier.cpp @@ -170,8 +170,12 @@ TemplateSimplifier::TokenAndName::TokenAndName(Token *token, std::string scope, if (isFunction()) tok1 = tok1->link()->next(); while (tok1 && !Token::Match(tok1, ";|{")) { - if (tok1->str() == "<") - tok1 = tok1->findClosingBracket(); + if (tok1->str() == "<") { + if (const Token* closing = tok1->findClosingBracket()) + tok1 = closing; + else + syntaxError(tok1); + } else if (Token::Match(tok1, "(|[") && tok1->link()) tok1 = tok1->link(); if (tok1) diff --git a/test/cli/fuzz-timeout/timeout-5225c0e6e895cdd05a15c388547d13a78a2574e2 b/test/cli/fuzz-timeout/timeout-5225c0e6e895cdd05a15c388547d13a78a2574e2 new file mode 100644 index 00000000000..71e751bb201 --- /dev/null +++ b/test/cli/fuzz-timeout/timeout-5225c0e6e895cdd05a15c388547d13a78a2574e2 @@ -0,0 +1 @@ +templatestruct e<; From 08db3048d54dcf6a3cc3b19613f286e30268cc9e Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Mon, 6 Jul 2026 09:11:57 +0200 Subject: [PATCH 069/165] Fix #14883 fuzzing crash (null-pointer-use) in Tokenizer::findGarbageCode() (#8692) --- lib/tokenize.cpp | 2 ++ .../fuzz-crash/crash-17be2b85446aeb0c7722bedfad4b0e4af27fae3d | 1 + 2 files changed, 3 insertions(+) create mode 100644 test/cli/fuzz-crash/crash-17be2b85446aeb0c7722bedfad4b0e4af27fae3d diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 61719f5291d..3046bea69cc 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -8962,6 +8962,8 @@ void Tokenizer::findGarbageCode() const const Token* const endTok = tok->linkAt(1); for (tok = tok->tokAt(2); tok != endTok; tok = tok->next()) { if (const Token* lam = findLambdaEndTokenWithoutAST(tok)) { + if (lam == endTok) + break; tok = lam; continue; } diff --git a/test/cli/fuzz-crash/crash-17be2b85446aeb0c7722bedfad4b0e4af27fae3d b/test/cli/fuzz-crash/crash-17be2b85446aeb0c7722bedfad4b0e4af27fae3d new file mode 100644 index 00000000000..0f06807b7ba --- /dev/null +++ b/test/cli/fuzz-crash/crash-17be2b85446aeb0c7722bedfad4b0e4af27fae3d @@ -0,0 +1 @@ +{for([]{});} From 42a08059f71f3952f7f992dfe82828e2af495c6e Mon Sep 17 00:00:00 2001 From: glankk Date: Tue, 7 Jul 2026 13:27:26 +0200 Subject: [PATCH 070/165] Fix #14898: Update simplecpp to 1.8.1 (#8702) --- .selfcheck_suppressions | 1 - externals/simplecpp/simplecpp.cpp | 216 +++++++++++++++++++----------- externals/simplecpp/simplecpp.h | 65 +++------ 3 files changed, 154 insertions(+), 128 deletions(-) diff --git a/.selfcheck_suppressions b/.selfcheck_suppressions index 402fdbeb75d..f21492e783a 100644 --- a/.selfcheck_suppressions +++ b/.selfcheck_suppressions @@ -79,4 +79,3 @@ useStlAlgorithm:externals/simplecpp/simplecpp.cpp funcArgNamesDifferentUnnamed:externals/simplecpp/simplecpp.h missingMemberCopy:externals/simplecpp/simplecpp.h shadowFunction:externals/simplecpp/simplecpp.h -knownConditionTrueFalse:externals/simplecpp/simplecpp.cpp \ No newline at end of file diff --git a/externals/simplecpp/simplecpp.cpp b/externals/simplecpp/simplecpp.cpp index 47e674837ba..d2c398c49e1 100644 --- a/externals/simplecpp/simplecpp.cpp +++ b/externals/simplecpp/simplecpp.cpp @@ -3,18 +3,12 @@ * Copyright (C) 2016-2023 simplecpp team */ +// needs to be specified here otherwise _mingw.h will define it as 0x0601 +// causing FileIdInfo not to be available #if defined(_WIN32) # ifndef _WIN32_WINNT # define _WIN32_WINNT 0x0602 # endif -# ifndef NOMINMAX -# define NOMINMAX -# endif -# ifndef WIN32_LEAN_AND_MEAN -# define WIN32_LEAN_AND_MEAN -# endif -# include -# undef ERROR #endif #include "simplecpp.h" @@ -51,10 +45,19 @@ #include #include -#ifdef _WIN32 +#if defined(_WIN32) +# ifndef NOMINMAX +# define NOMINMAX +# endif +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif +# include +# undef ERROR # include #else # include +# include #endif static bool isHex(const std::string &s) @@ -658,8 +661,6 @@ static const std::string COMMENT_END("*/"); void simplecpp::TokenList::readfile(Stream &stream, const std::string &filename, OutputList *outputList) { - std::stack loc; - unsigned int multiline = 0U; const Token *oldLastToken = nullptr; @@ -698,59 +699,44 @@ void simplecpp::TokenList::readfile(Stream &stream, const std::string &filename, if (oldLastToken != cback()) { oldLastToken = cback(); - const Token * const llTok = isLastLinePreprocessor(); - if (!llTok) + + // #line 3 + // #line 3 "file.c" + // #3 + // #3 "file.c" + const Token * ppTok = isLastLinePreprocessor(); + if (!ppTok) continue; - const Token * const llNextToken = llTok->next; - if (!llTok->next) + + const auto advanceAndSkipComments = [](const Token* tok) { + do { + tok = tok->next; + } while (tok && tok->comment); + return tok; + }; + + // skip # + ppTok = advanceAndSkipComments(ppTok); + if (!ppTok) continue; - if (llNextToken->next) { - // #file "file.c" - if (llNextToken->str() == "file" && - llNextToken->next->str()[0] == '\"') - { - const Token *strtok = cback(); - while (strtok->comment) - strtok = strtok->previous; - loc.push(location); - location.fileIndex = fileIndex(strtok->str().substr(1U, strtok->str().size() - 2U)); - location.line = 1U; - } - // TODO: add support for "# 3" - // #3 "file.c" - // #line 3 "file.c" - else if ((llNextToken->number && - llNextToken->next->str()[0] == '\"') || - (llNextToken->str() == "line" && - llNextToken->next->number && - llNextToken->next->next && - llNextToken->next->next->str()[0] == '\"')) - { - const Token *strtok = cback(); - while (strtok->comment) - strtok = strtok->previous; - const Token *numtok = strtok->previous; - while (numtok->comment) - numtok = numtok->previous; - lineDirective(fileIndex(replaceAll(strtok->str().substr(1U, strtok->str().size() - 2U),"\\\\","\\")), - std::atol(numtok->str().c_str()), location); - } - // #line 3 - else if (llNextToken->str() == "line" && - llNextToken->next->number) - { - const Token *numtok = cback(); - while (numtok->comment) - numtok = numtok->previous; - lineDirective(location.fileIndex, std::atol(numtok->str().c_str()), location); - } - } - // #endfile - else if (llNextToken->str() == "endfile" && !loc.empty()) - { - location = loc.top(); - loc.pop(); - } + + if (ppTok->str() == "line") + ppTok = advanceAndSkipComments(ppTok); + + if (!ppTok || !ppTok->number) + continue; + + const unsigned int line = std::atol(ppTok->str().c_str()); + ppTok = advanceAndSkipComments(ppTok); + + unsigned int fileindex; + + if (ppTok && ppTok->str()[0] == '\"') + fileindex = fileIndex(replaceAll(ppTok->str().substr(1U, ppTok->str().size() - 2U),"\\\\","\\")); + else + fileindex = location.fileIndex; + + lineDirective(fileindex, line, location); } continue; @@ -1031,8 +1017,7 @@ static bool isAlternativeAndBitandBitor(const simplecpp::Token* tok) void simplecpp::TokenList::combineOperators() { - std::stack executableScope; - executableScope.push(false); + std::stack> executableScope{{false}}; for (Token *tok = front(); tok; tok = tok->next) { if (tok->op == '{') { if (executableScope.top()) { @@ -1040,7 +1025,7 @@ void simplecpp::TokenList::combineOperators() continue; } const Token *prev = tok->previous; - while (prev && prev->isOneOf(";{}()")) + while (prev && prev->isOneOf(";{}(")) prev = prev->previous; executableScope.push(prev && prev->op == ')'); continue; @@ -2332,9 +2317,6 @@ namespace simplecpp { const Token *nextTok = B->next; if (canBeConcatenatedStringOrChar) { - if (unexpectedA) - throw invalidHashHash::unexpectedToken(tok->location, name(), A); - // It seems clearer to handle this case separately even though the code is similar-ish, but we don't want to merge here. // TODO The question is whether the ## or varargs may still apply, and how to provoke? if (expandArg(tokensB, B, parametertokens)) { @@ -3090,6 +3072,65 @@ static std::string openHeader(std::ifstream &f, const simplecpp::DUI &dui, const return ""; } +namespace { + struct FileID { +#ifdef _WIN32 + struct { + std::uint64_t VolumeSerialNumber; + struct { + std::uint64_t IdentifierHi; + std::uint64_t IdentifierLo; + } FileId; + } fileIdInfo; + + bool operator==(const FileID &that) const noexcept { + return fileIdInfo.VolumeSerialNumber == that.fileIdInfo.VolumeSerialNumber && + fileIdInfo.FileId.IdentifierHi == that.fileIdInfo.FileId.IdentifierHi && + fileIdInfo.FileId.IdentifierLo == that.fileIdInfo.FileId.IdentifierLo; + } +#else + dev_t dev; + ino_t ino; + + bool operator==(const FileID& that) const noexcept { + return dev == that.dev && ino == that.ino; + } +#endif + struct Hasher { + std::size_t operator()(const FileID &id) const { +#ifdef _WIN32 + return static_cast(id.fileIdInfo.FileId.IdentifierHi ^ id.fileIdInfo.FileId.IdentifierLo ^ + id.fileIdInfo.VolumeSerialNumber); +#else + return static_cast(id.dev) ^ static_cast(id.ino); +#endif + } + }; + }; +} + +struct simplecpp::FileDataCache::Impl +{ + void clear() + { + mIdMap.clear(); + } + + using id_map_type = std::unordered_map; + + id_map_type mIdMap; +}; + +simplecpp::FileDataCache::FileDataCache() + : mImpl(new Impl) +{} + +simplecpp::FileDataCache::~FileDataCache() = default; +simplecpp::FileDataCache::FileDataCache(FileDataCache &&) noexcept = default; +simplecpp::FileDataCache &simplecpp::FileDataCache::operator=(simplecpp::FileDataCache &&) noexcept = default; + +static bool getFileId(const std::string &path, FileID &id); + std::pair simplecpp::FileDataCache::tryload(FileDataCache::name_map_type::iterator &name_it, const simplecpp::DUI &dui, std::vector &filenames, simplecpp::OutputList *outputList) { const std::string &path = name_it->first; @@ -3098,8 +3139,8 @@ std::pair simplecpp::FileDataCache::tryload(FileDat if (!getFileId(path, fileId)) return {nullptr, false}; - const auto id_it = mIdMap.find(fileId); - if (id_it != mIdMap.end()) { + const auto id_it = mImpl->mIdMap.find(fileId); + if (id_it != mImpl->mIdMap.end()) { name_it->second = id_it->second; return {id_it->second, false}; } @@ -3110,9 +3151,12 @@ std::pair simplecpp::FileDataCache::tryload(FileDat data->tokens.removeComments(); name_it->second = data; - mIdMap.emplace(fileId, data); + mImpl->mIdMap.emplace(fileId, data); mData.emplace_back(data); + if (mLoadCallback) + mLoadCallback(*data); + return {data, true}; } @@ -3162,7 +3206,14 @@ std::pair simplecpp::FileDataCache::get(const std:: return {nullptr, false}; } -bool simplecpp::FileDataCache::getFileId(const std::string &path, FileID &id) +void simplecpp::FileDataCache::clear() +{ + mImpl->clear(); + mNameMap.clear(); + mData.clear(); +} + +static bool getFileId(const std::string &path, FileID &id) { #ifdef _WIN32 HANDLE hFile = CreateFileA(path.c_str(), 0, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); @@ -3349,20 +3400,20 @@ void simplecpp::preprocess(simplecpp::TokenList &output, const simplecpp::TokenL std::map sizeOfType(rawtokens.sizeOfType); sizeOfType.insert(std::make_pair("char", sizeof(char))); sizeOfType.insert(std::make_pair("short", sizeof(short))); - sizeOfType.insert(std::make_pair("short int", sizeOfType["short"])); + sizeOfType.insert(std::make_pair("short int", sizeof(short))); sizeOfType.insert(std::make_pair("int", sizeof(int))); sizeOfType.insert(std::make_pair("long", sizeof(long))); - sizeOfType.insert(std::make_pair("long int", sizeOfType["long"])); + sizeOfType.insert(std::make_pair("long int", sizeof(long))); sizeOfType.insert(std::make_pair("long long", sizeof(long long))); sizeOfType.insert(std::make_pair("float", sizeof(float))); sizeOfType.insert(std::make_pair("double", sizeof(double))); sizeOfType.insert(std::make_pair("long double", sizeof(long double))); sizeOfType.insert(std::make_pair("char *", sizeof(char *))); sizeOfType.insert(std::make_pair("short *", sizeof(short *))); - sizeOfType.insert(std::make_pair("short int *", sizeOfType["short *"])); + sizeOfType.insert(std::make_pair("short int *", sizeof(short *))); sizeOfType.insert(std::make_pair("int *", sizeof(int *))); sizeOfType.insert(std::make_pair("long *", sizeof(long *))); - sizeOfType.insert(std::make_pair("long int *", sizeOfType["long *"])); + sizeOfType.insert(std::make_pair("long int *", sizeof(long *))); sizeOfType.insert(std::make_pair("long long *", sizeof(long long *))); sizeOfType.insert(std::make_pair("float *", sizeof(float *))); sizeOfType.insert(std::make_pair("double *", sizeof(double *))); @@ -3466,8 +3517,19 @@ void simplecpp::preprocess(simplecpp::TokenList &output, const simplecpp::TokenL includetokenstack.push(rawtokens.cfront()); for (auto it = dui.includes.cbegin(); it != dui.includes.cend(); ++it) { const FileData *const filedata = cache.get("", *it, dui, false, files, outputList).first; - if (filedata != nullptr && filedata->tokens.cfront() != nullptr) + if (filedata == nullptr) { + if (outputList) { + simplecpp::Output err{ + simplecpp::Output::EXPLICIT_INCLUDE_NOT_FOUND, + {}, + "Can not open include file '" + *it + "' that is explicitly included." + }; + outputList->emplace_back(std::move(err)); + } + } + else if (filedata->tokens.cfront() != nullptr) { includetokenstack.push(filedata->tokens.cfront()); + } } std::map> maybeUsedMacros; diff --git a/externals/simplecpp/simplecpp.h b/externals/simplecpp/simplecpp.h index f29166ff061..3d6fc5262b9 100644 --- a/externals/simplecpp/simplecpp.h +++ b/externals/simplecpp/simplecpp.h @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -41,10 +42,6 @@ # define SIMPLECPP_LIB #endif -#ifndef _WIN32 -# include -#endif - #if defined(_MSC_VER) # pragma warning(push) // suppress warnings about "conversion from 'type1' to 'type2', possible loss of data" @@ -452,13 +449,14 @@ namespace simplecpp { class SIMPLECPP_LIB FileDataCache { public: - FileDataCache() = default; + FileDataCache(); + ~FileDataCache(); FileDataCache(const FileDataCache &) = delete; - FileDataCache(FileDataCache &&) = default; + FileDataCache(FileDataCache &&) noexcept; FileDataCache &operator=(const FileDataCache &) = delete; - FileDataCache &operator=(FileDataCache &&) = default; + FileDataCache &operator=(FileDataCache &&) noexcept; /** Get the cached data for a file, or load and then return it if it isn't cached. * returns the file data and true if the file was loaded, false if it was cached. */ @@ -472,11 +470,7 @@ namespace simplecpp { mNameMap.emplace(newdata->filename, newdata); } - void clear() { - mNameMap.clear(); - mIdMap.clear(); - mData.clear(); - } + void clear(); using container_type = std::vector>; using iterator = container_type::iterator; @@ -505,52 +499,23 @@ namespace simplecpp { return mData.cend(); } - private: - struct FileID { -#ifdef _WIN32 - struct { - std::uint64_t VolumeSerialNumber; - struct { - std::uint64_t IdentifierHi; - std::uint64_t IdentifierLo; - } FileId; - } fileIdInfo; - - bool operator==(const FileID &that) const noexcept { - return fileIdInfo.VolumeSerialNumber == that.fileIdInfo.VolumeSerialNumber && - fileIdInfo.FileId.IdentifierHi == that.fileIdInfo.FileId.IdentifierHi && - fileIdInfo.FileId.IdentifierLo == that.fileIdInfo.FileId.IdentifierLo; - } -#else - dev_t dev; - ino_t ino; + using load_callback_type = std::function; - bool operator==(const FileID& that) const noexcept { - return dev == that.dev && ino == that.ino; - } -#endif - struct Hasher { - std::size_t operator()(const FileID &id) const { -#ifdef _WIN32 - return static_cast(id.fileIdInfo.FileId.IdentifierHi ^ id.fileIdInfo.FileId.IdentifierLo ^ - id.fileIdInfo.VolumeSerialNumber); -#else - return static_cast(id.dev) ^ static_cast(id.ino); -#endif - } - }; - }; + void set_load_callback(load_callback_type cb) { + mLoadCallback = std::move(cb); + } - using name_map_type = std::unordered_map; - using id_map_type = std::unordered_map; + private: + struct Impl; + std::unique_ptr mImpl; - static bool getFileId(const std::string &path, FileID &id); + using name_map_type = std::unordered_map; std::pair tryload(name_map_type::iterator &name_it, const DUI &dui, std::vector &filenames, OutputList *outputList); container_type mData; name_map_type mNameMap; - id_map_type mIdMap; + load_callback_type mLoadCallback; }; /** Converts character literal (including prefix, but not ud-suffix) to long long value. From e7e54f7ea596fe252f39f405f4aae0c4f45d3b76 Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Tue, 7 Jul 2026 15:09:18 +0200 Subject: [PATCH 071/165] Fix #14889 FP constStatement with GNU statement expression (#8698) --- lib/checkother.cpp | 2 +- test/testincompletestatement.cpp | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/checkother.cpp b/lib/checkother.cpp index 51124c45d1c..ef6fb9003b1 100644 --- a/lib/checkother.cpp +++ b/lib/checkother.cpp @@ -2408,7 +2408,7 @@ void CheckOtherImpl::checkIncompleteStatement() !(tok->str() == "," && tok->astParent() && tok->astParent()->isAssignmentOp())) continue; // Skip statement expressions - if (Token::simpleMatch(rtok, "; } )")) + if (Token::simpleMatch(rtok, "; } )") || Token::simpleMatch(tok->next(), "; } )")) continue; if (!isConstStatement(tok, mSettings.library, false)) continue; diff --git a/test/testincompletestatement.cpp b/test/testincompletestatement.cpp index b72b6524872..806f734274e 100644 --- a/test/testincompletestatement.cpp +++ b/test/testincompletestatement.cpp @@ -758,6 +758,11 @@ class TestIncompleteStatement : public TestFixture { "}\n"); ASSERT_EQUALS("[test.cpp:4:6]: (warning) Redundant code: Found unused array access. [constStatement]\n", errout_str()); + + check("int f(int i) {\n" // #14889 + " return i ? 8 : ({ int x = 2; x; });\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); } void vardecl() { From 7cc7c0bb500d775d4d533ace64295c2cd0fa7134 Mon Sep 17 00:00:00 2001 From: correctmost <134317971+correctmost@users.noreply.github.com> Date: Wed, 8 Jul 2026 02:33:51 -0400 Subject: [PATCH 072/165] gtk.cfg: Add pure annotations for more GLib functions (#8687) This fixes assertWithSideEffect false positives for the following functions: g_error_matches g_list_find g_str_has_prefix g_str_has_suffix --- cfg/gtk.cfg | 3 +++ test/cfg/gtk.c | 13 +++++++++++++ 2 files changed, 16 insertions(+) diff --git a/cfg/gtk.cfg b/cfg/gtk.cfg index 71d0f3dee05..e28aa2ad7a5 100644 --- a/cfg/gtk.cfg +++ b/cfg/gtk.cfg @@ -2251,6 +2251,7 @@
+ false @@ -5218,6 +5219,7 @@ + false @@ -6586,6 +6588,7 @@ + false diff --git a/test/cfg/gtk.c b/test/cfg/gtk.c index 4accf7b63ec..6b48bca2f9e 100644 --- a/test/cfg/gtk.c +++ b/test/cfg/gtk.c @@ -59,6 +59,8 @@ void validCode(int argInt, GHashTableIter * hash_table_iter, GHashTable * hash_t g_string_free(pGStr1, TRUE); gchar * pGchar1 = g_strconcat("a", "b", NULL); + g_assert_true(g_str_has_prefix(pGchar1, "a")); + g_assert_true(g_str_has_suffix(pGchar1, "b")); printf("%s", pGchar1); g_free(pGchar1); @@ -406,6 +408,7 @@ void g_error_new_test() g_error_new(1, -2, "a %d", 1); const GError * pNew2 = g_error_new(1, -2, "a %d", 1); + g_assert_true(g_error_matches(pNew2, 1, -2)); printf("%p", pNew2); // cppcheck-suppress memleak } @@ -530,6 +533,16 @@ void g_variant_test() { // cppcheck-suppress memleak } +void g_list_test() { + GList *list1 = NULL; + gchar *c = "c"; + + list1 = g_list_append(list1, c); + g_assert_true(g_list_find(list1, c) != NULL); + + g_list_free(list1); +} + void g_queue_test() { // cppcheck-suppress leakReturnValNotUsed g_queue_new(); From ee22150faf8a585c0ad3406534f5159045601041 Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Wed, 8 Jul 2026 08:34:13 +0200 Subject: [PATCH 073/165] Fix #13846 FP invalidFunctionArgBool with Qt SLOT() macro (#8686) `` causes a warning when passing `false`, which is rejected by a modern compiler anyway. --------- Co-authored-by: chrchr-github --- cfg/qt.cfg | 1 - test/cfg/qt.cpp | 11 +++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/cfg/qt.cfg b/cfg/qt.cfg index 66f6e78b3b6..c7bf3d8779b 100644 --- a/cfg/qt.cfg +++ b/cfg/qt.cfg @@ -410,7 +410,6 @@ - diff --git a/test/cfg/qt.cpp b/test/cfg/qt.cpp index 78827d3583c..2b683648dcd 100644 --- a/test/cfg/qt.cpp +++ b/test/cfg/qt.cpp @@ -33,6 +33,7 @@ #include #include #include +#include // TODO: this is actually available via Core5Compat but I could not get it to work with pkg-config #if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) @@ -892,3 +893,13 @@ int qdateIsValid() Q_ASSERT(qd.isValid()); // Should not warn here with assertWithSideEffect return qd.month(); } + +struct S_QTimer_connect : QObject { // #13846 + S_QTimer_connect() { + // cppcheck-suppress checkLibraryFunction - timeout() is a signal from QTimer + QObject::connect(&timer, SIGNAL(timeout()), this, SLOT(update())); + } + QTimer timer; +private slots: + bool update(); +}; From a93e550d041337164dd17f15d240151010658641 Mon Sep 17 00:00:00 2001 From: glankk Date: Wed, 8 Jul 2026 11:52:51 +0200 Subject: [PATCH 074/165] Fix #14113 (Slow analysis: microchip xc16 code) (#7838) --- .github/workflows/selfcheck.yml | 2 +- .selfcheck_suppressions | 2 + lib/cppcheck.cpp | 113 ++++++++++++++++++------- lib/cppcheck.h | 5 +- lib/errorlogger.cpp | 9 +- lib/errorlogger.h | 18 ++-- lib/preprocessor.cpp | 142 +++++++++++++------------------- lib/preprocessor.h | 35 +++++--- test/cli/performance_test.py | 25 ++++++ test/helpers.cpp | 3 +- test/testcppcheck.cpp | 7 +- test/testpreprocessor.cpp | 63 ++++++++++++-- test/testtokenize.cpp | 8 +- 13 files changed, 283 insertions(+), 149 deletions(-) diff --git a/.github/workflows/selfcheck.yml b/.github/workflows/selfcheck.yml index 6d100c4ddc8..1a213039f93 100644 --- a/.github/workflows/selfcheck.yml +++ b/.github/workflows/selfcheck.yml @@ -121,7 +121,7 @@ jobs: - name: Self check (unusedFunction / no test / no gui) run: | - supprs="--suppress=unusedFunction:lib/errorlogger.h:197 --suppress=unusedFunction:lib/importproject.cpp:1671 --suppress=unusedFunction:lib/importproject.cpp:1695" + supprs="--suppress=unusedFunction:lib/errorlogger.h:198 --suppress=unusedFunction:lib/importproject.cpp:1671 --suppress=unusedFunction:lib/importproject.cpp:1695" ./cppcheck -q --template=selfcheck --error-exitcode=1 --library=cppcheck-lib -D__CPPCHECK__ -D__GNUC__ --enable=unusedFunction,information --exception-handling -rp=. --project=cmake.output.notest_nogui/compile_commands.json --suppressions-list=.selfcheck_unused_suppressions --inline-suppr $supprs env: DISABLE_VALUEFLOW: 1 diff --git a/.selfcheck_suppressions b/.selfcheck_suppressions index f21492e783a..63d33fd2704 100644 --- a/.selfcheck_suppressions +++ b/.selfcheck_suppressions @@ -62,6 +62,8 @@ templateInstantiation:test/testutils.cpp naming-varname:externals/simplecpp/simplecpp.h naming-privateMemberVariable:externals/simplecpp/simplecpp.h +# false positive; lambda captures its owner +danglingLifetime:externals/simplecpp/simplecpp.h:505 # TODO: these warnings need to be addressed upstream uninitMemberVar:externals/tinyxml2/tinyxml2.h diff --git a/lib/cppcheck.cpp b/lib/cppcheck.cpp index 50f7fa36e80..26d98c0c7b4 100644 --- a/lib/cppcheck.cpp +++ b/lib/cppcheck.cpp @@ -61,6 +61,7 @@ #include // IWYU pragma: keep #include #include +#include #include #include #include @@ -100,9 +101,9 @@ class CppCheck::CppCheckLogger : public ErrorLogger closePlist(); } - void setRemarkComments(std::vector remarkComments) + void addRemarkComments(const std::vector &remarkComments) { - mRemarkComments = std::move(remarkComments); + mRemarkComments.insert(mRemarkComments.end(), remarkComments.begin(), remarkComments.end()); } void setLocationMacros(const Token* startTok, const std::vector& files) @@ -124,17 +125,25 @@ class CppCheck::CppCheckLogger : public ErrorLogger mErrorList.clear(); } - void openPlist(const std::string& filename, const std::vector& files) + void openPlist(const std::string& filename) { mPlistFile.open(filename); - mPlistFile << ErrorLogger::plistHeader(version(), files); + mPlistFile << ErrorLogger::plistHeader(version()); + } + + void setPlistFilenames(std::vector files) + { + if (mPlistFile.is_open()) { + mPlistFilenames = std::move(files); + } } void closePlist() { if (mPlistFile.is_open()) { - mPlistFile << ErrorLogger::plistFooter(); + mPlistFile << ErrorLogger::plistFooter(mPlistFilenames); mPlistFile.close(); + mPlistFilenames.clear(); } } @@ -282,6 +291,7 @@ class CppCheck::CppCheckLogger : public ErrorLogger std::map> mLocationMacros; // What macros are used on a location? std::ofstream mPlistFile; + std::vector mPlistFilenames; unsigned int mExitCode{}; @@ -898,7 +908,7 @@ unsigned int CppCheck::checkFile(const FileWithDetails& file, const std::string return checkInternal(file, cfgname, f); } -void CppCheck::checkPlistOutput(const FileWithDetails& file, const std::vector& files) +void CppCheck::checkPlistOutput(const FileWithDetails& file) { if (!mSettings.plistOutput.empty()) { const bool slashFound = file.spath().find('/') != std::string::npos; @@ -909,7 +919,7 @@ void CppCheck::checkPlistOutput(const FileWithDetails& file, const std::vector {}(file.spath()); filename = mSettings.plistOutput + noSuffixFilename + "_" + std::to_string(fileNameHash) + ".plist"; - mLogger->openPlist(filename, files); + mLogger->openPlist(filename); } } @@ -1000,24 +1010,16 @@ unsigned int CppCheck::checkInternal(const FileWithDetails& file, const std::str if (preprocessor.reportOutput(outputList, true)) return mLogger->exitcode(); - if (!preprocessor.loadFiles(files)) - return mLogger->exitcode(); - - checkPlistOutput(file, files); + checkPlistOutput(file); - std::string dumpProlog; + std::string dumpFooter; if (mSettings.dump || !mSettings.addons.empty()) { - dumpProlog += getDumpFileContentsRawTokens(files, tokens1); + dumpFooter += getDumpFileContentsRawTokensFooter(tokens1); } // Parse comments and then remove them - mLogger->setRemarkComments(preprocessor.getRemarkComments()); + mLogger->addRemarkComments(preprocessor.getRemarkComments()); preprocessor.inlineSuppressions(mSuppressions.nomsg); - if (mSettings.dump || !mSettings.addons.empty()) { - std::ostringstream oss; - mSuppressions.nomsg.dump(oss); - dumpProlog += oss.str(); - } preprocessor.removeComments(); if (!mSettings.buildDir.empty()) { @@ -1040,19 +1042,45 @@ unsigned int CppCheck::checkInternal(const FileWithDetails& file, const std::str } // Get directives - std::list directives = preprocessor.createDirectives(); + std::list directives; + preprocessor.createDirectives(directives); preprocessor.simplifyPragmaAsm(); + std::set configurations; + std::set configDefines = { "__cplusplus" }; + + // Insert library defines + const auto getDefineName = [](const std::string &defineString) { + return defineString.substr(0, defineString.find_first_of("( ")); + }; + std::transform(mSettings.library.defines().begin(), + mSettings.library.defines().end(), + std::inserter(configDefines, configDefines.end()), + getDefineName); + + preprocessor.setLoadCallback([&](simplecpp::FileData &data) { + // Do preprocessing on included file + mLogger->addRemarkComments(preprocessor.getRemarkComments(data.tokens)); + preprocessor.inlineSuppressions(data.tokens, mSuppressions.nomsg); + Preprocessor::removeComments(data.tokens); + Preprocessor::createDirectives(data.tokens, directives); + Preprocessor::simplifyPragmaAsm(data.tokens); + // Discover new configurations from included file + if (configurations.size() < maxConfigs) + preprocessor.getConfigs(data.filename, data.tokens, configDefines, configurations); + }); + preprocessor.setPlatformInfo(); // Get configurations.. - std::set configurations; if (maxConfigs > 1) { Timer::run("Preprocessor::getConfigs", mTimerResults, [&]() { - configurations = preprocessor.getConfigs(); + configurations = { "" }; + preprocessor.getConfigs(configDefines, configurations); + preprocessor.loadFiles(files); }); } else { - configurations.insert(mSettings.userDefines); + configurations = { mSettings.userDefines }; } if (mSettings.checkConfiguration) { @@ -1089,7 +1117,6 @@ unsigned int CppCheck::checkInternal(const FileWithDetails& file, const std::str createDumpFile(mSettings, file, fdump, dumpFile); if (fdump.is_open()) { fdump << getLibraryDumpData(); - fdump << dumpProlog; if (!mSettings.dump) filesDeleter.addFile(dumpFile); } @@ -1259,12 +1286,20 @@ unsigned int CppCheck::checkInternal(const FileWithDetails& file, const std::str } // TODO: will not be closed if we encountered an exception - // dumped all configs, close root element now if (fdump.is_open()) { + // dump all filenames, raw tokens, suppressions + std::string dumpHeader = getDumpFileContentsRawTokensHeader(files); + fdump << getDumpFileContentsRawTokens(dumpHeader, dumpFooter); + mSuppressions.nomsg.dump(fdump); + // dumped all configs, close root element now fdump << "" << std::endl; fdump.close(); } + if (!mSettings.plistOutput.empty()) { + mLogger->setPlistFilenames(std::move(files)); + } + executeAddons(dumpFile, file); } catch (const TerminateException &) { // Analysis is terminated @@ -1892,9 +1927,26 @@ bool CppCheck::isPremiumCodingStandardId(const std::string& id) const { return false; } -std::string CppCheck::getDumpFileContentsRawTokens(const std::vector& files, const simplecpp::TokenList& tokens1) const { +std::string CppCheck::getDumpFileContentsRawTokens(const std::vector& files, const simplecpp::TokenList& tokens1) const +{ + std::string header = getDumpFileContentsRawTokensHeader(files); + std::string footer = getDumpFileContentsRawTokensFooter(tokens1); + return getDumpFileContentsRawTokens(header, footer); +} + +std::string CppCheck::getDumpFileContentsRawTokens(const std::string& header, const std::string& footer) +{ std::string dumpProlog; dumpProlog += " \n"; + dumpProlog += header; + dumpProlog += footer; + dumpProlog += " \n"; + return dumpProlog; +} + +std::string CppCheck::getDumpFileContentsRawTokensHeader(const std::vector& files) const +{ + std::string dumpProlog; for (unsigned int i = 0; i < files.size(); ++i) { dumpProlog += " \n"; } + return dumpProlog; +} + +std::string CppCheck::getDumpFileContentsRawTokensFooter(const simplecpp::TokenList& tokens1) +{ + std::string dumpProlog; for (const simplecpp::Token *tok = tokens1.cfront(); tok; tok = tok->next) { dumpProlog += " location.line); dumpProlog += "\" "; - dumpProlog +="column=\""; + dumpProlog += "column=\""; dumpProlog += std::to_string(tok->location.col); dumpProlog += "\" "; @@ -1923,6 +1981,5 @@ std::string CppCheck::getDumpFileContentsRawTokens(const std::vector contents, this is only public for testing purposes */ std::string getDumpFileContentsRawTokens(const std::vector& files, const simplecpp::TokenList& tokens1) const; + static std::string getDumpFileContentsRawTokens(const std::string& header, const std::string& footer); + std::string getDumpFileContentsRawTokensHeader(const std::vector& files) const; + static std::string getDumpFileContentsRawTokensFooter(const simplecpp::TokenList& tokens1); std::string getLibraryDumpData() const; @@ -183,7 +186,7 @@ class CPPCHECKLIB CppCheck { */ unsigned int checkFile(const FileWithDetails& file, const std::string &cfgname); - void checkPlistOutput(const FileWithDetails& file, const std::vector& files); + void checkPlistOutput(const FileWithDetails& file); /** * @brief Check a file using buffer diff --git a/lib/errorlogger.cpp b/lib/errorlogger.cpp index 3b05a7d5a8f..d58c5abcbba 100644 --- a/lib/errorlogger.cpp +++ b/lib/errorlogger.cpp @@ -821,7 +821,7 @@ std::string ErrorLogger::toxml(const std::string &str) return xml; } -std::string ErrorLogger::plistHeader(const std::string &version, const std::vector &files) +std::string ErrorLogger::plistHeader(const std::string &version) { std::ostringstream ostr; ostr << "\r\n" @@ -829,12 +829,7 @@ std::string ErrorLogger::plistHeader(const std::string &version, const std::vect << "\r\n" << "\r\n" << " clang_version\r\n" - << "cppcheck version " << version << "\r\n" - << " files\r\n" - << " \r\n"; - for (const std::string & file : files) - ostr << " " << ErrorLogger::toxml(file) << "\r\n"; - ostr << " \r\n" + << " cppcheck version " << version << "\r\n" << " diagnostics\r\n" << " \r\n"; return ostr.str(); diff --git a/lib/errorlogger.h b/lib/errorlogger.h index daf683bd0a3..97cc3e7f82e 100644 --- a/lib/errorlogger.h +++ b/lib/errorlogger.h @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -271,12 +272,19 @@ class CPPCHECKLIB ErrorLogger { */ static std::string toxml(const std::string &str); - static std::string plistHeader(const std::string &version, const std::vector &files); + static std::string plistHeader(const std::string &version); static std::string plistData(const ErrorMessage &msg); - static const char *plistFooter() { - return " \r\n" - "\r\n" - ""; + static std::string plistFooter(const std::vector& files) { + std::ostringstream ostr; + ostr << " \r\n" + << " files\r\n" + << " \r\n"; + for (const std::string& file : files) + ostr << " " << ErrorLogger::toxml(file) << "\r\n"; + ostr << " \r\n" + << "\r\n" + << ""; + return ostr.str(); } static bool isCriticalErrorId(const std::string& id) { diff --git a/lib/preprocessor.cpp b/lib/preprocessor.cpp index 4246da39c83..3e0b33c7f10 100644 --- a/lib/preprocessor.cpp +++ b/lib/preprocessor.cpp @@ -336,67 +336,49 @@ static void addInlineSuppressions(const simplecpp::TokenList &tokens, const Sett } } -void Preprocessor::inlineSuppressions(SuppressionList &suppressions) +void Preprocessor::inlineSuppressions(SuppressionList &suppressions) const +{ + inlineSuppressions(mTokens, suppressions); +} + +void Preprocessor::inlineSuppressions(const simplecpp::TokenList &tokens, SuppressionList &suppressions) const { if (!mSettings.inlineSuppressions) return; std::list err; - ::addInlineSuppressions(mTokens, mSettings, suppressions, err); - for (const auto &filedata : mFileCache) { - ::addInlineSuppressions(filedata->tokens, mSettings, suppressions, err); - } + ::addInlineSuppressions(tokens, mSettings, suppressions, err); for (const BadInlineSuppression &bad : err) { invalidSuppression(bad.location, bad.errmsg); } } -std::vector Preprocessor::getRemarkComments() const +void Preprocessor::createDirectives(std::list &directives) const { - std::vector ret; - addRemarkComments(mTokens, ret); - for (const auto &filedata : mFileCache) { - addRemarkComments(filedata->tokens, ret); - } - return ret; + createDirectives(mTokens, directives); } -std::list Preprocessor::createDirectives() const +void Preprocessor::createDirectives(const simplecpp::TokenList &tokens, std::list &directives) { - // directive list.. - std::list directives; - - std::vector list; - list.reserve(1U + mFileCache.size()); - list.push_back(&mTokens); - std::transform(mFileCache.cbegin(), mFileCache.cend(), std::back_inserter(list), - [](const std::unique_ptr &filedata) { - return &filedata->tokens; - }); - - for (const simplecpp::TokenList *tokenList : list) { - for (const simplecpp::Token *tok = tokenList->cfront(); tok; tok = tok->next) { - if ((tok->op != '#') || (tok->previous && tok->previous->location.line == tok->location.line)) - continue; - if (tok->next && tok->next->str() == "endfile") + for (const simplecpp::Token *tok = tokens.cfront(); tok; tok = tok->next) { + if ((tok->op != '#') || (tok->previous && tok->previous->location.line == tok->location.line)) + continue; + if (tok->next && tok->next->str() == "endfile") + continue; + Directive directive(tokens, tok->location, ""); + for (const simplecpp::Token *tok2 = tok; tok2 && tok2->location.line == directive.linenr; tok2 = tok2->next) { + if (tok2->comment) continue; - Directive directive(mTokens, tok->location, ""); - for (const simplecpp::Token *tok2 = tok; tok2 && tok2->location.line == directive.linenr; tok2 = tok2->next) { - if (tok2->comment) - continue; - if (!directive.str.empty() && (tok2->location.col > tok2->previous->location.col + tok2->previous->str().size())) - directive.str += ' '; - if (directive.str == "#" && tok2->str() == "file") - directive.str += "include"; - else - directive.str += tok2->str(); - - directive.strTokens.emplace_back(*tok2); - } - directives.push_back(std::move(directive)); + if (!directive.str.empty() && (tok2->location.col > tok2->previous->location.col + tok2->previous->str().size())) + directive.str += ' '; + if (directive.str == "#" && tok2->str() == "file") + directive.str += "include"; + else + directive.str += tok2->str(); + + directive.strTokens.emplace_back(*tok2); } + directives.push_back(std::move(directive)); } - - return directives; } static std::string readcondition(const simplecpp::Token *iftok, const std::set &defined, const std::set &undefined) @@ -769,36 +751,21 @@ static void getConfigs(const simplecpp::TokenList &tokens, std::set ret.insert(std::move(elseError)); } - -std::set Preprocessor::getConfigs() const +void Preprocessor::getConfigs(std::set &defined, std::set &configs) const { - std::set ret = { "" }; if (!mTokens.cfront()) - return ret; - - std::set defined = { "__cplusplus" }; - - // Insert library defines - for (const auto &define : mSettings.library.defines()) { - - const std::string::size_type paren = define.find("("); - const std::string::size_type space = define.find(" "); - std::string::size_type end = space; - - if (paren != std::string::npos && paren < space) - end = paren; - - defined.insert(define.substr(0, end)); - } + return; - ::getConfigs(mTokens, defined, mSettings.userDefines, mSettings.userUndefs, ret); + ::getConfigs(mTokens, defined, mSettings.userDefines, mSettings.userUndefs, configs); +} - for (const auto &filedata : mFileCache) { - if (!mSettings.configurationExcluded(filedata->filename)) - ::getConfigs(filedata->tokens, defined, mSettings.userDefines, mSettings.userUndefs, ret); - } +void Preprocessor::getConfigs(const std::string &filename, const simplecpp::TokenList &tokens, std::set &defined, std::set &configs) const +{ + if (!tokens.cfront()) + return; - return ret; + if (!mSettings.configurationExcluded(filename)) + ::getConfigs(tokens, defined, mSettings.userDefines, mSettings.userUndefs, configs); } static void splitcfg(const std::string &cfgStr, std::list &defines, const std::string &defaultValue) @@ -871,16 +838,18 @@ bool Preprocessor::loadFiles(std::vector &files) const simplecpp::DUI dui = createDUI(mSettings, "", mLang); simplecpp::OutputList outputList; - mFileCache = simplecpp::load(mTokens, files, dui, &outputList); + mFileCache = simplecpp::load(mTokens, files, dui, &outputList, std::move(mFileCache)); return !handleErrors(outputList); } void Preprocessor::removeComments() { - mTokens.removeComments(); - for (const auto &filedata : mFileCache) { - filedata->tokens.removeComments(); - } + removeComments(mTokens); +} + +void Preprocessor::removeComments(simplecpp::TokenList &tokens) +{ + tokens.removeComments(); } void Preprocessor::setPlatformInfo() @@ -1016,12 +985,12 @@ static std::string simplecppErrToId(simplecpp::Output::Type type) cppcheck::unreachable(); } -void Preprocessor::error(const simplecpp::Location& loc, const std::string &msg, simplecpp::Output::Type type) +void Preprocessor::error(const simplecpp::Location& loc, const std::string &msg, simplecpp::Output::Type type) const { error(loc, msg, simplecppErrToId(type)); } -void Preprocessor::error(const simplecpp::Location& loc, const std::string &msg, const std::string& id) +void Preprocessor::error(const simplecpp::Location& loc, const std::string &msg, const std::string& id) const { std::list locationList; if (!mTokens.file(loc).empty()) { @@ -1059,7 +1028,7 @@ void Preprocessor::missingInclude(const simplecpp::Location& loc, const std::str mErrorLogger.reportErr(errmsg); } -void Preprocessor::invalidSuppression(const simplecpp::Location& loc, const std::string &msg) +void Preprocessor::invalidSuppression(const simplecpp::Location& loc, const std::string &msg) const { error(loc, msg, "invalidSuppression"); } @@ -1143,13 +1112,10 @@ std::size_t Preprocessor::calculateHash(const std::string &toolinfo) const void Preprocessor::simplifyPragmaAsm() { - Preprocessor::simplifyPragmaAsmPrivate(mTokens); - for (const auto &filedata : mFileCache) { - Preprocessor::simplifyPragmaAsmPrivate(filedata->tokens); - } + simplifyPragmaAsm(mTokens); } -void Preprocessor::simplifyPragmaAsmPrivate(simplecpp::TokenList &tokenList) +void Preprocessor::simplifyPragmaAsm(simplecpp::TokenList &tokenList) { // assembler code.. for (simplecpp::Token *tok = tokenList.front(); tok; tok = tok->next) { @@ -1196,9 +1162,15 @@ void Preprocessor::simplifyPragmaAsmPrivate(simplecpp::TokenList &tokenList) } } +std::vector Preprocessor::getRemarkComments() const +{ + return getRemarkComments(mTokens); +} -void Preprocessor::addRemarkComments(const simplecpp::TokenList &tokens, std::vector &remarkComments) const +std::vector Preprocessor::getRemarkComments(const simplecpp::TokenList &tokens) const { + std::vector remarkComments; + for (const simplecpp::Token *tok = tokens.cfront(); tok; tok = tok->next) { if (!tok->comment) continue; @@ -1245,4 +1217,6 @@ void Preprocessor::addRemarkComments(const simplecpp::TokenList &tokens, std::ve // Add the suppressions. remarkComments.emplace_back(relativeFilename, remarkedToken->location.line, remarkText); } + + return remarkComments; } diff --git a/lib/preprocessor.h b/lib/preprocessor.h index ba4d55a1e60..3a5a8393a3e 100644 --- a/lib/preprocessor.h +++ b/lib/preprocessor.h @@ -98,24 +98,36 @@ class CPPCHECKLIB RemarkComment { * configurations that exist in a source file. */ class CPPCHECKLIB WARN_UNUSED Preprocessor { + friend class TestPreprocessor; + public: /** character that is inserted in expanded macros */ static char macroChar; Preprocessor(simplecpp::TokenList& tokens, const Settings& settings, ErrorLogger &errorLogger, Standards::Language lang); - void inlineSuppressions(SuppressionList &suppressions); + void inlineSuppressions(SuppressionList &suppressions) const; + + void inlineSuppressions(const simplecpp::TokenList &tokens, SuppressionList &suppressions) const; + + void createDirectives(std::list &directives) const; - std::list createDirectives() const; + static void createDirectives(const simplecpp::TokenList &tokens, std::list &directives); - std::set getConfigs() const; + void getConfigs(std::set &defined, std::set &configs) const; + + void getConfigs(const std::string &filename, const simplecpp::TokenList &tokens, std::set &defined, std::set &configs) const; std::vector getRemarkComments() const; + std::vector getRemarkComments(const simplecpp::TokenList &tokens) const; + bool loadFiles(std::vector &files); void removeComments(); + static void removeComments(simplecpp::TokenList &tokens); + void setPlatformInfo(); simplecpp::TokenList preprocess(const std::string &cfgStr, std::vector &files, simplecpp::OutputList& outputList); @@ -132,6 +144,8 @@ class CPPCHECKLIB WARN_UNUSED Preprocessor { void simplifyPragmaAsm(); + static void simplifyPragmaAsm(simplecpp::TokenList &tokenList); + static void getErrorMessages(ErrorLogger &errorLogger, const Settings &settings); /** @@ -141,12 +155,15 @@ class CPPCHECKLIB WARN_UNUSED Preprocessor { const simplecpp::Output* reportOutput(const simplecpp::OutputList &outputList, bool showerror); - void error(const simplecpp::Location& loc, const std::string &msg, simplecpp::Output::Type type); + void error(const simplecpp::Location& loc, const std::string &msg, simplecpp::Output::Type type) const; const simplecpp::Output* handleErrors(const simplecpp::OutputList &outputList); + void setLoadCallback(simplecpp::FileDataCache::load_callback_type cb) { + mFileCache.set_load_callback(std::move(cb)); + } + private: - static void simplifyPragmaAsmPrivate(simplecpp::TokenList &tokenList); /** * Include file types. @@ -157,18 +174,14 @@ class CPPCHECKLIB WARN_UNUSED Preprocessor { }; void missingInclude(const simplecpp::Location& loc, const std::string &header, HeaderTypes headerType); - void invalidSuppression(const simplecpp::Location& loc, const std::string &msg); - void error(const simplecpp::Location& loc, const std::string &msg, const std::string& id); - - void addRemarkComments(const simplecpp::TokenList &tokens, std::vector &remarkComments) const; + void invalidSuppression(const simplecpp::Location& loc, const std::string &msg) const; + void error(const simplecpp::Location& loc, const std::string &msg, const std::string& id) const; simplecpp::TokenList& mTokens; const Settings& mSettings; ErrorLogger &mErrorLogger; - /** list of all directives met while preprocessing file */ - simplecpp::FileDataCache mFileCache; /** filename for cpp/c file - useful when reporting errors */ diff --git a/test/cli/performance_test.py b/test/cli/performance_test.py index 55da3b3b04e..5be958619fc 100644 --- a/test/cli/performance_test.py +++ b/test/cli/performance_test.py @@ -3,6 +3,7 @@ import os import sys +import time import pytest @@ -413,3 +414,27 @@ class C { } }""") cppcheck([filename]) # should not take more than ~1 second + + +@pytest.mark.timeout(60) +def test_slow_many_headers(tmpdir): + # 14113 + c_file = os.path.join(tmpdir, 'source.c') + h_file = os.path.join(tmpdir, 'header.h') + n_hdr = 128 + with open(c_file, 'wt') as f: + f.write('#include "header.h"\n') + with open(h_file, 'wt') as f: + for i in range(n_hdr): + f.write(f'#ifdef CONFIG{i}\n#include "header{i}.h"\n#endif\n') + for i in range(n_hdr): + h_file_i = os.path.join(tmpdir, f"header{i}.h") + with open(h_file_i, 'wt') as f: + for j in range(2048): + f.write(f'#define MACRO{j}{(" "+str(j))*128}\n') + f.write(f'MACRO{i}\n') + # creating the files used for testing can be slow, so we use perf counter here instead + start = time.perf_counter_ns() + cppcheck(['-DCONFIG0', c_file]) + end = time.perf_counter_ns() + assert end - start < 2 * 10**9 # max 2 sec diff --git a/test/helpers.cpp b/test/helpers.cpp index 252658cc531..70437207a84 100644 --- a/test/helpers.cpp +++ b/test/helpers.cpp @@ -124,7 +124,8 @@ void SimpleTokenizer2::preprocess(const char* code, std::size_t size, std::vecto // Tokenizer.. tokenizer.list.createTokens(std::move(tokens2)); - std::list directives = preprocessor.createDirectives(); + std::list directives; + preprocessor.createDirectives(directives); tokenizer.setDirectives(std::move(directives)); } diff --git a/test/testcppcheck.cpp b/test/testcppcheck.cpp index 84db6db6c28..17c5b8eff3c 100644 --- a/test/testcppcheck.cpp +++ b/test/testcppcheck.cpp @@ -527,7 +527,6 @@ class TestCppcheck : public TestFixture { void checkPlistOutput() const { Suppressions supprs; ErrorLogger2 errorLogger; - std::vector files = {"textfile.txt"}; { const auto s = dinit(Settings, $.templateFormat = templateFormat, $.plistOutput = "output"); @@ -535,7 +534,7 @@ class TestCppcheck : public TestFixture { CppCheck cppcheck(s, supprs, errorLogger, nullptr, false, {}); const FileWithDetails fileWithDetails {file.path(), Path::identify(file.path(), false), 0}; - cppcheck.checkPlistOutput(fileWithDetails, files); + cppcheck.checkPlistOutput(fileWithDetails); const std::string outputFile {"outputfile_" + std::to_string(std::hash {}(fileWithDetails.spath())) + ".plist"}; ASSERT(Path::exists(outputFile)); std::remove(outputFile.c_str()); @@ -547,7 +546,7 @@ class TestCppcheck : public TestFixture { CppCheck cppcheck(s, supprs, errorLogger, nullptr, false, {}); const FileWithDetails fileWithDetails {file.path(), Path::identify(file.path(), false), 0}; - cppcheck.checkPlistOutput(fileWithDetails, files); + cppcheck.checkPlistOutput(fileWithDetails); const std::string outputFile {"outputfile_" + std::to_string(std::hash {}(fileWithDetails.spath())) + ".plist"}; ASSERT(Path::exists(outputFile)); std::remove(outputFile.c_str()); @@ -557,7 +556,7 @@ class TestCppcheck : public TestFixture { Settings s; const ScopedFile file("file.c", ""); CppCheck cppcheck(s, supprs, errorLogger, nullptr, false, {}); - cppcheck.checkPlistOutput(FileWithDetails(file.path(), Path::identify(file.path(), false), 0), files); + cppcheck.checkPlistOutput(FileWithDetails(file.path(), Path::identify(file.path(), false), 0)); } } diff --git a/test/testpreprocessor.cpp b/test/testpreprocessor.cpp index b90a879738d..5da298a2714 100644 --- a/test/testpreprocessor.cpp +++ b/test/testpreprocessor.cpp @@ -32,7 +32,9 @@ #include "fixture.h" #include "helpers.h" +#include #include +#include #include #include #include @@ -137,8 +139,11 @@ class TestPreprocessor : public TestFixture { preprocessor.simplifyPragmaAsm(); std::map cfgcode; - if (cfgs.empty()) - cfgs = preprocessor.getConfigs(); + if (cfgs.empty()) { + cfgs.insert(""); + std::set configDefines = { "__cplusplus" }; + preprocessor.getConfigs(configDefines, cfgs); + } for (const std::string & config : cfgs) { try { const bool writeLocations = (strstr(code, "#include") != nullptr); @@ -368,6 +373,8 @@ class TestPreprocessor : public TestFixture { TEST_CASE(testMissingIncludeMixed); TEST_CASE(testMissingIncludeCheckConfig); + TEST_CASE(testLazyInclude); + TEST_CASE(hasInclude); TEST_CASE(limitsDefines); @@ -394,10 +401,23 @@ class TestPreprocessor : public TestFixture { simplecpp::OutputList outputList; simplecpp::TokenList tokens(code,files,"test.c",&outputList); Preprocessor preprocessor(tokens, settings, *this, Standards::Language::C); + std::set configs = { "" }; + std::set configDefines = { "__cplusplus" }; + const auto getDefineName = [](const std::string &defineString) { + return defineString.substr(0, defineString.find_first_of("( ")); + }; + std::transform(settings.library.defines().begin(), + settings.library.defines().end(), + std::inserter(configDefines, configDefines.end()), + getDefineName); + preprocessor.setLoadCallback([&](simplecpp::FileData &data) { + Preprocessor::removeComments(data.tokens); + preprocessor.getConfigs(data.filename, data.tokens, configDefines, configs); + }); + preprocessor.removeComments(); + preprocessor.getConfigs(configDefines, configs); ASSERT(preprocessor.loadFiles(files)); ASSERT(!preprocessor.reportOutput(outputList, true)); - preprocessor.removeComments(); - const std::set configs = preprocessor.getConfigs(); std::string ret; for (const std::string & config : configs) ret += config + '\n'; @@ -409,8 +429,11 @@ class TestPreprocessor : public TestFixture { std::vector files; simplecpp::TokenList tokens(code,files,"test.c"); Preprocessor preprocessor(tokens, settingsDefault, *this, Standards::Language::C); - ASSERT(preprocessor.loadFiles(files)); + preprocessor.setLoadCallback([](simplecpp::FileData &data) { + Preprocessor::removeComments(data.tokens); + }); preprocessor.removeComments(); + ASSERT(preprocessor.loadFiles(files)); return preprocessor.calculateHash(""); } @@ -3033,6 +3056,36 @@ class TestPreprocessor : public TestFixture { "test.c:11:2: information: Include file: <" + missing4 + "> not found. Please note: Standard library headers do not need to be provided to get proper results. [missingIncludeSystem]\n", errout_str()); } + void testLazyInclude() { + const char *code = "#ifdef CONFIG1\n" + "#include \"header1.h\"\n" + "#include \"missing1.h\"\n" + "#else\n" + "#include \"header2.h\"\n" + "#include \"missing2.h\"\n" + "#endif\n"; + + std::vector files; + simplecpp::TokenList tokens(code, files, "test.c"); + + ScopedFile header1("header1.h", "1"); + ScopedFile header2("header2.h", "2"); + + Settings settings; + Preprocessor preprocessor(tokens, settings, *this, Standards::Language::CPP); + + simplecpp::OutputList outputList; + simplecpp::TokenList tokens2 = preprocessor.preprocess("CONFIG1", files, outputList); + std::string out = tokens2.stringify(); + + const simplecpp::FileDataCache &cache = preprocessor.mFileCache; + + ASSERT_EQUALS("\n#line 1 \"header1.h\"\n1", out); + ASSERT_EQUALS(1, outputList.size()); + ASSERT_EQUALS("Header not found: \"missing1.h\"", outputList.begin()->msg); + ASSERT_EQUALS(1, cache.size()); + } + void hasInclude() { const char code[] = "#if __has_include()\n123\n#endif"; Settings settings; diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp index 167d5411553..0617007744a 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -603,9 +603,13 @@ class TestTokenizer : public TestFixture { std::vector files; simplecpp::TokenList tokens1(code, files, filename, &outputList); Preprocessor preprocessor(tokens1, settings, *this, Path::identify(tokens1.getFiles()[0], false)); - (void)preprocessor.reportOutput(outputList, true); + std::list directives; + preprocessor.setLoadCallback([&](const simplecpp::FileData &data) { + Preprocessor::createDirectives(data.tokens, directives); + }); + preprocessor.createDirectives(directives); ASSERT(preprocessor.loadFiles(files)); - std::list directives = preprocessor.createDirectives(); + (void)preprocessor.reportOutput(outputList, true); TokenList tokenlist{settings, Path::identify(filename, false)}; Tokenizer tokenizer(std::move(tokenlist), *this); From 4517bc76720511a5e832803931fa4b1ce2ee8917 Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Wed, 8 Jul 2026 14:27:36 +0200 Subject: [PATCH 075/165] Fix #14888 FP functionConst with array to pointer decay (#8696) Co-authored-by: chrchr-github --- lib/checkclass.cpp | 9 ++++++--- test/testclass.cpp | 17 +++++++++++++++++ 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/lib/checkclass.cpp b/lib/checkclass.cpp index e04df8b5748..51d5718159f 100644 --- a/lib/checkclass.cpp +++ b/lib/checkclass.cpp @@ -2608,9 +2608,12 @@ bool CheckClassImpl::checkConstFunc(const Scope *scope, const Function *func, Me return false; } else { if (lhs->isAssignmentOp()) { - const Variable* lhsVar = lhs->previous()->variable(); - if (lhsVar && !lhsVar->isConst() && lhsVar->isReference() && lhs == lhsVar->nameToken()->next()) - return false; + if (const Variable* lhsVar = lhs->previous()->variable()) { + if (!lhsVar->isConst() && lhsVar->isReference() && lhs == lhsVar->nameToken()->next()) + return false; + if (lhsVar->isPointer() && v && v->isArray() && !(lhsVar->valueType() && lhsVar->valueType()->isConst(/*indirect*/ 1))) + return false; + } } } diff --git a/test/testclass.cpp b/test/testclass.cpp index ae5068dcb9d..1d647eb33a1 100644 --- a/test/testclass.cpp +++ b/test/testclass.cpp @@ -196,6 +196,7 @@ class TestClass : public TestFixture { TEST_CASE(const99); TEST_CASE(const100); TEST_CASE(const101); + TEST_CASE(const102); TEST_CASE(const_handleDefaultParameters); TEST_CASE(const_passThisToMemberOfOtherClass); @@ -6998,6 +6999,22 @@ class TestClass : public TestFixture { ASSERT_EQUALS("", errout_str()); } + void const102() { + checkConst("struct S {\n" // #14888 + " void f() {\n" + " int *p = a;\n" + " *p = 0;\n" + " }\n" + " void g() {\n" + " const int *p = a;\n" + " if (*p) {}\n" + " }\n" + " int a[3];\n" + "};\n"); + ASSERT_EQUALS("[test.cpp:6:10]: (style, inconclusive) Technically the member function 'S::g' can be const. [functionConst]\n", + errout_str()); + } + void const_handleDefaultParameters() { checkConst("struct Foo {\n" " void foo1(int i, int j = 0) {\n" From b555588b969640a77c655fbdb177dd9c763ebf62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Duval?= Date: Thu, 9 Jul 2026 08:38:33 +0200 Subject: [PATCH 076/165] implement Path::getCurrentExecutablePath for Haiku (#8677) --- lib/path.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/lib/path.cpp b/lib/path.cpp index c4758dfeae9..fc059cdea4e 100644 --- a/lib/path.cpp +++ b/lib/path.cpp @@ -51,6 +51,8 @@ #endif #if defined(__APPLE__) #include +#elif defined(__HAIKU__) +#include #endif @@ -158,6 +160,17 @@ std::string Path::getCurrentExecutablePath(const char* fallback) #elif defined(__APPLE__) uint32_t size = sizeof(buf); success = (_NSGetExecutablePath(buf, &size) == 0); +#elif defined(__HAIKU__) + int32 cookie = 0; + image_info info; + while (get_next_image_info(B_CURRENT_TEAM, &cookie, &info) == B_OK) + { + if (info.type == B_APP_IMAGE) + { + break; + } + } + return std::string(info.name); #else const char* procPath = #ifdef __SVR4 // Solaris From 592e7b7c29eee72ec0882fe9867b51d3de44fe46 Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Thu, 9 Jul 2026 08:49:30 +0200 Subject: [PATCH 077/165] Fix #14890 fuzzing timeout (hang) in Tokenizer::simplifyTypedef() (#8706) Co-authored-by: chrchr-github --- lib/tokenize.cpp | 20 +++++++++++-------- ...t-5e798df7f1bc86caef9901d6662319a4d636f269 | 1 + 2 files changed, 13 insertions(+), 8 deletions(-) create mode 100644 test/cli/fuzz-timeout/timeout-5e798df7f1bc86caef9901d6662319a4d636f269 diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 3046bea69cc..d2ad6f581e7 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -9145,14 +9145,18 @@ void Tokenizer::findGarbageCode() const } if (!tok2->next() || tok2->isControlFlowKeyword() || Token::Match(tok2, "typedef|static|.")) syntaxError(tok); - if (Token::Match(tok2, "%name% %name%") && tok2->str() == tok2->strAt(1)) { - if (Token::simpleMatch(tok2->tokAt(2), ";")) - continue; - if (tok2->isStandardType() && tok2->str() == "long") - continue; - if (Token::Match(tok2->tokAt(-1), "enum|struct|union") || (isCPP() && Token::Match(tok2->tokAt(-1), "class|::"))) - continue; - syntaxError(tok2); + if (Token::Match(tok2, "%name% %name%")) { + if (tok2->str() == tok2->strAt(1)) { + if (Token::simpleMatch(tok2->tokAt(2), ";")) + continue; + if (tok2->isStandardType() && tok2->str() == "long") + continue; + if (Token::Match(tok2->tokAt(-1), "enum|struct|union") || (isCPP() && Token::Match(tok2->tokAt(-1), "class|::"))) + continue; + syntaxError(tok2); + } + if (Token::Match(tok2->tokAt(2), "%name%") && tok2->isNameOnly() && tok2->tokAt(1)->isNameOnly() && tok2->tokAt(2)->isNameOnly()) + syntaxError(tok2); } } } diff --git a/test/cli/fuzz-timeout/timeout-5e798df7f1bc86caef9901d6662319a4d636f269 b/test/cli/fuzz-timeout/timeout-5e798df7f1bc86caef9901d6662319a4d636f269 new file mode 100644 index 00000000000..35e56badcc8 --- /dev/null +++ b/test/cli/fuzz-timeout/timeout-5e798df7f1bc86caef9901d6662319a4d636f269 @@ -0,0 +1 @@ +typedef consted e,{} From a05554448f3724b7e4f33a5a727b23f74702b951 Mon Sep 17 00:00:00 2001 From: Paul Fultz II Date: Thu, 9 Jul 2026 01:50:44 -0500 Subject: [PATCH 078/165] Fix 14895: FP knownConditionTrueFalse: regression related to ' Partial fix for 9049: False negative: uninitialized variable with nested ifs (#8680)' (#8701) Co-authored-by: Your Name --- lib/forwardanalyzer.cpp | 5 +++++ test/testvalueflow.cpp | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/lib/forwardanalyzer.cpp b/lib/forwardanalyzer.cpp index 727c64b076d..ced1cfbda8d 100644 --- a/lib/forwardanalyzer.cpp +++ b/lib/forwardanalyzer.cpp @@ -395,6 +395,11 @@ namespace { bool structuralUnknown = false; const bool structuralEscape = isEscapeScope(branch.endBlock, structuralUnknown); branch.escapeUnknown = !structuralEscape || structuralUnknown; + // The traversal stopped at the escape, so the rest of the scope was not walked; a + // fall-through path could still modify the value there - include the whole scope's + // actions so isModified() sees it. + if (branch.escapeUnknown) + branch.action |= analyzeScope(branch.endBlock); } else { // Detect an escape the traversal did not flag (e.g. an unknown noreturn call); // escapeUnknown reports a possible (unknown) escape. diff --git a/test/testvalueflow.cpp b/test/testvalueflow.cpp index 888710ce57d..8a0d181900d 100644 --- a/test/testvalueflow.cpp +++ b/test/testvalueflow.cpp @@ -3214,6 +3214,38 @@ class TestValueFlow : public TestFixture { " return x;\n" "}\n"; ASSERT_EQUALS(true, testValueOfXKnown(code, 3U, 0)); + + code = "bool f();\n" // a modification after a conditional escape must still be seen + "void g() {\n" + " bool x = false;\n" + " if (f()) {\n" + " if (f()) return;\n" + " if (f()) x = true;\n" + " }\n" + " if (x) {}\n" + "}\n"; + ASSERT_EQUALS(true, testValueOfX(code, 8U, 0)); + ASSERT_EQUALS(false, testValueOfXKnown(code, 8U, 0)); + + code = "bool f();\n" + "void g() {\n" + " bool x = false;\n" + " if (f()) {\n" + " if (f()) return;\n" + " x = true;\n" + " }\n" + " if (x) {}\n" + "}\n"; + ASSERT_EQUALS(true, testValueOfX(code, 8U, 0)); + ASSERT_EQUALS(false, testValueOfXKnown(code, 8U, 0)); + + code = "bool f();\n" // the branch always escapes - keep the known value + "void g() {\n" + " bool x = false;\n" + " if (f()) { x = true; return; }\n" + " if (x) {}\n" + "}\n"; + ASSERT_EQUALS(true, testValueOfXKnown(code, 5U, 0)); } void valueFlowAfterSwap() From 376b31e0fac39db72295171d8b386c48daf6e2e8 Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Thu, 9 Jul 2026 08:51:19 +0200 Subject: [PATCH 079/165] Partial fix for #14859 FN bufferAccessOutOfBounds (memset on std::vector) (#8690) --- lib/checkbufferoverrun.cpp | 28 +++++++++++++++++++++------- lib/checkbufferoverrun.h | 2 +- test/testbufferoverrun.cpp | 6 ++++++ 3 files changed, 28 insertions(+), 8 deletions(-) diff --git a/lib/checkbufferoverrun.cpp b/lib/checkbufferoverrun.cpp index c72db22a68c..d28ac7c64f7 100644 --- a/lib/checkbufferoverrun.cpp +++ b/lib/checkbufferoverrun.cpp @@ -65,7 +65,10 @@ static const CWE CWE_BUFFER_OVERRUN(788U); // Access of Memory Location After static const ValueFlow::Value *getBufferSizeValue(const Token *tok) { const std::list &tokenValues = tok->values(); - const auto it = std::find_if(tokenValues.cbegin(), tokenValues.cend(), std::mem_fn(&ValueFlow::Value::isBufferSizeValue)); + auto it = std::find_if(tokenValues.cbegin(), tokenValues.cend(), std::mem_fn(&ValueFlow::Value::isBufferSizeValue)); + if (it != tokenValues.cend()) + return &*it; + it = std::find_if(tokenValues.cbegin(), tokenValues.cend(), std::mem_fn(&ValueFlow::Value::isContainerSizeValue)); return it == tokenValues.cend() ? nullptr : &*it; } @@ -552,7 +555,7 @@ void CheckBufferOverrunImpl::pointerArithmeticError(const Token *tok, const Toke //--------------------------------------------------------------------------- -ValueFlow::Value CheckBufferOverrunImpl::getBufferSize(const Token *bufTok) const +ValueFlow::Value CheckBufferOverrunImpl::getBufferSize(const Token *bufTok, const Settings& settings) const { if (!bufTok->valueType()) return ValueFlow::Value(-1); @@ -569,9 +572,20 @@ ValueFlow::Value CheckBufferOverrunImpl::getBufferSize(const Token *bufTok) cons const Variable *var = bufTok->variable(); if (!var || var->dimensions().empty()) { - const ValueFlow::Value *value = getBufferSizeValue(bufTok); - if (value) - return *value; + if (const ValueFlow::Value *value = getBufferSizeValue(bufTok)) { + if (value->isBufferSizeValue()) + return *value; + if (value->isContainerSizeValue() && bufTok->valueType() && bufTok->valueType()->container) { + const ValueType vtElement = ValueType::parseDecl(bufTok->valueType()->containerTypeToken, settings); + const size_t elementSize = vtElement.getSizeOf(settings, ValueType::Accuracy::ExactOrZero, ValueType::SizeOf::Pointer); + if (elementSize > 0) { + ValueFlow::Value bufSizeVal; + bufSizeVal.valueType = ValueFlow::Value::ValueType::BUFFER_SIZE; + bufSizeVal.intvalue = value->intvalue * elementSize; + return bufSizeVal; + } + } + } } if (!var || var->isPointer() || (astIsContainer(bufTok) && var->getTypeName() != "std::array")) @@ -671,7 +685,7 @@ void CheckBufferOverrunImpl::bufferOverflow() if (argtok->valueType() && argtok->valueType()->pointer == 0) continue; // TODO: strcpy(buf+10, "hello"); - const ValueFlow::Value bufferSize = getBufferSize(argtok); + const ValueFlow::Value bufferSize = getBufferSize(argtok, mSettings); if (bufferSize.intvalue <= 0) continue; // buffer size == 1 => do not warn for dynamic memory @@ -782,7 +796,7 @@ void CheckBufferOverrunImpl::stringNotZeroTerminated() const Token *sizeToken = args[2]; if (!sizeToken->hasKnownIntValue()) continue; - const ValueFlow::Value &bufferSize = getBufferSize(args[0]); + const ValueFlow::Value &bufferSize = getBufferSize(args[0], mSettings); if (bufferSize.intvalue < 0 || sizeToken->getKnownIntValue() < bufferSize.intvalue) continue; if (Token::simpleMatch(args[1], "(") && Token::simpleMatch(args[1]->astOperand1(), ". c_str") && args[1]->astOperand1()->astOperand1()) { diff --git a/lib/checkbufferoverrun.h b/lib/checkbufferoverrun.h index b0e8b28eba0..b9b82c897e0 100644 --- a/lib/checkbufferoverrun.h +++ b/lib/checkbufferoverrun.h @@ -129,7 +129,7 @@ class CPPCHECKLIB CheckBufferOverrunImpl : public CheckImpl void objectIndex(); void objectIndexError(const Token *tok, const ValueFlow::Value *v, bool known); - ValueFlow::Value getBufferSize(const Token *bufTok) const; + ValueFlow::Value getBufferSize(const Token *bufTok, const Settings& settings) const; // CTU static bool isCtuUnsafeBufferUsage(const Settings &settings, const Token *argtok, CTU::FileInfo::Value *offset, int type); diff --git a/test/testbufferoverrun.cpp b/test/testbufferoverrun.cpp index 387a0eeea8a..f9e55910c01 100644 --- a/test/testbufferoverrun.cpp +++ b/test/testbufferoverrun.cpp @@ -3545,6 +3545,12 @@ class TestBufferOverrun : public TestFixture { " std::memset(&buf[0], 0, 25);\n" "}\n"); ASSERT_EQUALS("", errout_str()); + + check("void f() {\n" // #14859 + " std::vector buf(25);\n" + " std::memset(&buf[0], 0, 26);\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:3:17]: (error) Buffer is accessed out of bounds: &buf[0] [bufferAccessOutOfBounds]\n", errout_str()); } void buffer_overrun_errorpath() { From 41e87ac9fd291442b9e39958e4c19558c1e7a07c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20St=C3=B6neberg?= Date: Fri, 10 Jul 2026 16:03:06 +0200 Subject: [PATCH 080/165] compilerDefinitions.cmake: fixed typo in if condition (#8709) fixes compiler error with libc++ on recent clang versions: ``` /usr/bin/../include/c++/v1/__configuration/hardening.h:25:4: error: "_LIBCPP_ENABLE_ASSERTIONS has been removed, please use _LIBCPP_HARDENING_MODE= instead (see docs)" 25 | # error "_LIBCPP_ENABLE_ASSERTIONS has been removed, please use _LIBCPP_HARDENING_MODE= instead (see docs)" | ^ ``` --- cmake/compilerDefinitions.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/compilerDefinitions.cmake b/cmake/compilerDefinitions.cmake index 5f03b83dcee..3daf0e7ba87 100644 --- a/cmake/compilerDefinitions.cmake +++ b/cmake/compilerDefinitions.cmake @@ -20,7 +20,7 @@ endif() if ((USE_LIBCXX AND CMAKE_CXX_COMPILER_ID MATCHES "Clang") OR CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang") if(CPPCHK_GLIBCXX_DEBUG AND CMAKE_BUILD_TYPE STREQUAL "Debug") # TODO: determine proper version for AppleClang - current value is based on the oldest version avaialble in CI - if((CMAKE_CXX_COMPILER_ID STREQUALS "Clang" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 18) OR + if((CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 18) OR (CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 17)) add_definitions(-D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_DEBUG) else() From b839fa5a914e1ecf7db0195ae34559ecfe867acc Mon Sep 17 00:00:00 2001 From: Paul Fultz II Date: Fri, 10 Jul 2026 15:55:28 -0500 Subject: [PATCH 081/165] Fix issue 14892: Inconsistent nullPointerOutOfResources after possible noreturn function (#8700) Co-authored-by: Your Name --- lib/forwardanalyzer.cpp | 48 ++++++++++++++++++++++++------------ lib/valueflow.cpp | 23 ++++++++++++++--- test/testnullpointer.cpp | 53 ++++++++++++++++++++++++++++++++++++++++ test/testvalueflow.cpp | 38 ++++++++++++++++++++++++++++ 4 files changed, 143 insertions(+), 19 deletions(-) diff --git a/lib/forwardanalyzer.cpp b/lib/forwardanalyzer.cpp index ced1cfbda8d..368ac761a53 100644 --- a/lib/forwardanalyzer.cpp +++ b/lib/forwardanalyzer.cpp @@ -412,6 +412,27 @@ namespace { return p; } + // Update the branch that the evaluated condition takes + Progress updateTakenBranch(Branch& branch, const Token* skippedBlock, const Token* condTok, int depth) + { + // The condition is only "known" because of an earlier assumption, so the + // skipped block could still modify the value -> lower to possible + if (!condTok->hasKnownIntValue() && skippedBlock && analyzeScope(skippedBlock).isModified() && + !analyzer->lowerToPossible()) + return Break(Analyzer::Terminate::Bail); + if (!branch.endBlock) + return Progress::Continue; + updateScopeState(branch.endBlock); + if (updateBranch(branch, depth - 1) == Progress::Break) + return Progress::Break; + // The branch was entered because of the tracked value; if it might not + // return (it ends in a call to an unknown, possibly noreturn function) + // then the value might not flow past the branch. + if (!condTok->hasKnownIntValue() && !branch.escape && branch.escapeUnknown && !analyzer->lowerToInconclusive()) + return Break(Analyzer::Terminate::Bail); + return Progress::Continue; + } + bool reentersLoop(Token* endBlock, const Token* condTok, const Token* stepTok) const { if (!condTok) return true; @@ -563,16 +584,21 @@ namespace { return updateLoop(endToken, endBlock, condTok, initTok, stepTok, true); } - Progress updateScope(Token* endBlock, int depth = 20) + void updateScopeState(const Token* endBlock) { - if (!endBlock) - return Break(); assert(endBlock->link()); - Token* ctx = endBlock->link()->previous(); + const Token* ctx = endBlock->link()->previous(); if (Token::simpleMatch(ctx, ")")) ctx = ctx->link()->previous(); if (ctx) analyzer->updateState(ctx); + } + + Progress updateScope(Token* endBlock, int depth = 20) + { + if (!endBlock) + return Break(); + updateScopeState(endBlock); return updateRange(endBlock->link(), endBlock, depth); } @@ -743,19 +769,11 @@ namespace { const bool hasElse = Token::simpleMatch(endBlock, "} else {"); tok = hasElse ? endBlock->linkAt(2) : endBlock; if (thenBranch.check) { - // The condition is only "known" because of an earlier assumption, so the - // skipped else block could still modify the value -> lower to possible - if (!condTok->hasKnownIntValue() && hasElse && - analyzeScope(elseBranch.endBlock).isModified() && !analyzer->lowerToPossible()) - return Break(Analyzer::Terminate::Bail); - if (updateScope(thenBranch.endBlock, depth - 1) == Progress::Break) + if (updateTakenBranch(thenBranch, hasElse ? elseBranch.endBlock : nullptr, condTok, depth) == + Progress::Break) return Break(); } else if (elseBranch.check) { - // Likewise the skipped then block could still modify the value - if (!condTok->hasKnownIntValue() && analyzeScope(thenBranch.endBlock).isModified() && - !analyzer->lowerToPossible()) - return Break(Analyzer::Terminate::Bail); - if (elseBranch.endBlock && updateScope(elseBranch.endBlock, depth - 1) == Progress::Break) + if (updateTakenBranch(elseBranch, thenBranch.endBlock, condTok, depth) == Progress::Break) return Break(); } else { const bool conditional = stopOnCondition(condTok); diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index ef81fc772ac..8c77b17cf94 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -4650,6 +4650,14 @@ struct ConditionHandler { }); } + static void lowerToInconclusive(std::list& values) + { + for (ValueFlow::Value& v : values) { + if (!v.isImpossible()) + v.setInconclusive(); + } + } + void afterCondition(TokenList& tokenlist, const SymbolDatabase& symboldatabase, ErrorLogger& errorLogger, @@ -4882,10 +4890,13 @@ struct ConditionHandler { else if (!dead_if) dead_if = isReturnScope(after, settings.library, &unknownFunction); + // If the taken branch might not return (it ends in a call to an unknown, + // possibly noreturn function) then its values might not flow past the + // conditional code -> lower them to inconclusive. if (!dead_if && unknownFunction) { if (settings.debugwarnings) bailout(tokenlist, errorLogger, unknownFunction, "possible noreturn scope"); - return; + lowerToInconclusive(thenValues); } if (Token::simpleMatch(after, "} else {")) { @@ -4896,7 +4907,7 @@ struct ConditionHandler { if (!dead_else && unknownFunction) { if (settings.debugwarnings) bailout(tokenlist, errorLogger, unknownFunction, "possible noreturn scope"); - return; + lowerToInconclusive(elseValues); } } @@ -4912,11 +4923,15 @@ struct ConditionHandler { std::copy_if(thenValues.cbegin(), thenValues.cend(), std::back_inserter(values), - std::mem_fn(&ValueFlow::Value::isPossible)); + [](const ValueFlow::Value& v) { + return v.isPossible() || v.isInconclusive(); + }); std::copy_if(elseValues.cbegin(), elseValues.cend(), std::back_inserter(values), - std::mem_fn(&ValueFlow::Value::isPossible)); + [](const ValueFlow::Value& v) { + return v.isPossible() || v.isInconclusive(); + }); } if (values.empty()) diff --git a/test/testnullpointer.cpp b/test/testnullpointer.cpp index 2483a967947..02810906fb2 100644 --- a/test/testnullpointer.cpp +++ b/test/testnullpointer.cpp @@ -4468,6 +4468,59 @@ class TestNullPointer : public TestFixture { "[test.cpp:3:13]: (warning) If resource allocation fails, then there is a possible null pointer dereference: fid [nullPointerOutOfResources]\n" "[test.cpp:4:12]: (warning) If resource allocation fails, then there is a possible null pointer dereference: fid [nullPointerOutOfResources]\n", errout_str()); + + // the guard might call an unknown, possibly noreturn function -> no warning + check("void f() {\n" + " FILE* fid = fopen(\"x.txt\", \"w\");\n" + " if (fid == NULL)\n" + " g();\n" + " fclose(fid);\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + + // .. but an inconclusive warning is reported with --inconclusive + check("void f() {\n" + " FILE* fid = fopen(\"x.txt\", \"w\");\n" + " if (fid == NULL)\n" + " g();\n" + " fclose(fid);\n" + "}\n", + dinit(CheckOptions, $.inconclusive = true)); + ASSERT_EQUALS( + "[test.cpp:5:12]: (warning, inconclusive) If resource allocation fails, then there is a possible null pointer dereference: fid [nullPointerOutOfResources]\n", + errout_str()); + + check("int f(const int* p) {\n" + " if (p == nullptr)\n" + " g();\n" + " return *p;\n" + "}\n", + dinit(CheckOptions, $.inconclusive = true)); + ASSERT_EQUALS( + "[test.cpp:2:11] -> [test.cpp:4:13]: (warning, inconclusive) Either the condition 'p==nullptr' is redundant or there is possible null pointer dereference: p. [nullPointerRedundantCheck]\n", + errout_str()); + + check("void f() {\n" + " FILE* fid = fopen(\"x.txt\", \"w\");\n" + " if (fid != NULL)\n" + " ;\n" + " else\n" + " g();\n" + " fclose(fid);\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + + // guard function is known to return -> warning + check("void g() {}\n" + "void f() {\n" + " FILE* fid = fopen(\"x.txt\", \"w\");\n" + " if (fid == NULL)\n" + " g();\n" + " fclose(fid);\n" + "}\n"); + ASSERT_EQUALS( + "[test.cpp:6:12]: (warning) If resource allocation fails, then there is a possible null pointer dereference: fid [nullPointerOutOfResources]\n", + errout_str()); } void functioncalllibrary() { diff --git a/test/testvalueflow.cpp b/test/testvalueflow.cpp index 8a0d181900d..1f144900c4d 100644 --- a/test/testvalueflow.cpp +++ b/test/testvalueflow.cpp @@ -3866,6 +3866,44 @@ class TestValueFlow : public TestFixture { " return x;\n" "}\n"; ASSERT_EQUALS(true, testValueOfX(code, 4U, 0)); + + // if the guarded block calls an unknown, possibly noreturn function + // then the condition value is lowered to inconclusive after the block + code = "int f(int x) {\n" + " if (x == 0)\n" + " g();\n" + " return x;\n" + "}\n"; + ASSERT_EQUALS(true, testValueOfXInconclusive(code, 4U, 0)); + + // .. also when the guard is in the else branch + code = "int f(int x) {\n" + " if (x != 0)\n" + " ;\n" + " else\n" + " g();\n" + " return x;\n" + "}\n"; + ASSERT_EQUALS(true, testValueOfXInconclusive(code, 6U, 0)); + + // a declared function is assumed to return + code = "void g();\n" + "int f(int x) {\n" + " if (x == 0)\n" + " g();\n" + " return x;\n" + "}\n"; + ASSERT_EQUALS(true, testValueOfX(code, 5U, 0)); + ASSERT_EQUALS(false, testValueOfXInconclusive(code, 5U, 0)); + + // a noreturn function conclusively escapes + code = "int f(int x) {\n" + " if (x == 0)\n" + " abort();\n" + " return x;\n" + "}\n"; + ASSERT_EQUALS(false, testValueOfX(code, 4U, 0)); + ASSERT_EQUALS(true, testValueOfXImpossible(code, 4U, 0)); } void valueFlowAfterConditionTernary() From c9cb62fc1e6026533245e53f16f5011cb14f5cf4 Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Sat, 11 Jul 2026 14:30:26 +0200 Subject: [PATCH 082/165] Fix #14897 fuzzing crash (null-pointer-use) in SymbolDatabase::createSymbolDatabaseSetScopePointers() (#8703) --- lib/symboldatabase.cpp | 8 +++++++- .../crash-def181ea7bf444e7a9d0f85b3ad264c31a0b90e4 | 1 + 2 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 test/cli/fuzz-crash/crash-def181ea7bf444e7a9d0f85b3ad264c31a0b90e4 diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index b687c9f77a4..6e6a98ee81e 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -138,8 +138,14 @@ const Token* SymbolDatabase::isEnumDefinition(const Token* tok) if (tok->str() == "{") return tok; tok = tok->next(); // skip ':' - while (Token::Match(tok, "%name%|::")) + bool hasType = false; + while (Token::Match(tok, "%name%|::")) { + if (tok->isName()) + hasType = true; tok = tok->next(); + } + if (!hasType) + throw InternalError(tok, "SymbolDatabase bailout; invalid enum", InternalError::SYNTAX); return Token::simpleMatch(tok, "{") ? tok : nullptr; } diff --git a/test/cli/fuzz-crash/crash-def181ea7bf444e7a9d0f85b3ad264c31a0b90e4 b/test/cli/fuzz-crash/crash-def181ea7bf444e7a9d0f85b3ad264c31a0b90e4 new file mode 100644 index 00000000000..3b609c62362 --- /dev/null +++ b/test/cli/fuzz-crash/crash-def181ea7bf444e7a9d0f85b3ad264c31a0b90e4 @@ -0,0 +1 @@ +enumf:{}; From cad91dab8e98ec3506269eaa36128446ce7d3406 Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Sat, 11 Jul 2026 14:31:25 +0200 Subject: [PATCH 083/165] Fix #14742 fuzzing crash (stack-overflow) in CheckNullPointer::nullPointerByDeRefAndCheck() (#8693) --- lib/tokenlist.cpp | 5 ++++- test/cli/fuzz-crash_c/14742 | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) create mode 100644 test/cli/fuzz-crash_c/14742 diff --git a/lib/tokenlist.cpp b/lib/tokenlist.cpp index 5921621fed2..c28075fcec7 100644 --- a/lib/tokenlist.cpp +++ b/lib/tokenlist.cpp @@ -1951,8 +1951,11 @@ void TokenList::validateAst(bool print) const if (tok->str() == "?") { if (!tok->astOperand1() || !tok->astOperand2()) throw InternalError(tok, "AST broken, ternary operator missing operand(s)", InternalError::AST); - if (tok->astOperand2()->str() != ":") + const Token* colon = tok->astOperand2(); + if (colon->str() != ":") throw InternalError(tok, "Syntax Error: AST broken, ternary operator lacks ':'.", InternalError::AST); + if ((colon->astOperand1() && !precedes(colon->astOperand1(), colon)) || !succeeds(colon->astOperand2(), colon)) + throw InternalError(tok, "AST broken, ternary operator has bad operand(s)", InternalError::AST); } // Check for endless recursion diff --git a/test/cli/fuzz-crash_c/14742 b/test/cli/fuzz-crash_c/14742 new file mode 100644 index 00000000000..a645277c405 --- /dev/null +++ b/test/cli/fuzz-crash_c/14742 @@ -0,0 +1 @@ +i(){b?8:{}!$} From 0a43e46cb526163f4aa9fd6f15e3e0cc6e35d577 Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Sat, 11 Jul 2026 14:33:29 +0200 Subject: [PATCH 084/165] Fix #14436 fuzzing crash (null-pointer-use) in getEnumType() (#8711) --- lib/tokenlist.cpp | 2 +- .../fuzz-crash/crash-793c09dbb007b0e1a295f592813f40f8d6d449d1 | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 test/cli/fuzz-crash/crash-793c09dbb007b0e1a295f592813f40f8d6d449d1 diff --git a/lib/tokenlist.cpp b/lib/tokenlist.cpp index c28075fcec7..594de5c0295 100644 --- a/lib/tokenlist.cpp +++ b/lib/tokenlist.cpp @@ -2005,7 +2005,7 @@ void TokenList::validateAst(bool print) const if (Token::simpleMatch(tok->previous(), "operator")) continue; // Skip incomplete code - if (!tok->astOperand1() && !tok->astOperand2() && !tok->astParent()) + if (!tok->astOperand1() && !tok->astOperand2() && !tok->astParent() && !(tok->str().size() == 2 && tok->str()[1] == '=')) continue; // Skip lambda assignment and/or initializer if (Token::Match(tok, "= {|^|[")) diff --git a/test/cli/fuzz-crash/crash-793c09dbb007b0e1a295f592813f40f8d6d449d1 b/test/cli/fuzz-crash/crash-793c09dbb007b0e1a295f592813f40f8d6d449d1 new file mode 100644 index 00000000000..706fe52b407 --- /dev/null +++ b/test/cli/fuzz-crash/crash-793c09dbb007b0e1a295f592813f40f8d6d449d1 @@ -0,0 +1 @@ +enum{A=s(u)0&=s}; From dd04e094b5e8e1b1c5fce7df4f26898c5260998d Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Sat, 11 Jul 2026 21:11:34 +0200 Subject: [PATCH 085/165] [Refactor] Redundant checks for noreturn functions (#8712) --- lib/astutils.cpp | 34 ++++++++++------------------------ lib/checkother.cpp | 2 +- 2 files changed, 11 insertions(+), 25 deletions(-) diff --git a/lib/astutils.cpp b/lib/astutils.cpp index c433036cfcc..27a01ab0382 100644 --- a/lib/astutils.cpp +++ b/lib/astutils.cpp @@ -2226,23 +2226,18 @@ static bool isEscapedOrJump(const Token* tok, bool functionsScope, const Library return Token::Match(tok, "return|goto|throw|continue|break"); } +static bool isNoreturnFunction(const Token* ftok, const Library& library) +{ + if (const Function* function = ftok->function()) + return function->isEscapeFunction() || function->isAttributeNoreturn(); + return library.isnoreturn(ftok); +} + bool isEscapeFunction(const Token* ftok, const Library& library) { if (!Token::Match(ftok, "%name% (")) return false; - if (Token::Match(ftok, "exit|abort")) - return true; - const Function* function = ftok->function(); - if (function) { - if (function->isEscapeFunction()) - return true; - if (function->isAttributeNoreturn()) - return true; - } else { - if (library.isnoreturn(ftok)) - return true; - } - return false; + return isNoreturnFunction(ftok, library); } static bool hasNoreturnFunction(const Token* tok, const Library& library, const Token** unknownFunc) @@ -2253,18 +2248,9 @@ static bool hasNoreturnFunction(const Token* tok, const Library& library, const while (Token::simpleMatch(ftok, "(")) ftok = ftok->astOperand1(); if (ftok) { - const Function * function = ftok->function(); - if (function) { - if (function->isEscapeFunction()) - return true; - if (function->isAttributeNoreturn()) - return true; - } else if (library.isnoreturn(ftok)) { - return true; - } else if (Token::Match(ftok, "exit|abort")) { + if (isNoreturnFunction(ftok, library)) return true; - } - if (unknownFunc && !function && library.functions().count(library.getFunctionName(ftok)) == 0) + if (unknownFunc && !ftok->function() && library.functions().count(library.getFunctionName(ftok)) == 0) *unknownFunc = ftok; return false; } diff --git a/lib/checkother.cpp b/lib/checkother.cpp index ef6fb9003b1..5ea199f38e8 100644 --- a/lib/checkother.cpp +++ b/lib/checkother.cpp @@ -791,7 +791,7 @@ void CheckOtherImpl::redundantAssignmentSameValueError(const Token *tok, const V //--------------------------------------------------------------------------- static inline bool isFunctionOrBreakPattern(const Token *tok) { - return Token::Match(tok, "%name% (") || Token::Match(tok, "break|continue|return|exit|goto|throw"); + return Token::Match(tok, "%name% (") || (tok->isKeyword() && Token::Match(tok, "break|continue|return|goto|throw")); } void CheckOtherImpl::redundantBitwiseOperationInSwitchError() From 168777d93257e5bb0372df1e6663fc120371b946 Mon Sep 17 00:00:00 2001 From: correctmost <134317971+correctmost@users.noreply.github.com> Date: Sun, 12 Jul 2026 04:09:48 -0400 Subject: [PATCH 086/165] gtk.cfg: Add G_DEPRECATED_FOR and G_ENCODE_VERSION (#8708) `G_DEPRECATED_FOR` is defined in [glib/gmacros.h](https://github.com/GNOME/glib/blob/2.89.1/glib/gmacros.h#L1313). `G_ENCODE_VERSION` is defined in [glib/gversionmacros.h](https://github.com/GNOME/glib/blob/2.89.1/glib/gversionmacros.h.in#L49). --- cfg/gtk.cfg | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cfg/gtk.cfg b/cfg/gtk.cfg index e28aa2ad7a5..5e94a0bbb5c 100644 --- a/cfg/gtk.cfg +++ b/cfg/gtk.cfg @@ -92,6 +92,7 @@ + @@ -126,6 +127,7 @@ + From ef5c1f02530b77a52f40f3ebda73dfb203b5b035 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludvig=20Gunne=20Lindstr=C3=B6m?= Date: Mon, 13 Jul 2026 08:09:54 +0200 Subject: [PATCH 087/165] Fix #14869: Attribute [[maybe_unused]] used after variable (#8713) --- lib/tokenize.cpp | 2 +- test/testtokenize.cpp | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index d2ad6f581e7..4475bfcb44f 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -9780,7 +9780,7 @@ void Tokenizer::simplifyCPPAttribute() if (!head) syntaxError(tok); - if (Token::simpleMatch(head, ";")) { + if (Token::Match(head, ";|,|)")) { Token *backTok = tok; while (Token::Match(backTok, "]|[|)")) { if (Token::Match(backTok, "]|)")) diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp index 0617007744a..e33c98861c7 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -290,6 +290,7 @@ class TestTokenizer : public TestFixture { TEST_CASE(cppMaybeUnusedBefore); TEST_CASE(cppMaybeUnusedAfter1); TEST_CASE(cppMaybeUnusedAfter2); + TEST_CASE(cppMaybeUnusedAfter3); TEST_CASE(cppMaybeUnusedStructuredBinding); TEST_CASE(attributeAlignasBefore); @@ -4381,6 +4382,19 @@ class TestTokenizer : public TestFixture { ASSERT(var && var->isAttributeMaybeUnused()); } + void cppMaybeUnusedAfter3() { + const char code[] = "void foo(int x [[maybe_unused]]) {}"; + const char expected[] = "void foo ( int x ) { }"; + + SimpleTokenizer tokenizer(settingsDefault, *this); + ASSERT(tokenizer.tokenize(code)); + + ASSERT_EQUALS(expected, tokenizer.tokens()->stringifyList(nullptr, false)); + + const Token *x = Token::findsimplematch(tokenizer.tokens(), "x"); + ASSERT(x && x->isAttributeMaybeUnused()); + } + void cppMaybeUnusedStructuredBinding() { const char code[] = "[[maybe_unused]] auto [var1, var2] = f();"; const char expected[] = "auto [ var1 , var2 ] = f ( ) ;"; From 4e3063edf0e9d4736c7a8b98867d7806585807ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludvig=20Gunne=20Lindstr=C3=B6m?= Date: Mon, 13 Jul 2026 08:10:40 +0200 Subject: [PATCH 088/165] Fix #14791: FN shadowFunction depending on order of declaration of member functions (#8609) --- lib/checkother.cpp | 3 ++- lib/filesettings.h | 8 ++++---- lib/token.h | 42 +++++++++++++++++++-------------------- lib/tokenize.cpp | 18 ++++++++--------- test/testother.cpp | 3 +++ test/testpreprocessor.cpp | 4 ++-- 6 files changed, 41 insertions(+), 37 deletions(-) diff --git a/lib/checkother.cpp b/lib/checkother.cpp index 5ea199f38e8..f0d7fbd91f1 100644 --- a/lib/checkother.cpp +++ b/lib/checkother.cpp @@ -4153,7 +4153,8 @@ static const Token *findShadowed(const Scope *scope, const Variable& var, int li return v.nameToken(); } auto it = std::find_if(scope->functionList.cbegin(), scope->functionList.cend(), [&](const Function& f) { - return f.type == FunctionType::eFunction && f.name() == var.name() && precedes(f.tokenDef, var.nameToken()); + return f.type == FunctionType::eFunction && f.name() == var.name() + && (scope->isClassOrStructOrUnion() || precedes(f.tokenDef, var.nameToken())); }); if (it != scope->functionList.end()) return it->tokenDef; diff --git a/lib/filesettings.h b/lib/filesettings.h index 0b4f15dd7e1..0ef53db85c5 100644 --- a/lib/filesettings.h +++ b/lib/filesettings.h @@ -46,9 +46,9 @@ class FileWithDetails throw std::runtime_error("empty path specified"); } - void setPath(std::string path) + void setPath(std::string p) { - mPath = std::move(path); + mPath = std::move(p); mPathSimplified = Path::simplifyPath(mPath); mPathAbsolute.clear(); } @@ -76,9 +76,9 @@ class FileWithDetails return mSize; } - void setLang(Standards::Language lang) + void setLang(Standards::Language language) { - mLang = lang; + mLang = language; } Standards::Language lang() const diff --git a/lib/token.h b/lib/token.h index 3328af31fa0..fd4804ec980 100644 --- a/lib/token.h +++ b/lib/token.h @@ -249,35 +249,35 @@ class CPPCHECKLIB Token { * For example index 1 would return next token, and 2 * would return next from that one. */ - const Token *tokAt(int index) const + const Token *tokAt(int idx) const { - return tokAtImpl(this, index); + return tokAtImpl(this, idx); } - Token *tokAt(int index) + Token *tokAt(int idx) { - return tokAtImpl(this, index); + return tokAtImpl(this, idx); } /** * @return the link to the token in given index, related to this token. * For example index 1 would return the link to next token. */ - const Token *linkAt(int index) const + const Token *linkAt(int idx) const { - return linkAtImpl(this, index); + return linkAtImpl(this, idx); } - Token *linkAt(int index) + Token *linkAt(int idx) { - return linkAtImpl(this, index); + return linkAtImpl(this, idx); } /** * @return String of the token in given index, related to this token. * If that token does not exist, an empty string is being returned. */ - const std::string &strAt(int index) const + const std::string &strAt(int idx) const { - const Token *tok = this->tokAt(index); + const Token *tok = this->tokAt(idx); return tok ? tok->mStr : mEmptyString; } @@ -604,11 +604,11 @@ class CPPCHECKLIB Token { bool hasAttributeCleanup() const { return !mImpl->mAttributeCleanup.empty(); } - void setCppcheckAttribute(CppcheckAttributesType type, MathLib::bigint value) { - mImpl->setCppcheckAttribute(type, value); + void setCppcheckAttribute(CppcheckAttributesType attrType, MathLib::bigint value) { + mImpl->setCppcheckAttribute(attrType, value); } - bool getCppcheckAttribute(CppcheckAttributesType type, MathLib::bigint &value) const { - return mImpl->getCppcheckAttribute(type, value); + bool getCppcheckAttribute(CppcheckAttributesType attrType, MathLib::bigint &value) const { + return mImpl->getCppcheckAttribute(attrType, value); } // cppcheck-suppress unusedFunction bool hasCppcheckAttributes() const { @@ -899,15 +899,15 @@ class CPPCHECKLIB Token { private: template )> - static T *tokAtImpl(T *tok, int index) + static T *tokAtImpl(T *tok, int idx) { - while (index > 0 && tok) { + while (idx > 0 && tok) { tok = tok->next(); - --index; + --idx; } - while (index < 0 && tok) { + while (idx < 0 && tok) { tok = tok->previous(); - ++index; + ++idx; } return tok; } @@ -916,9 +916,9 @@ class CPPCHECKLIB Token { * @throws InternalError thrown if index is out of range */ template )> - static T *linkAtImpl(T *thisTok, int index) + static T *linkAtImpl(T *thisTok, int idx) { - T *tok = thisTok->tokAt(index); + T *tok = thisTok->tokAt(idx); if (!tok) { throw InternalError(thisTok, "Internal error. Token::linkAt called with index outside the tokens range."); } diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 4475bfcb44f..2a1920b42e9 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -568,23 +568,23 @@ namespace { const std::pair rangeBefore(start, Token::findsimplematch(start, "{")); // find typedef name token - Token* nameToken = rangeBefore.second->link()->next(); - while (Token::Match(nameToken, "%name%|* %name%|*")) - nameToken = nameToken->next(); - const std::pair rangeQualifiers(rangeBefore.second->link()->next(), nameToken); + Token* nameTok = rangeBefore.second->link()->next(); + while (Token::Match(nameTok, "%name%|* %name%|*")) + nameTok = nameTok->next(); + const std::pair rangeQualifiers(rangeBefore.second->link()->next(), nameTok); - if (Token::Match(nameToken, "%name% ;")) { + if (Token::Match(nameTok, "%name% ;")) { if (Token::Match(rangeBefore.second->previous(), "enum|struct|union|class {")) - rangeBefore.second->previous()->insertToken(nameToken->str()); + rangeBefore.second->previous()->insertToken(nameTok->str()); mRangeType = rangeBefore; mRangeTypeQualifiers = rangeQualifiers; Token* typeName = rangeBefore.second->previous(); if (typeName->isKeyword()) { // TODO typeName->insertToken("T:" + std::to_string(num++)); - typeName->insertToken(nameToken->str()); + typeName->insertToken(nameTok->str()); } - mNameToken = nameToken; - mEndToken = nameToken->next(); + mNameToken = nameTok; + mEndToken = nameTok->next(); return; } } diff --git a/test/testother.cpp b/test/testother.cpp index 02418df5627..ca42ef23deb 100644 --- a/test/testother.cpp +++ b/test/testother.cpp @@ -13207,6 +13207,9 @@ class TestOther : public TestFixture { check("struct S { static int i(); static void f(int i) {} };\n"); ASSERT_EQUALS("[test.cpp:1:23] -> [test.cpp:1:46]: (style) Argument 'i' shadows outer function [shadowFunction]\n", errout_str()); + + check("struct S { void g(float f) {} void f() {} };\n"); + ASSERT_EQUALS("[test.cpp:1:36] -> [test.cpp:1:25]: (style) Argument 'f' shadows outer function [shadowFunction]\n", errout_str()); } void knownArgument() { diff --git a/test/testpreprocessor.cpp b/test/testpreprocessor.cpp index 5da298a2714..55fcafd4f4f 100644 --- a/test/testpreprocessor.cpp +++ b/test/testpreprocessor.cpp @@ -146,8 +146,8 @@ class TestPreprocessor : public TestFixture { } for (const std::string & config : cfgs) { try { - const bool writeLocations = (strstr(code, "#include") != nullptr); - cfgcode[config] = preprocessor.getcode(config, files, writeLocations); + const bool writeLocs = (strstr(code, "#include") != nullptr); + cfgcode[config] = preprocessor.getcode(config, files, writeLocs); } catch (const simplecpp::Output &) { cfgcode[config] = ""; } From 80ab5388763157ec42bd00449c95221b7d17af68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludvig=20Gunne=20Lindstr=C3=B6m?= Date: Mon, 13 Jul 2026 08:11:37 +0200 Subject: [PATCH 089/165] Fix #14803: `ValueType::BOOL` set for `&&` in rvalue reference declaration (#8606) --- lib/symboldatabase.cpp | 2 +- test/testsymboldatabase.cpp | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index 6e6a98ee81e..b82a3f790b0 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -7823,7 +7823,7 @@ void SymbolDatabase::setValueTypeInTokenList(bool reportDebugWarnings, Token *to setValueType(tok, ValueType(sign, type, 0U)); } - } else if (tok->isComparisonOp() || tok->tokType() == Token::eLogicalOp) { + } else if ((tok->isComparisonOp() || tok->tokType() == Token::eLogicalOp) && tok->astOperand1()) { if (tok->isCpp() && tok->isComparisonOp() && (getClassScope(tok->astOperand1()) || getClassScope(tok->astOperand2()))) { const Function *function = getOperatorFunction(tok); if (function) { diff --git a/test/testsymboldatabase.cpp b/test/testsymboldatabase.cpp index 84681b00c85..345bfdb7990 100644 --- a/test/testsymboldatabase.cpp +++ b/test/testsymboldatabase.cpp @@ -10192,6 +10192,15 @@ class TestSymbolDatabase : public TestFixture { ASSERT(tok); TODO_ASSERT(tok->valueType() && "container(std :: string|wstring|u16string|u32string)" == tok->valueType()->str()); } + { + GET_SYMBOL_DB("void f() {\n" + " int &&x = 0;\n" + "}\n"); + + const Token* tok = Token::findsimplematch(tokenizer.tokens(), "&&"); + ASSERT(tok); + ASSERT_EQUALS(static_cast(nullptr), tok->valueType()); + } } void valueTypeThis() { From ad04c7aff4217928764073e7fe7f53e6dc8e58b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludvig=20Gunne=20Lindstr=C3=B6m?= Date: Mon, 13 Jul 2026 08:12:40 +0200 Subject: [PATCH 090/165] Fix #14836: FP syntaxError for anonymous struct in for loop (#8710) --- lib/tokenize.cpp | 13 ++++++++++++- test/testtokenize.cpp | 5 +++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 2a1920b42e9..4e00e0d184e 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -8973,7 +8973,7 @@ void Tokenizer::findGarbageCode() const if (tok->strAt(-1) == ",") syntaxError(tok); colons++; - } else if (tok->str() == "(") { // skip pairs of ( ) + } else if (tok->str() == "(" || tok->str() == "{") { // skip pairs of ( ) tok = tok->link(); } } @@ -9417,6 +9417,7 @@ void Tokenizer::simplifyStructDecl() if (Token::Match(after->next(), "const|static|volatile| *|&| const| (| %type% )| ,|;|[|=|(|{")) { after->insertToken(";"); after = after->next(); + Token *declEnd = after; while (!Token::Match(start, "struct|class|union|enum")) { after->insertToken(start->str()); after = after->next(); @@ -9459,6 +9460,16 @@ void Tokenizer::simplifyStructDecl() } } } + + // pull declaration out of for loop + if (Token::simpleMatch(start->tokAt(-2), "for ( struct")) { + Token *link = start->linkAt(-1); + start->deletePrevious(2); + declEnd->insertToken("("); + declEnd->next()->link(link); + link->link(declEnd->next()); + declEnd->insertToken("for"); + } } } diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp index e33c98861c7..c4de2be00e7 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -2274,6 +2274,11 @@ class TestTokenizer : public TestFixture { const char code4[] = "union U { struct { int a; int b; }; int ab[2]; };"; const char expected4[] = "union U { struct { int a ; int b ; } ; int ab [ 2 ] ; } ;"; ASSERT_EQUALS(expected4, tokenizeAndStringify(code4)); + + // #14836: FP syntaxError for anonymous struct in for loop + const char code5[] = "void f(void) { for (struct { int a; } it = {0}; it.a < 10; it.a++) {} }"; + const char expected5[] = "void f ( ) { struct Anonymous0 { int a ; } ; for ( struct Anonymous0 it = { 0 } ; it . a < 10 ; it . a ++ ) { } }"; + ASSERT_EQUALS(expected5, tokenizeAndStringify(code5)); } void vardecl1() { From f49f1aa318d46f92109da3c59e4f1b011889339a Mon Sep 17 00:00:00 2001 From: Paul Fultz II Date: Mon, 13 Jul 2026 01:19:10 -0500 Subject: [PATCH 091/165] Fix 14900: FP knownConditionTrueFalse on variable after if/else-if chain (#8715) Co-authored-by: Your Name --- lib/forwardanalyzer.cpp | 7 ++++++- test/testcondition.cpp | 14 ++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/lib/forwardanalyzer.cpp b/lib/forwardanalyzer.cpp index 368ac761a53..c38d93155ea 100644 --- a/lib/forwardanalyzer.cpp +++ b/lib/forwardanalyzer.cpp @@ -834,8 +834,13 @@ namespace { ++ft.forkDepth; ft.updateRange(thenBranch.endBlock, end, depth - 1); } - if (pElse == Progress::Break) + if (pElse == Progress::Break) { + // Only the else branch escaped; the then branch falls through, so + // the scope as a whole does not always escape. + if (terminate == Analyzer::Terminate::Escape && !thenBranch.isEscape()) + terminate = Analyzer::Terminate::None; return Break(); + } } } } else if (Token::simpleMatch(tok, "try {")) { diff --git a/test/testcondition.cpp b/test/testcondition.cpp index 837cd4e78ba..da4ecae43b3 100644 --- a/test/testcondition.cpp +++ b/test/testcondition.cpp @@ -4935,6 +4935,20 @@ class TestCondition : public TestFixture { " if (v > 0) {}\n" "}\n"); ASSERT_EQUALS("", errout_str()); + + check("bool f(int x) {\n" // only the innermost else escapes - x is 0 or >1 afterwards, not known + " if (!x) {}\n" + " else if (x > 1) {}\n" + " else return false;\n" + " return x ? false : true;\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + + check("bool f(int x) {\n" // the branch's fall-through path must clear the escape + " if (x) { if (x > 1) {} else return false; }\n" + " return x ? false : true;\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); } void alwaysTrueSymbolic() From 3d88880e833ed9f60e1ba48f256498440368d86c Mon Sep 17 00:00:00 2001 From: Paul Fultz II Date: Mon, 13 Jul 2026 01:59:30 -0500 Subject: [PATCH 092/165] Fix issue 13254: FN: containerOutOfBounds (std::equal) (#8695) This adds a new check `algorithmOutOfBounds` that checks when one of the algorithms will access elements out of bounds based on the sizes of other containers passed in. Right now, it directly checks for the stl algorithms, but we could add attributes to the Library to better describe these algorithms so it can be used for other algorithm libraries. --------- Co-authored-by: Your Name --- lib/checkers.cpp | 1 + lib/checkstl.cpp | 407 ++++++++++++++++++++++++++- lib/checkstl.h | 16 ++ lib/valueflow.cpp | 12 + man/checkers/algorithmOutOfBounds.md | 69 +++++ releasenotes.txt | 1 + test/cli/other_test.py | 9 +- test/teststl.cpp | 372 +++++++++++++++++++++++- test/testvalueflow.cpp | 42 +++ 9 files changed, 908 insertions(+), 21 deletions(-) create mode 100644 man/checkers/algorithmOutOfBounds.md diff --git a/lib/checkers.cpp b/lib/checkers.cpp index cc8c4054ea2..56d91cc4f05 100644 --- a/lib/checkers.cpp +++ b/lib/checkers.cpp @@ -167,6 +167,7 @@ namespace checkers { {"CheckSizeof::sizeofVoid","portability"}, {"CheckSizeof::sizeofsizeof","warning"}, {"CheckSizeof::suspiciousSizeofCalculation","warning,inconclusive"}, + {"CheckStl::algorithmOutOfBounds",""}, {"CheckStl::checkDereferenceInvalidIterator","warning"}, {"CheckStl::checkDereferenceInvalidIterator2",""}, {"CheckStl::checkFindInsert","performance"}, diff --git a/lib/checkstl.cpp b/lib/checkstl.cpp index 743ac8a3cb4..500adc08b01 100644 --- a/lib/checkstl.cpp +++ b/lib/checkstl.cpp @@ -35,6 +35,7 @@ #include "checknullpointer.h" #include +#include #include #include #include @@ -127,6 +128,16 @@ static const Token* getContainerFromSize(const Library::Container* container, co return nullptr; } +// A value that out of bounds analysis can use: not impossible, and inconclusive only when enabled +static bool isUsableValue(const ValueFlow::Value& value, const Settings& settings) +{ + if (value.isImpossible()) + return false; + if (value.isInconclusive() && !settings.certainty.isEnabled(Certainty::inconclusive)) + return false; + return true; +} + void CheckStlImpl::outOfBounds() { logChecker("CheckStl::outOfBounds"); @@ -148,9 +159,7 @@ void CheckStlImpl::outOfBounds() for (const ValueFlow::Value &value : tok->values()) { if (!value.isContainerSizeValue()) continue; - if (value.isImpossible()) - continue; - if (value.isInconclusive() && !mSettings.certainty.isEnabled(Certainty::inconclusive)) + if (!isUsableValue(value, mSettings)) continue; if (!value.errorSeverity() && !mSettings.severity.isEnabled(Severity::warning)) continue; @@ -2482,8 +2491,6 @@ void CheckStlImpl::checkDereferenceInvalidIterator() void CheckStlImpl::checkDereferenceInvalidIterator2() { - const bool printInconclusive = (mSettings.certainty.isEnabled(Certainty::inconclusive)); - logChecker("CheckStl::checkDereferenceInvalidIterator2"); for (const Token *tok = mTokenizer->tokens(); tok; tok = tok->next()) { @@ -2496,20 +2503,16 @@ void CheckStlImpl::checkDereferenceInvalidIterator2() continue; std::vector contValues; - std::copy_if(tok->values().cbegin(), tok->values().cend(), std::back_inserter(contValues), [&](const ValueFlow::Value& value) { - if (value.isImpossible()) - return false; - if (!printInconclusive && value.isInconclusive()) - return false; - return value.isContainerSizeValue(); + std::copy_if(tok->values().cbegin(), + tok->values().cend(), + std::back_inserter(contValues), + [&](const ValueFlow::Value& value) { + return isUsableValue(value, mSettings) && value.isContainerSizeValue(); }); - // Can iterator point to END or before START? for (const ValueFlow::Value& value:tok->values()) { - if (value.isImpossible()) - continue; - if (!printInconclusive && value.isInconclusive()) + if (!isUsableValue(value, mSettings)) continue; if (!value.isIteratorValue()) continue; @@ -3379,6 +3382,378 @@ void CheckStlImpl::eraseIteratorOutOfBounds() } } +namespace { +// An iterator position described by the ValueFlow values attached to the iterator expression + struct IteratorPosition { + const ValueFlow::Value* value = nullptr; // ITERATOR_START or ITERATOR_END value + const ValueFlow::Value* sizeValue = nullptr; // container size value with the same path, if available + bool fromEnd() const { + return value->isIteratorEndValue(); + } + explicit operator bool() const { + return value != nullptr; + } + }; + +// A number of elements together with the ValueFlow values it was derived from + struct ElementCount { + MathLib::bigint count = 0; + std::vector values; + explicit operator bool() const { + return !values.empty(); + } + }; + +// The best candidate proving an out of bounds access, preferring proofs without possible values + struct BestCandidate { + ElementCount best; + bool certain = false; + void consider(const ElementCount& candidate) + { + const bool candidateCertain = + std::none_of(candidate.values.cbegin(), candidate.values.cend(), std::mem_fn(&ValueFlow::Value::isPossible)); + if (best && (certain || !candidateCertain)) + return; + best = candidate; + certain = candidateCertain; + } + }; +} // namespace + +// Get the first ValueFlow value of a token matching the predicate, preferring known values +template +static const ValueFlow::Value* selectPreferredValue(const Token* tok, const Predicate& pred) +{ + const ValueFlow::Value* result = nullptr; + for (const ValueFlow::Value& value : tok->values()) { + if (!pred(value)) + continue; + if (result && !(value.isKnown() && !result->isKnown())) + continue; + result = &value; + } + return result; +} + +// Get the iterator value of an iterator expression together with the container size value that +// ValueFlow has added to the iterator +static IteratorPosition getIteratorPosition(const Token* tok, const Settings& settings) +{ + IteratorPosition position; + if (!tok) + return position; + position.value = selectPreferredValue(tok, [&](const ValueFlow::Value& value) { + return isUsableValue(value, settings) && value.isIteratorValue(); + }); + if (!position.value) + return position; + position.sizeValue = selectPreferredValue(tok, [&](const ValueFlow::Value& value) { + return isUsableValue(value, settings) && value.isContainerSizeValue() && value.path == position.value->path; + }); + return position; +} + +// Compute the distance last-first between two iterators into the same container +static ElementCount getIteratorDistance(const IteratorPosition& first, const IteratorPosition& last) +{ + ElementCount distance; + if (first.value->path != last.value->path) + return distance; + // bounded values could make the distance an overestimate + if (first.value->bound != ValueFlow::Value::Bound::Point || last.value->bound != ValueFlow::Value::Bound::Point) + return distance; + if (first.fromEnd() == last.fromEnd()) { // the container size cancels out + distance.count = last.value->intvalue - first.value->intvalue; + distance.values = {first.value, last.value}; + return distance; + } + const IteratorPosition& endPosition = first.fromEnd() ? first : last; + if (!endPosition.sizeValue || endPosition.sizeValue->bound != ValueFlow::Value::Bound::Point) + return distance; + const MathLib::bigint endIndex = endPosition.sizeValue->intvalue + endPosition.value->intvalue; + distance.count = last.fromEnd() ? endIndex - first.value->intvalue : last.value->intvalue - endIndex; + distance.values = {first.value, last.value, endPosition.sizeValue}; + return distance; +} + +// Compute the number of elements available in the container behind the iterator position +static ElementCount getAvailableSpace(const IteratorPosition& position) +{ + ElementCount available; + // the position could be smaller, which would make more elements available + if (position.value->bound == ValueFlow::Value::Bound::Upper) + return available; + if (position.fromEnd()) { // the container size cancels out + available.count = -position.value->intvalue; + available.values = {position.value}; + return available; + } + // the container size could be larger, which would make more elements available + if (!position.sizeValue || position.sizeValue->bound == ValueFlow::Value::Bound::Lower) + return available; + available.count = position.sizeValue->intvalue - position.value->intvalue; + available.values = {position.value, position.sizeValue}; + return available; +} + +// Find iterator values and paired container sizes of the iterator that prove accessing +// elements to be out of bounds, preferring a proof that does not rely on possible values +static ElementCount findInsufficientSpace(const Token* tok, + MathLib::bigint accessed, + MathLib::bigint sourcePath, + const Settings& settings) +{ + BestCandidate insufficient; + if (!tok) + return insufficient.best; + const auto consider = [&](const ElementCount& candidate) { + if (!candidate) + return; + if (candidate.count < 0 || accessed <= candidate.count) + return; // the space is sufficient + insufficient.consider(candidate); + }; + for (const ValueFlow::Value& value : tok->values()) { + if (!isUsableValue(value, settings) || !value.isIteratorValue()) + continue; + if (value.path != 0 && sourcePath != 0 && value.path != sourcePath) + continue; + IteratorPosition position; + position.value = &value; + if (position.fromEnd()) { // the available space does not depend on the container size + consider(getAvailableSpace(position)); + continue; + } + for (const ValueFlow::Value& sizeValue : tok->values()) { + if (!isUsableValue(sizeValue, settings) || !sizeValue.isContainerSizeValue() || sizeValue.path != value.path) + continue; + position.sizeValue = &sizeValue; + consider(getAvailableSpace(position)); + } + } + return insufficient.best; +} + +// Find iterator values and paired container sizes of the source range that prove more than +// elements to be accessed, preferring a proof that does not rely on possible values +static ElementCount findExcessiveDistance(const Token* firstTok, + const Token* lastTok, + MathLib::bigint available, + MathLib::bigint destPath, + const Settings& settings) +{ + BestCandidate excessive; + const auto consider = [&](const ElementCount& candidate) { + if (!candidate) + return; + if (candidate.count <= available) + return; // the access is within bounds + excessive.consider(candidate); + }; + for (const ValueFlow::Value& firstValue : firstTok->values()) { + if (!isUsableValue(firstValue, settings) || !firstValue.isIteratorValue()) + continue; + if (firstValue.path != 0 && destPath != 0 && firstValue.path != destPath) + continue; + for (const ValueFlow::Value& lastValue : lastTok->values()) { + if (!isUsableValue(lastValue, settings) || !lastValue.isIteratorValue()) + continue; + IteratorPosition first, last; + first.value = &firstValue; + last.value = &lastValue; + if (first.fromEnd() == last.fromEnd()) { // the distance does not depend on the container size + consider(getIteratorDistance(first, last)); + continue; + } + IteratorPosition& endPosition = first.fromEnd() ? first : last; + const Token* const endTok = first.fromEnd() ? firstTok : lastTok; + for (const ValueFlow::Value& sizeValue : endTok->values()) { + if (!isUsableValue(sizeValue, settings) || !sizeValue.isContainerSizeValue() || + sizeValue.path != endPosition.value->path) + continue; + endPosition.sizeValue = &sizeValue; + consider(getIteratorDistance(first, last)); + } + } + } + return excessive.best; +} + +// Find count values of a count-based algorithm that prove more than elements to be accessed +static ElementCount findExcessiveCount(const Token* tok, + MathLib::bigint available, + MathLib::bigint destPath, + const Settings& settings) +{ + BestCandidate excessive; + if (!tok) + return excessive.best; + for (const ValueFlow::Value& value : tok->values()) { + if (!isUsableValue(value, settings) || !value.isIntValue()) + continue; + // a count with an upper bound could be smaller, which would make fewer elements accessed + if (value.bound == ValueFlow::Value::Bound::Upper) + continue; + if (value.path != 0 && destPath != 0 && value.path != destPath) + continue; + if (value.intvalue <= available) + continue; // the access is within bounds + ElementCount candidate; + candidate.count = value.intvalue; + candidate.values.push_back(&value); + excessive.consider(candidate); + } + return excessive.best; +} + +// Do not warn when the proof relies on possible values on both sides +static bool bothSidesPossible(const ElementCount& accessed, const ElementCount& available) +{ + const auto isPossible = std::mem_fn(&ValueFlow::Value::isPossible); + return std::any_of(accessed.values.cbegin(), accessed.values.cend(), isPossible) && + std::any_of(available.values.cbegin(), available.values.cend(), isPossible); +} + +// Get the number of accessed elements of a count-based algorithm such as std::fill_n +static const ValueFlow::Value* getCountValue(const Token* tok, const Settings& settings) +{ + if (!tok) + return nullptr; + return selectPreferredValue(tok, [&](const ValueFlow::Value& value) { + // a count with an upper bound could be smaller, which would make fewer elements accessed + return isUsableValue(value, settings) && value.isIntValue() && value.bound != ValueFlow::Value::Bound::Upper; + }); +} + +void CheckStlImpl::algorithmOutOfBounds() +{ + logChecker("CheckStl::algorithmOutOfBounds"); + for (const Scope* function : mTokenizer->getSymbolDatabase()->functionScopes) { + for (const Token* tok = function->bodyStart; tok != function->bodyEnd; tok = tok->next()) { + if (!Token::Match(tok, "std :: %name% (")) + continue; + const Token* const nameTok = tok->tokAt(2); + // algorithms accessing the range denoted by the third argument exactly last1-first1 times.. + const bool exact = Token::Match( + nameTok, + "copy|move|swap_ranges|transform|replace_copy|replace_copy_if|reverse_copy|equal|mismatch|is_permutation|partial_sum|adjacent_difference|inner_product ("); + // ..or at most last1-first1 times, depending on the values in the input range.. + const bool atMost = !exact && Token::Match(nameTok, "copy_if|remove_copy|remove_copy_if|unique_copy ("); + // ..or accessing their iterator arguments as many times as the count argument says + const bool countBased = !exact && !atMost && Token::Match(nameTok, "copy_n|fill_n|generate_n ("); + if (!exact && !atMost && !countBased) + continue; + if (atMost && !mSettings.certainty.isEnabled(Certainty::inconclusive)) + continue; + const std::vector args = getArguments(nameTok); + if (args.size() < 3) + continue; + ElementCount accessed; // source access count using the preferred values + std::vector iterArgs; + if (countBased) { + if (const ValueFlow::Value* countValue = getCountValue(args[1], mSettings)) { + accessed.count = countValue->intvalue; + accessed.values.push_back(countValue); + } + iterArgs.push_back(args[0]); + if (Token::simpleMatch(nameTok, "copy_n")) + iterArgs.push_back(args[2]); // copy_n also writes through the third argument + } else { + // two-range overloads taking a last2 iterator do not access the second range out of bounds + if (Token::Match(nameTok, "equal|mismatch|is_permutation") && args.size() >= 4 && astIsIterator(args[3])) + continue; + // both iterators must refer to the same container + const ValueFlow::Value firstLifetime = getLifetimeIteratorValue(args[0]); + const ValueFlow::Value lastLifetime = getLifetimeIteratorValue(args[1]); + if (!firstLifetime.tokvalue || !lastLifetime.tokvalue) + continue; + if (!isSameIteratorContainerExpression(firstLifetime.tokvalue, + lastLifetime.tokvalue, + mSettings, + firstLifetime.lifetimeKind)) + continue; + const IteratorPosition first = getIteratorPosition(args[0], mSettings); + const IteratorPosition last = getIteratorPosition(args[1], mSettings); + if (first && last) + accessed = getIteratorDistance(first, last); + iterArgs.push_back(args[2]); + if (Token::simpleMatch(nameTok, "transform") && args.size() == 5) + iterArgs.push_back(args[3]); // binary transform also writes through the fourth argument + } + if (accessed.count <= 0) + accessed = ElementCount(); // there is no preferred source access count + for (const Token* const iterArg : iterArgs) { + // check the preferred source access count against all destination values.. + ElementCount sourceCount = accessed; + ElementCount available; + if (sourceCount) + available = + findInsufficientSpace(iterArg, sourceCount.count, sourceCount.values.front()->path, mSettings); + if (!available || bothSidesPossible(sourceCount, available)) { + // ..or all source access counts against the preferred destination values + const IteratorPosition dest = getIteratorPosition(iterArg, mSettings); + if (!dest) + continue; + available = getAvailableSpace(dest); + if (!available || available.count < 0) + continue; + sourceCount = + countBased + ? findExcessiveCount(args[1], available.count, dest.value->path, mSettings) + : findExcessiveDistance(args[0], args[1], available.count, dest.value->path, mSettings); + if (!sourceCount || bothSidesPossible(sourceCount, available)) + continue; + } + const ValueFlow::Value* conditionValue = nullptr; + bool inconclusiveValues = false; + std::vector usedValues = sourceCount.values; + usedValues.insert(usedValues.end(), available.values.cbegin(), available.values.cend()); + for (const ValueFlow::Value* value : usedValues) { + if (!conditionValue && value->condition) + conditionValue = value; + inconclusiveValues |= value->isInconclusive(); + } + if (conditionValue && !mSettings.severity.isEnabled(Severity::warning)) + continue; + const ValueFlow::Value* pathValue = conditionValue ? conditionValue : available.values.back(); + algorithmOutOfBoundsError(iterArg, + "std::" + nameTok->str(), + sourceCount.count, + available.count, + pathValue, + atMost, + atMost || inconclusiveValues); + } + } + } +} + +void CheckStlImpl::algorithmOutOfBoundsError(const Token* tok, + const std::string& algoName, + MathLib::bigint accessed, + MathLib::bigint available, + const ValueFlow::Value* value, + bool mayAccessFewer, + bool inconclusive) +{ + const Token* const condition = value ? value->condition : nullptr; + const std::string iterExpr = tok ? tok->expressionString() : "it"; + const std::string accessedStr = MathLib::toString(accessed) + (accessed == 1 ? " element" : " elements"); + const std::string availableStr = MathLib::toString(available) + (available == 1 ? " element is" : " elements are"); + const std::string body = "algorithm '" + algoName + "' " + (mayAccessFewer ? "may access up to " : "accesses ") + + accessedStr + " through the iterator '" + iterExpr + "' but only " + availableStr + + " available."; + const std::string msg = + condition ? (ValueFlow::eitherTheConditionIsRedundant(condition) + " or the " + body) : ("The " + body); + ErrorPath errorPath = getErrorPath(tok, value, "Access out of bounds"); + reportError(std::move(errorPath), + (condition || mayAccessFewer) ? Severity::warning : Severity::error, + "algorithmOutOfBounds", + msg, + CWE788, + inconclusive ? Certainty::inconclusive : Certainty::normal); +} + static bool isMutex(const Variable* var) { const Token* tok = Token::typeDecl(var->nameToken()).first; @@ -3478,6 +3853,7 @@ void CheckStl::runChecks(const Tokenizer &tokenizer, ErrorLogger& errorLogger) checkStl.mismatchingContainerIterator(); checkStl.knownEmptyContainer(); checkStl.eraseIteratorOutOfBounds(); + checkStl.algorithmOutOfBounds(); checkStl.stlBoundaries(); checkStl.checkDereferenceInvalidIterator(); @@ -3529,6 +3905,7 @@ void CheckStl::getErrorMessages(ErrorLogger& errorLogger, const Settings& settin c.dereferenceInvalidIteratorError(nullptr, "i"); // TODO: derefInvalidIteratorRedundantCheck c.eraseIteratorOutOfBoundsError(nullptr, nullptr); + c.algorithmOutOfBoundsError(nullptr, "std::copy", 10, 6, nullptr, false, false); c.useStlAlgorithmError(nullptr, ""); c.knownEmptyContainerError(nullptr, ""); c.globalLockGuardError(nullptr); diff --git a/lib/checkstl.h b/lib/checkstl.h index 4218090e707..0f9a70a7a15 100644 --- a/lib/checkstl.h +++ b/lib/checkstl.h @@ -26,6 +26,7 @@ #include "checkimpl.h" #include "config.h" #include "errortypes.h" +#include "mathlib.h" #include #include @@ -73,6 +74,7 @@ class CPPCHECKLIB CheckStl : public Check { "- useless calls of string and STL functions\n" "- dereferencing an invalid iterator\n" "- erasing an iterator that is out of bounds\n" + "- out of bounds access of an iterator passed to an STL algorithm\n" "- reading from empty STL container\n" "- iterating over an empty STL container\n" "- consider using an STL algorithm instead of raw loop\n" @@ -183,6 +185,12 @@ class CPPCHECKLIB CheckStlImpl : public CheckImpl { void eraseIteratorOutOfBounds(); + /** + * Check that the iterator given to an STL algorithm is not accessed + * out of bounds: std::equal(in.begin(), in.end(), out.begin()) + */ + void algorithmOutOfBounds(); + void checkMutexes(); bool isContainerSize(const Token *containerToken, const Token *expr) const; @@ -235,6 +243,14 @@ class CPPCHECKLIB CheckStlImpl : public CheckImpl { void eraseIteratorOutOfBoundsError(const Token* ftok, const Token* itertok, const ValueFlow::Value* val = nullptr); + void algorithmOutOfBoundsError(const Token* tok, + const std::string& algoName, + MathLib::bigint accessed, + MathLib::bigint available, + const ValueFlow::Value* value, + bool mayAccessFewer, + bool inconclusive); + void globalLockGuardError(const Token *tok); void localMutexError(const Token *tok); }; diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index 8c77b17cf94..096e3d56f56 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -3844,12 +3844,24 @@ static void valueFlowForwardConst(Token* start, { if (!precedes(start, end)) throw InternalError(var->nameToken(), "valueFlowForwardConst: start token does not precede the end token."); + const bool hasContainerSizeValue = std::any_of(values.begin(), values.end(), [](const ValueFlow::Value& value) { + return value.isContainerSizeValue(); + }); for (Token* tok = start; tok != end; tok = tok->next()) { if (tok->varId() == var->declarationId()) { for (const ValueFlow::Value& value : values) setTokenValue(tok, value, settings); } else { [&] { + // Add the container size to iterators of the container (mirrors ContainerExpressionAnalyzer::match) + if (hasContainerSizeValue && astIsIterator(tok) && isAliasOf(tok, var->declarationId())) { + for (const ValueFlow::Value& value : values) { + if (!value.isContainerSizeValue()) + continue; + setTokenValue(tok, value, settings); + } + return; + } // Follow references const auto& refs = tok->refs(); auto it = std::find_if(refs.cbegin(), refs.cend(), [&](const ReferenceToken& ref) { diff --git a/man/checkers/algorithmOutOfBounds.md b/man/checkers/algorithmOutOfBounds.md new file mode 100644 index 00000000000..8e446f82895 --- /dev/null +++ b/man/checkers/algorithmOutOfBounds.md @@ -0,0 +1,69 @@ +# algorithmOutOfBounds + +**Message**: The algorithm 'std::copy' accesses 5 elements through the iterator 'v1.begin()' but only 3 elements are available.
+**Category**: Correctness
+**Severity**: Error
+**Language**: C++ + +## Description + +Many STL algorithms take an iterator that denotes the beginning of a second range (typically an output range) and +assume that this range is large enough. If it is not, the algorithm writes or reads past the end of the container, +which is undefined behavior. + +This checker uses the ValueFlow analysis to compare the number of elements an algorithm accesses with the number of +elements that are actually available through the iterator, and warns when the access is out of bounds. Three groups +of algorithms are checked: + +- Algorithms that access exactly `last1 - first1` elements through the other iterator: `std::copy`, `std::move`, + `std::swap_ranges`, `std::transform`, `std::replace_copy`, `std::replace_copy_if`, `std::reverse_copy`, + `std::equal`, `std::mismatch`, `std::is_permutation`, `std::partial_sum`, `std::adjacent_difference` and + `std::inner_product`. +- Algorithms that access at most `last1 - first1` elements, depending on the values in the input range: + `std::copy_if`, `std::remove_copy`, `std::remove_copy_if` and `std::unique_copy`. Since the actual number of + accessed elements is not known, these are only reported as inconclusive warnings (with `--inconclusive`). +- Count-based algorithms that access as many elements as the count argument says: `std::copy_n`, `std::fill_n` and + `std::generate_n`. + +The severity is `error` when the out of bounds access always happens. When the analysis depends on an earlier +condition in the code, the severity is `warning` and the message has the form "Either the condition 'v.size()==3' +is redundant or the algorithm ... ". + +The checker does not warn when: + +- The second range is given with both a begin and an end iterator (for example the two-range overloads of + `std::equal`, `std::mismatch` and `std::is_permutation`), since such overloads do not access the second range out + of bounds. +- An iterator adaptor such as `std::back_inserter` or `std::inserter` is used, since those grow the container as + needed. +- The proof would rely on "possible" (non-known) values on both the accessed and the available side. + +## How to fix + +Make sure the destination range is large enough before calling the algorithm, or use an iterator adaptor such as +`std::back_inserter` that grows the container as needed. + +Before: +```cpp +void f(const std::vector& v0) { + std::vector v1(3); + // If v0 has more than 3 elements, this writes past the end of v1 + std::copy(v0.begin(), v0.end(), v1.begin()); +} +``` + +After: +```cpp +void f(const std::vector& v0) { + std::vector v1(v0.size()); + std::copy(v0.begin(), v0.end(), v1.begin()); +} +``` + +Or let the container grow: +```cpp +void f(const std::vector& v0) { + std::vector v1; + std::copy(v0.begin(), v0.end(), std::back_inserter(v1)); +} +``` diff --git a/releasenotes.txt b/releasenotes.txt index 0ca26f2374a..1c0739dec0d 100644 --- a/releasenotes.txt +++ b/releasenotes.txt @@ -7,6 +7,7 @@ Major bug fixes & crashes: New checks: - Warn when feof() is used as a while loop condition (wrongfeofUsage). - ftell() result is unspecified when file is opened in mode "t". +- Detect when an STL algorithm such as std::copy, std::equal, std::transform, etc. accesses more elements through an iterator than are available in the container (algorithmOutOfBounds). C/C++ support: - diff --git a/test/cli/other_test.py b/test/cli/other_test.py index c79fd0c8e50..c48a0b50354 100644 --- a/test/cli/other_test.py +++ b/test/cli/other_test.py @@ -1,4 +1,3 @@ - # python -m pytest test-other.py import os @@ -4429,25 +4428,25 @@ def __test_active_checkers(tmp_path, active_cnt, total_cnt, use_misra=False, use def test_active_unusedfunction_only(tmp_path): - __test_active_checkers(tmp_path, 1, 187, use_unusedfunction_only=True) + __test_active_checkers(tmp_path, 1, 188, use_unusedfunction_only=True) def test_active_unusedfunction_only_builddir(tmp_path): checkers_exp = [ 'CheckUnusedFunctions::check' ] - __test_active_checkers(tmp_path, 1, 187, use_unusedfunction_only=True, checkers_exp=checkers_exp) + __test_active_checkers(tmp_path, 1, 188, use_unusedfunction_only=True, checkers_exp=checkers_exp) def test_active_unusedfunction_only_misra(tmp_path): - __test_active_checkers(tmp_path, 1, 387, use_unusedfunction_only=True, use_misra=True) + __test_active_checkers(tmp_path, 1, 388, use_unusedfunction_only=True, use_misra=True) def test_active_unusedfunction_only_misra_builddir(tmp_path): checkers_exp = [ 'CheckUnusedFunctions::check' ] - __test_active_checkers(tmp_path, 1, 387, use_unusedfunction_only=True, use_misra=True, checkers_exp=checkers_exp) + __test_active_checkers(tmp_path, 1, 388, use_unusedfunction_only=True, use_misra=True, checkers_exp=checkers_exp) def test_analyzerinfo(tmp_path): diff --git a/test/teststl.cpp b/test/teststl.cpp index 93b53b43671..ed9c5503d45 100644 --- a/test/teststl.cpp +++ b/test/teststl.cpp @@ -78,6 +78,7 @@ class TestStl : public TestFixture { TEST_CASE(iteratorSameExpression); TEST_CASE(mismatchingContainerIterator); TEST_CASE(eraseIteratorOutOfBounds); + TEST_CASE(algorithmOutOfBounds); TEST_CASE(dereference); TEST_CASE(dereference_break); // #3644 - handle "break" @@ -2421,6 +2422,372 @@ class TestStl : public TestFixture { errout_str()); } + void algorithmOutOfBounds() + { + check("void f() {\n" + " const std::deque d0{1,2,3,4,5,6,7,8,9,10};\n" + " const std::deque d1{1,2,3,4,5,6};\n" + " if(std::equal(d0.cbegin(), d0.cend(), d1.cbegin())) {}\n" + "}\n"); + ASSERT_EQUALS( + "[test.cpp:4:52]: (error) The algorithm 'std::equal' accesses 10 elements through the iterator 'd1.cbegin()' but only 6 elements are available. [algorithmOutOfBounds]\n", + errout_str()); + + check("void f() {\n" + " const std::deque d0{1,2,3,4,5,6};\n" + " const std::deque d1{1,2,3,4,5,6};\n" + " if(std::equal(d0.cbegin(), d0.cend(), d1.cbegin())) {}\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + + // two-range overload does not access the second range out of bounds + check("void f() {\n" + " const std::deque d0{1,2,3,4,5,6,7,8,9,10};\n" + " const std::deque d1{1,2,3,4,5,6};\n" + " if(std::equal(d0.cbegin(), d0.cend(), d1.cbegin(), d1.cend())) {}\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + + check("void f() {\n" + " const std::vector v0{1,2,3,4,5};\n" + " std::vector v1(3);\n" + " std::copy(v0.begin(), v0.end(), v1.begin());\n" + "}\n"); + ASSERT_EQUALS( + "[test.cpp:4:45]: (error) The algorithm 'std::copy' accesses 5 elements through the iterator 'v1.begin()' but only 3 elements are available. [algorithmOutOfBounds]\n", + errout_str()); + + check("void f() {\n" + " const std::vector v0{1,2,3,4,5};\n" + " std::vector v1(5);\n" + " std::copy(v0.begin(), v0.end(), v1.begin());\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + + // iterator arithmetic + check("void f() {\n" + " const std::vector v0{1,2,3,4,5};\n" + " std::vector v1(6);\n" + " std::copy(v0.begin(), v0.end(), v1.begin() + 3);\n" + " std::copy(v0.begin() + 3, v0.end(), v1.begin());\n" + "}\n"); + ASSERT_EQUALS( + "[test.cpp:4:48]: (error) The algorithm 'std::copy' accesses 5 elements through the iterator 'v1.begin()+3' but only 3 elements are available. [algorithmOutOfBounds]\n", + errout_str()); + + // don't warn when using iterator adaptors + check("void f() {\n" + " const std::deque d0{1,2,3,4,5,6,7,8,9,10};\n" + " std::deque d1;\n" + " std::copy(d0.cbegin(), d0.cend(), std::back_inserter(d1));\n" + " std::copy(d0.cbegin(), d0.cend(), std::inserter(d1, d1.begin()));\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + + // algorithms that access at most last-first elements are inconclusive + check("void f() {\n" + " const std::vector v0{1,2,3,4,5};\n" + " std::vector v1(3);\n" + " std::copy_if(v0.begin(), v0.end(), v1.begin(), [](int i) { return i != 3; });\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + + check("void f() {\n" + " const std::vector v0{1,2,3,4,5};\n" + " std::vector v1(3);\n" + " std::copy_if(v0.begin(), v0.end(), v1.begin(), [](int i) { return i != 3; });\n" + "}\n", + dinit(CheckOptions, $.inconclusive = true)); + ASSERT_EQUALS( + "[test.cpp:4:48]: (warning, inconclusive) The algorithm 'std::copy_if' may access up to 5 elements through the iterator 'v1.begin()' but only 3 elements are available. [algorithmOutOfBounds]\n", + errout_str()); + + check("void f() {\n" + " const std::vector v0{1,2,3,4,5};\n" + " std::vector v1(3);\n" + " std::transform(v0.begin(), v0.end(), v1.begin(), [](int i) { return i * 2; });\n" + "}\n"); + ASSERT_EQUALS( + "[test.cpp:4:50]: (error) The algorithm 'std::transform' accesses 5 elements through the iterator 'v1.begin()' but only 3 elements are available. [algorithmOutOfBounds]\n", + errout_str()); + + // binary transform reads the third argument and writes the fourth argument + check("void f() {\n" + " const std::vector v0{1,2,3,4,5};\n" + " const std::vector v1{1,2,3};\n" + " std::vector v2(5);\n" + " std::transform(v0.begin(), v0.end(), v1.begin(), v2.begin(), [](int a, int b) { return a + b; });\n" + "}\n"); + ASSERT_EQUALS( + "[test.cpp:5:50]: (error) The algorithm 'std::transform' accesses 5 elements through the iterator 'v1.begin()' but only 3 elements are available. [algorithmOutOfBounds]\n", + errout_str()); + + check("void f() {\n" + " const std::vector v0{1,2,3,4,5};\n" + " const std::vector v1{1,2,3,4,5};\n" + " std::vector v2(3);\n" + " std::transform(v0.begin(), v0.end(), v1.begin(), v2.begin(), [](int a, int b) { return a + b; });\n" + "}\n"); + ASSERT_EQUALS( + "[test.cpp:5:62]: (error) The algorithm 'std::transform' accesses 5 elements through the iterator 'v2.begin()' but only 3 elements are available. [algorithmOutOfBounds]\n", + errout_str()); + + // copying a range within the same container + check("void f() {\n" + " std::vector v{1,2,3,4,5,6,7,8,9,10};\n" + " std::copy(v.begin(), v.begin() + 3, v.begin() + 7);\n" + " std::copy(v.begin(), v.begin() + 4, v.begin() + 7);\n" + "}\n"); + ASSERT_EQUALS( + "[test.cpp:4:51]: (error) The algorithm 'std::copy' accesses 4 elements through the iterator 'v.begin()+7' but only 3 elements are available. [algorithmOutOfBounds]\n", + errout_str()); + + // unknown container sizes + check("void f(const std::vector& v0, std::vector& v1) {\n" + " std::copy(v0.begin(), v0.end(), v1.begin());\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + + // don't warn for iterator variables when the container size changes before the algorithm is called + check("void f() {\n" + " const std::vector v0{1,2,3,4,5};\n" + " std::list l1(3);\n" + " auto it = l1.begin();\n" + " l1.resize(10);\n" + " std::copy(v0.begin(), v0.end(), it);\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + + // iterator variables carry the container size + check("void f() {\n" + " const std::vector v0{1,2,3,4,5};\n" + " std::vector v1(3);\n" + " auto it = v1.begin();\n" + " std::copy(v0.begin(), v0.end(), it);\n" + "}\n"); + ASSERT_EQUALS( + "[test.cpp:5:37]: (error) The algorithm 'std::copy' accesses 5 elements through the iterator 'it' but only 3 elements are available. [algorithmOutOfBounds]\n", + errout_str()); + + // ..and the size is the size at the call, not at the creation of the iterator + check("void f() {\n" + " const std::vector v0{1,2,3,4,5};\n" + " std::list l1(10);\n" + " auto it = l1.begin();\n" + " l1.resize(3);\n" + " std::copy(v0.begin(), v0.end(), it);\n" + "}\n"); + ASSERT_EQUALS( + "[test.cpp:6:37]: (error) The algorithm 'std::copy' accesses 5 elements through the iterator 'it' but only 3 elements are available. [algorithmOutOfBounds]\n", + errout_str()); + + // conditional container size + check("void f(std::vector& v) {\n" + " const std::vector v0{1,2,3,4,5};\n" + " if (v.size() == 3)\n" + " std::copy(v0.begin(), v0.end(), v.begin());\n" + "}\n"); + ASSERT_EQUALS( + "[test.cpp:3:18] -> [test.cpp:4:48]: (warning) Either the condition 'v.size()==3' is redundant or the algorithm 'std::copy' accesses 5 elements through the iterator 'v.begin()' but only 3 elements are available. [algorithmOutOfBounds]\n", + errout_str()); + + check("void f(std::vector& v) {\n" + " const std::vector v0{1,2,3,4,5};\n" + " if (v.size() < 5)\n" + " std::copy(v0.begin(), v0.end(), v.begin());\n" + "}\n"); + ASSERT_EQUALS( + "[test.cpp:3:18] -> [test.cpp:4:48]: (warning) Either the condition 'v.size()<5' is redundant or the algorithm 'std::copy' accesses 5 elements through the iterator 'v.begin()' but only 4 elements are available. [algorithmOutOfBounds]\n", + errout_str()); + + check("void f(std::vector& v) {\n" + " const std::vector v0{1,2,3,4,5};\n" + " if (v.size() >= 5)\n" + " std::copy(v0.begin(), v0.end(), v.begin());\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + + // writing through the end iterator + check("void f() {\n" + " const std::vector v0{1,2,3};\n" + " std::vector v1(10);\n" + " std::copy(v0.begin(), v0.end(), v1.end());\n" + "}\n"); + ASSERT_EQUALS( + "[test.cpp:4:43]: (error) The algorithm 'std::copy' accesses 3 elements through the iterator 'v1.end()' but only 0 elements are available. [algorithmOutOfBounds]\n", + errout_str()); + + // the source range is known even when the container size is not + check("void f(const std::vector& v) {\n" + " std::vector v1(3);\n" + " std::copy(v.begin(), v.begin() + 5, v1.begin());\n" + "}\n"); + ASSERT_EQUALS( + "[test.cpp:3:49]: (error) The algorithm 'std::copy' accesses 5 elements through the iterator 'v1.begin()' but only 3 elements are available. [algorithmOutOfBounds]\n", + errout_str()); + + // count-based algorithms access both iterator arguments times + check("void f() {\n" + " const std::vector v0{1,2,3,4,5};\n" + " std::vector v1(3);\n" + " std::copy_n(v0.begin(), 5, v1.begin());\n" + "}\n"); + ASSERT_EQUALS( + "[test.cpp:4:40]: (error) The algorithm 'std::copy_n' accesses 5 elements through the iterator 'v1.begin()' but only 3 elements are available. [algorithmOutOfBounds]\n", + errout_str()); + + check("void f() {\n" + " const std::vector v0{1,2,3,4,5};\n" + " std::vector v1(10);\n" + " std::copy_n(v0.begin(), 10, v1.begin());\n" + "}\n"); + ASSERT_EQUALS( + "[test.cpp:4:25]: (error) The algorithm 'std::copy_n' accesses 10 elements through the iterator 'v0.begin()' but only 5 elements are available. [algorithmOutOfBounds]\n", + errout_str()); + + check("void f() {\n" + " const std::vector v0{1,2,3,4,5};\n" + " std::vector v1(5);\n" + " std::copy_n(v0.begin(), 5, v1.begin());\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + + check("void f() {\n" + " std::vector v(5);\n" + " std::fill_n(v.begin(), 10, 0);\n" + " std::fill_n(v.begin() + 3, 3, 0);\n" + " std::fill_n(v.begin(), 5, 0);\n" + "}\n"); + ASSERT_EQUALS( + "[test.cpp:3:24]: (error) The algorithm 'std::fill_n' accesses 10 elements through the iterator 'v.begin()' but only 5 elements are available. [algorithmOutOfBounds]\n" + "[test.cpp:4:27]: (error) The algorithm 'std::fill_n' accesses 3 elements through the iterator 'v.begin()+3' but only 2 elements are available. [algorithmOutOfBounds]\n", + errout_str()); + + check("void f() {\n" + " std::vector v;\n" + " std::fill_n(std::back_inserter(v), 10, 0);\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + + check("void f() {\n" + " std::vector v(5);\n" + " std::generate_n(v.begin(), 6, [] { return 1; });\n" + "}\n"); + ASSERT_EQUALS( + "[test.cpp:3:28]: (error) The algorithm 'std::generate_n' accesses 6 elements through the iterator 'v.begin()' but only 5 elements are available. [algorithmOutOfBounds]\n", + errout_str()); + + // conditional count + check("void f(std::vector& v, int n) {\n" + " if (v.size() == 5 && n > 5)\n" + " std::fill_n(v.begin(), n, 0);\n" + "}\n"); + ASSERT_EQUALS( + "[test.cpp:2:28] -> [test.cpp:3:28]: (warning) Either the condition 'n>5' is redundant or the algorithm 'std::fill_n' accesses 6 elements through the iterator 'v.begin()' but only 5 elements are available. [algorithmOutOfBounds]\n", + errout_str()); + + // an upper bound of the count cannot tell whether the access is out of bounds + check("void f(int n) {\n" + " std::vector v(3);\n" + " if (n < 5)\n" + " std::fill_n(v.begin(), n, 0);\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + + // a lower bound of the container size cannot tell whether the access is out of bounds + check("void f(std::vector& v) {\n" + " const std::vector v0{1,2,3,4,5};\n" + " if (v.size() >= 4)\n" + " std::copy(v0.begin(), v0.end(), v.begin());\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + + // unknown count + check("void f(std::vector& v, int n) {\n" + " std::fill_n(v.begin(), n, 0);\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + + // all container size values are checked, not only the first one + check("void f(bool b) {\n" + " const std::vector v0{1,2,3,4,5};\n" + " std::vector v1;\n" + " if (b)\n" + " v1.resize(3);\n" + " else\n" + " v1.resize(10);\n" + " std::copy(v0.begin(), v0.end(), v1.begin());\n" + "}\n"); + ASSERT_EQUALS( + "[test.cpp:8:45]: (error) The algorithm 'std::copy' accesses 5 elements through the iterator 'v1.begin()' but only 3 elements are available. [algorithmOutOfBounds]\n", + errout_str()); + + check("void f(bool b) {\n" + " const std::vector v0{1,2,3,4,5};\n" + " std::vector v1;\n" + " if (b)\n" + " v1.resize(5);\n" + " else\n" + " v1.resize(10);\n" + " std::copy(v0.begin(), v0.end(), v1.begin());\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + + // all iterator position values are checked as well + check("void f(bool b) {\n" + " const std::vector v0{1,2,3,4};\n" + " std::vector v1(5);\n" + " auto it = b ? v1.begin() : v1.begin() + 3;\n" + " std::copy(v0.begin(), v0.end(), it);\n" + "}\n"); + ASSERT_EQUALS( + "[test.cpp:5:37]: (error) The algorithm 'std::copy' accesses 4 elements through the iterator 'it' but only 2 elements are available. [algorithmOutOfBounds]\n", + errout_str()); + + // do not combine possible values on both sides + check("void f(bool b, std::vector& v0, std::vector& v1) {\n" + " if (b) v0.resize(5); else v0.resize(2);\n" + " if (b) v1.resize(3); else v1.resize(10);\n" + " std::copy(v0.begin(), v0.end(), v1.begin());\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + + // all source range values are checked against the preferred destination values + check("void f(bool b) {\n" + " std::vector v0;\n" + " if (b)\n" + " v0.resize(3);\n" + " else\n" + " v0.resize(10);\n" + " std::vector v1(5);\n" + " std::copy(v0.begin(), v0.end(), v1.begin());\n" + "}\n"); + ASSERT_EQUALS( + "[test.cpp:8:45]: (error) The algorithm 'std::copy' accesses 10 elements through the iterator 'v1.begin()' but only 5 elements are available. [algorithmOutOfBounds]\n", + errout_str()); + + check("void f(bool b) {\n" + " std::vector v0;\n" + " if (b)\n" + " v0.resize(3);\n" + " else\n" + " v0.resize(5);\n" + " std::vector v1(5);\n" + " std::copy(v0.begin(), v0.end(), v1.begin());\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + + // all count values are checked as well + check("void f(bool b) {\n" + " std::vector v(5);\n" + " const int n = b ? 3 : 10;\n" + " std::fill_n(v.begin(), n, 0);\n" + "}\n"); + ASSERT_EQUALS( + "[test.cpp:4:24]: (error) The algorithm 'std::fill_n' accesses 10 elements through the iterator 'v.begin()' but only 5 elements are available. [algorithmOutOfBounds]\n", + errout_str()); + } + // Dereferencing invalid pointer void dereference() { check("void f()\n" @@ -7047,7 +7414,10 @@ class TestStl : public TestFixture { " std::copy(v1.begin(), v1.end(), v2.begin());\n" "}\n", dinit(CheckOptions, $.inconclusive = true)); - ASSERT_EQUALS("[test.cpp:4:45]: (style) Using copy with iterator 'v2.begin()' that is always empty. [knownEmptyContainer]\n", errout_str()); + ASSERT_EQUALS( + "[test.cpp:4:45]: (style) Using copy with iterator 'v2.begin()' that is always empty. [knownEmptyContainer]\n" + "[test.cpp:4:45]: (error) The algorithm 'std::copy' accesses 2 elements through the iterator 'v2.begin()' but only 0 elements are available. [algorithmOutOfBounds]\n", + errout_str()); check("void f() {\n" " std::vector v;\n" diff --git a/test/testvalueflow.cpp b/test/testvalueflow.cpp index 1f144900c4d..abeb603b660 100644 --- a/test/testvalueflow.cpp +++ b/test/testvalueflow.cpp @@ -137,6 +137,7 @@ class TestValueFlow : public TestFixture { TEST_CASE(valueFlowConditionExpressions); TEST_CASE(valueFlowContainerSize); + TEST_CASE(valueFlowContainerSizeIterator); TEST_CASE(valueFlowContainerElement); TEST_CASE(valueFlowDynamicBufferSize); @@ -7662,6 +7663,47 @@ class TestValueFlow : public TestFixture { ASSERT(!isKnownContainerSizeValue(tokenValues(code, "m ."), 0).empty()); } + void valueFlowContainerSizeIterator() { + const char* code; + + // valueFlowForwardConst: the container size is added to iterators of a const container + code = "void f() {\n" + " const std::vector v{1, 2, 3};\n" + " auto it = v.begin();\n" + " if (it != v.end()) {}\n" + "}"; + ASSERT_EQUALS( + "", + isKnownContainerSizeValue(tokenValues(code, "it !=", ValueFlow::Value::ValueType::CONTAINER_SIZE), 3)); + + // ..also to iterators created in place + code = "void f() {\n" + " const std::deque d{1, 2, 3, 4, 5, 6};\n" + " if (std::equal(d.cbegin(), d.cend(), d.cbegin())) {}\n" + "}"; + ASSERT_EQUALS( + "", + isKnownContainerSizeValue(tokenValues(code, "( ) ,", ValueFlow::Value::ValueType::CONTAINER_SIZE), 6)); + + // ..and to iterators of containers with a static size + code = "void f() {\n" + " std::array a;\n" + " auto it = a.begin();\n" + " if (it != a.end()) {}\n" + "}"; + ASSERT_EQUALS( + "", + isKnownContainerSizeValue(tokenValues(code, "it !=", ValueFlow::Value::ValueType::CONTAINER_SIZE), 5)); + + // the size of another container is not added to the iterator + code = "void f(std::vector& w) {\n" + " const std::vector v{1, 2, 3};\n" + " auto it = w.begin();\n" + " if (it != w.end()) {}\n" + "}"; + ASSERT(tokenValues(code, "it !=", ValueFlow::Value::ValueType::CONTAINER_SIZE).empty()); + } + void valueFlowContainerElement() { const char* code; From 174a5692e78af69120710d2d127d67afabee4f61 Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Mon, 13 Jul 2026 09:01:07 +0200 Subject: [PATCH 093/165] Fix #13148 FN: constStatement (static_cast(integer|nullptr|NULL)) (#8694) Co-authored-by: chrchr-github --- lib/checkother.cpp | 38 ++++++++++----------------- test/cli/proj-inline-suppress/cfg.c | 4 +-- test/testincompletestatement.cpp | 40 ++++++++++++++++++++--------- test/testother.cpp | 7 +++-- 4 files changed, 48 insertions(+), 41 deletions(-) diff --git a/lib/checkother.cpp b/lib/checkother.cpp index f0d7fbd91f1..d8f2f6ff6f4 100644 --- a/lib/checkother.cpp +++ b/lib/checkother.cpp @@ -2323,18 +2323,12 @@ static bool isConstStatement(const Token *tok, const Library& library, bool plat static bool isVoidStmt(const Token *tok) { - if (Token::simpleMatch(tok, "( void")) + if (Token::simpleMatch(tok, "( void") && !(tok->astOperand1() && (tok->astOperand1()->isLiteral() || isNullOperand(tok->astOperand1())))) return true; - if (isCPPCast(tok) && tok->astOperand1() && Token::Match(tok->astOperand1()->next(), "< void *| >")) + if (isCPPCast(tok) && tok->astOperand1() && Token::Match(tok->astOperand1()->next(), "< void *| >") && + !(tok->astOperand2() && (tok->astOperand2()->isLiteral() || isNullOperand(tok->astOperand2())))) return true; - const Token *tok2 = tok; - while (tok2->astOperand1()) - tok2 = tok2->astOperand1(); - if (Token::simpleMatch(tok2->previous(), ")") && Token::simpleMatch(tok2->linkAt(-1), "( void")) - return true; - if (Token::simpleMatch(tok2, "( void")) - return true; - return Token::Match(tok2->previous(), "delete|throw|return"); + return false; } static bool isConstTop(const Token *tok) @@ -2425,10 +2419,6 @@ void CheckOtherImpl::checkIncompleteStatement() void CheckOtherImpl::constStatementError(const Token *tok, const std::string &type, bool inconclusive) { - const Token *valueTok = tok; - while (valueTok && valueTok->isCast()) - valueTok = valueTok->astOperand2() ? valueTok->astOperand2() : valueTok->astOperand1(); - std::string msg; if (Token::simpleMatch(tok, "==")) msg = "Found suspicious equality comparison. Did you intend to assign a value instead?"; @@ -2436,26 +2426,24 @@ void CheckOtherImpl::constStatementError(const Token *tok, const std::string &ty msg = "Found suspicious operator '" + tok->str() + "', result is not used."; else if (Token::Match(tok, "%var%")) msg = "Unused variable value '" + tok->str() + "'"; - else if (isConstant(valueTok)) { + else if (isConstant(tok)) { std::string typeStr("string"); - if (valueTok->isNumber()) + if (tok->isNumber()) typeStr = "numeric"; - else if (valueTok->isBoolean()) + else if (tok->isBoolean()) typeStr = "bool"; - else if (valueTok->tokType() == Token::eChar) + else if (tok->tokType() == Token::eChar) typeStr = "character"; - else if (isNullOperand(valueTok)) - typeStr = "NULL"; - else if (valueTok->isEnumerator()) + else if (isNullOperand(tok)) + typeStr = "null"; + else if (tok->isEnumerator()) typeStr = "enumerator"; msg = "Redundant code: Found a statement that begins with " + typeStr + " constant."; } else if (!tok) msg = "Redundant code: Found a statement that begins with " + type + " constant."; - else if (tok->isCast() && tok->tokType() == Token::Type::eExtendedOp) { - msg = "Redundant code: Found unused cast "; - msg += valueTok ? "of expression '" + valueTok->expressionString() + "'." : "expression."; - } + else if (tok->isCast() && tok->tokType() == Token::Type::eExtendedOp) + msg = "Redundant code: Found unused cast in expression '" + tok->expressionString() + "'."; else if (tok->str() == "?" && tok->tokType() == Token::Type::eExtendedOp) msg = "Redundant code: Found unused result of ternary operator."; else if (tok->str() == "." && tok->tokType() == Token::Type::eOther) diff --git a/test/cli/proj-inline-suppress/cfg.c b/test/cli/proj-inline-suppress/cfg.c index b597217fa32..42709095dcf 100644 --- a/test/cli/proj-inline-suppress/cfg.c +++ b/test/cli/proj-inline-suppress/cfg.c @@ -2,9 +2,9 @@ void f() { #if DEF_1 // cppcheck-suppress id - (void)0; + ; #endif // cppcheck-suppress id - (void)0; + ; } diff --git a/test/testincompletestatement.cpp b/test/testincompletestatement.cpp index 806f734274e..da238d304b2 100644 --- a/test/testincompletestatement.cpp +++ b/test/testincompletestatement.cpp @@ -180,9 +180,25 @@ class TestIncompleteStatement : public TestFixture { } void void0() { // #6327 - check("void f() { (void*)0; }"); + check("#define assert(x) ((void)0)\n" + "void f(int* p) {\n" + " assert(p);\n" + "}\n"); ASSERT_EQUALS("", errout_str()); + check("void f() { (void*)0; }"); + ASSERT_EQUALS("[test.cpp:1:12]: (warning) Redundant code: Found unused cast in expression '(void*)0'. [constStatement]\n", errout_str()); + + check("void f() {\n" // #13148 + " static_cast(1);\n" + " static_cast(nullptr);\n" + " (void)NULL;\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:2:22]: (warning) Redundant code: Found unused cast in expression 'static_cast(1)'. [constStatement]\n" + "[test.cpp:3:22]: (warning) Redundant code: Found unused cast in expression 'static_cast(nullptr)'. [constStatement]\n" + "[test.cpp:4:5]: (warning) Redundant code: Found unused cast in expression '(void)NULL'. [constStatement]\n", + errout_str()); + check("#define X 0\n" "void f() { X; }"); ASSERT_EQUALS("", errout_str()); @@ -432,11 +448,11 @@ class TestIncompleteStatement : public TestFixture { "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("[test.cpp:2:5]: (warning) Redundant code: Found a statement that begins with numeric constant. [constStatement]\n" "[test.cpp:3:6]: (warning) Redundant code: Found a statement that begins with numeric constant. [constStatement]\n" - "[test.cpp:4:5]: (warning) Redundant code: Found a statement that begins with numeric constant. [constStatement]\n" - "[test.cpp:5:6]: (warning) Redundant code: Found a statement that begins with numeric constant. [constStatement]\n" + "[test.cpp:4:5]: (warning) Redundant code: Found unused cast in expression '(char)1'. [constStatement]\n" + "[test.cpp:5:6]: (warning) Redundant code: Found unused cast in expression '(char)1'. [constStatement]\n" "[test.cpp:6:5]: (warning, inconclusive) Found suspicious operator '!', result is not used. [constStatement]\n" "[test.cpp:7:6]: (warning, inconclusive) Found suspicious operator '!', result is not used. [constStatement]\n" - "[test.cpp:8:5]: (warning) Redundant code: Found unused cast of expression '!x'. [constStatement]\n" + "[test.cpp:8:5]: (warning) Redundant code: Found unused cast in expression '(unsigned int)!x'. [constStatement]\n" "[test.cpp:9:5]: (warning, inconclusive) Found suspicious operator '~', result is not used. [constStatement]\n", errout_str()); @@ -447,7 +463,7 @@ class TestIncompleteStatement : public TestFixture { ASSERT_EQUALS("", errout_str()); check("void f(int x) { static_cast(x); }"); - ASSERT_EQUALS("[test.cpp:1:38]: (warning) Redundant code: Found unused cast of expression 'x'. [constStatement]\n", errout_str()); + ASSERT_EQUALS("[test.cpp:1:38]: (warning) Redundant code: Found unused cast in expression 'static_cast(x)'. [constStatement]\n", errout_str()); check("void f(int x, int* p) {\n" " static_cast(x);\n" @@ -465,9 +481,9 @@ class TestIncompleteStatement : public TestFixture { " static_cast((char)i);\n" " (char)static_cast(i);\n" "}\n"); - ASSERT_EQUALS("[test.cpp:2:5]: (warning) Redundant code: Found unused cast of expression 'i'. [constStatement]\n" - "[test.cpp:3:23]: (warning) Redundant code: Found unused cast of expression 'i'. [constStatement]\n" - "[test.cpp:4:5]: (warning) Redundant code: Found unused cast of expression 'i'. [constStatement]\n", + ASSERT_EQUALS("[test.cpp:2:5]: (warning) Redundant code: Found unused cast in expression '(float)(char)i'. [constStatement]\n" + "[test.cpp:3:23]: (warning) Redundant code: Found unused cast in expression 'static_cast((char)i)'. [constStatement]\n" + "[test.cpp:4:5]: (warning) Redundant code: Found unused cast in expression '(char)static_cast(i)'. [constStatement]\n", errout_str()); check("namespace M {\n" @@ -476,7 +492,7 @@ class TestIncompleteStatement : public TestFixture { "void f(int i) {\n" " (M::N::T)i;\n" "}\n"); - ASSERT_EQUALS("[test.cpp:5:5]: (warning) Redundant code: Found unused cast of expression 'i'. [constStatement]\n", errout_str()); + ASSERT_EQUALS("[test.cpp:5:5]: (warning) Redundant code: Found unused cast in expression '(char)i'. [constStatement]\n", errout_str()); check("void f(int (g)(int a, int b)) {\n" // #10873 " int p = 0, q = 1;\n" @@ -528,7 +544,7 @@ class TestIncompleteStatement : public TestFixture { " for (L\"y\"; ;) {}\n" "}\n"); ASSERT_EQUALS("[test.cpp:2:10]: (warning) Unused variable value 'i' [constStatement]\n" - "[test.cpp:3:10]: (warning) Redundant code: Found unused cast of expression 'i'. [constStatement]\n" + "[test.cpp:3:10]: (warning) Redundant code: Found unused cast in expression '(long)i'. [constStatement]\n" "[test.cpp:4:10]: (warning) Redundant code: Found a statement that begins with numeric constant. [constStatement]\n" "[test.cpp:5:10]: (warning) Redundant code: Found a statement that begins with bool constant. [constStatement]\n" "[test.cpp:6:10]: (warning) Redundant code: Found a statement that begins with character constant. [constStatement]\n" @@ -696,8 +712,8 @@ class TestIncompleteStatement : public TestFixture { " NULL;\n" " nullptr;\n" "}\n"); - ASSERT_EQUALS("[test.cpp:2:5]: (warning) Redundant code: Found a statement that begins with NULL constant. [constStatement]\n" - "[test.cpp:3:5]: (warning) Redundant code: Found a statement that begins with NULL constant. [constStatement]\n", + ASSERT_EQUALS("[test.cpp:2:5]: (warning) Redundant code: Found a statement that begins with null constant. [constStatement]\n" + "[test.cpp:3:5]: (warning) Redundant code: Found a statement that begins with null constant. [constStatement]\n", errout_str()); check("struct S { int i; };\n" // #6504 diff --git a/test/testother.cpp b/test/testother.cpp index ca42ef23deb..0b87a07f160 100644 --- a/test/testother.cpp +++ b/test/testother.cpp @@ -3914,7 +3914,9 @@ class TestOther : public TestFixture { " (void)(true);\n" " if (r) {}\n" "}\n"); - ASSERT_EQUALS("[test.cpp:1:13]: (style) Parameter 'r' can be declared as reference to const [constParameterReference]\n", errout_str()); + ASSERT_EQUALS("[test.cpp:2:5]: (warning) Redundant code: Found unused cast in expression '(void)(true)'. [constStatement]\n" + "[test.cpp:1:13]: (style) Parameter 'r' can be declared as reference to const [constParameterReference]\n", + errout_str()); check("struct S { void f(int&); };\n" // #12216 "void g(S& s, int& r, void (S::* p2m)(int&)) {\n" @@ -7012,7 +7014,8 @@ class TestOther : public TestFixture { " std::pair(1, 2);\n" " (void)0;\n" "}\n"); - ASSERT_EQUALS("[test.cpp:2:10]: (style) Instance of 'std::string' object is destroyed immediately. [unusedScopedObject]\n" + ASSERT_EQUALS("[test.cpp:5:5]: (warning) Redundant code: Found unused cast in expression '(void)0'. [constStatement]\n" + "[test.cpp:2:10]: (style) Instance of 'std::string' object is destroyed immediately. [unusedScopedObject]\n" "[test.cpp:3:10]: (style) Instance of 'std::string' object is destroyed immediately. [unusedScopedObject]\n" "[test.cpp:4:10]: (style) Instance of 'std::pair' object is destroyed immediately. [unusedScopedObject]\n", errout_str()); From df67f2b84f2295c65ac1b6bd386a80979cac1254 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Mon, 13 Jul 2026 17:13:13 +0200 Subject: [PATCH 094/165] CI: suppress with symbolname (#8714) --- .github/workflows/selfcheck.yml | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/.github/workflows/selfcheck.yml b/.github/workflows/selfcheck.yml index 1a213039f93..3517486df31 100644 --- a/.github/workflows/selfcheck.yml +++ b/.github/workflows/selfcheck.yml @@ -121,8 +121,25 @@ jobs: - name: Self check (unusedFunction / no test / no gui) run: | - supprs="--suppress=unusedFunction:lib/errorlogger.h:198 --suppress=unusedFunction:lib/importproject.cpp:1671 --suppress=unusedFunction:lib/importproject.cpp:1695" - ./cppcheck -q --template=selfcheck --error-exitcode=1 --library=cppcheck-lib -D__CPPCHECK__ -D__GNUC__ --enable=unusedFunction,information --exception-handling -rp=. --project=cmake.output.notest_nogui/compile_commands.json --suppressions-list=.selfcheck_unused_suppressions --inline-suppr $supprs + echo ' + + + unusedFunction + lib/errorlogger.h + verboseMessage + + + unusedFunction + lib/importproject.cpp + selectVsConfigurations + + + unusedFunction + lib/importproject.cpp + getVSConfigs + + ' > supprs.xml + ./cppcheck -q --template=selfcheck --error-exitcode=1 --library=cppcheck-lib -D__CPPCHECK__ -D__GNUC__ --enable=unusedFunction,information --exception-handling -rp=. --project=cmake.output.notest_nogui/compile_commands.json --suppressions-list=.selfcheck_unused_suppressions --inline-suppr --suppress-xml=supprs.xml env: DISABLE_VALUEFLOW: 1 UNUSEDFUNCTION_ONLY: 1 From b6e1f451ca73418fe6433da095c07d69c8addfbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludvig=20Gunne=20Lindstr=C3=B6m?= Date: Tue, 14 Jul 2026 08:21:25 +0200 Subject: [PATCH 095/165] Fix #14910: Wrong tokenization of qualified function-pointer member definition (#8718) --- lib/tokenize.cpp | 9 +++++++-- test/testsimplifyusing.cpp | 8 ++++++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 4e00e0d184e..f273cd623ec 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -3389,12 +3389,17 @@ bool Tokenizer::simplifyUsing() } else if (fpArgList && fpQual && Token::Match(tok1->next(), "%name%")) { // function pointer const bool isFuncDecl = Token::simpleMatch(tok1->tokAt(2), "("); - TokenList::copyTokens(tok1->next(), fpArgList, usingEnd->previous()); + Token *dest = tok1->next(); + while (Token::Match(dest, "%name% :: %name%")) + dest = dest->tokAt(2); + TokenList::copyTokens(dest, fpArgList, usingEnd->previous()); Token* const copyEnd = TokenList::copyTokens(tok1, start, fpQual->link()->previous()); Token* leftPar = copyEnd->previous(); while (leftPar->str() != "(") leftPar = leftPar->previous(); - Token* const insertTok = isFuncDecl ? copyEnd->linkAt(2) : copyEnd->next(); + Token *insertTok = isFuncDecl ? copyEnd->linkAt(2) : copyEnd->next(); + while (Token::Match(insertTok, "%name% :: %name%")) + insertTok = insertTok->tokAt(2); Token* const rightPar = insertTok->insertToken(")"); Token::createMutualLinks(leftPar, rightPar); tok1->deleteThis(); diff --git a/test/testsimplifyusing.cpp b/test/testsimplifyusing.cpp index 160f80762a8..5210d484d40 100644 --- a/test/testsimplifyusing.cpp +++ b/test/testsimplifyusing.cpp @@ -78,6 +78,7 @@ class TestSimplifyUsing : public TestFixture { TEST_CASE(simplifyUsing38); TEST_CASE(simplifyUsing39); TEST_CASE(simplifyUsing40); + TEST_CASE(simplifyUsing41); TEST_CASE(simplifyUsing8970); TEST_CASE(simplifyUsing8971); @@ -948,6 +949,13 @@ class TestSimplifyUsing : public TestFixture { ASSERT_EQUALS(expected, tok(code)); } + void simplifyUsing41() { + const char code[] = "using FpHandler = void(*)(const SourceLocation&);\n" + "inline FpHandler AssertImpl::m_fpHandler = nullptr;\n"; + const char expected[] = "void ( * AssertImpl :: m_fpHandler ) ( const SourceLocation & ) ; m_fpHandler = nullptr ;"; + ASSERT_EQUALS(expected, tok(code)); + } + void simplifyUsing8970() { const char code[] = "using V = std::vector;\n" "struct A {\n" From 1444cd8b8a1d8a918647cc422c89219254947ef5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludvig=20Gunne=20Lindstr=C3=B6m?= Date: Tue, 14 Jul 2026 11:29:22 +0200 Subject: [PATCH 096/165] Fix #14782: Partially or fully missing valuetype info for auto declarations (#8599) --- lib/symboldatabase.cpp | 62 +++++++++++++++++++++++++++++----- test/testsymboldatabase.cpp | 67 +++++++++++++++++++++++++++++++++++++ 2 files changed, 120 insertions(+), 9 deletions(-) diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index b82a3f790b0..0f612d5f45a 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -7021,6 +7021,10 @@ void SymbolDatabase::setValueType(Token* tok, const ValueType& valuetype, const setAutoTokenProperties(autoTok); if (vt2->pointer > vt.pointer) vt.pointer++; + if (Token::simpleMatch(autoTok->next(), "&")) + vt.reference = Reference::LValue; + if (Token::simpleMatch(autoTok->next(), "&&")) + vt.reference = Reference::RValue; setValueType(var1Tok, vt); if (var1Tok != parent->previous()) setValueType(parent->previous(), vt); @@ -7295,15 +7299,55 @@ void SymbolDatabase::setValueType(Token* tok, const ValueType& valuetype, const } // c++17 auto type deduction of braced init list - if (parent->isCpp() && mSettings.standards.cpp >= Standards::CPP17 && vt2 && Token::Match(parent->tokAt(-2), "auto %var% {")) { - Token *autoTok = parent->tokAt(-2); - setValueType(autoTok, *vt2); - setAutoTokenProperties(autoTok); - if (parent->previous()->variable()) - const_cast(parent->previous()->variable())->setValueType(*vt2); - else - debugMessage(parent->previous(), "debug", "Missing variable class for variable with varid"); - return; + if (parent->isCpp() && mSettings.standards.cpp >= Standards::CPP17 + && Token::Match(parent->astOperand1(), "%var% {") && vt2) { + + auto reference = Reference::None; + nonneg int pointer = 0; + nonneg int constness = 0; + nonneg int volatileness = 0; + + Token *varTok = parent->astOperand1(); + Token *typeTok = varTok->previous(); + + while (Token::Match(typeTok, "&|&&|*|const|volatile")) { + if (typeTok->str() == "&") + reference = Reference::LValue; + else if (typeTok->str() == "&&") + reference = Reference::RValue; + else if (typeTok->str() == "*") + pointer++; + else if (typeTok->str() == "const") + constness |= 1 << pointer; + else if (typeTok->str() == "volatile") + volatileness |= 1 << pointer; + typeTok = typeTok->previous(); + } + + if (typeTok->str() == "auto") { + setValueType(typeTok, *vt2); + setAutoTokenProperties(typeTok); + + auto *varVt = new ValueType(*vt2); + + varVt->reference = reference; + varVt->constness |= constness; + varVt->volatileness |= volatileness; + + if (Token::simpleMatch(typeTok->previous(), "const auto")) + varVt->constness |= 1 << pointer; + + if (Token::simpleMatch(typeTok->previous(), "volatile auto")) + varVt->volatileness |= 1 << pointer; + + varTok->setValueType(varVt); + + if (varTok->variable()) + const_cast(varTok->variable())->setValueType(*varVt); + else + debugMessage(varTok, "debug", "Missing variable class for variable with varid"); + return; + } } if (!vt1) diff --git a/test/testsymboldatabase.cpp b/test/testsymboldatabase.cpp index 345bfdb7990..69d345a1cc5 100644 --- a/test/testsymboldatabase.cpp +++ b/test/testsymboldatabase.cpp @@ -220,6 +220,8 @@ class TestSymbolDatabase : public TestFixture { TEST_CASE(VariableValueType4); // smart pointer type TEST_CASE(VariableValueType5); // smart pointer type TEST_CASE(VariableValueType6); // smart pointer type + TEST_CASE(VariableValueType7); + TEST_CASE(VariableValueType8); TEST_CASE(VariableValueTypeReferences); TEST_CASE(VariableValueTypeTemplate); @@ -1316,6 +1318,71 @@ class TestSymbolDatabase : public TestFixture { ASSERT(check->valueType()->smartPointerTypeToken); } + void VariableValueType7() { + GET_SYMBOL_DB("void f() {\n" + " auto x0 = 0;\n" + " auto &x1 = x0;\n" + " auto &x2 {x0};\n" + " auto &&x3 = 0;\n" + " auto &&x4 {0};\n" + "}\n"); + + const Token* x1 = Token::findsimplematch(tokenizer.tokens(), "x1"); + const Token* x2 = Token::findsimplematch(tokenizer.tokens(), "x2"); + const Token* x3 = Token::findsimplematch(tokenizer.tokens(), "x3"); + const Token* x4 = Token::findsimplematch(tokenizer.tokens(), "x4"); + + ASSERT(x1); + ASSERT(x2); + ASSERT(x3); + ASSERT(x4); + + ASSERT_EQUALS_ENUM(ValueType::INT, x1->valueType()->type); + ASSERT_EQUALS_ENUM(ValueType::INT, x2->valueType()->type); + ASSERT_EQUALS_ENUM(ValueType::INT, x3->valueType()->type); + ASSERT_EQUALS_ENUM(ValueType::INT, x4->valueType()->type); + + ASSERT_EQUALS_ENUM(Reference::LValue, x1->valueType()->reference); + ASSERT_EQUALS_ENUM(Reference::LValue, x2->valueType()->reference); + ASSERT_EQUALS_ENUM(Reference::RValue, x3->valueType()->reference); + ASSERT_EQUALS_ENUM(Reference::RValue, x4->valueType()->reference); + } + + void VariableValueType8() { + GET_SYMBOL_DB("void f() {\n" + " char buf[128];\n" + " const auto *const x0 {buf};\n" + " auto *const x1 {buf};\n" + " const auto *x2 {buf};\n" + " auto x3 {buf};\n" + "}\n"); + + const Token* x0 = Token::findsimplematch(tokenizer.tokens(), "x0"); + const Token* x1 = Token::findsimplematch(tokenizer.tokens(), "x1"); + const Token* x2 = Token::findsimplematch(tokenizer.tokens(), "x2"); + const Token* x3 = Token::findsimplematch(tokenizer.tokens(), "x3"); + + ASSERT(x0); + ASSERT(x1); + ASSERT(x2); + ASSERT(x3); + + ASSERT_EQUALS_ENUM(ValueType::CHAR, x0->valueType()->type); + ASSERT_EQUALS_ENUM(ValueType::CHAR, x1->valueType()->type); + ASSERT_EQUALS_ENUM(ValueType::CHAR, x2->valueType()->type); + ASSERT_EQUALS_ENUM(ValueType::CHAR, x3->valueType()->type); + + ASSERT_EQUALS(3, x0->valueType()->constness); + ASSERT_EQUALS(1, x1->valueType()->constness); + ASSERT_EQUALS(2, x2->valueType()->constness); + ASSERT_EQUALS(0, x3->valueType()->constness); + + ASSERT_EQUALS(1, x0->valueType()->pointer); + ASSERT_EQUALS(1, x1->valueType()->pointer); + ASSERT_EQUALS(1, x2->valueType()->pointer); + ASSERT_EQUALS(1, x3->valueType()->pointer); + } + void VariableValueTypeReferences() { { GET_SYMBOL_DB("void foo(int x) {}\n"); From a1beb847d99392a77382b8a32171d3e140bd568b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludvig=20Gunne=20Lindstr=C3=B6m?= Date: Tue, 14 Jul 2026 13:12:01 +0200 Subject: [PATCH 097/165] Add test for #14797: internalAstError with if in do while loop (#8725) Fixed in 42a08059f71f3952f7f992dfe82828e2af495c6e. --- test/testtokenize.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp index c4de2be00e7..f1a2a85e212 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -92,6 +92,7 @@ class TestTokenizer : public TestFixture { TEST_CASE(tokenize40); // #13181 TEST_CASE(tokenize41); // #13847 TEST_CASE(tokenize42); // #13861 + TEST_CASE(tokenize43); // #13861 TEST_CASE(validate); @@ -941,6 +942,12 @@ class TestTokenizer : public TestFixture { (void)errout_str(); } + void tokenize43() { + const char code[] = "void f(int i) { do if (i &= 1) {} while (0); }"; + ASSERT_NO_THROW(tokenizeAndStringify(code)); + (void)errout_str(); + } + void validate() { // C++ code in C file ASSERT_THROW_INTERNAL(tokenizeAndStringify(";using namespace std;",dinit(TokenizeOptions, $.expand = false, $.cpp = false)), SYNTAX); From 3deb36d1f386553bbcee076082e33e7b58d68537 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludvig=20Gunne=20Lindstr=C3=B6m?= Date: Tue, 14 Jul 2026 13:13:58 +0200 Subject: [PATCH 098/165] Fix #14901: fuzzing timeout (hang) in Tokenizer::simplifyTypedef() (#8717) --- lib/tokenize.cpp | 18 ++++++++++++++++++ ...ut-242e02017d15d072fd7a230de22faeef0816693d | 1 + test/testsimplifytypedef.cpp | 10 ++++++++-- 3 files changed, 27 insertions(+), 2 deletions(-) create mode 100644 test/cli/fuzz-timeout/timeout-242e02017d15d072fd7a230de22faeef0816693d diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index f273cd623ec..3dc83082e4e 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -589,12 +589,27 @@ namespace { } } + const auto checkForRecursion = [this]() { + if (Token::Match(mTypedefToken, "typedef %name% %name% ;")) + return; + for (const Token *tok = mTypedefToken; tok != mEndToken; tok = tok->next()) { + if (tok == mNameToken) + continue; + if (tok->str() != mNameToken->str()) + continue; + if (Token::Match(tok->previous(), "struct|class|enum|union")) + continue; + throw InternalError(tok, "recursive typedef encountered"); + } + }; + for (Token* type = start; Token::Match(type, "%name%|*|&|&&"); type = type->next()) { if (type != start && Token::Match(type, "%name% ;") && !type->isStandardType()) { mRangeType.first = start; mRangeType.second = type; mNameToken = type; mEndToken = mNameToken->next(); + checkForRecursion(); return; } if (type != start && Token::Match(type, "%name% [")) { @@ -609,6 +624,7 @@ namespace { mEndToken = end->next(); mRangeAfterVar.first = mNameToken->next(); mRangeAfterVar.second = mEndToken; + checkForRecursion(); return; } if (Token::Match(type->next(), "( * const| %name% ) (") && Token::simpleMatch(type->linkAt(1)->linkAt(1), ") ;")) { @@ -618,6 +634,7 @@ namespace { mRangeType.second = mNameToken; mRangeAfterVar.first = mNameToken->next(); mRangeAfterVar.second = mEndToken; + checkForRecursion(); return; } if (type != start && Token::Match(type, "%name% ( !!(") && Token::simpleMatch(type->linkAt(1), ") ;") && !type->isStandardType()) { @@ -627,6 +644,7 @@ namespace { mRangeType.second = type; mRangeAfterVar.first = mNameToken->next(); mRangeAfterVar.second = mEndToken; + checkForRecursion(); return; } } diff --git a/test/cli/fuzz-timeout/timeout-242e02017d15d072fd7a230de22faeef0816693d b/test/cli/fuzz-timeout/timeout-242e02017d15d072fd7a230de22faeef0816693d new file mode 100644 index 00000000000..c269baf1efe --- /dev/null +++ b/test/cli/fuzz-timeout/timeout-242e02017d15d072fd7a230de22faeef0816693d @@ -0,0 +1 @@ +typedef const v*v,*; \ No newline at end of file diff --git a/test/testsimplifytypedef.cpp b/test/testsimplifytypedef.cpp index 84a95a81cfc..5a14399e406 100644 --- a/test/testsimplifytypedef.cpp +++ b/test/testsimplifytypedef.cpp @@ -233,6 +233,7 @@ class TestSimplifyTypedef : public TestFixture { TEST_CASE(simplifyTypedef160); TEST_CASE(simplifyTypedef161); TEST_CASE(simplifyTypedef162); + TEST_CASE(simplifyTypedef163); TEST_CASE(simplifyTypedefFunction1); TEST_CASE(simplifyTypedefFunction2); // ticket #1685 @@ -3836,11 +3837,11 @@ class TestSimplifyTypedef : public TestFixture { "}"; ASSERT_EQUALS(exp, tok(code)); - const char code2[] = "typedef stuct T* T;\n" // #14669 + const char code2[] = "typedef struct T* T;\n" // #14669 "struct T {\n" " T p;\n" "};\n"; - const char exp2[] = "struct T { stuct T * p ; } ;"; + const char exp2[] = "struct T { struct T * p ; } ;"; ASSERT_EQUALS(exp2, simplifyTypedefC(code2)); } @@ -3868,6 +3869,11 @@ class TestSimplifyTypedef : public TestFixture { ASSERT_EQUALS(exp, tok(code)); } + void simplifyTypedef163() { + const char code[] = "typedef v *v;"; + ASSERT_THROW_INTERNAL(tok(code), INTERNAL); + } + void simplifyTypedefFunction1() { { const char code[] = "typedef void (*my_func)();\n" From 5aa31d0da84926c8abf213942498c53cba2445c1 Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Wed, 15 Jul 2026 08:33:20 +0200 Subject: [PATCH 099/165] Fix #14452 fuzzing crash (null-pointer-use) in ReverseTraversal::traverse() (#8723) --- lib/tokenlist.cpp | 3 +++ .../crash-85cab41781812453dfc8e74e1f0b915225f7a0a1 | 1 + 2 files changed, 4 insertions(+) create mode 100644 test/cli/fuzz-crash_c/crash-85cab41781812453dfc8e74e1f0b915225f7a0a1 diff --git a/lib/tokenlist.cpp b/lib/tokenlist.cpp index 594de5c0295..53d1c4f94dd 100644 --- a/lib/tokenlist.cpp +++ b/lib/tokenlist.cpp @@ -1947,6 +1947,9 @@ void TokenList::validateAst(bool print) const if ((tok->isAssignmentOp() || tok->isComparisonOp() || Token::Match(tok,"[|^/%]")) && tok->astOperand1() && !tok->astOperand2()) throw InternalError(tok, "Syntax Error: AST broken, binary operator has only one operand.", InternalError::AST); + if (!(tok->astOperand1() && tok->astOperand2()) && ((isC() && tok->str() == "&&") || Token::Match(tok, "%or%|%oror%"))) + throw InternalError(tok, "Syntax Error: AST broken, binary operator is missing operand(s).", InternalError::AST); + // Syntax error if we encounter "?" with operand2 that is not ":" if (tok->str() == "?") { if (!tok->astOperand1() || !tok->astOperand2()) diff --git a/test/cli/fuzz-crash_c/crash-85cab41781812453dfc8e74e1f0b915225f7a0a1 b/test/cli/fuzz-crash_c/crash-85cab41781812453dfc8e74e1f0b915225f7a0a1 new file mode 100644 index 00000000000..a2e58c69ea7 --- /dev/null +++ b/test/cli/fuzz-crash_c/crash-85cab41781812453dfc8e74e1f0b915225f7a0a1 @@ -0,0 +1 @@ +n(f=n){n&&,n} From a0a31d927acd129c125d4f85008380eee334d710 Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Wed, 15 Jul 2026 08:35:20 +0200 Subject: [PATCH 100/165] Fix #14741 fuzzing crash (null-pointer-use) in SymbolicConditionHandler::parse() (#8722) --- lib/tokenlist.cpp | 4 ++-- .../crash-401f925d3c6fd78f864ffd7bf0531bd6a76bb832 | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) create mode 100644 test/cli/fuzz-crash_c/crash-401f925d3c6fd78f864ffd7bf0531bd6a76bb832 diff --git a/lib/tokenlist.cpp b/lib/tokenlist.cpp index 53d1c4f94dd..ca509904db3 100644 --- a/lib/tokenlist.cpp +++ b/lib/tokenlist.cpp @@ -2032,9 +2032,9 @@ void TokenList::validateAst(bool print) const "' doesn't have two operands.", InternalError::AST); } - if (tok->str() == "case" && !tok->astOperand1()) { + if (!tok->astOperand1() && Token::Match(tok, "case|!")) { throw InternalError(tok, - "Syntax Error: AST broken, 'case' doesn't have an operand.", + "Syntax Error: AST broken, '" + tok->str() + "' doesn't have an operand.", InternalError::AST); } diff --git a/test/cli/fuzz-crash_c/crash-401f925d3c6fd78f864ffd7bf0531bd6a76bb832 b/test/cli/fuzz-crash_c/crash-401f925d3c6fd78f864ffd7bf0531bd6a76bb832 new file mode 100644 index 00000000000..a778e6e2823 --- /dev/null +++ b/test/cli/fuzz-crash_c/crash-401f925d3c6fd78f864ffd7bf0531bd6a76bb832 @@ -0,0 +1 @@ +i(){!!:!=!&&d} From ae6a77d2e284a5d56b957f117af021a2414405f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludvig=20Gunne=20Lindstr=C3=B6m?= Date: Wed, 15 Jul 2026 09:54:56 +0200 Subject: [PATCH 101/165] Fix #14798: internalError on sscanf format string (#8724) --- lib/checkio.cpp | 2 ++ test/testio.cpp | 9 +++++++++ 2 files changed, 11 insertions(+) diff --git a/lib/checkio.cpp b/lib/checkio.cpp index 3d82bdb796a..468e2867619 100644 --- a/lib/checkio.cpp +++ b/lib/checkio.cpp @@ -841,6 +841,8 @@ void CheckIOImpl::checkFormatString(const Token * const tok, } ++i; } + while (!width.empty() && width[0] == '0') + width = width.substr(1); auto bracketBeg = formatString.cend(); if (i != formatString.cend() && *i == '[') { bracketBeg = i; diff --git a/test/testio.cpp b/test/testio.cpp index f90773d4cf4..843c5a62ccc 100644 --- a/test/testio.cpp +++ b/test/testio.cpp @@ -53,6 +53,7 @@ class TestIO : public TestFixture { TEST_CASE(testScanf3); // #3494 TEST_CASE(testScanf4); // #ticket 2553 TEST_CASE(testScanf5); // #10632 + TEST_CASE(testScanf6); mNewTemplate = false; TEST_CASE(testScanfArgument); @@ -892,6 +893,14 @@ class TestIO : public TestFixture { "[test.cpp:3:5]: (error) Width 42 given in format string (no. 2) is larger than destination buffer 's2[42]', use %41[a-z] to prevent overflowing it. [invalidScanfFormatWidth]\n", errout_str()); } + void testScanf6() { + ASSERT_NO_THROW(check("int f(const char *p) {\n" + " char a[3];\n" + " return sscanf(p, \"%02s\", a);\n" + "}\n")); + ASSERT_EQUALS("", errout_str()); + } + #define TEST_SCANF_CODE(format, type) \ "void f(){" type " x; scanf(\"" format "\", &x);}" From 0873197005c7a44abce603dbb48188b03d3629e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludvig=20Gunne=20Lindstr=C3=B6m?= Date: Wed, 15 Jul 2026 09:55:15 +0200 Subject: [PATCH 102/165] Fix #14704: False positive: IOWithoutPositioning reported for user functions fread and fwrite (#8726) --- lib/checkio.cpp | 2 ++ test/testio.cpp | 17 +++++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/lib/checkio.cpp b/lib/checkio.cpp index 468e2867619..0a0ca70a833 100644 --- a/lib/checkio.cpp +++ b/lib/checkio.cpp @@ -155,6 +155,8 @@ void CheckIOImpl::checkFileUsage() tok = tok->linkAt(1); continue; } + if (tok->function() && tok->function()->nestedIn) + continue; if (tok->str() == "{") indent++; else if (tok->str() == "}") { diff --git a/test/testio.cpp b/test/testio.cpp index 843c5a62ccc..2d191555ba6 100644 --- a/test/testio.cpp +++ b/test/testio.cpp @@ -694,6 +694,23 @@ class TestIO : public TestFixture { " fwrite(X::data(), sizeof(char), buffer.size(), d->file);\n" "}"); ASSERT_EQUALS("[test.cpp:9:5]: (error) Read and write operations without a call to a positioning function (fseek, fsetpos or rewind) or fflush in between result in undefined behaviour. [IOWithoutPositioning]\n", errout_str()); + + check("struct MemStream {\n" + " char buf[1024];\n" + " int pos = 0;\n" + " void fwrite(const void *ptr, size_t n) { memcpy(buf + pos, ptr, n); pos += (int)n; }\n" + "};\n" + "struct FileStream {\n" + " FILE *fp;\n" + " size_t _fread(void *ptr, size_t n) { return ::fread(ptr, 1, n, fp); }\n" + " size_t fread(void *ptr, size_t n) { return _fread(ptr, n); }\n" + " void copy_to(MemStream *dst, size_t n) {\n" + " char tmp[256];\n" + " fread(tmp, n);\n" + " dst->fwrite(tmp, n);\n" + " }\n" + "};\n"); + ASSERT_EQUALS("", errout_str()); } void seekOnAppendedFile() { From fdd606703d11911910d49a62692770b4c928e837 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludvig=20Gunne=20Lindstr=C3=B6m?= Date: Wed, 15 Jul 2026 13:26:00 +0200 Subject: [PATCH 103/165] Add test for #14684 (#8728) Fixed by 1444cd8b8a1d8a918647cc422c89219254947ef5. --- test/testunusedvar.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/test/testunusedvar.cpp b/test/testunusedvar.cpp index 03ef0a14a83..849d34b49b0 100644 --- a/test/testunusedvar.cpp +++ b/test/testunusedvar.cpp @@ -156,6 +156,7 @@ class TestUnusedVar : public TestFixture { TEST_CASE(localvar70); TEST_CASE(localvar71); TEST_CASE(localvar72); + TEST_CASE(localvar73); TEST_CASE(localvarloops); // loops TEST_CASE(localvaralias1); TEST_CASE(localvaralias2); // ticket #1637 @@ -4074,6 +4075,16 @@ class TestUnusedVar : public TestFixture { ASSERT_EQUALS("[test.cpp:4:12]: (style) Unused variable: mp [unusedVariable]\n", errout_str()); } + void localvar73() { + functionVariableUsage("struct S { S(); ~S(); };\n" + "void f() {\n" + " auto a{ S() };\n" + " auto const &b{ S() };\n" + " const auto &&c{ S() };\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + } + void localvarloops() { // loops functionVariableUsage("void fun(int c) {\n" From 8e5682d993323cc605de65896ac090fe9db93876 Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Wed, 15 Jul 2026 15:55:24 +0200 Subject: [PATCH 104/165] Fix #14437 fuzzing crash (null-pointer-use) in ValueFlowAnalyzer::assume() (#8730) --- lib/tokenize.cpp | 2 +- .../fuzz-crash/crash-b4bd9ce1af8a423d15d034f42c7b99dc0f8a0a7d | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 test/cli/fuzz-crash/crash-b4bd9ce1af8a423d15d034f42c7b99dc0f8a0a7d diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 3dc83082e4e..031ab624bfb 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -6920,7 +6920,7 @@ Token *Tokenizer::simplifyAddBracesToCommand(Token *tok) // before the "while" if (tokEnd) { tokEnd=tokEnd->next(); - if (!tokEnd || tokEnd->str()!="while") // no while + if (!Token::simpleMatch(tokEnd, "while (") || !Token::simpleMatch(tokEnd->linkAt(1), ") ;")) // no while syntaxError(tok); } } diff --git a/test/cli/fuzz-crash/crash-b4bd9ce1af8a423d15d034f42c7b99dc0f8a0a7d b/test/cli/fuzz-crash/crash-b4bd9ce1af8a423d15d034f42c7b99dc0f8a0a7d new file mode 100644 index 00000000000..e7b11b223da --- /dev/null +++ b/test/cli/fuzz-crash/crash-b4bd9ce1af8a423d15d034f42c7b99dc0f8a0a7d @@ -0,0 +1 @@ +d o(n c){do if(c){}while(0)n} From bc9349a87163483fd1d70cbce66455c690eff38d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludvig=20Gunne=20Lindstr=C3=B6m?= Date: Thu, 16 Jul 2026 10:58:58 +0200 Subject: [PATCH 105/165] Fix #14919: FP constVariableReference (initialization with parentheses) (#8731) --- lib/astutils.cpp | 2 +- test/testother.cpp | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/lib/astutils.cpp b/lib/astutils.cpp index 27a01ab0382..3c5c51498ba 100644 --- a/lib/astutils.cpp +++ b/lib/astutils.cpp @@ -3001,7 +3001,7 @@ bool isVariableChanged(const Variable * var, const Settings &settings, int depth const Token * start = var->declEndToken(); if (!start) return false; - if (Token::Match(start, "; %varid% =", var->declarationId())) + if (Token::Match(start, "; %varid% =", var->declarationId()) && !Token::simpleMatch(start->previous(), ")")) start = start->tokAt(2); if (Token::simpleMatch(start, "=")) { const Token* next = nextAfterAstRightmostLeafGeneric(start); diff --git a/test/testother.cpp b/test/testother.cpp index 0b87a07f160..92fefb72fd3 100644 --- a/test/testother.cpp +++ b/test/testother.cpp @@ -4146,6 +4146,14 @@ class TestOther : public TestFixture { " *o = 1;\n" "}\n"); ASSERT_EQUALS("", errout_str()); + + check("int f() {\n" + " int x = 0;\n" + " int& r(x);\n" + " r = x;\n" + " return r;\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); } void constParameterCallback() { From d32c01d1b9fd2612417dedff95bf96be71915805 Mon Sep 17 00:00:00 2001 From: Robert Reif Date: Thu, 16 Jul 2026 05:01:21 -0400 Subject: [PATCH 106/165] Fix #14880 add support for Folders in slnx project file and skip non C++ projects (#8681) --- lib/importproject.cpp | 46 ++++++--- test/cli/project_test.py | 46 +++++++++ test/cli/slnx-folders/app/app.cpp | 7 ++ test/cli/slnx-folders/app/app.vcxproj | 102 ++++++++++++++++++++ test/cli/slnx-folders/lib/lib.cpp | 9 ++ test/cli/slnx-folders/lib/lib.h | 1 + test/cli/slnx-folders/lib/lib.vcxproj | 97 +++++++++++++++++++ test/cli/slnx-folders/slnx-folders.cppcheck | 17 ++++ test/cli/slnx-folders/slnx-folders.slnx | 12 +++ test/cli/slnx-folders_test.py | 73 ++++++++++++++ 10 files changed, 399 insertions(+), 11 deletions(-) create mode 100644 test/cli/slnx-folders/app/app.cpp create mode 100644 test/cli/slnx-folders/app/app.vcxproj create mode 100644 test/cli/slnx-folders/lib/lib.cpp create mode 100644 test/cli/slnx-folders/lib/lib.h create mode 100644 test/cli/slnx-folders/lib/lib.vcxproj create mode 100644 test/cli/slnx-folders/slnx-folders.cppcheck create mode 100644 test/cli/slnx-folders/slnx-folders.slnx create mode 100644 test/cli/slnx-folders_test.py diff --git a/lib/importproject.cpp b/lib/importproject.cpp index 2d63fa8bbb7..0e6ca353480 100644 --- a/lib/importproject.cpp +++ b/lib/importproject.cpp @@ -529,27 +529,51 @@ bool ImportProject::importSlnx(const std::string& filename, const std::vectorName(), "Solution") != 0) { + errors.emplace_back("Invalid Visual Studio solution file format"); + return false; + } + std::map variables; variables["SolutionDir"] = Path::simplifyPath(Path::getPathFromFilename(filename)); bool found = false; std::vector sharedItemsProjects; + auto processProject = [&](const tinyxml2::XMLElement* projectNode) { + const char* pathAttribute = projectNode->Attribute("Path"); + if (pathAttribute == nullptr) + return true; + + std::string vcxproj(pathAttribute); + vcxproj = Path::toNativeSeparators(std::move(vcxproj)); + + if (Path::getFilenameExtensionInLowerCase(vcxproj) != ".vcxproj") + return true; // skip other project types + + if (!Path::isAbsolute(vcxproj)) + vcxproj = variables["SolutionDir"] + vcxproj; + + vcxproj = Path::fromNativeSeparators(std::move(vcxproj)); + if (!importVcxproj(vcxproj, variables, "", fileFilters, sharedItemsProjects)) { + errors.emplace_back("failed to load '" + vcxproj + "' from Visual Studio solution"); + return false; + } + found = true; + return true; + }; + for (const tinyxml2::XMLElement* node = rootnode->FirstChildElement(); node; node = node->NextSiblingElement()) { const char* name = node->Name(); if (std::strcmp(name, "Project") == 0) { - const char* labelAttribute = node->Attribute("Path"); - if (labelAttribute) { - std::string vcxproj(labelAttribute); - vcxproj = Path::toNativeSeparators(std::move(vcxproj)); - if (!Path::isAbsolute(vcxproj)) - vcxproj = variables["SolutionDir"] + vcxproj; - vcxproj = Path::fromNativeSeparators(std::move(vcxproj)); - if (!importVcxproj(vcxproj, variables, "", fileFilters, sharedItemsProjects)) { - errors.emplace_back("failed to load '" + vcxproj + "' from Visual Studio solution"); - return false; + if (!processProject(node)) + return false; + } else if (std::strcmp(name, "Folder") == 0) { + for (const tinyxml2::XMLElement* childNode = node->FirstChildElement(); childNode; childNode = childNode->NextSiblingElement()) { + if (std::strcmp(childNode->Name(), "Project") == 0) { + if (!processProject(childNode)) + return false; } - found = true; } } } diff --git a/test/cli/project_test.py b/test/cli/project_test.py index 7421ca406a6..64bb406a709 100644 --- a/test/cli/project_test.py +++ b/test/cli/project_test.py @@ -147,6 +147,16 @@ def test_slnx_no_xml_root(tmpdir): __test_project_error(tmpdir, "slnx", content, expected) +def test_slnx_invalid_xml_root(tmpdir): + content = '\r\n' \ + "\r\n" \ + "\r\n" + + expected = "Invalid Visual Studio solution file format" + + __test_project_error(tmpdir, "slnx", content, expected) + + def test_slnx_no_projects(tmpdir): content = '\r\n' \ "\r\n" \ @@ -161,6 +171,22 @@ def test_slnx_no_projects(tmpdir): __test_project_error(tmpdir, "slnx", content, expected) +def test_slnx_no_projects_in_folder(tmpdir): + content = '\r\n' \ + "\r\n" \ + " \r\n" \ + ' \r\n' \ + ' \r\n' \ + " \r\n" \ + ' \r\n' \ + ' \r\n' \ + "\r\n" + + expected = "no projects found in Visual Studio solution file" + + __test_project_error(tmpdir, "slnx", content, expected) + + def test_slnx_project_file_not_found(tmpdir): content = '\r\n' \ "\r\n" \ @@ -179,6 +205,26 @@ def test_slnx_project_file_not_found(tmpdir): __test_project_error(tmpdir, "slnx", content, expected) +def test_slnx_project_file_in_folder_not_found(tmpdir): + content = '\r\n' \ + "\r\n" \ + " \r\n" \ + ' \r\n' \ + ' \r\n' \ + " \r\n" \ + ' \r\n' \ + ' \r\n' \ + ' \r\n' \ + "\r\n" + + expected = "Visual Studio project file is not a valid XML - XML_ERROR_FILE_NOT_FOUND\n" \ + "cppcheck: error: failed to load '{}' from Visual Studio solution".format(os.path.join(tmpdir, "common/test.vcxproj")) + if sys.platform == "win32": + expected = expected.replace('\\', '/') + + __test_project_error(tmpdir, "slnx", content, expected) + + def test_vcxproj_no_xml_root(tmpdir): content = '' diff --git a/test/cli/slnx-folders/app/app.cpp b/test/cli/slnx-folders/app/app.cpp new file mode 100644 index 00000000000..3454c2de254 --- /dev/null +++ b/test/cli/slnx-folders/app/app.cpp @@ -0,0 +1,7 @@ +#include "../lib/lib.h" + +int main(int argc, char *argv[]) +{ + int x = 3 / 0; (void)x; // ERROR + return foo(); +} diff --git a/test/cli/slnx-folders/app/app.vcxproj b/test/cli/slnx-folders/app/app.vcxproj new file mode 100644 index 00000000000..b72ae55c565 --- /dev/null +++ b/test/cli/slnx-folders/app/app.vcxproj @@ -0,0 +1,102 @@ + + + + + Debug + x64 + + + Release + x64 + + + + 18.0 + Win32Proj + {0de77c38-881a-4f9f-bdfa-2c429968985e} + unused + 10.0 + + + + Application + true + v145 + Unicode + + + Application + false + v145 + true + Unicode + + + + + + + + + + + + + + + ..\x64\Debug\ + x64\Debug\ + + + ..\x64\Release\ + x64\Release\ + + + + Level3 + true + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + stdcpp20 + + + + + Console + true + ../lib + + + true + + + + + Level3 + true + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + stdcpp20 + + + Console + true + + + true + + + + + + + + {93BE1430-BE74-35DF-1882-AF70E49C9898} + + + + + + diff --git a/test/cli/slnx-folders/lib/lib.cpp b/test/cli/slnx-folders/lib/lib.cpp new file mode 100644 index 00000000000..b4a89cee1c7 --- /dev/null +++ b/test/cli/slnx-folders/lib/lib.cpp @@ -0,0 +1,9 @@ +#include +#include "lib.h" + +int foo() +{ + std::cout << "hello world\n"; + int x = 3 / 0; (void)x; // ERROR + return 0; +} diff --git a/test/cli/slnx-folders/lib/lib.h b/test/cli/slnx-folders/lib/lib.h new file mode 100644 index 00000000000..cf790ac3eab --- /dev/null +++ b/test/cli/slnx-folders/lib/lib.h @@ -0,0 +1 @@ +extern int foo(); diff --git a/test/cli/slnx-folders/lib/lib.vcxproj b/test/cli/slnx-folders/lib/lib.vcxproj new file mode 100644 index 00000000000..232c2478e2f --- /dev/null +++ b/test/cli/slnx-folders/lib/lib.vcxproj @@ -0,0 +1,97 @@ + + + + + Debug + x64 + + + Release + x64 + + + + 18.0 + Win32Proj + {93BE1430-BE74-35DF-1882-AF70E49C9898} + unused + 10.0 + + + + StaticLibrary + true + v145 + Unicode + + + StaticLibrary + false + v145 + true + Unicode + + + + + + + + + + + + + + + ..\x64\Debug\ + x64\Debug\ + + + ..\x64\Release\ + x64\Release\ + + + + Level3 + true + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + stdcpp20 + + + + + Console + true + ../lib + + + true + + + + + Level3 + true + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + stdcpp20 + + + Console + true + + + true + + + + + + + + + diff --git a/test/cli/slnx-folders/slnx-folders.cppcheck b/test/cli/slnx-folders/slnx-folders.cppcheck new file mode 100644 index 00000000000..4fa0c4e7623 --- /dev/null +++ b/test/cli/slnx-folders/slnx-folders.cppcheck @@ -0,0 +1,17 @@ + + + slnx-folders-cppcheck-build-dir + slnx-folders.slnx + false + true + true + true + 2 + 100 + + Debug + Release + + + slnx-folders + diff --git a/test/cli/slnx-folders/slnx-folders.slnx b/test/cli/slnx-folders/slnx-folders.slnx new file mode 100644 index 00000000000..ce6b9014431 --- /dev/null +++ b/test/cli/slnx-folders/slnx-folders.slnx @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/test/cli/slnx-folders_test.py b/test/cli/slnx-folders_test.py new file mode 100644 index 00000000000..b9dd5f09c92 --- /dev/null +++ b/test/cli/slnx-folders_test.py @@ -0,0 +1,73 @@ + +# python -m pytest slnx-folders_test.py + +import os +import re + +from testutils import cppcheck + +__script_dir = os.path.dirname(os.path.abspath(__file__)) +__proj_dir = os.path.join(__script_dir, 'slnx-folders') + +def get_lines(s): + return sorted(s.split('\n')) + +# Get Visual Studio configurations checking a file +# Checking {file} {config}... +def __getVsConfigs(stdout, filename): + ret = [] + for line in stdout.split('\n'): + if not line.startswith('Checking %s ' % filename): + continue + if not line.endswith('...'): + continue + res = re.match(r'.* ([A-Za-z0-9|]+)...', line) + if res: + ret.append(res.group(1)) + ret.sort() + return ' '.join(ret) + +def test_relative_path(): + args = [ + '--template=cppcheck1', + 'slnx-folders' + ] + ret, stdout, stderr = cppcheck(args, cwd=__script_dir) + filename1 = os.path.join('slnx-folders', 'app', 'app.cpp') + filename2 = os.path.join('slnx-folders', 'lib', 'lib.cpp') + assert ret == 0, stdout + expected = ( + '[%s:5]: (error) Division by zero.\n' + '[%s:7]: (error) Division by zero.\n' % (filename1, filename2) + ) + assert get_lines(stderr) == get_lines(expected) + +def test_local_path(): + args = [ + '--template=cppcheck1', + '.' + ] + ret, stdout, stderr = cppcheck(args, cwd=__proj_dir) + filename1 = os.path.join('app', 'app.cpp') + filename2 = os.path.join('lib', 'lib.cpp') + assert ret == 0, stdout + expected = ( + '[%s:5]: (error) Division by zero.\n' + '[%s:7]: (error) Division by zero.\n' % (filename1, filename2) + ) + assert get_lines(stderr) == get_lines(expected) + +def test_absolute_path(): + args = [ + '--template=cppcheck1', + __proj_dir + ] + ret, stdout, stderr = cppcheck(args) + filename1 = os.path.join(__proj_dir, 'app', 'app.cpp') + filename2 = os.path.join(__proj_dir, 'lib', 'lib.cpp') + assert ret == 0, stdout + expected = ( + '[%s:5]: (error) Division by zero.\n' + '[%s:7]: (error) Division by zero.\n' % (filename1, filename2) + ) + assert get_lines(stderr) == get_lines(expected) From 6edf26edb3e136945886bee40d1fceee567d3aff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20St=C3=B6neberg?= Date: Fri, 17 Jul 2026 16:15:28 +0200 Subject: [PATCH 107/165] fixed #14922 - do not use absolute paths in CMake `INSTALL()` / added TODOs (#8734) --- .github/workflows/CI-unixish.yml | 1 + .github/workflows/CI-windows.yml | 4 ++++ cli/CMakeLists.txt | 17 +++++++++++------ cmake/options.cmake | 8 ++++++-- cmake/printInfo.cmake | 2 ++ gui/CMakeLists.txt | 4 ++-- 6 files changed, 26 insertions(+), 10 deletions(-) diff --git a/.github/workflows/CI-unixish.yml b/.github/workflows/CI-unixish.yml index 4a7d94c4057..8fb5c8d76d6 100644 --- a/.github/workflows/CI-unixish.yml +++ b/.github/workflows/CI-unixish.yml @@ -150,6 +150,7 @@ jobs: - name: Run CMake install run: | cmake --build cmake.output --target install + # TODO: validate the installed files - name: Run CMake on ubuntu (no CLI) if: matrix.os == 'ubuntu-22.04' diff --git a/.github/workflows/CI-windows.yml b/.github/workflows/CI-windows.yml index f9d108eefc9..ce73819bc70 100644 --- a/.github/workflows/CI-windows.yml +++ b/.github/workflows/CI-windows.yml @@ -21,6 +21,7 @@ defaults: jobs: + # TODO: use Debug build to speed it up? build_qt: strategy: matrix: @@ -68,7 +69,10 @@ jobs: - name: Run CMake install run: | + rem TODO: this performs a Debug build + rem TODO: the Qt DLLS are not being installed (because of the missing windeployqt?) cmake --build build --target install + rem TODO: validate the installed files build_cmake_cxxstd: strategy: diff --git a/cli/CMakeLists.txt b/cli/CMakeLists.txt index f63f3291849..52103bdb8ec 100644 --- a/cli/CMakeLists.txt +++ b/cli/CMakeLists.txt @@ -40,27 +40,32 @@ if (BUILD_CLI) endif() install(TARGETS cppcheck - RUNTIME DESTINATION ${CMAKE_INSTALL_FULL_BINDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT applications) install(PROGRAMS ${CMAKE_SOURCE_DIR}/htmlreport/cppcheck-htmlreport - DESTINATION ${CMAKE_INSTALL_FULL_BINDIR} + DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT applications) + # TODO: leverage CMAKE_INSTALL_DATAROOTDIR (share)? + install(FILES ${addons_py} - DESTINATION ${FILESDIR_DEF}/addons + DESTINATION ${FILESDIR_INSTALL}/addons COMPONENT headers) install(FILES ${addons_json} - DESTINATION ${FILESDIR_DEF}/addons + DESTINATION ${FILESDIR_INSTALL}/addons COMPONENT headers) install(FILES ${cfgs} - DESTINATION ${FILESDIR_DEF}/cfg + DESTINATION ${FILESDIR_INSTALL}/cfg COMPONENT headers) install(FILES ${platforms} - DESTINATION ${FILESDIR_DEF}/platforms + DESTINATION ${FILESDIR_INSTALL}/platforms COMPONENT headers) + # TODO: install manpage into CMAKE_INSTALL_MANDIR + # TODO: install documentation into CMAKE_INSTALL_DOCDIR? + endif() diff --git a/cmake/options.cmake b/cmake/options.cmake index 0fa27e4734b..bda080fe77b 100644 --- a/cmake/options.cmake +++ b/cmake/options.cmake @@ -134,18 +134,22 @@ set(CMAKE_DISABLE_PRECOMPILE_HEADERS Off CACHE BOOL "Disable precompiled headers # see https://gitlab.kitware.com/cmake/cmake/-/issues/21219 set(CMAKE_PCH_PROLOGUE "") +# TODO: do we need to set these? set(CMAKE_INCLUDE_DIRS_CONFIGCMAKE ${CMAKE_INSTALL_PREFIX}/include CACHE PATH "Output directory for headers") set(CMAKE_LIB_DIRS_CONFIGCMAKE ${CMAKE_INSTALL_PREFIX}/lib CACHE PATH "Output directory for libraries") +# TODO: do we need to set these? set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin) set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib) set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib) string(LENGTH "${FILESDIR}" _filesdir_len) # override FILESDIR if it is set or empty +# needs to be an absolute path in Cppcheck but a relative one for CMake install if(FILESDIR OR ${_filesdir_len} EQUAL 0) -# TODO: verify that it is an absolute path? + set(FILESDIR_INSTALL "${FILESDIR}") # TODO: make relative - leverage CMAKE_INSTALL_DATAROOTDIR? set(FILESDIR_DEF "${FILESDIR}") else() - set(FILESDIR_DEF ${CMAKE_INSTALL_PREFIX}/share/${PROJECT_NAME} CACHE STRING "Cppcheck files directory") + set(FILESDIR_INSTALL "share/${PROJECT_NAME}") + set(FILESDIR_DEF "${CMAKE_INSTALL_PREFIX}/${FILESDIR_INSTALL}") endif() diff --git a/cmake/printInfo.cmake b/cmake/printInfo.cmake index 87c7e41f284..7869169708d 100644 --- a/cmake/printInfo.cmake +++ b/cmake/printInfo.cmake @@ -8,6 +8,7 @@ message(STATUS "Compiler Version = ${CMAKE_CXX_COMPILER_VERSION}") message(STATUS "Build type = ${CMAKE_BUILD_TYPE}") message(STATUS "CMake C++ Standard = ${CMAKE_CXX_STANDARD}") message(STATUS "CMAKE_INSTALL_PREFIX = ${CMAKE_INSTALL_PREFIX}") +message(STATUS "CMAKE_INSTALL_BINDIR = ${CMAKE_INSTALL_BINDIR}") message(STATUS "CMAKE_DISABLE_PRECOMPILE_HEADERS = ${CMAKE_DISABLE_PRECOMPILE_HEADERS}") message(STATUS "C++ flags (General) = ${CMAKE_CXX_FLAGS}") message(STATUS "C++ flags (Release) = ${CMAKE_CXX_FLAGS_RELEASE}") @@ -109,6 +110,7 @@ message(STATUS) message(STATUS "USE_LIBCXX = ${USE_LIBCXX}") message(STATUS) message(STATUS "FILESDIR = ${FILESDIR}") +message(STATUS "FILESDIR_INSTALL = ${FILESDIR_INSTALL}") message(STATUS "FILESDIR_DEF = ${FILESDIR_DEF}") message(STATUS) diff --git a/gui/CMakeLists.txt b/gui/CMakeLists.txt index d640c341458..50980bfb262 100644 --- a/gui/CMakeLists.txt +++ b/gui/CMakeLists.txt @@ -71,8 +71,8 @@ CheckOptions: add_dependencies(cppcheck-gui online-help.qhc) endif() - install(TARGETS cppcheck-gui RUNTIME DESTINATION ${CMAKE_INSTALL_FULL_BINDIR} COMPONENT applications) - install(FILES ${qms} DESTINATION ${CMAKE_INSTALL_FULL_BINDIR} COMPONENT applications) + install(TARGETS cppcheck-gui RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT applications) + install(FILES ${qms} DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT applications) install(FILES cppcheck-gui.desktop DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/applications) From 95a327779a199d973763a8e05e1308f638027c6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20St=C3=B6neberg?= Date: Sat, 18 Jul 2026 20:43:27 +0200 Subject: [PATCH 108/165] CI-windows.yml: cleaned up and sped up `build_qt` job (#8735) --- .github/workflows/CI-windows.yml | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/.github/workflows/CI-windows.yml b/.github/workflows/CI-windows.yml index ce73819bc70..a63be4e0ad9 100644 --- a/.github/workflows/CI-windows.yml +++ b/.github/workflows/CI-windows.yml @@ -21,7 +21,6 @@ defaults: jobs: - # TODO: use Debug build to speed it up? build_qt: strategy: matrix: @@ -52,27 +51,26 @@ jobs: - name: Run CMake run: | rem TODO: enable rules? - rem specify Release build so matchcompiler is used - cmake -S . -B build -Werror=dev --warn-uninitialized -DCMAKE_BUILD_TYPE=Release -DCMAKE_COMPILE_WARNING_AS_ERROR=On -DBUILD_TESTING=Off -DBUILD_GUI=On -DWITH_QCHART=On -DBUILD_TRIAGE=On -DBUILD_ONLINE_HELP=On -DCMAKE_INSTALL_PREFIX=cppcheck-cmake-install -DCMAKE_COMPILE_WARNING_AS_ERROR=On || exit /b !errorlevel! + cmake -S . -B build -Werror=dev --warn-uninitialized -DCMAKE_BUILD_TYPE=Debug -DCMAKE_COMPILE_WARNING_AS_ERROR=On -DBUILD_TESTING=Off -DBUILD_GUI=On -DWITH_QCHART=On -DBUILD_TRIAGE=On -DBUILD_ONLINE_HELP=On -DISABLE_DMAKE=On -DCMAKE_INSTALL_PREFIX=cppcheck-cmake-install -DCMAKE_COMPILE_WARNING_AS_ERROR=On || exit /b !errorlevel! - - name: Build GUI release + - name: Build GUI run: | - cmake --build build --target cppcheck-gui --config Release || exit /b !errorlevel! + cmake --build build --config Debug --target cppcheck-gui || exit /b !errorlevel! + # TODO: can this be done in CMake? - name: Deploy GUI run: | - windeployqt build\bin\Release || exit /b !errorlevel! - del build\bin\Release\cppcheck-gui.ilk || exit /b !errorlevel! - del build\bin\Release\cppcheck-gui.pdb || exit /b !errorlevel! + windeployqt --no-translations build\bin\Debug || exit /b !errorlevel! + del build\bin\Debug\cppcheck-gui.pdb || exit /b !errorlevel! # TODO: run GUI tests - name: Run CMake install run: | - rem TODO: this performs a Debug build - rem TODO: the Qt DLLS are not being installed (because of the missing windeployqt?) - cmake --build build --target install + rem TODO: the Qt DLLs are not being installed + cmake --build build --config Debug --target install rem TODO: validate the installed files + rem TODO: the structure does not match an actual Windows installation build_cmake_cxxstd: strategy: From d01dca600b0ddea551011bae55e1468ce91c0af1 Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Sat, 18 Jul 2026 22:24:17 +0200 Subject: [PATCH 109/165] Fix #14909 internalAstError with x.size() passed to template parameter (#8716) --- lib/templatesimplifier.cpp | 2 +- test/testtokenize.cpp | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/lib/templatesimplifier.cpp b/lib/templatesimplifier.cpp index 6fdd423628b..24cc0bcbe1d 100644 --- a/lib/templatesimplifier.cpp +++ b/lib/templatesimplifier.cpp @@ -496,7 +496,7 @@ unsigned int TemplateSimplifier::templateParameters(const Token *tok) return 0; // num/type .. - if (!tok->isNumber() && tok->tokType() != Token::eChar && tok->tokType() != Token::eString && !tok->isName() && !tok->isOp()) + if (!tok->isNumber() && tok->tokType() != Token::eChar && tok->tokType() != Token::eString && !tok->isName() && !tok->isOp() && tok->str() != ".") return 0; tok = tok->next(); if (!tok) diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp index f1a2a85e212..79da0177e19 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -241,6 +241,7 @@ class TestTokenizer : public TestFixture { TEST_CASE(vardecl_stl_3); TEST_CASE(vardecl_template_1); TEST_CASE(vardecl_template_2); + TEST_CASE(vardecl_template_3); TEST_CASE(vardecl_union); TEST_CASE(vardecl_par); // #2743 - set links if variable type contains parentheses TEST_CASE(vardecl_par2); // #3912 - set correct links @@ -2394,6 +2395,19 @@ class TestTokenizer : public TestFixture { ASSERT_EQUALS(expected, tokenizeAndStringify(code)); } + void vardecl_template_3() { + const char code[] = "template \n" // #14909 + "void f(T x) {\n" + " const auto y = h;\n" + "}"; + const char expected[] = "template < class T >\n" + "void f ( T x ) {\n" + "const auto y = h < T , x . size ( ) > ;\n" + "}"; + ASSERT_EQUALS(expected, tokenizeAndStringify(code)); + ASSERT_EQUALS("[test.cpp:3:11]: (debug) auto token with no type. [autoNoType]\n", errout_str()); + } + void vardecl_union() { // ticket #1976 const char code1[] = "class Fred { public: union { int a ; int b ; } ; } ;"; From 1fb66305f057029071f6b7175bc557eefaebfb87 Mon Sep 17 00:00:00 2001 From: Felix Patschkowski <49550034+Patschkowski@users.noreply.github.com> Date: Sun, 19 Jul 2026 15:41:59 +0700 Subject: [PATCH 110/165] Added configuration file for Microsoft.GSL library (#8738) Added configuration file to support: https://github.com/microsoft/gsl --- AUTHORS | 1 + cfg/microsoft_gsl.cfg | 17 ++++++++ man/manual.md | 1 + releasenotes.txt | 2 +- test/cfg/microsoft_gsl.cpp | 72 +++++++++++++++++++++++++++++++ test/cfg/runtests.sh | 5 ++- test/tools/donate_cpu_lib_test.py | 1 + tools/donate_cpu_lib.py | 1 + win_installer/cppcheck.wxs | 1 + 9 files changed, 99 insertions(+), 2 deletions(-) create mode 100644 cfg/microsoft_gsl.cfg create mode 100644 test/cfg/microsoft_gsl.cpp diff --git a/AUTHORS b/AUTHORS index 1a7543b0d93..b4917d7d157 100644 --- a/AUTHORS +++ b/AUTHORS @@ -133,6 +133,7 @@ Felipe Pena Felix Faber Felix Geyer Felix Passenberg +Felix Patschkowski Felix Wolff Florian Mueller Florin Iucha diff --git a/cfg/microsoft_gsl.cfg b/cfg/microsoft_gsl.cfg new file mode 100644 index 00000000000..07fbfcb74a6 --- /dev/null +++ b/cfg/microsoft_gsl.cfg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/man/manual.md b/man/manual.md index 47a3a43fd36..7db916d4777 100644 --- a/man/manual.md +++ b/man/manual.md @@ -1161,6 +1161,7 @@ To use a `.cfg` file shipped with Cppcheck, pass the `--library=` option. T | `lua.cfg` | | | | `mfc.cfg` | [MFC](https://learn.microsoft.com/en-us/cpp/mfc/mfc-desktop-applications) | | | `microsoft_atl.cfg` | [ATL](https://learn.microsoft.com/en-us/cpp/atl/active-template-library-atl-concepts) | | +| `microsoft_gsl.cfg` | [Microsoft.GSL](https://github.com/microsoft/gsl) | | | `microsoft_sal.cfg` | [SAL annotations](https://learn.microsoft.com/en-us/cpp/c-runtime-library/sal-annotations) | | | `microsoft_unittest.cfg` | [CppUnitTest](https://learn.microsoft.com/en-us/visualstudio/test/microsoft-visualstudio-testtools-cppunittestframework-api-reference) | | | `motif.cfg` | | | diff --git a/releasenotes.txt b/releasenotes.txt index 1c0739dec0d..4b3ef047c5c 100644 --- a/releasenotes.txt +++ b/releasenotes.txt @@ -22,4 +22,4 @@ Infrastructure & dependencies: - Other: -- +- Added configuration file for Microsoft.GSL (Guideline Support Library). diff --git a/test/cfg/microsoft_gsl.cpp b/test/cfg/microsoft_gsl.cpp new file mode 100644 index 00000000000..4241cce045d --- /dev/null +++ b/test/cfg/microsoft_gsl.cpp @@ -0,0 +1,72 @@ +// Test library configuration for microsoft_gsl.cfg +// +// Usage: +// $ cppcheck --check-library --library=microsoft_gsl --enable=style,information --inconclusive --error-exitcode=1 --inline-suppr --suppress=autoNoType test/cfg/microsoft_gsl.cpp +// => +// No warnings about bad library configuration, unmatched suppressions, etc. exitcode=0 +// + +// C++ Standard Library +#include + +// Guideline Support Library +#include + +struct owner_type +{ + owner_type() = default; + owner_type(const owner_type &) = delete; + owner_type(owner_type &&) = default; + + ~owner_type() { delete ptr_; } + + auto operator=(const owner_type &) -> owner_type & = delete; + auto operator=(owner_type &&) -> owner_type & = default; + +private: + gsl::owner ptr_{new int(42)}; +}; + +auto pre_and_post_condition_test(int i) -> int +{ + Expects(i > 0); + + const auto result{i * 2}; + + Ensures(result > 0); + return result; +} + +auto suppress_macro_test(std::span s) -> int +{ + GSL_SUPPRESS("bounds.1") + return s[0]; +} + +auto iterate_over_container_test(const std::vector &v) -> int +{ + int sum{0}; + + for (gsl::index i{0}; i < v.size(); ++i) + { + sum += v[i]; + } + return sum; +} + +void not_null_test(gsl::not_null p) +{ + Expects(p != nullptr); + *p = 42; +} + +void strict_not_null_test(gsl::strict_not_null p) +{ + Expects(p != nullptr); + *p = 42; +} + +auto byte_test(gsl::byte b) -> gsl::byte +{ + return b | 0x81; +} diff --git a/test/cfg/runtests.sh b/test/cfg/runtests.sh index c8c1515e66c..4cf17b3a9df 100755 --- a/test/cfg/runtests.sh +++ b/test/cfg/runtests.sh @@ -549,7 +549,7 @@ function check_file { kde.cpp) # TODO: "kde-4config" is no longer commonly available in recent distros #kde_fn - cppcheck_run --library="$lib" --library=qt "${DIR}""$f" + cppcheck_run --library="$lib" --library=qt "${DIR}""$f" ;; libcurl.c) libcurl_fn @@ -563,6 +563,9 @@ function check_file { lua_fn cppcheck_run --library="$lib" "${DIR}""$f" ;; + microsoft_gsl.cpp) + cppcheck_run --suppress=autoNoType --library="$lib" "${DIR}""$f" + ;; mfc.cpp) mfc_fn cppcheck_run --platform=win64 --library="$lib" "${DIR}""$f" diff --git a/test/tools/donate_cpu_lib_test.py b/test/tools/donate_cpu_lib_test.py index e00a3d296a0..141781192aa 100644 --- a/test/tools/donate_cpu_lib_test.py +++ b/test/tools/donate_cpu_lib_test.py @@ -58,6 +58,7 @@ def test_library_includes(tmpdir): _test_library_includes(tmpdir, ['posix', 'gnu', 'bsd', 'opengl'], '#include\t ') _test_library_includes(tmpdir, ['posix', 'gnu', 'bsd', 'nspr'], '#include\t"prtypes.h"') _test_library_includes(tmpdir, ['posix', 'gnu', 'bsd', 'lua'], '#include \t') + _test_library_includes(tmpdir, ['posix', 'gnu', 'bsd', 'microsoft_gsl'], '#include ') def test_match_multiple_time(tmpdir): libinc = LibraryIncludes() diff --git a/tools/donate_cpu_lib.py b/tools/donate_cpu_lib.py index c292d2b9a13..ed345cb10c9 100644 --- a/tools/donate_cpu_lib.py +++ b/tools/donate_cpu_lib.py @@ -723,6 +723,7 @@ def __init__(self): 'wxwidgets': [''], + 'microsoft_gsl': [''], } self.__library_includes_re = {} diff --git a/win_installer/cppcheck.wxs b/win_installer/cppcheck.wxs index e7b597e2046..91d08c1c946 100644 --- a/win_installer/cppcheck.wxs +++ b/win_installer/cppcheck.wxs @@ -107,6 +107,7 @@ + From 2807561de51f59afd4993dd4b1e96d786fb546bf Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Mon, 20 Jul 2026 11:34:29 +0200 Subject: [PATCH 111/165] Followup to #8731: use isSplittedVarDeclEq() (#8739) --- lib/astutils.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/astutils.cpp b/lib/astutils.cpp index 3c5c51498ba..74d2274ae6c 100644 --- a/lib/astutils.cpp +++ b/lib/astutils.cpp @@ -3001,7 +3001,7 @@ bool isVariableChanged(const Variable * var, const Settings &settings, int depth const Token * start = var->declEndToken(); if (!start) return false; - if (Token::Match(start, "; %varid% =", var->declarationId()) && !Token::simpleMatch(start->previous(), ")")) + if (start->isSplittedVarDeclEq() && Token::Match(start, "; %varid% =", var->declarationId())) start = start->tokAt(2); if (Token::simpleMatch(start, "=")) { const Token* next = nextAfterAstRightmostLeafGeneric(start); From 678290cf0670ba88a4e1fcecc9d9d22b37cdb003 Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Tue, 21 Jul 2026 08:23:08 +0200 Subject: [PATCH 112/165] Add test for #14422 (#8742) Co-authored-by: chrchr-github --- test/testnullpointer.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/test/testnullpointer.cpp b/test/testnullpointer.cpp index 02810906fb2..86b0f4aeeb9 100644 --- a/test/testnullpointer.cpp +++ b/test/testnullpointer.cpp @@ -145,6 +145,7 @@ class TestNullPointer : public TestFixture { TEST_CASE(nullpointer105); // #13861 TEST_CASE(nullpointer106); // #13682 TEST_CASE(nullpointer107); // #13682 (FP/FN cases around guards that depend on the pointer indirectly) + TEST_CASE(nullpointer108); TEST_CASE(nullpointer_addressOf); // address of TEST_CASE(nullpointerSwitch); // #2626 TEST_CASE(nullpointer_cast); // #4692 @@ -3105,6 +3106,15 @@ class TestNullPointer : public TestFixture { ASSERT_EQUALS("", errout_str()); } + void nullpointer108() { // #14422 + check("void f() {\n" + " int *p{};\n" + " int *&r{p};\n" + " if (*r) {}\n" + "}"); + ASSERT_EQUALS("[test.cpp:4:10]: (error) Null pointer dereference: r [nullPointer]\n", errout_str()); + } + void nullpointer_addressOf() { // address of check("void f() {\n" " struct X *x = 0;\n" From 4ba79f2c5885f6916851ce0ea5642beac9b70a8a Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Thu, 23 Jul 2026 09:24:31 +0200 Subject: [PATCH 113/165] Fix #14929 Crash in CheckBufferOverrunImpl::getBufferSize() (#8743) Co-authored-by: chrchr-github --- lib/checkbufferoverrun.cpp | 2 +- test/testbufferoverrun.cpp | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/checkbufferoverrun.cpp b/lib/checkbufferoverrun.cpp index d28ac7c64f7..246d428802e 100644 --- a/lib/checkbufferoverrun.cpp +++ b/lib/checkbufferoverrun.cpp @@ -575,7 +575,7 @@ ValueFlow::Value CheckBufferOverrunImpl::getBufferSize(const Token *bufTok, cons if (const ValueFlow::Value *value = getBufferSizeValue(bufTok)) { if (value->isBufferSizeValue()) return *value; - if (value->isContainerSizeValue() && bufTok->valueType() && bufTok->valueType()->container) { + if (value->isContainerSizeValue() && bufTok->valueType() && bufTok->valueType()->containerTypeToken) { const ValueType vtElement = ValueType::parseDecl(bufTok->valueType()->containerTypeToken, settings); const size_t elementSize = vtElement.getSizeOf(settings, ValueType::Accuracy::ExactOrZero, ValueType::SizeOf::Pointer); if (elementSize > 0) { diff --git a/test/testbufferoverrun.cpp b/test/testbufferoverrun.cpp index f9e55910c01..b44fd742ab1 100644 --- a/test/testbufferoverrun.cpp +++ b/test/testbufferoverrun.cpp @@ -3551,6 +3551,12 @@ class TestBufferOverrun : public TestFixture { " std::memset(&buf[0], 0, 26);\n" "}\n"); ASSERT_EQUALS("[test.cpp:3:17]: (error) Buffer is accessed out of bounds: &buf[0] [bufferAccessOutOfBounds]\n", errout_str()); + + check("void f(FILE *fp) {\n" // #14929 + " std::string s;\n" + " fwrite(&s, 1, 1, fp);\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); // don't crash } void buffer_overrun_errorpath() { From e0e5a04717d7d30b5ac068c44a591ec4f9c6c041 Mon Sep 17 00:00:00 2001 From: glankk Date: Thu, 23 Jul 2026 10:07:27 +0200 Subject: [PATCH 114/165] Fix #14931: dump file: Add classDef to scope (#8747) --- lib/symboldatabase.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index 0f612d5f45a..4dbd09e98c4 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -4457,6 +4457,11 @@ void SymbolDatabase::printXml(std::ostream &out) const outs += ErrorLogger::toxml(scope->className); outs += "\""; } + if (scope->classDef) { + outs += " classDef=\""; + outs += id_string(scope->classDef); + outs += "\""; + } if (scope->bodyStart) { outs += " bodyStart=\""; outs += id_string(scope->bodyStart); From f87363d10451c97a6987d5e729369cd5084d69b7 Mon Sep 17 00:00:00 2001 From: Paul Fultz II Date: Thu, 23 Jul 2026 04:26:30 -0500 Subject: [PATCH 115/165] Fix 14924: FP containerOutOfBounds (copy accessed in loop) (#8740) Co-authored-by: Your Name --- lib/programmemory.cpp | 29 +++++++++++++++++++++++++++-- test/teststl.cpp | 12 ++++++++++++ 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/lib/programmemory.cpp b/lib/programmemory.cpp index 013906d00ae..9571e04ea00 100644 --- a/lib/programmemory.cpp +++ b/lib/programmemory.cpp @@ -1512,6 +1512,31 @@ namespace { return unknown(); } + // Get the size of the container. If the container itself is not tracked in the program + // memory then check if it is symbolically equal to a container whose size is tracked. + ValueFlow::Value executeContainerSize(const Token* containerTok) + { + ValueFlow::Value v = execute(containerTok); + if (v.isContainerSizeValue()) + return v; + for (const ValueFlow::Value& value : containerTok->values()) { + if (!value.isSymbolicValue()) + continue; + if (value.isImpossible()) + continue; + if (value.intvalue != 0) + continue; + if (!value.tokvalue) + continue; + if (value.tokvalue->exprId() == 0) + continue; + const ValueFlow::Value* sizeValue = pm->getValue(value.tokvalue->exprId()); + if (sizeValue && sizeValue->isContainerSizeValue()) + return *sizeValue; + } + return unknown(); + } + ValueFlow::Value executeImpl(const Token* expr) { const ValueFlow::Value* value = nullptr; @@ -1540,14 +1565,14 @@ namespace { const Token* containerTok = expr->tokAt(-2)->astOperand1(); const Library::Container::Yield yield = containerTok->valueType()->container->getYield(expr->strAt(-1)); if (yield == Library::Container::Yield::SIZE) { - ValueFlow::Value v = execute(containerTok); + ValueFlow::Value v = executeContainerSize(containerTok); if (!v.isContainerSizeValue()) return unknown(); v.valueType = ValueFlow::Value::ValueType::INT; return v; } if (yield == Library::Container::Yield::EMPTY) { - ValueFlow::Value v = execute(containerTok); + ValueFlow::Value v = executeContainerSize(containerTok); if (!v.isContainerSizeValue()) return unknown(); if (v.isImpossible() && v.intvalue == 0) diff --git a/test/teststl.cpp b/test/teststl.cpp index ed9c5503d45..c030fb4c6f6 100644 --- a/test/teststl.cpp +++ b/test/teststl.cpp @@ -1003,6 +1003,18 @@ class TestStl : public TestFixture { "}\n"); ASSERT_EQUALS("[test.cpp:2:13]: error: Out of bounds access in 'v[2]', if 'v' size is 1 and '2' is 2 [containerOutOfBounds]\n", errout_str()); + + checkNormal("std::string f(const std::string& str) {\n" // do not warn, the copy has the same size as 'str' + " std::string outStr = str;\n" + " if (!outStr.empty())\n" + " outStr[0] = 'a';\n" + " for (int i = 0; i < str.size(); ++i) {\n" + " if (outStr[i] == '_')\n" + " outStr[i] = ' ';\n" + " }\n" + " return outStr;\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); } void outOfBoundsSymbolic() From 7aa7114cce28124d409ebf76e0e2a022f21e1553 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludvig=20Gunne=20Lindstr=C3=B6m?= Date: Thu, 23 Jul 2026 11:44:22 +0200 Subject: [PATCH 116/165] Fix #14796: FP assertWithSideEffect for member functions without definition (#8607) --- lib/checkassert.cpp | 6 +++--- lib/checkassert.h | 2 +- test/testassert.cpp | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/checkassert.cpp b/lib/checkassert.cpp index 1d0ecde7959..4578f7395ba 100644 --- a/lib/checkassert.cpp +++ b/lib/checkassert.cpp @@ -83,7 +83,7 @@ void CheckAssertImpl::assertWithSideEffects() if (!scope) { // guess that const method doesn't have side effects if (f->nestedIn->isClassOrStruct() && !f->isConst() && !f->isStatic()) - sideEffectInAssertError(tmp, f->name()); // Non-const member function called, assume it has side effects + sideEffectInAssertError(tmp, f->name(), " If there are no side effects, consider declaring the method const."); // Non-const member function called, assume it has side effects continue; } @@ -117,12 +117,12 @@ void CheckAssertImpl::assertWithSideEffects() //--------------------------------------------------------------------------- -void CheckAssertImpl::sideEffectInAssertError(const Token *tok, const std::string& functionName) +void CheckAssertImpl::sideEffectInAssertError(const Token *tok, const std::string& functionName, const std::string &extra) { reportError(tok, Severity::warning, "assertWithSideEffect", "$symbol:" + functionName + "\n" - "Assert statement calls a function which may have desired side effects: '$symbol'.\n" + "Assert statement calls a function which may have desired side effects: '$symbol'." + extra + "\n" "Non-pure function: '$symbol' is called inside assert statement. " "Assert statements are removed from release builds so the code inside " "assert statement is not executed. If the code is needed also in release " diff --git a/lib/checkassert.h b/lib/checkassert.h index 2db9d804fcb..15f97fb1746 100644 --- a/lib/checkassert.h +++ b/lib/checkassert.h @@ -65,7 +65,7 @@ class CPPCHECKLIB CheckAssertImpl : public CheckImpl { void checkVariableAssignment(const Token* assignTok, const Scope *assertionScope); static bool inSameScope(const Token* returnTok, const Token* assignTok); - void sideEffectInAssertError(const Token *tok, const std::string& functionName); + void sideEffectInAssertError(const Token *tok, const std::string& functionName, const std::string &extra = ""); void assignmentInAssertError(const Token *tok, const std::string &varname); }; /// @} diff --git a/test/testassert.cpp b/test/testassert.cpp index 80bb5d3b827..ea170c43f2d 100644 --- a/test/testassert.cpp +++ b/test/testassert.cpp @@ -156,7 +156,7 @@ class TestAssert : public TestFixture { "void foo(SquarePack s) {\n" " assert( s.Foo() );\n" "}"); - ASSERT_EQUALS("[test.cpp:5:14]: (warning) Assert statement calls a function which may have desired side effects: 'Foo'. [assertWithSideEffect]\n", errout_str()); + ASSERT_EQUALS("[test.cpp:5:14]: (warning) Assert statement calls a function which may have desired side effects: 'Foo'. If there are no side effects, consider declaring the method const. [assertWithSideEffect]\n", errout_str()); check("struct SquarePack {\n" " int Foo() const;\n" From d272996589c5d7c75fd6f2e4e4f52d00e5224a36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludvig=20Gunne=20Lindstr=C3=B6m?= Date: Thu, 23 Jul 2026 11:46:18 +0200 Subject: [PATCH 117/165] Fix #14894: false positive: co_return not recognized as return in combination with {} (#8741) --- lib/astutils.cpp | 20 ++++++++++++++++++++ lib/astutils.h | 2 ++ lib/forwardanalyzer.cpp | 2 +- test/testnullpointer.cpp | 13 +++++++++++++ 4 files changed, 36 insertions(+), 1 deletion(-) diff --git a/lib/astutils.cpp b/lib/astutils.cpp index 74d2274ae6c..ea54232b551 100644 --- a/lib/astutils.cpp +++ b/lib/astutils.cpp @@ -3918,3 +3918,23 @@ const Token *skipUnreachableBranch(const Token *tok) return tok; } + +bool isEscapeKeyword(const Token *tok, const Settings &settings) +{ + if (!tok) + return false; + + if (tok->str() == "return") + return true; + + if (!tok->isCpp()) + return false; + + if (tok->str() == "throw") + return true; + + if (settings.standards.cpp < Standards::CPP20) + return false; + + return tok->str() == "co_return"; +} diff --git a/lib/astutils.h b/lib/astutils.h index 2c6650068b5..79a607108fd 100644 --- a/lib/astutils.h +++ b/lib/astutils.h @@ -463,4 +463,6 @@ bool isUnreachableOperand(const Token *tok); const Token *skipUnreachableBranch(const Token *tok); +bool isEscapeKeyword(const Token *tok, const Settings &settings); + #endif // astutilsH diff --git a/lib/forwardanalyzer.cpp b/lib/forwardanalyzer.cpp index c38d93155ea..3e227873b26 100644 --- a/lib/forwardanalyzer.cpp +++ b/lib/forwardanalyzer.cpp @@ -144,7 +144,7 @@ namespace { // If we are in a loop then jump to the end if (out) *out = loopEnds.back(); - } else if (Token::Match(tok, "return|throw")) { + } else if (isEscapeKeyword(tok, settings)) { traverseRecursive(tok->astOperand2(), f, traverseUnknown); traverseRecursive(tok->astOperand1(), f, traverseUnknown); return Break(Analyzer::Terminate::Escape); diff --git a/test/testnullpointer.cpp b/test/testnullpointer.cpp index 86b0f4aeeb9..698946b8efa 100644 --- a/test/testnullpointer.cpp +++ b/test/testnullpointer.cpp @@ -146,6 +146,7 @@ class TestNullPointer : public TestFixture { TEST_CASE(nullpointer106); // #13682 TEST_CASE(nullpointer107); // #13682 (FP/FN cases around guards that depend on the pointer indirectly) TEST_CASE(nullpointer108); + TEST_CASE(nullpointer109); TEST_CASE(nullpointer_addressOf); // address of TEST_CASE(nullpointerSwitch); // #2626 TEST_CASE(nullpointer_cast); // #4692 @@ -3115,6 +3116,18 @@ class TestNullPointer : public TestFixture { ASSERT_EQUALS("[test.cpp:4:10]: (error) Null pointer dereference: r [nullPointer]\n", errout_str()); } + void nullpointer109() + { + check("boost::asio::awaitable test()\n" + "{\n" + " const auto *s = getStr();\n" + " if(!s) co_return int{1};\n" + " std::print(\"{}\",*s);\n" + " co_return int{9};\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + } + void nullpointer_addressOf() { // address of check("void f() {\n" " struct X *x = 0;\n" From 55ae8c452452de1214e9598fcc3ac02e651fff26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludvig=20Gunne=20Lindstr=C3=B6m?= Date: Thu, 23 Jul 2026 11:47:05 +0200 Subject: [PATCH 118/165] Fix #14896: false positive: missing co_return in void function (#8719) --- lib/checkfunctions.cpp | 2 ++ lib/symboldatabase.cpp | 14 ++++++++++++++ lib/symboldatabase.h | 1 + test/testfunctions.cpp | 9 +++++++++ 4 files changed, 26 insertions(+) diff --git a/lib/checkfunctions.cpp b/lib/checkfunctions.cpp index 23db248816d..1edfdfab6ac 100644 --- a/lib/checkfunctions.cpp +++ b/lib/checkfunctions.cpp @@ -329,6 +329,8 @@ void CheckFunctionsImpl::checkMissingReturn() continue; if (Function::returnsVoid(function, true)) continue; + if (Function::isCoroutine(function, mSettings.standards, *mTokenizer)) + continue; const Token *errorToken = checkMissingReturnScope(scope->bodyEnd, mSettings.library); if (errorToken) missingReturnError(errorToken); diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index 4dbd09e98c4..d98c66770e1 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -3407,6 +3407,20 @@ bool Function::returnsVoid(const Function* function, bool unknown) }); } +bool Function::isCoroutine(const Function* function, const Standards &standards, const Tokenizer &tokens) +{ + if (!tokens.isCPP() || standards.cpp < Standards::CPP20) + return false; + if (!function->functionScope) + return false; + const Scope *scope = function->functionScope; + for (const Token *tok = scope->bodyStart; tok != scope->bodyEnd; tok = tok->next()) { + if (Token::Match(tok, "co_return|co_await|co_yield")) + return true; + } + return false; +} + std::vector Function::findReturns(const Function* f) { std::vector result; diff --git a/lib/symboldatabase.h b/lib/symboldatabase.h index 166f228ad99..7d52d0bfb32 100644 --- a/lib/symboldatabase.h +++ b/lib/symboldatabase.h @@ -945,6 +945,7 @@ class CPPCHECKLIB Function { static bool returnsStandardType(const Function* function, bool unknown = false); static bool returnsVoid(const Function* function, bool unknown = false); + static bool isCoroutine(const Function* function, const Standards &standards, const Tokenizer &tokens); static std::vector findReturns(const Function* f); diff --git a/test/testfunctions.cpp b/test/testfunctions.cpp index 788ff7a0d14..f5067bc31dc 100644 --- a/test/testfunctions.cpp +++ b/test/testfunctions.cpp @@ -86,6 +86,7 @@ class TestFunctions : public TestFixture { TEST_CASE(checkMissingReturn5); TEST_CASE(checkMissingReturn6); // #13180 TEST_CASE(checkMissingReturn7); // #14370 - FN try/catch + TEST_CASE(checkMissingReturn8); TEST_CASE(checkMissingReturnStdInt); // #14482 - FN std::int32_t // std::move for locar variable @@ -1927,6 +1928,14 @@ class TestFunctions : public TestFixture { ASSERT_EQUALS("[test.cpp:3:19]: (error) Found an exit path from function with non-void return type that has missing return statement [missingReturn]\n", errout_str()); } + void checkMissingReturn8() { + const Settings s = settingsBuilder(settings).cpp(Standards::CPP20).build(); + check("boost::asio::awaitable test() {\n" + " co_return;\n" + "}\n",s); + ASSERT_EQUALS("", errout_str()); + } + void checkMissingReturnStdInt() {// #14482 - FN check("std::int32_t f() {}\n"); ASSERT_EQUALS("[test.cpp:1:19]: (error) Found an exit path from function with non-void return type that has missing return statement [missingReturn]\n", errout_str()); From 354edf03694e7d2d2f91e5cf496356a4c458a73e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Fri, 24 Jul 2026 06:01:24 +0200 Subject: [PATCH 119/165] Fixed #14930 (Manual: Document hash value for warnings) (#8745) --- man/manual-premium.md | 28 ++++++++++++++++++++++++++++ man/manual.md | 28 ++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+) diff --git a/man/manual-premium.md b/man/manual-premium.md index 4c30dc6d4b3..c8e38666530 100644 --- a/man/manual-premium.md +++ b/man/manual-premium.md @@ -572,6 +572,34 @@ The usage of the suppressions file is as follows: cppcheck --suppress-xml=suppressions.xml src/ +### The `` element + +Cppcheck calculates a unique ID for each error, called the hash. The hash depends on the code that +is related to the error, not on where that code is located. This means that the hash for an error +stays the same even when unrelated code elsewhere in the file is added, removed or moved, shifting +the line numbers around. The hash only changes if the related code itself is modified. + +This makes hash-based suppressions more robust than line-based suppressions: once you have +reviewed and suppressed a specific warning, the suppression keeps working even after the file is +edited, as long as the offending code is not changed. + +The hash for an error is included as the `hash` attribute in the [XML output](#the-error-element). +You can copy that value into a `` element in a suppressions XML file: + + + + + uninitvar + src/file1.c + 12345678 + + + +A suppression can use `` on its own, without ``, to suppress a specific error regardless +of its id. It is also possible to combine `` with ``, ``, `` and +``; when several of these are specified, all of them must match for the suppression to +apply. + ## Inline suppressions Suppressions can also be added directly in the code by adding comments that contain special keywords. diff --git a/man/manual.md b/man/manual.md index 7db916d4777..93d67e8f402 100644 --- a/man/manual.md +++ b/man/manual.md @@ -573,6 +573,34 @@ The usage of the suppressions file is as follows: cppcheck --suppress-xml=suppressions.xml src/ +### The `` element + +Cppcheck calculates a unique ID for each error, called the hash. The hash depends on the code that +is related to the error, not on where that code is located. This means that the hash for an error +stays the same even when unrelated code elsewhere in the file is added, removed or moved, shifting +the line numbers around. The hash only changes if the related code itself is modified. + +This makes hash-based suppressions more robust than line-based suppressions: once you have +reviewed and suppressed a specific warning, the suppression keeps working even after the file is +edited, as long as the offending code is not changed. + +The hash for an error is included as the `hash` attribute in the [XML output](#the-error-element). +You can copy that value into a `` element in a suppressions XML file: + + + + + uninitvar + src/file1.c + 12345678 + + + +A suppression can use `` on its own, without ``, to suppress a specific error regardless +of its id. It is also possible to combine `` with ``, ``, `` and +``; when several of these are specified, all of them must match for the suppression to +apply. + ## Inline suppressions Suppressions can also be added directly in the code by adding comments that contain special keywords. From 93546a2bcf80347b1fab523c52ecf1db1a0e0d3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludvig=20Gunne=20Lindstr=C3=B6m?= Date: Fri, 24 Jul 2026 11:37:17 +0200 Subject: [PATCH 120/165] Fix #14565 xml suppression: add macro attribute for specifying macro name (#8749) --- lib/suppressions.cpp | 5 ++- test/testsuppressions.cpp | 81 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 85 insertions(+), 1 deletion(-) diff --git a/lib/suppressions.cpp b/lib/suppressions.cpp index fe483e347fe..b45ba151914 100644 --- a/lib/suppressions.cpp +++ b/lib/suppressions.cpp @@ -136,7 +136,10 @@ std::string SuppressionList::parseXmlFile(const char *filename) s.lineNumber = strToInt(text); else if (std::strcmp(name, "symbolName") == 0) s.symbolName = text; - else if (*text && std::strcmp(name, "hash") == 0) + else if (std::strcmp(name, "macroName") == 0) { + s.macroName = text; + s.type = SuppressionList::Type::macro; + } else if (*text && std::strcmp(name, "hash") == 0) s.hash = strToInt(text); else return std::string("unknown element '") + name + "' in suppressions XML '" + filename + "', expected id/fileName/lineNumber/symbolName/hash."; diff --git a/test/testsuppressions.cpp b/test/testsuppressions.cpp index 90c64eb809e..949bad20bb4 100644 --- a/test/testsuppressions.cpp +++ b/test/testsuppressions.cpp @@ -119,6 +119,7 @@ class TestSuppressions : public TestFixture { TEST_CASE(addSuppressionLineMultiple); TEST_CASE(suppressionsParseXmlFile); + TEST_CASE(xmlMacroSuppressions); TEST_CASE(toString); @@ -1705,6 +1706,25 @@ class TestSuppressions : public TestFixture { ASSERT_EQUALS("sym", suppr.symbolName); } + { + ScopedFile file("suppressparsexml.xml", + "\n" + "\n" + "uninitvar\n" + "MACRO_NAME\n" + "\n" + ""); + + SuppressionList supprList; + ASSERT_EQUALS("", supprList.parseXmlFile(file.path().c_str())); + const auto& supprs = supprList.getSuppressions(); + ASSERT_EQUALS(1, supprs.size()); + const auto& suppr = *supprs.cbegin(); + ASSERT_EQUALS("uninitvar", suppr.errorId); + ASSERT_EQUALS("MACRO_NAME", suppr.macroName); + ASSERT_EQUALS_ENUM(SuppressionList::Type::macro, suppr.type); + } + // no file specified { SuppressionList supprList; @@ -1758,6 +1778,67 @@ class TestSuppressions : public TestFixture { } } + #define testXmlSuppressions(...) testXmlSuppressions_(__FILE__,__LINE__,__VA_ARGS__) + void testXmlSuppressions_(const char *thisfile, + int thisline, + const std::string &xml, + const std::string &code, + const std::string &expected) + { + const char *xmlpath = "testsupressions.xml"; + const char *sourcepath = "test.c"; + + Suppressions supprs; + const ScopedFile xmlfile(xmlpath, xml); + ASSERT_EQUALS_LOC("", supprs.nomsg.parseXmlFile(xmlpath), thisfile, thisline); + + Settings settings; + settings.templateFormat = templateFormat; + settings.quiet = true; + + const FileWithDetails sourcefile(sourcepath, Standards::Language::C, 0); + CppCheck instance(settings, supprs, *this, nullptr, true, nullptr); + instance.checkBuffer(sourcefile, code.c_str(), code.size()); + + ASSERT_EQUALS_LOC(expected, errout_str(), thisfile, thisline); + } + + void xmlMacroSuppressions() + { + testXmlSuppressions( + "\n" + "\n" + "uninitvar\n" + "VAR\n" + "\n" + "", + + "#define VAR x\n" + "int f(void) {\n" + " int VAR;\n" + " return VAR;\n" + "}\n", + + "" + ); + testXmlSuppressions( + "\n" + "\n" + "uninitvar\n" + "WRONG\n" + "\n" + "", + + "#define VAR x\n" + "int f(void) {\n" + " int VAR;\n" + " return VAR;\n" + "}\n", + + "[test.c:4:12]: (error) Uninitialized variable: x [uninitvar]\n" + ); + } + void addSuppressionDuplicate() const { SuppressionList supprs; From 74747650087f9755bc0b8f66a71c76ae3ba3f356 Mon Sep 17 00:00:00 2001 From: Daniel <52839433+DanTheMan2000@users.noreply.github.com> Date: Fri, 24 Jul 2026 12:41:04 -0500 Subject: [PATCH 121/165] Fix #14371: FP redundantAssignment for nested union members (#8748) --- lib/checkother.cpp | 6 +++++- test/testother.cpp | 42 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/lib/checkother.cpp b/lib/checkother.cpp index d8f2f6ff6f4..2e6d5eafa4e 100644 --- a/lib/checkother.cpp +++ b/lib/checkother.cpp @@ -700,8 +700,12 @@ void CheckOtherImpl::checkRedundantAssignment() // Get next assignment.. const Token *nextAssign = fwdAnalysis.reassign(tokenToCheck, start, scope->bodyEnd); // extra check for union - if (nextAssign && tokenToCheck != tok->astOperand1()) + if (nextAssign && tokenToCheck != tok->astOperand1()) { nextAssign = fwdAnalysis.reassign(tok->astOperand1(), start, scope->bodyEnd); + // reading another member of the same union in the rhs is a use through aliasing + if (nextAssign && fwdAnalysis.hasOperand(nextAssign->astOperand2(), tokenToCheck)) + nextAssign = nullptr; + } if (!nextAssign) continue; diff --git a/test/testother.cpp b/test/testother.cpp index 92fefb72fd3..1fddea4b536 100644 --- a/test/testother.cpp +++ b/test/testother.cpp @@ -11063,6 +11063,48 @@ class TestOther : public TestFixture { " Dst.s->y = Src.s->y;\n" "}\n"); ASSERT_EQUALS("", errout_str()); + + // Ticket #14371 "redundantAssignment when using a union" + check("union U {\n" + " struct {\n" + " unsigned int abcd;\n" + " } u32;\n" + " struct {\n" + " unsigned short ab;\n" + " unsigned short cd;\n" + " } u16;\n" + "};\n" + "void f1() {\n" + " U m;\n" + " m.u32.abcd = 1234;\n" + " m.u32.abcd = 5 * m.u16.ab;\n" + "}\n" + "void f2(unsigned int a, unsigned short b) {\n" + " U m;\n" + " m.u32.abcd = a;\n" + " m.u32.abcd += 0x8000;\n" + " m.u32.abcd = m.u16.ab * b;\n" + "}\n" + "void f3(unsigned int seed) {\n" + " U m, other;\n" + " other.u32.abcd = seed;\n" + " m.u32.abcd = 1234;\n" + " m.u32.abcd = other.u16.ab * 2;\n" + "}\n" + "void f4(unsigned short x) {\n" + " U m;\n" + " m.u16.ab = x;\n" + " m.u16.cd = 0;\n" + " m.u16.ab = m.u32.abcd / 53;\n" + "}\n" + "void f5(unsigned short x, unsigned int y) {\n" + " U m;\n" + " m.u16.ab = x;\n" + " m.u16.cd = 0;\n" + " m.u16.ab = y;\n" + "}\n", dinit(CheckOptions, $.inconclusive = false)); + ASSERT_EQUALS("[test.cpp:24:16] -> [test.cpp:25:16]: (style) Variable 'm.u32.abcd' is reassigned a value before the old one has been used. [redundantAssignment]\n" + "[test.cpp:35:14] -> [test.cpp:37:14]: (style) Variable 'm.u16.ab' is reassigned a value before the old one has been used. [redundantAssignment]\n", errout_str()); } void redundantVarAssignment_7133() { From 807ce9ff3b9715940fa9a2fcddd633037b2e5421 Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Fri, 24 Jul 2026 19:54:03 +0200 Subject: [PATCH 122/165] Refs #14935: Fix index values in function call in for loop (#8753) --- lib/astutils.cpp | 2 +- test/testvalueflow.cpp | 21 +++++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/lib/astutils.cpp b/lib/astutils.cpp index ea54232b551..2a231dccfd5 100644 --- a/lib/astutils.cpp +++ b/lib/astutils.cpp @@ -2778,7 +2778,7 @@ bool isVariableChanged(const Token *tok, int indirect, const Settings &settings, if (ftok->str() == "(" && Token::simpleMatch(ftok->astOperand1(), "[")) // operator() on array element, bail out return true; const Token * ptok = tok2; - while (Token::Match(ptok->astParent(), ".|::|[")) + while (Token::Match(ptok->astParent(), ".|::")) ptok = ptok->astParent(); int pindirect = indirect; if (indirect == 0 && astIsLHS(tok2) && Token::Match(ptok, ". %var%") && astIsPointer(ptok->next())) diff --git a/test/testvalueflow.cpp b/test/testvalueflow.cpp index abeb603b660..45c7f884715 100644 --- a/test/testvalueflow.cpp +++ b/test/testvalueflow.cpp @@ -5112,6 +5112,27 @@ class TestValueFlow : public TestFixture { ++it; ASSERT_EQUALS(0, it->intvalue); ASSERT(it->isPossible()); + + code = "void g(int*);\n" + "void f(int* a) {\n" + " for (int i = 0; i < 5; ++i) {\n" + " g(&a[i]);\n" + " }\n" + "}\n"; + values = tokenValues(code, "i ]"); + ASSERT_EQUALS(4, values.size()); + it = values.begin(); + ASSERT_EQUALS(0, it->intvalue); + ASSERT(it->isPossible()); + ++it; + ASSERT_EQUALS(-1, it->intvalue); + ASSERT(it->isImpossible()); + ++it; + ASSERT_EQUALS(4, it->intvalue); + ASSERT(it->isPossible()); + ++it; + ASSERT_EQUALS(5, it->intvalue); + ASSERT(it->isImpossible()); } void valueFlowSubFunction() { From 1ef5ef36c18b7769569ce1a517ce8188a8a058c3 Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Fri, 24 Jul 2026 19:54:54 +0200 Subject: [PATCH 123/165] Fix #14928 Duplicate accessMoved in range-based for (#8746) --- lib/vf_settokenvalue.cpp | 2 +- test/testother.cpp | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/vf_settokenvalue.cpp b/lib/vf_settokenvalue.cpp index 315f4a40129..aab64170890 100644 --- a/lib/vf_settokenvalue.cpp +++ b/lib/vf_settokenvalue.cpp @@ -384,7 +384,7 @@ namespace ValueFlow setTokenValueCast(parent, valueType, std::move(value), settings); } - else if (parent->str() == ":") { + else if (parent->str() == ":" && Token::simpleMatch(parent->astParent(), "?")) { setTokenValue(parent,std::move(value),settings); } diff --git a/test/testother.cpp b/test/testother.cpp index 1fddea4b536..39eb23110a0 100644 --- a/test/testother.cpp +++ b/test/testother.cpp @@ -12945,6 +12945,13 @@ class TestOther : public TestFixture { " cif::condition mWhere;\n" "};\n"); ASSERT_EQUALS("", errout_str()); + + check("void g(std::string);\n" // #14928 + "void f(std::string s) {\n" + " g(std::move(s));\n" + " for (char c : s) {}\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:4:19]: (warning) Access of moved variable 's'. [accessMoved]\n", errout_str()); } void moveTernary() From 3daba5fe546e25ec2a35f1f90a3177d0e2d87561 Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Sun, 26 Jul 2026 09:49:18 +0200 Subject: [PATCH 124/165] Fix #14891 FP knownConditionTrueFalse (dereferencing pointer to array member) (#8704) Co-authored-by: chrchr-github --- lib/valueflow.cpp | 3 +++ test/testvalueflow.cpp | 9 +++++++++ 2 files changed, 12 insertions(+) diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index 096e3d56f56..5f6fc1cf622 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -3606,6 +3606,9 @@ static void valueFlowSymbolic(const TokenList& tokenlist, const SymbolDatabase& continue; if (tok->astOperand2()->exprId() == 0) continue; + if (tok->astOperand2()->variable() && tok->astOperand2()->variable()->isArray() && + tok->astOperand1()->valueType() && tok->astOperand1()->valueType()->pointer) // array to pointer decay + continue; if (!isConstExpression(tok->astOperand2(), settings.library)) continue; if (tok->astOperand1()->valueType() && tok->astOperand2()->valueType()) { diff --git a/test/testvalueflow.cpp b/test/testvalueflow.cpp index 45c7f884715..c98680b8180 100644 --- a/test/testvalueflow.cpp +++ b/test/testvalueflow.cpp @@ -9225,6 +9225,15 @@ class TestValueFlow : public TestFixture { " return x;\n" "}\n"; ASSERT_EQUALS(false, testValueOfX(code, 3U, "malloc(10)", 0)); + + code = "struct S {\n" // #14891 + " void f() const {\n" + " const int* p = a;\n" + " if (*p) {}\n" + " }\n" + " int a[3];\n" + "};\n"; + ASSERT(tokenValues(code, "* p )").empty()); } void valueFlowSymbolicIdentity() From 6640862c9381f447f05950b5dd186f83ead9a91d Mon Sep 17 00:00:00 2001 From: Robert Reif Date: Sun, 26 Jul 2026 07:32:28 -0400 Subject: [PATCH 125/165] Fix #14933: Each GUI log entry line should be output on a separate line (#8744) --- gui/resultsview.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/gui/resultsview.cpp b/gui/resultsview.cpp index 55f673ab80c..d11cae35bc6 100644 --- a/gui/resultsview.cpp +++ b/gui/resultsview.cpp @@ -518,6 +518,7 @@ void ResultsView::logCopyComplete() const QListWidgetItem * item = mUI->mListLog->item(i); if (nullptr != item) { logText += item->text(); + logText += "\n"; } } QClipboard *clipboard = QApplication::clipboard(); From 9c8507f5cea972b85112a71448a117bf4ac99869 Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Mon, 27 Jul 2026 08:53:13 +0200 Subject: [PATCH 126/165] Fix #14913 FN duplicateExpression with parenthesized subexpression (#8727) --- lib/astutils.cpp | 2 +- lib/checkother.cpp | 10 ++++++++++ test/testother.cpp | 30 ++++++++++++++++++++++++++++++ 3 files changed, 41 insertions(+), 1 deletion(-) diff --git a/lib/astutils.cpp b/lib/astutils.cpp index 2a231dccfd5..c99e9b19bd5 100644 --- a/lib/astutils.cpp +++ b/lib/astutils.cpp @@ -1700,7 +1700,7 @@ bool isSameExpression(bool macro, const Token *tok1, const Token *tok2, const Se compare = true; } } - if (compare && astIsBoolLike(varTok1, settings) && astIsBoolLike(varTok2, settings)) + if (compare && varTok1 != varTok2 && astIsBoolLike(varTok1, settings) && astIsBoolLike(varTok2, settings)) return isSameExpression(macro, varTok1, varTok2, settings, pure, followVar, errors); } diff --git a/lib/checkother.cpp b/lib/checkother.cpp index 2e6d5eafa4e..7f22e531230 100644 --- a/lib/checkother.cpp +++ b/lib/checkother.cpp @@ -3058,6 +3058,16 @@ void CheckOtherImpl::checkDuplicateExpression() checkDuplicate(ast1->astOperand1(), tok->astOperand2(), ast1); ast1 = ast1->astOperand1(); } + if (tok->str() != "=") { + const Token* par = tok->astParent(); + while (par && tok->str() == par->str() && precedes(par->astOperand1(), tok)) { // chain of identical operators with parentheses + checkDuplicate(par->astOperand1(), tok->astOperand1(), par); + checkDuplicate(par->astOperand1(), tok->astOperand2(), par); + checkDuplicate(par->astOperand2(), tok->astOperand1(), par); + checkDuplicate(par->astOperand2(), tok->astOperand2(), par); + par = par->astParent(); + } + } } } } else if (tok->astOperand1() && tok->astOperand2() && tok->str() == ":" && tok->astParent() && tok->astParent()->str() == "?") { diff --git a/test/testother.cpp b/test/testother.cpp index 39eb23110a0..f69c7cae1c2 100644 --- a/test/testother.cpp +++ b/test/testother.cpp @@ -201,6 +201,7 @@ class TestOther : public TestFixture { TEST_CASE(duplicateExpression19); TEST_CASE(duplicateExpression20); TEST_CASE(duplicateExpression21); + TEST_CASE(duplicateExpression22); TEST_CASE(duplicateExpressionLoop); TEST_CASE(duplicateValueTernary); TEST_CASE(duplicateValueTernarySizeof); // #13773 @@ -8366,6 +8367,35 @@ class TestOther : public TestFixture { ASSERT_EQUALS("", errout_str()); } + void duplicateExpression22() { + check("int f() {\n" // #14913 + " return 0x1 | (0x2 | 0x4) | 0x1;\n" + "}\n" + "int g() {\n" + " return 0x1 | (0x2 | 0x1);\n" + "}\n" + "int h() {\n" + " return 0x1 | (0x1 | 0x2);\n" + "}\n" + "int i() {\n" + " return 0x2 | (0x4 | 0x1) | 0x1;\n" + "}\n" + "int j() {\n" + " return 0x2 | (0x1 | 0x4) | 0x1;\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:2:30]: (style) Same expression '0x1' found multiple times in chain of '|' operators. [duplicateExpression]\n" + "[test.cpp:5:23]: (style) Same expression '0x1' found multiple times in chain of '|' operators. [duplicateExpression]\n" + "[test.cpp:8:23]: (style) Same expression '0x1' found multiple times in chain of '|' operators. [duplicateExpression]\n" + "[test.cpp:11:23]: (style) Same expression '0x1' found multiple times in chain of '|' operators. [duplicateExpression]\n" + "[test.cpp:14:23]: (style) Same expression '0x1' found multiple times in chain of '|' operators. [duplicateExpression]\n", + errout_str()); + + check("bool f(const int** a, const int** b) {\n" + " return (a[0] != nullptr) != (b[0] != nullptr);\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + } + void duplicateExpressionLoop() { check("void f() {\n" " int a = 1;\n" From 422e90c953ae5e825e24f68ff53145a06c4a406f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludvig=20Gunne=20Lindstr=C3=B6m?= Date: Mon, 27 Jul 2026 08:53:51 +0200 Subject: [PATCH 127/165] fix #14795: FP unusedStructMember when type is a template parameter (#8600) --- lib/checkunusedvar.cpp | 21 +++++++++++++++++++++ test/testunusedvar.cpp | 15 +++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/lib/checkunusedvar.cpp b/lib/checkunusedvar.cpp index fe85260fc8d..f4ced7f158d 100644 --- a/lib/checkunusedvar.cpp +++ b/lib/checkunusedvar.cpp @@ -1676,6 +1676,27 @@ void CheckUnusedVarImpl::checkStructMemberUsage() if (use) break; } + // Class used in template with unknown definition + if (Token::Match(tok, "%name% <") && tok->linkAt(1)) { + if (tok->function()) + continue; + if (tok->type() && tok->type()->classScope) + continue; + const Token *start = tok; + while (Token::Match(start->tokAt(-2), "%name% ::")) + start = start->tokAt(-2); + if (mSettings.library.detectContainer(start)) + continue; + const Token *end = tok->linkAt(1); + for (; tok != end; tok = tok->next()) { + if (tok->type() && tok->type()->classScope == &scope) { + use = true; + break; + } + } + if (use) + break; + } if (tok->variable() != &var) continue; if (tok != var.nameToken()) { diff --git a/test/testunusedvar.cpp b/test/testunusedvar.cpp index 849d34b49b0..0cf50a5ceb9 100644 --- a/test/testunusedvar.cpp +++ b/test/testunusedvar.cpp @@ -80,6 +80,7 @@ class TestUnusedVar : public TestFixture { TEST_CASE(structmember32); // #14483 TEST_CASE(structmember33); TEST_CASE(structmember34); + TEST_CASE(structmember35); TEST_CASE(structmember_macro); TEST_CASE(structmember_template_argument); // #13887 - do not report that member used in template argument is unused TEST_CASE(classmember); @@ -2102,6 +2103,20 @@ class TestUnusedVar : public TestFixture { ASSERT_EQUALS("[test.cpp:2:24]: (style) struct member 'S::p' is never used. [unusedStructMember]\n", errout_str()); } + void structmember35() { + checkStructMemberUsage("struct S { int i; };\n" + "int f() { return g(); }\n"); + ASSERT_EQUALS("", errout_str()); + + checkStructMemberUsage("struct S { int i; };\n" + "int f() { A *a = nullptr; (void) a; }\n"); + ASSERT_EQUALS("", errout_str()); + + checkStructMemberUsage("struct S { int i; };\n" + "int f() { const std::vector a {}; (void) a; }\n"); + ASSERT_EQUALS("[test.cpp:1:16]: (style) struct member 'S::i' is never used. [unusedStructMember]\n", errout_str()); + } + void structmember_macro() { checkStructMemberUsageP("#define S(n) struct n { int a, b, c; };\n" "S(unused);\n"); From 6d7e1da9dd61ea3ba584caf8b24ddda633fff8bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludvig=20Gunne=20Lindstr=C3=B6m?= Date: Tue, 28 Jul 2026 10:02:37 +0200 Subject: [PATCH 128/165] Fix #14936: Failures to add suppressions are ignored in `importCppcheckGuiProject` (#8757) --- lib/importproject.cpp | 13 ++++++++++++- test/cli/more-projects_test.py | 1 - test/cli/project-suppressions.py | 33 ++++++++++++++++++++++++++++++++ test/testimportproject.cpp | 21 ++++++++++++++++++++ 4 files changed, 66 insertions(+), 2 deletions(-) create mode 100644 test/cli/project-suppressions.py diff --git a/lib/importproject.cpp b/lib/importproject.cpp index 0e6ca353480..242c1719ba9 100644 --- a/lib/importproject.cpp +++ b/lib/importproject.cpp @@ -1653,7 +1653,18 @@ bool ImportProject::importCppcheckGuiProject(std::istream &istr, Settings &setti for (const std::string &p : paths) guiProject.pathNames.push_back(Path::fromNativeSeparators(p)); - supprs.nomsg.addSuppressions(std::move(suppressions)); // TODO: check result + + bool ok = true; + for (const auto &suppression : suppressions) { + const std::string addError = supprs.nomsg.addSuppression(suppression); + if (!addError.empty()) { + errors.emplace_back(addError); + ok = false; + } + } + if (!ok) + return false; + settings.checkHeaders = temp.checkHeaders; settings.checkUnusedTemplates = temp.checkUnusedTemplates; settings.maxCtuDepth = temp.maxCtuDepth; diff --git a/test/cli/more-projects_test.py b/test/cli/more-projects_test.py index 504a2b14431..98304bbe8aa 100644 --- a/test/cli/more-projects_test.py +++ b/test/cli/more-projects_test.py @@ -173,7 +173,6 @@ def test_project_empty_fields(tmpdir): - diff --git a/test/cli/project-suppressions.py b/test/cli/project-suppressions.py new file mode 100644 index 00000000000..e2b6ba5e7d6 --- /dev/null +++ b/test/cli/project-suppressions.py @@ -0,0 +1,33 @@ + +# python -m pytest project-suppressions.py + +from testutils import create_gui_project_file, assert_cppcheck + +def test_cli_and_project_suppressions(tmp_path): + # Uninitvar suppressed in project file + suppressions = [{ 'id': 'uninitvar' }] + project_path = tmp_path / 'project.cppcheck' + create_gui_project_file(project_path, root_path=str(tmp_path), suppressions=suppressions) + + # Uninitvar suppressed on command line before import + args = ['--suppress=uninitvar', f'--project={project_path}'] + out_exp = [ + "cppcheck: error: suppression 'uninitvar' already exists", + f"cppcheck: error: failed to load project '{project_path}'. An error occurred." + ] + assert_cppcheck(args, ec_exp=1, out_exp=out_exp) + +def test_multiple_cli_and_project_suppressions(tmp_path): + # Uninitvar and unreadVariable suppressed in project file + suppressions = [{ 'id': 'uninitvar' }, { 'id': 'unreadVariable' },] + project_path = tmp_path / 'project.cppcheck' + create_gui_project_file(project_path, root_path=str(tmp_path), suppressions=suppressions) + + # Uninitvar and unreadVariable suppressed on command line before import + args = ['--suppress=uninitvar', '--suppress=unreadVariable', f'--project={project_path}'] + out_exp = [ + "cppcheck: error: suppression 'uninitvar' already exists", + "cppcheck: error: suppression 'unreadVariable' already exists", + f"cppcheck: error: failed to load project '{project_path}'. An error occurred." + ] + assert_cppcheck(args, ec_exp=1, out_exp=out_exp) diff --git a/test/testimportproject.cpp b/test/testimportproject.cpp index c9889445c3c..873272030f6 100644 --- a/test/testimportproject.cpp +++ b/test/testimportproject.cpp @@ -79,6 +79,7 @@ class TestImportProject : public TestFixture { TEST_CASE(importCompileCommandsDirectoryMissing); // 'directory' field missing TEST_CASE(importCompileCommandsDirectoryInvalid); // 'directory' field not a string TEST_CASE(importCppcheckGuiProject); + TEST_CASE(importCppcheckGuiProjectDuplicateSuppressions); TEST_CASE(importCppcheckGuiProjectPremiumMisra); TEST_CASE(ignorePaths); TEST_CASE(testVcxprojUnicode); @@ -536,6 +537,26 @@ class TestImportProject : public TestFixture { ASSERT_EQUALS(true, s.inlineSuppressions); } + void importCppcheckGuiProjectDuplicateSuppressions() const { + REDIRECT; + constexpr char xml[] = "\n" + "\n" + " \n" + " test test\n" + " \n" + " uninitvar\n" + " uninitvar\n" + " \n" + "\n"; + std::istringstream istr(xml); + Settings s; + Suppressions supprs; + TestImporter project; + ASSERT_EQUALS(false, project.importCppcheckGuiProject(istr, s, supprs)); + ASSERT_EQUALS(1, project.errors.size()); + ASSERT_EQUALS("suppression 'uninitvar' already exists", project.errors[0]); + } + void importCppcheckGuiProjectPremiumMisra() const { REDIRECT; constexpr char xml[] = "\n" From f26de0cc37b8ebd9142c43346150999c21c2a879 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludvig=20Gunne=20Lindstr=C3=B6m?= Date: Tue, 28 Jul 2026 12:55:08 +0200 Subject: [PATCH 129/165] Fix #14941: FN memleak with `_create_locale` (#8758) --- cfg/windows.cfg | 37 +++++++++++++++++++++++++++++++++++++ test/cfg/windows.cpp | 22 ++++++++++++++++++++++ 2 files changed, 59 insertions(+) diff --git a/cfg/windows.cfg b/cfg/windows.cfg index 6a0bd111afa..b2251900d42 100644 --- a/cfg/windows.cfg +++ b/cfg/windows.cfg @@ -1331,6 +1331,11 @@ AllocateAndInitializeSid FreeSid + + _create_locale + _wcreate_locale + _free_locale + + + + false + + + + + + + + + + + false + + + + + + + + + + false + + + + + arg1 diff --git a/test/cfg/windows.cpp b/test/cfg/windows.cpp index c01e57f6f91..37c580a0134 100644 --- a/test/cfg/windows.cpp +++ b/test/cfg/windows.cpp @@ -23,6 +23,7 @@ #include #include #include +#include bool UpdateTraceACalled(TRACEHANDLE traceHandle, LPCSTR loggerName, EVENT_TRACE_PROPERTIES* pProperties) { @@ -615,6 +616,27 @@ void memleak_malloca() // cppcheck-suppress memleak } +void memleak_create_locale() +{ + // cppcheck-suppress-begin valueFlowBailoutIncompleteVar + _locale_t locale = _create_locale(LC_ALL, "C"); + _locale_t wlocale = _wcreate_locale(LC_ALL, L"C"); + (void) locale; + (void) wlocale; + // cppcheck-suppress-end valueFlowBailoutIncompleteVar + // cppcheck-suppress memleak +} + +void no_memleak_create_locale() +{ + // cppcheck-suppress-begin valueFlowBailoutIncompleteVar + _locale_t locale = _create_locale(LC_ALL, "C"); + _locale_t wlocale = _wcreate_locale(LC_ALL, L"C"); + _free_locale(locale); + _free_locale(wlocale); + // cppcheck-suppress-end valueFlowBailoutIncompleteVar +} + void memleak_AllocateAndInitializeSid() { PSID pEveryoneSID = NULL; From bc88becf0b4344dc214a0f93c294f0e602a68dd4 Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Tue, 28 Jul 2026 13:47:08 +0200 Subject: [PATCH 130/165] Fix #14935 FN bufferAccessOutOfBounds (memset() in loop) (#8754) --- lib/checkbufferoverrun.cpp | 16 +++++++++++----- test/testbufferoverrun.cpp | 11 +++++++++-- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/lib/checkbufferoverrun.cpp b/lib/checkbufferoverrun.cpp index 246d428802e..46d8e1c7c6c 100644 --- a/lib/checkbufferoverrun.cpp +++ b/lib/checkbufferoverrun.cpp @@ -560,12 +560,18 @@ ValueFlow::Value CheckBufferOverrunImpl::getBufferSize(const Token *bufTok, cons if (!bufTok->valueType()) return ValueFlow::Value(-1); + MathLib::bigint index = 0; if (bufTok->isUnaryOp("&")) { bufTok = bufTok->astOperand1(); if (Token::simpleMatch(bufTok, "[")) { - const Token* index = bufTok->astOperand2(); - if (!(index && index->hasKnownIntValue() && index->getKnownIntValue() == 0)) - return ValueFlow::Value(-1); + if (const Token* indexTok = bufTok->astOperand2()) { + if (indexTok->hasKnownIntValue()) + index = indexTok->getKnownIntValue(); + else if (const ValueFlow::Value* maxValue = indexTok->getMaxValue(false)) + index = maxValue->intvalue; + else + return ValueFlow::Value(-1); + } bufTok = bufTok->astOperand1(); } } @@ -600,10 +606,10 @@ ValueFlow::Value CheckBufferOverrunImpl::getBufferSize(const Token *bufTok, cons v.valueType = ValueFlow::Value::ValueType::BUFFER_SIZE; if (var->isPointerArray()) - v.intvalue = dim * mSettings.platform.sizeof_pointer; + v.intvalue = (dim - index) * mSettings.platform.sizeof_pointer; else { const size_t typeSize = bufTok->valueType()->getSizeOf(mSettings, ValueType::Accuracy::ExactOrZero, ValueType::SizeOf::Pointee); - v.intvalue = dim * typeSize; + v.intvalue = (dim - index) * typeSize; } return v; diff --git a/test/testbufferoverrun.cpp b/test/testbufferoverrun.cpp index b44fd742ab1..37ab7083902 100644 --- a/test/testbufferoverrun.cpp +++ b/test/testbufferoverrun.cpp @@ -3537,7 +3537,7 @@ class TestBufferOverrun : public TestFixture { "}\n"); TODO_ASSERT_EQUALS("[test.cpp:3:12]: (error) Buffer is accessed out of bounds: &a[5] [bufferAccessOutOfBounds]\n" "[test.cpp:7:12]: (error) Buffer is accessed out of bounds: &a[0][0] [bufferAccessOutOfBounds]\n", - "", + "[test.cpp:3:12]: (error) Buffer is accessed out of bounds: &a[5] [bufferAccessOutOfBounds]\n", errout_str()); check("void f() {\n" // #14866 @@ -3557,6 +3557,13 @@ class TestBufferOverrun : public TestFixture { " fwrite(&s, 1, 1, fp);\n" "}\n"); ASSERT_EQUALS("", errout_str()); // don't crash + + check("void f() {\n" // #14935 + " int a[5];\n" + " for (int i = 0; i < 5; ++i)\n" + " memset(&a[i], 0, sizeof(a));\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:4:16]: (error) Buffer is accessed out of bounds: &a[i] [bufferAccessOutOfBounds]\n", errout_str()); } void buffer_overrun_errorpath() { @@ -3814,7 +3821,7 @@ class TestBufferOverrun : public TestFixture { " int i[10];\n" " memset(&i[1], 0, 1000);\n" "}"); - TODO_ASSERT_EQUALS("[test.cpp:3:10]: (error) Buffer is accessed out of bounds: &i[1] [bufferAccessOutOfBounds]\n", "", errout_str()); + ASSERT_EQUALS("[test.cpp:3:10]: (error) Buffer is accessed out of bounds: &i[1] [bufferAccessOutOfBounds]\n", errout_str()); check("struct S { int x; };\n" // #8616 "void f() {\n" From 8effc6c60d7b135df159a305e23ac95d29b02b1b Mon Sep 17 00:00:00 2001 From: Paul Fultz II Date: Wed, 29 Jul 2026 01:33:02 -0500 Subject: [PATCH 131/165] Fix 14937: False positive: inconclusive nullPointerRedundantCheck with thunk (#8755) --- lib/symboldatabase.cpp | 30 +++++++++---- lib/symboldatabase.h | 12 +++++- test/testnullpointer.cpp | 19 ++++++++ test/testsymboldatabase.cpp | 86 +++++++++++++++++++++++++++++++++++++ 4 files changed, 136 insertions(+), 11 deletions(-) diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index d98c66770e1..e6f676e7a20 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -5861,7 +5861,10 @@ bool Scope::hasInlineOrLambdaFunction(const Token** tokStart, bool onlyInline) c }); } -void Scope::findFunctionInBase(const Token* tok, size_t args, std::vector & matches) const +void Scope::findFunctionInBase(const std::string& name, + const Token* tok, + size_t args, + std::vector& matches) const { if (isClassOrStruct() && definedType && !definedType->derivedFrom.empty()) { const std::vector &derivedFrom = definedType->derivedFrom; @@ -5871,7 +5874,7 @@ void Scope::findFunctionInBase(const Token* tok, size_t args, std::vectorclassScope == this) // Ticket #5120, #5125: Recursive class; tok should have been found already continue; - auto range = base->classScope->functionMap.equal_range(tok->str()); + auto range = base->classScope->functionMap.equal_range(name); for (auto it = range.first; it != range.second; ++it) { const Function *func = it->second; if (func->isDestructor() && !Token::simpleMatch(tok->tokAt(-1), "~")) @@ -5882,7 +5885,7 @@ void Scope::findFunctionInBase(const Token* tok, size_t args, std::vectorclassScope->findFunctionInBase(tok, args, matches); + base->classScope->findFunctionInBase(name, tok, args, matches); } } } @@ -6021,8 +6024,10 @@ static bool hasMatchingConstructor(const Scope* classScope, const ValueType* arg }); } -const Function* Scope::findFunction(const Token *tok, bool requireConst, Reference ref) const +const Function* Scope::findFunction(const Token* tok, bool requireConst, Reference ref, const std::string& funcName) const { + const std::string& name = funcName.empty() ? tok->str() : funcName; + const bool isCall = Token::Match(tok->next(), "(|{"); const std::vector arguments = getArguments(tok); @@ -6032,8 +6037,8 @@ const Function* Scope::findFunction(const Token *tok, bool requireConst, Referen // find all the possible functions that could match const std::size_t args = arguments.size(); - auto addMatchingFunctions = [&](const Scope *scope) { - auto range = scope->functionMap.equal_range(tok->str()); + auto addMatchingFunctions = [&](const Scope* scope) { + auto range = scope->functionMap.equal_range(name); for (auto it = range.first; it != range.second; ++it) { const Function *func = it->second; if (ref == Reference::LValue && func->hasRvalRefQualifier()) @@ -6068,7 +6073,7 @@ const Function* Scope::findFunction(const Token *tok, bool requireConst, Referen const std::size_t numberOfMatchesNonBase = matches.size(); // check in base classes - findFunctionInBase(tok, args, matches); + findFunctionInBase(name, tok, args, matches); // Non-call => Do not match parameters if (!isCall) { @@ -6298,8 +6303,8 @@ const Function* Scope::findFunction(const Token *tok, bool requireConst, Referen matches.erase(itPure); // Only one candidate left - if (matches.size() == 1 && std::none_of(functionList.begin(), functionList.end(), [tok](const Function& f) { - return startsWith(f.name(), tok->str() + " <"); + if (matches.size() == 1 && std::none_of(functionList.begin(), functionList.end(), [&name](const Function& f) { + return startsWith(f.name(), name + " <"); })) return matches[0]; @@ -7792,6 +7797,13 @@ static const Function* getFunction(const Token* tok) { lambda = lvar->nameToken()->tokAt(2)->function(); if (lambda && lambda->retDef) return lambda; + // calling an object of a class that overloads operator() + if (tok != lvar->nameToken() && !lvar->isPointer() && !lvar->isArray() && lvar->typeScope()) { + const Function* callOp = + lvar->typeScope()->findFunction(tok, lvar->isConst(), Reference::LValue, "operator()"); + if (callOp && callOp->retDef) + return callOp; + } } return nullptr; } diff --git a/lib/symboldatabase.h b/lib/symboldatabase.h index 7d52d0bfb32..86ce9419999 100644 --- a/lib/symboldatabase.h +++ b/lib/symboldatabase.h @@ -1144,9 +1144,14 @@ class CPPCHECKLIB Scope { * @brief find a function * @param tok token of function call * @param requireConst if const refers to a const variable only const methods should be matched + * @param ref reference qualification of the object the function is called on + * @param funcName name to look up instead of tok->str(), e.g. "operator()" when tok is a variable that is called * @return pointer to function if found or NULL if not found */ - const Function *findFunction(const Token *tok, bool requireConst=false, Reference ref=Reference::None) const; + const Function* findFunction(const Token* tok, + bool requireConst = false, + Reference ref = Reference::None, + const std::string& funcName = "") const; const Scope *findRecordInNestedList(const std::string & name, bool isC = false) const; Scope *findRecordInNestedList(const std::string & name, bool isC = false); @@ -1210,7 +1215,10 @@ class CPPCHECKLIB Scope { */ bool isVariableDeclaration(const Token* tok, const Token*& vartok, const Token*& typetok) const; - void findFunctionInBase(const Token* tok, size_t args, std::vector & matches) const; + void findFunctionInBase(const std::string& name, + const Token* tok, + size_t args, + std::vector& matches) const; /** @brief initialize varlist */ void getVariableList(const Token *start, const Token *end); diff --git a/test/testnullpointer.cpp b/test/testnullpointer.cpp index 698946b8efa..c1bf766b8bb 100644 --- a/test/testnullpointer.cpp +++ b/test/testnullpointer.cpp @@ -147,6 +147,7 @@ class TestNullPointer : public TestFixture { TEST_CASE(nullpointer107); // #13682 (FP/FN cases around guards that depend on the pointer indirectly) TEST_CASE(nullpointer108); TEST_CASE(nullpointer109); + TEST_CASE(nullpointer110); // #14937 TEST_CASE(nullpointer_addressOf); // address of TEST_CASE(nullpointerSwitch); // #2626 TEST_CASE(nullpointer_cast); // #4692 @@ -3128,6 +3129,24 @@ class TestNullPointer : public TestFixture { ASSERT_EQUALS("", errout_str()); } + void nullpointer110() + { // #14937 - noreturn member function called on operator() result + check("struct A {\n" + " [[noreturn]] void g(int);\n" + "};\n" + "template\n" + "struct Thunk {\n" + " T& operator()() const;\n" + "};\n" + "void f(Thunk thunk, int* p) {\n" + " if (!p)\n" + " thunk().g(0);\n" + " *p = 1;\n" + "}", + dinit(CheckOptions, $.inconclusive = true)); + ASSERT_EQUALS("", errout_str()); + } + void nullpointer_addressOf() { // address of check("void f() {\n" " struct X *x = 0;\n" diff --git a/test/testsymboldatabase.cpp b/test/testsymboldatabase.cpp index 69d345a1cc5..1ce349cf969 100644 --- a/test/testsymboldatabase.cpp +++ b/test/testsymboldatabase.cpp @@ -542,6 +542,8 @@ class TestSymbolDatabase : public TestFixture { TEST_CASE(findFunction60); TEST_CASE(findFunction61); TEST_CASE(findFunction62); // #14272 - pointer passed to function is const + TEST_CASE(findFunction63); // #14937 - member function of type returned by operator() + TEST_CASE(findFunction64); // overloaded operator() TEST_CASE(findFunctionRef1); TEST_CASE(findFunctionRef2); // #13328 TEST_CASE(findFunctionContainer); @@ -8875,6 +8877,90 @@ class TestSymbolDatabase : public TestFixture { ASSERT_EQUALS(2, functionCall->function()->token->linenr()); } + void findFunction63() + { // #14937 + GET_SYMBOL_DB("struct A {\n" + " void g(int);\n" + "};\n" + "template\n" + "struct Thunk {\n" + " T& operator()() const;\n" + "};\n" + "void f(Thunk thunk) {\n" + " thunk().g(0);\n" + "}\n"); + const Token* g = Token::findsimplematch(tokenizer.tokens(), "g ( 0 )"); + ASSERT(g); + ASSERT(g->function()); + ASSERT(g->function()->tokenDef); + ASSERT_EQUALS(2, g->function()->tokenDef->linenr()); + const Token* call = Token::findsimplematch(tokenizer.tokens(), "( ) . g"); + ASSERT(call && call->valueType()); + ASSERT(call->valueType()->typeScope && call->valueType()->typeScope->className == "A"); + ASSERT_EQUALS(static_cast(Reference::LValue), static_cast(call->valueType()->reference)); + } + + void findFunction64() + { // overloaded operator() + { + GET_SYMBOL_DB("struct A { void g(int); };\n" // overloads distinguished by argument count + "struct B { void h(int); };\n" + "template\n" + "struct C {\n" + " A& operator()();\n" + " B& operator()(int);\n" + "};\n" + "void f(C c) {\n" + " c().g(1);\n" + " c(1).h(1);\n" + "}\n"); + const Token* g = Token::findsimplematch(tokenizer.tokens(), "g ( 1 )"); + ASSERT(g && g->function()); + ASSERT_EQUALS(1, g->function()->tokenDef->linenr()); + const Token* h = Token::findsimplematch(tokenizer.tokens(), "h ( 1 )"); + ASSERT(h && h->function()); + ASSERT_EQUALS(2, h->function()->tokenDef->linenr()); + } + { + GET_SYMBOL_DB("struct A { void g(int); };\n" // overloads distinguished by constness of the object + "struct B { void h(int); };\n" + "template\n" + "struct C {\n" + " A& operator()();\n" + " B& operator()() const;\n" + "};\n" + "void f(C c, const C& k) {\n" + " c().g(1);\n" + " k().h(1);\n" + "}\n"); + const Token* g = Token::findsimplematch(tokenizer.tokens(), "g ( 1 )"); + ASSERT(g && g->function()); + ASSERT_EQUALS(1, g->function()->tokenDef->linenr()); + const Token* h = Token::findsimplematch(tokenizer.tokens(), "h ( 1 )"); + ASSERT(h && h->function()); + ASSERT_EQUALS(2, h->function()->tokenDef->linenr()); + } + { + GET_SYMBOL_DB("struct A { void g(int); };\n" // overloads distinguished by argument type + "struct B { void h(int); };\n" + "template\n" + "struct C {\n" + " A& operator()(int);\n" + " B& operator()(double);\n" + "};\n" + "void f(C c, int i, double d) {\n" + " c(i).g(1);\n" + " c(d).h(1);\n" + "}\n"); + const Token* g = Token::findsimplematch(tokenizer.tokens(), "g ( 1 )"); + ASSERT(g && g->function()); + ASSERT_EQUALS(1, g->function()->tokenDef->linenr()); + const Token* h = Token::findsimplematch(tokenizer.tokens(), "h ( 1 )"); + ASSERT(h && h->function()); + ASSERT_EQUALS(2, h->function()->tokenDef->linenr()); + } + } + void findFunctionRef1() { GET_SYMBOL_DB("struct X {\n" " const std::vector getInts() const & { return mInts; }\n" From 0911ee6994d6ea0a25580a45672ad51bd5b4c873 Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Thu, 30 Jul 2026 09:10:01 +0200 Subject: [PATCH 132/165] Fix #14818 FP returnDanglingLifetime when passing c_str() to function (#8750) Co-authored-by: chrchr-github --- lib/valueflow.cpp | 2 ++ test/testautovariables.cpp | 9 +++++++++ 2 files changed, 11 insertions(+) diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index 5f6fc1cf622..63543e1a8f5 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -2542,6 +2542,8 @@ static void valueFlowLifetimeFunction(Token *tok, const TokenList &tokenlist, Er for (const Token* returnTok : returns) { if (returnTok == tok) continue; + if (!ValueFlow::isLifetimeBorrowed(returnTok, settings)) + return; const Variable *returnVar = ValueFlow::getLifetimeVariable(returnTok, settings); if (returnVar && returnVar->isArgument() && (returnVar->isConst() || !isVariableChanged(returnVar, settings))) { LifetimeStore ls = LifetimeStore::fromFunctionArg(f, tok, returnVar, tokenlist, settings, errorLogger); diff --git a/test/testautovariables.cpp b/test/testautovariables.cpp index df421d6879c..7774d7fa733 100644 --- a/test/testautovariables.cpp +++ b/test/testautovariables.cpp @@ -2962,6 +2962,15 @@ class TestAutoVariables : public TestFixture { " int m;\n" "}\n"); ASSERT_EQUALS("", errout_str()); + + check("std::string to_string(const char* p) {\n" // #14818 + " return p;\n" + "}\n" + "std::string get() {\n" + " std::string s;\n" + " return to_string(s.c_str());\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); } void danglingLifetimeContainerView() From 71de6753d64f176e30335b5e4b93bc90464908e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludvig=20Gunne=20Lindstr=C3=B6m?= Date: Thu, 30 Jul 2026 09:39:24 +0200 Subject: [PATCH 133/165] Fix #14914: fuzzing timeout (hang) in Tokenizer::simplifyTypedef() (#8762) --- lib/tokenize.cpp | 29 ++++++++++--------- ...m-6fd8356f0baeb3bb43463298803b94ac8ea93cac | 1 + test/testsimplifytypedef.cpp | 6 ++++ 3 files changed, 22 insertions(+), 14 deletions(-) create mode 100644 test/cli/fuzz-timeout/oom-6fd8356f0baeb3bb43463298803b94ac8ea93cac diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 031ab624bfb..5ebf6c51951 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -563,6 +563,20 @@ namespace { if (Token::simpleMatch(start, "typename")) start = start->next(); + const auto checkForRecursion = [this]() { + if (Token::Match(mTypedefToken, "typedef %name% %name% ;")) + return; + for (const Token *tok = mTypedefToken; tok != mEndToken; tok = tok->next()) { + if (tok == mNameToken) + continue; + if (tok->str() != mNameToken->str()) + continue; + if (Token::Match(tok->previous(), "struct|class|enum|union")) + continue; + throw InternalError(tok, "recursive typedef encountered"); + } + }; + // TODO handle unnamed structs etc if (Token::Match(start, "const| enum|struct|union|class %name%| {")) { const std::pair rangeBefore(start, Token::findsimplematch(start, "{")); @@ -585,24 +599,11 @@ namespace { } mNameToken = nameTok; mEndToken = nameTok->next(); + checkForRecursion(); return; } } - const auto checkForRecursion = [this]() { - if (Token::Match(mTypedefToken, "typedef %name% %name% ;")) - return; - for (const Token *tok = mTypedefToken; tok != mEndToken; tok = tok->next()) { - if (tok == mNameToken) - continue; - if (tok->str() != mNameToken->str()) - continue; - if (Token::Match(tok->previous(), "struct|class|enum|union")) - continue; - throw InternalError(tok, "recursive typedef encountered"); - } - }; - for (Token* type = start; Token::Match(type, "%name%|*|&|&&"); type = type->next()) { if (type != start && Token::Match(type, "%name% ;") && !type->isStandardType()) { mRangeType.first = start; diff --git a/test/cli/fuzz-timeout/oom-6fd8356f0baeb3bb43463298803b94ac8ea93cac b/test/cli/fuzz-timeout/oom-6fd8356f0baeb3bb43463298803b94ac8ea93cac new file mode 100644 index 00000000000..29e36cf8c55 --- /dev/null +++ b/test/cli/fuzz-timeout/oom-6fd8356f0baeb3bb43463298803b94ac8ea93cac @@ -0,0 +1 @@ +typedef struct D{itoftor;}tor tor; \ No newline at end of file diff --git a/test/testsimplifytypedef.cpp b/test/testsimplifytypedef.cpp index 5a14399e406..42718a2f99c 100644 --- a/test/testsimplifytypedef.cpp +++ b/test/testsimplifytypedef.cpp @@ -234,6 +234,7 @@ class TestSimplifyTypedef : public TestFixture { TEST_CASE(simplifyTypedef161); TEST_CASE(simplifyTypedef162); TEST_CASE(simplifyTypedef163); + TEST_CASE(simplifyTypedef164); TEST_CASE(simplifyTypedefFunction1); TEST_CASE(simplifyTypedefFunction2); // ticket #1685 @@ -3874,6 +3875,11 @@ class TestSimplifyTypedef : public TestFixture { ASSERT_THROW_INTERNAL(tok(code), INTERNAL); } + void simplifyTypedef164() { + const char code[] = "typedef struct D{x;}y y;"; + ASSERT_THROW_INTERNAL(tok(code), INTERNAL); + } + void simplifyTypedefFunction1() { { const char code[] = "typedef void (*my_func)();\n" From a156364fa3f5edbcba3ad7a5bd37310e6ea7d8ae Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Thu, 30 Jul 2026 18:29:55 +0200 Subject: [PATCH 134/165] Partial fix for #14911 FN knownConditionTrueFalse for number literals (regression) (#8737) Co-authored-by: chrchr-github --- lib/checkcondition.cpp | 19 ++++++++++++++----- test/testcondition.cpp | 22 ++++++++++++++++++++++ 2 files changed, 36 insertions(+), 5 deletions(-) diff --git a/lib/checkcondition.cpp b/lib/checkcondition.cpp index e77641f89e7..4776cbea38f 100644 --- a/lib/checkcondition.cpp +++ b/lib/checkcondition.cpp @@ -1575,10 +1575,19 @@ void CheckConditionImpl::alwaysTrueFalse() continue; if (Token::simpleMatch(tok->astParent(), "return") && Token::Match(tok, ".|%var%")) continue; - if (Token::Match(tok, "%num%|%bool%|%char%")) - continue; - if (Token::Match(tok, "! %num%|%bool%|%char%")) - continue; + bool warnForNumber = false; + if (Token::Match(tok, "%num%|%bool%|%char%")) { + const bool isZeroOrOne = (tok->getKnownIntValue() >> 1) == 0; + warnForNumber = !isZeroOrOne && tok->tokType() == Token::eNumber && tok->astParent() == condition->astParent(); + if (!warnForNumber) + continue; + } + if (Token::Match(tok, "! %num%|%bool%|%char%")) { + const bool isZeroOrOne = tok->next()->hasKnownIntValue() && (tok->next()->getKnownIntValue() >> 1) == 0; + warnForNumber = !isZeroOrOne && tok->next()->tokType() == Token::eNumber && tok->astParent() == condition->astParent(); + if (!warnForNumber) + continue; + } if (Token::Match(tok, "%oror%|&&")) { bool bail = false; for (const Token* op : { tok->astOperand1(), tok->astOperand2() }) { @@ -1603,7 +1612,7 @@ void CheckConditionImpl::alwaysTrueFalse() true)) continue; - if (!pedantic && isConstVarExpression(tok, [](const Token* tok) { + if (!pedantic && !warnForNumber && isConstVarExpression(tok, [](const Token* tok) { return Token::Match(tok, "[|(|&|+|-|*|/|%|^|>>|<<") && !Token::simpleMatch(tok, "( )"); })) continue; diff --git a/test/testcondition.cpp b/test/testcondition.cpp index da4ecae43b3..85efa6eab63 100644 --- a/test/testcondition.cpp +++ b/test/testcondition.cpp @@ -4949,6 +4949,28 @@ class TestCondition : public TestFixture { " return x ? false : true;\n" "}\n"); ASSERT_EQUALS("", errout_str()); + + check("void f() {\n" + " if (42) {}\n" + " if (42U) {}\n" + " if (42L) {}\n" + " if (42UL) {}\n" + " if (42LL) {}\n" + " if (042) {}\n" + " if (0x42) {}\n" + " if (0b101010) {}\n" + " if (!42) {}\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:2:9]: (style) Condition '42' is always true [knownConditionTrueFalse]\n" + "[test.cpp:3:9]: (style) Condition '42U' is always true [knownConditionTrueFalse]\n" + "[test.cpp:4:9]: (style) Condition '42L' is always true [knownConditionTrueFalse]\n" + "[test.cpp:5:9]: (style) Condition '42UL' is always true [knownConditionTrueFalse]\n" + "[test.cpp:6:9]: (style) Condition '42LL' is always true [knownConditionTrueFalse]\n" + "[test.cpp:7:9]: (style) Condition '042' is always true [knownConditionTrueFalse]\n" + "[test.cpp:8:9]: (style) Condition '0x42' is always true [knownConditionTrueFalse]\n" + "[test.cpp:9:9]: (style) Condition '0b101010' is always true [knownConditionTrueFalse]\n" + "[test.cpp:10:9]: (style) Condition '!42' is always false [knownConditionTrueFalse]\n", + errout_str()); } void alwaysTrueSymbolic() From 8745a78a43281593e755c91c835cc6211ce99ed9 Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Thu, 30 Jul 2026 22:28:32 +0200 Subject: [PATCH 135/165] Fix #14945 FN memleak with nested scopes. (#8761) --- lib/checkleakautovar.cpp | 2 ++ test/testleakautovar.cpp | 29 +++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/lib/checkleakautovar.cpp b/lib/checkleakautovar.cpp index e8271f9eed0..e5220e701a3 100644 --- a/lib/checkleakautovar.cpp +++ b/lib/checkleakautovar.cpp @@ -342,6 +342,8 @@ bool CheckLeakAutoVarImpl::checkScope(const Token * const startToken, } } + if (tok == tok->scope()->bodyEnd && tok->scope()->type == ScopeType::eUnconditional) + ret(tok, varInfo, /*isEndOfScope*/ true); // look for end of statement const bool isInit = Token::Match(tok->tokAt(-1), "%var% {|(") && tok->tokAt(-1)->variable() && tok->tokAt(-1) == tok->tokAt(-1)->variable()->nameToken(); diff --git a/test/testleakautovar.cpp b/test/testleakautovar.cpp index b7f8b024a8c..6b6397851fb 100644 --- a/test/testleakautovar.cpp +++ b/test/testleakautovar.cpp @@ -211,6 +211,7 @@ class TestLeakAutoVar : public TestFixture { TEST_CASE(inlineFunction); // #3989 TEST_CASE(smartPtrInContainer); // #8262 + TEST_CASE(unconditionalScope); TEST_CASE(functionCallCastConfig); // #9652 TEST_CASE(functionCallLeakIgnoreConfig); // #7923 @@ -3178,6 +3179,34 @@ class TestLeakAutoVar : public TestFixture { ASSERT_EQUALS("", errout_str()); } + void unconditionalScope() { + check("void f() {\n" // #14945 + " {\n" + " int* p = new int;\n" + " *p = 1;\n" + " }\n" + " {\n" + " int* q = new int;\n" + " *q = 2;\n" + " delete q;\n" + " }\n" + " int* r = new int;\n" + " *r = 3;\n" + " delete r;\n" + "}\n", dinit(CheckOptions, $.cpp = true)); + ASSERT_EQUALS("[test.cpp:5:5]: (error) Memory leak: p [memleak]\n", errout_str()); + + check("void f() {\n" + " int* p = new int;\n" + " {\n" + " (void)p;\n" + " }\n" + " *p = 1;\n" + " delete p;\n" + "}\n", dinit(CheckOptions, $.cpp = true)); + ASSERT_EQUALS("", errout_str()); + } + void functionCallCastConfig() { // #9652 constexpr char xmldata[] = "\n" "\n" From da92ba351e39bb86c03879920e8a2de35d435aff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludvig=20Gunne=20Lindstr=C3=B6m?= Date: Fri, 31 Jul 2026 11:50:48 +0200 Subject: [PATCH 136/165] Fix #14951: FP unreadVariable with function pointer member (#8768) --- lib/tokenize.cpp | 4 +++- test/testsymboldatabase.cpp | 17 +++++++++++++++++ test/testunusedvar.cpp | 12 ++++++++++++ 3 files changed, 32 insertions(+), 1 deletion(-) diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 5ebf6c51951..07ffa4c666c 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -4549,7 +4549,7 @@ static void setVarIdStructMembers(Token *&tok1, return; } - while (Token::Match(tok->next(), ")| . %name% !!(")) { + while (Token::Match(tok->next(), ")| . %name%")) { // Don't set varid for trailing return type if (tok->strAt(1) == ")" && Token::Match(tok->linkAt(1)->tokAt(-1), "%name%|]") && !tok->linkAt(1)->tokAt(-1)->isKeyword() && TokenList::isFunctionHead(tok->linkAt(1), "{;")) { @@ -4571,6 +4571,8 @@ static void setVarIdStructMembers(Token *&tok1, std::map& members = structMembers[struct_varid]; const auto it = utils::as_const(members).find(tok->str()); if (it == members.cend()) { + if (Token::Match(tok, "%name% (")) + break; members[tok->str()] = ++varId; tok->varId(varId); } else { diff --git a/test/testsymboldatabase.cpp b/test/testsymboldatabase.cpp index 1ce349cf969..eeaed0cbf3f 100644 --- a/test/testsymboldatabase.cpp +++ b/test/testsymboldatabase.cpp @@ -233,6 +233,7 @@ class TestSymbolDatabase : public TestFixture { TEST_CASE(rangeBasedFor); TEST_CASE(memberVar1); + TEST_CASE(memberVar2); TEST_CASE(arrayMemberVar1); TEST_CASE(arrayMemberVar2); TEST_CASE(arrayMemberVar3); @@ -1864,6 +1865,22 @@ class TestSymbolDatabase : public TestFixture { ASSERT(Token::simpleMatch(tok->variable()->typeStartToken(), "int x ;")); } + void memberVar2() { + GET_SYMBOL_DB( "struct S { void (*fp)(); };\n" + "void g();\n" + "void f() {\n" + " S s;\n" + " s.fp = g;\n" + " s.fp();\n" + "}\n"); + + ASSERT(db != nullptr); + const Token *fp1 = Token::findsimplematch(tokenizer.tokens(), "fp ="); + const Token *fp2 = Token::findsimplematch(tokenizer.tokens(), "fp ("); + ASSERT(fp1->varId()); + ASSERT_EQUALS(fp2->varId(), fp1->varId()); + } + void arrayMemberVar1() { GET_SYMBOL_DB("struct Foo {\n" " int x;\n" diff --git a/test/testunusedvar.cpp b/test/testunusedvar.cpp index 0cf50a5ceb9..a56af38c0f5 100644 --- a/test/testunusedvar.cpp +++ b/test/testunusedvar.cpp @@ -158,6 +158,7 @@ class TestUnusedVar : public TestFixture { TEST_CASE(localvar71); TEST_CASE(localvar72); TEST_CASE(localvar73); + TEST_CASE(localvar74); TEST_CASE(localvarloops); // loops TEST_CASE(localvaralias1); TEST_CASE(localvaralias2); // ticket #1637 @@ -4100,6 +4101,17 @@ class TestUnusedVar : public TestFixture { ASSERT_EQUALS("", errout_str()); } + void localvar74() { + functionVariableUsage("struct S { void (*fp)(); };\n" + "void g();\n" + "void f() {\n" + " S s;\n" + " s.fp = g;\n" + " s.fp();\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + } + void localvarloops() { // loops functionVariableUsage("void fun(int c) {\n" From cb9f2a2c365f5d9468e99d4c1e5aa5765f0edbc3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludvig=20Gunne=20Lindstr=C3=B6m?= Date: Fri, 31 Jul 2026 11:53:12 +0200 Subject: [PATCH 137/165] Fix #14712: FP constVariableReference , taking non const reference to member (#8767) --- lib/symboldatabase.cpp | 2 +- test/testother.cpp | 11 +++++++++++ test/testsymboldatabase.cpp | 12 ++++++++++++ 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index e6f676e7a20..a666c15b536 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -5088,7 +5088,7 @@ void Scope::getVariableList() void Scope::getVariableList(const Token* start, const Token* end) { // Variable declared in condition: if (auto x = bar()) - if (Token::Match(classDef, "if|while ( %type%") && Token::simpleMatch(classDef->next()->astOperand2(), "=")) { + if (Token::Match(classDef, "if|while|switch ( %type%") && Token::simpleMatch(classDef->next()->astOperand2(), "=")) { checkVariable(classDef->tokAt(2), defaultAccess()); } diff --git a/test/testother.cpp b/test/testother.cpp index f69c7cae1c2..b12e26e1ffa 100644 --- a/test/testother.cpp +++ b/test/testother.cpp @@ -4155,6 +4155,17 @@ class TestOther : public TestFixture { " return r;\n" "}\n"); ASSERT_EQUALS("", errout_str()); + + check("struct Item { int state; };\n" + "void foo(std::vector &items) {\n" + " for (auto &item : items) {\n" + " switch (auto &s = item.state) {\n" + " case 0: s = 1; break;\n" + " default: break;\n" + " }\n" + " }\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); } void constParameterCallback() { diff --git a/test/testsymboldatabase.cpp b/test/testsymboldatabase.cpp index eeaed0cbf3f..8fe107080b6 100644 --- a/test/testsymboldatabase.cpp +++ b/test/testsymboldatabase.cpp @@ -204,6 +204,7 @@ class TestSymbolDatabase : public TestFixture { TEST_CASE(isVariableDeclarationRValueRef); TEST_CASE(isVariableDeclarationDoesNotIdentifyCase); TEST_CASE(isVariableDeclarationIf); + TEST_CASE(isVariableDeclarationSwitch); TEST_CASE(isVariableStlType); TEST_CASE(isVariablePointerToConstPointer); TEST_CASE(isVariablePointerToVolatilePointer); @@ -1235,6 +1236,17 @@ class TestSymbolDatabase : public TestFixture { ASSERT(y->variable()); } + void isVariableDeclarationSwitch() { + GET_SYMBOL_DB("void foo(void) {\n" + " int x = 0;\n" + " switch (auto &s = x) {}\n" + "}\n"); + const Token *s = Token::findsimplematch(tokenizer.tokens(), "s"); + ASSERT(s); + ASSERT(s->varId()); + ASSERT(s->variable()); + } + void VariableValueType1() { GET_SYMBOL_DB("typedef uint8_t u8;\n" "static u8 x;"); From cb694dd86322e83fad8caea77ceb8fa687fd0f1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludvig=20Gunne=20Lindstr=C3=B6m?= Date: Mon, 3 Aug 2026 14:57:08 +0200 Subject: [PATCH 138/165] Fix #14954: False negatives: `noCopyConstructor`, `noOperatorEq` and `unsafeClassCanLeak` for file descriptor member (#8769) Co-authored-by: Aaron Danen --- lib/checkclass.cpp | 9 ++++++--- lib/checkmemoryleak.cpp | 2 +- test/testclass.cpp | 32 +++++++++++++++++++++++++++++++- test/testmemleak.cpp | 12 +++++++++++- 4 files changed, 49 insertions(+), 6 deletions(-) diff --git a/lib/checkclass.cpp b/lib/checkclass.cpp index 51d5718159f..d691834097d 100644 --- a/lib/checkclass.cpp +++ b/lib/checkclass.cpp @@ -473,7 +473,7 @@ void CheckClassImpl::copyconstructors() if (Token::Match(tok, "%var% ( new") || (Token::Match(tok, "%var% ( %name% (") && mSettings.library.getAllocFuncInfo(tok->tokAt(2)))) { const Variable* var = tok->variable(); - if (var && var->isPointer() && var->scope() == scope) + if (var && var->scope() == scope && var->valueType() && var->valueType()->type != ValueType::SMART_POINTER) allocatedVars[tok->varId()] = tok; } } @@ -481,7 +481,7 @@ void CheckClassImpl::copyconstructors() if (Token::Match(tok, "%var% = new") || (Token::Match(tok, "%var% = %name% (") && mSettings.library.getAllocFuncInfo(tok->tokAt(2)))) { const Variable* var = tok->variable(); - if (var && var->isPointer() && var->scope() == scope && !var->isStatic()) + if (var && var->scope() == scope && !var->isStatic() && var->valueType() && var->valueType()->type != ValueType::SMART_POINTER) allocatedVars[tok->varId()] = tok; } } @@ -493,7 +493,10 @@ void CheckClassImpl::copyconstructors() (Token::Match(tok, "%name% ( %var%") && mSettings.library.getDeallocFuncInfo(tok))) { const Token *vartok = tok->str() == "delete" ? tok->next() : tok->tokAt(2); const Variable* var = vartok->variable(); - if (var && var->isPointer() && var->scope() == scope && !var->isStatic()) + if (var && var->scope() == scope && !var->isStatic() && + var->valueType() && ((var->valueType()->type != ValueType::CONTAINER && + var->valueType()->type != ValueType::RECORD && + var->valueType()->type != ValueType::UNKNOWN_TYPE) || var->valueType()->pointer)) deallocatedVars[vartok->varId()] = vartok; } } diff --git a/lib/checkmemoryleak.cpp b/lib/checkmemoryleak.cpp index cc8b6853f11..398240b06ab 100644 --- a/lib/checkmemoryleak.cpp +++ b/lib/checkmemoryleak.cpp @@ -517,7 +517,7 @@ void CheckMemoryLeakInClassImpl::check() // only check classes and structures for (const Scope * scope : symbolDatabase->classAndStructScopes) { for (const Variable &var : scope->varlist) { - if (!var.isStatic() && (var.isPointer() || var.isPointerArray())) { + if (!var.isStatic()) { // allocation but no deallocation of private variables in public function.. const Token *tok = var.typeStartToken(); // Either it is of standard type or a non-derived type diff --git a/test/testclass.cpp b/test/testclass.cpp index 1d647eb33a1..457ab5932fe 100644 --- a/test/testclass.cpp +++ b/test/testclass.cpp @@ -38,7 +38,7 @@ class TestClass : public TestFixture { const Settings settings0_i = settingsBuilder(settings0).certainty(Certainty::inconclusive).build(); const Settings settings1 = settingsBuilder().severity(Severity::warning).library("std.cfg").build(); const Settings settings2 = settingsBuilder().severity(Severity::style).library("std.cfg").certainty(Certainty::inconclusive).build(); - const Settings settings3 = settingsBuilder().severity(Severity::style).library("std.cfg").severity(Severity::warning).build(); + const Settings settings3 = settingsBuilder().severity(Severity::style).library("std.cfg").severity(Severity::warning).library("posix.cfg").build(); const Settings settings3_i = settingsBuilder(settings3).certainty(Certainty::inconclusive).build(); const Settings settings4 = settingsBuilder().severity(Severity::warning).severity(Severity::portability).library("std.cfg").library("posix.cfg").build(); @@ -62,6 +62,8 @@ class TestClass : public TestFixture { TEST_CASE(copyConstructor4); // base class with private constructor TEST_CASE(copyConstructor5); // multiple inheritance TEST_CASE(copyConstructor6); // array of pointers + TEST_CASE(copyConstructor7); // ticket #14954 + TEST_CASE(copyConstructor8); TEST_CASE(deletedMemberPointer); // deleted member pointer in destructor TEST_CASE(noOperatorEq); // class with memory management should have operator eq TEST_CASE(noDestructor); // class with memory management should have destructor @@ -1094,6 +1096,25 @@ class TestClass : public TestFixture { errout_str()); } + void copyConstructor7() { // ticket #14954 + checkCopyConstructor("struct S {\n" + " explicit S(char *name) { m_fd = mkstemp(name); }\n" + " ~S() { /* close(m_fd); */ }\n" + " S &operator =(const S&);\n" + " int m_fd;\n" + "};\n"); + ASSERT_EQUALS("[test.cpp:2:30]: (warning) Struct 'S' does not have a copy constructor which is recommended since it has dynamic memory/resource management. [noCopyConstructor]\n", errout_str()); + } + + void copyConstructor8() { + checkCopyConstructor("struct S {\n" + " S() : m_ptr(new int) {}\n" + " ~S();\n" + " std::unique_ptr m_ptr;\n" + "};\n"); + ASSERT_EQUALS("", errout_str()); + } + void deletedMemberPointer() { // delete ... @@ -1158,6 +1179,15 @@ class TestClass : public TestFixture { " ~F();\n" "};"); ASSERT_EQUALS("", errout_str()); + + checkCopyConstructor("struct S {\n" + " explicit S(char *name) { m_fd = mkstemp(name); }\n" + " S(const S&);\n" + " ~S() { /* close(m_fd); */ }\n" + " int m_fd;\n" + "};\n"); + ASSERT_EQUALS("[test.cpp:2:30]: (warning) Struct 'S' does not have a operator= which is recommended since it has dynamic memory/resource management. [noOperatorEq]\n", errout_str()); + } void noDestructor() { diff --git a/test/testmemleak.cpp b/test/testmemleak.cpp index 783a10ad089..2999fd3f441 100644 --- a/test/testmemleak.cpp +++ b/test/testmemleak.cpp @@ -488,7 +488,7 @@ class TestMemleakInClass : public TestFixture { TestMemleakInClass() : TestFixture("TestMemleakInClass") {} private: - const Settings settings = settingsBuilder().severity(Severity::warning).severity(Severity::style).library("std.cfg").build(); + const Settings settings = settingsBuilder().severity(Severity::warning).severity(Severity::style).library("std.cfg").library("posix.cfg").build(); /** * Tokenize and execute leak check for given code @@ -533,6 +533,7 @@ class TestMemleakInClass : public TestFixture { TEST_CASE(class25); // ticket #4367 - false positive implementation for destructor is not seen TEST_CASE(class26); // ticket #10789 TEST_CASE(class27); // ticket #8126 + TEST_CASE(class28); // ticket #14954 TEST_CASE(staticvar); @@ -1484,6 +1485,15 @@ class TestMemleakInClass : public TestFixture { ASSERT_EQUALS("[test.cpp:6:11]: (style) Class 'S' is unsafe, 'S::a' can leak by wrong usage. [unsafeClassCanLeak]\n", errout_str()); } + void class28() { // ticket #14954 + check("struct S {\n" + " explicit S(char *name) { m_fd = mkstemp(name); }\n" + " ~S() { /* close(m_fd); */ }\n" + " int m_fd;\n" + "};\n"); + ASSERT_EQUALS("[test.cpp:4:9]: (style) Class 'S' is unsafe, 'S::m_fd' can leak by wrong usage. [unsafeClassCanLeak]\n", errout_str()); + } + void staticvar() { check("class A\n" "{\n" From 1f1a07f41409747e4a051b9f1f0a02ce6dc97cf5 Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Tue, 4 Aug 2026 08:25:50 +0200 Subject: [PATCH 139/165] Fix #11437 FP knownConditionTrueFalse when comparing clamped value (#8751) --- lib/valueflow.cpp | 1 + test/testcondition.cpp | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index 63543e1a8f5..766f65e9f32 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -4276,6 +4276,7 @@ static void valueFlowAfterAssign(const TokenList &tokenlist, continue; const Token* expr = value.tokvalue; value.intvalue = -value.intvalue; + value.invertBound(); value.tokvalue = tok->astOperand1(); // Skip if it intersects with an already assigned symbol diff --git a/test/testcondition.cpp b/test/testcondition.cpp index 85efa6eab63..8567d9b11a7 100644 --- a/test/testcondition.cpp +++ b/test/testcondition.cpp @@ -5244,6 +5244,12 @@ class TestCondition : public TestFixture { " if (c) {}\n" "}\n"); ASSERT_EQUALS("", errout_str()); + + check("void f(int a, int b) {\n" // #11437 + " a = a < b ? b : a;\n" + " if (a != b) {}\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); } void alwaysTrueInfer() { From cd55e0888f74053250ad3f2da092f76ce87cf3c8 Mon Sep 17 00:00:00 2001 From: Paul Fultz II Date: Tue, 4 Aug 2026 01:28:16 -0500 Subject: [PATCH 140/165] Fix 14947: FP algorithmOutOfBounds with array of arrays (#8766) --- lib/astutils.cpp | 11 ++++ lib/astutils.h | 3 + lib/checkbufferoverrun.cpp | 17 +++-- lib/checkstl.cpp | 19 +++++- lib/valueflow.cpp | 52 +++++++++------ lib/vf_analyzers.cpp | 19 +++++- lib/vf_common.cpp | 8 ++- lib/vf_settokenvalue.cpp | 22 +++++++ lib/vfvalue.h | 4 ++ test/testbufferoverrun.cpp | 64 +++++++++++++++++++ test/teststl.cpp | 15 +++++ test/testvalueflow.cpp | 126 +++++++++++++++++++++++++++++++++++++ 12 files changed, 332 insertions(+), 28 deletions(-) diff --git a/lib/astutils.cpp b/lib/astutils.cpp index c99e9b19bd5..25249e7be6f 100644 --- a/lib/astutils.cpp +++ b/lib/astutils.cpp @@ -1069,6 +1069,17 @@ bool isAliasOf(const Token *tok, nonneg int varid, bool* inconclusive) return false; } +bool isIteratorOf(const Token* tok, nonneg int exprId) +{ + if (!astIsIterator(tok)) + return false; + // An iterator into a subcontainer (e.g. c[0].begin()) aliases the container but iterates + // an unrelated range, so require an iterator value recording the container itself + return std::any_of(tok->values().cbegin(), tok->values().cend(), [&](const ValueFlow::Value& v) { + return v.isIteratorValue() && v.container && v.container->exprId() == exprId; + }); +} + bool isAliasOf(const Token* tok, const Token* expr, nonneg int* indirect) { if (indirect) diff --git a/lib/astutils.h b/lib/astutils.h index 79a607108fd..578763124ac 100644 --- a/lib/astutils.h +++ b/lib/astutils.h @@ -386,6 +386,9 @@ bool isAliasOf(const Token *tok, nonneg int varid, bool* inconclusive = nullptr) bool isAliasOf(const Token* tok, const Token* expr, nonneg int* indirect = nullptr); +/// If token is an iterator into the container expression with the given expression id +bool isIteratorOf(const Token* tok, nonneg int exprId); + const Token* getArgumentStart(const Token* ftok); /** Determines the number of arguments - if token is a function call or macro diff --git a/lib/checkbufferoverrun.cpp b/lib/checkbufferoverrun.cpp index 46d8e1c7c6c..8c8912ed06d 100644 --- a/lib/checkbufferoverrun.cpp +++ b/lib/checkbufferoverrun.cpp @@ -230,7 +230,8 @@ static bool getDimensionsEtc(const Token * const arrayToken, const Settings &set const size_t typeSize = array->valueType()->getSizeOf(settings, ValueType::Accuracy::ExactOrZero, sizeOf); if (typeSize == 0) return false; - dim.num = value->intvalue / typeSize; + // a container size counts elements, a buffer size counts bytes + dim.num = value->isContainerSizeValue() ? value->intvalue : value->intvalue / typeSize; dimensions.emplace_back(dim); } return !dimensions.empty(); @@ -581,9 +582,17 @@ ValueFlow::Value CheckBufferOverrunImpl::getBufferSize(const Token *bufTok, cons if (const ValueFlow::Value *value = getBufferSizeValue(bufTok)) { if (value->isBufferSizeValue()) return *value; - if (value->isContainerSizeValue() && bufTok->valueType() && bufTok->valueType()->containerTypeToken) { - const ValueType vtElement = ValueType::parseDecl(bufTok->valueType()->containerTypeToken, settings); - const size_t elementSize = vtElement.getSizeOf(settings, ValueType::Accuracy::ExactOrZero, ValueType::SizeOf::Pointer); + if (value->isContainerSizeValue() && bufTok->valueType()) { + size_t elementSize = 0; + if (bufTok->valueType()->containerTypeToken) { + const ValueType vtElement = ValueType::parseDecl(bufTok->valueType()->containerTypeToken, settings); + elementSize = + vtElement.getSizeOf(settings, ValueType::Accuracy::ExactOrZero, ValueType::SizeOf::Pointer); + } else if (bufTok->valueType()->pointer == 1) { + elementSize = bufTok->valueType()->getSizeOf(settings, + ValueType::Accuracy::ExactOrZero, + ValueType::SizeOf::Pointee); + } if (elementSize > 0) { ValueFlow::Value bufSizeVal; bufSizeVal.valueType = ValueFlow::Value::ValueType::BUFFER_SIZE; diff --git a/lib/checkstl.cpp b/lib/checkstl.cpp index 500adc08b01..de1d82792ac 100644 --- a/lib/checkstl.cpp +++ b/lib/checkstl.cpp @@ -765,6 +765,16 @@ static ValueFlow::Value getLifetimeIteratorValue(const Token* tok, MathLib::bigi return ValueFlow::Value{}; } +// Whether a container size value found on an iterator token belongs to the range of the given +// iterator value. Both values record the container they belong to when it is known. +static bool sizeValueAppliesToIterator(const ValueFlow::Value& sizeValue, const ValueFlow::Value& iterValue) +{ + if (!sizeValue.container || !iterValue.container) + return true; // the container of the size or of the iterator is not known + return iterValue.container == sizeValue.container || + (iterValue.container->exprId() != 0 && iterValue.container->exprId() == sizeValue.container->exprId()); +} + bool CheckStlImpl::checkIteratorPair(const Token* tok1, const Token* tok2) { if (!tok1) @@ -2526,6 +2536,8 @@ void CheckStlImpl::checkDereferenceInvalidIterator2() auto it = std::find_if(contValues.cbegin(), contValues.cend(), [&](const ValueFlow::Value& c) { if (value.path != c.path) return false; + if (!sizeValueAppliesToIterator(c, value)) + return false; if (value.isIteratorStartValue() && value.intvalue >= c.intvalue) return true; if (value.isIteratorEndValue() && -value.intvalue > c.intvalue) @@ -3448,7 +3460,8 @@ static IteratorPosition getIteratorPosition(const Token* tok, const Settings& se if (!position.value) return position; position.sizeValue = selectPreferredValue(tok, [&](const ValueFlow::Value& value) { - return isUsableValue(value, settings) && value.isContainerSizeValue() && value.path == position.value->path; + return isUsableValue(value, settings) && value.isContainerSizeValue() && value.path == position.value->path && + sizeValueAppliesToIterator(value, *position.value); }); return position; } @@ -3527,6 +3540,8 @@ static ElementCount findInsufficientSpace(const Token* tok, for (const ValueFlow::Value& sizeValue : tok->values()) { if (!isUsableValue(sizeValue, settings) || !sizeValue.isContainerSizeValue() || sizeValue.path != value.path) continue; + if (!sizeValueAppliesToIterator(sizeValue, value)) + continue; position.sizeValue = &sizeValue; consider(getAvailableSpace(position)); } @@ -3571,6 +3586,8 @@ static ElementCount findExcessiveDistance(const Token* firstTok, if (!isUsableValue(sizeValue, settings) || !sizeValue.isContainerSizeValue() || sizeValue.path != endPosition.value->path) continue; + if (!sizeValueAppliesToIterator(sizeValue, *endPosition.value)) + continue; endPosition.sizeValue = &sizeValue; consider(getIteratorDistance(first, last)); } diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index 766f65e9f32..29eb07bcc90 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -401,10 +401,14 @@ void ValueFlow::combineValueProperties(const ValueFlow::Value &value1, const Val result.valueType = value2.valueType; result.tokvalue = value2.tokvalue; } - if (value1.isIteratorValue()) + if (value1.isIteratorValue()) { result.valueType = value1.valueType; - if (value2.isIteratorValue()) + result.container = value1.container; + } + if (value2.isIteratorValue()) { result.valueType = value2.valueType; + result.container = value2.container; + } result.condition = value1.condition ? value1.condition : value2.condition; result.varId = (value1.varId != 0) ? value1.varId : value2.varId; result.varvalue = (result.varId == value1.varId) ? value1.varvalue : value2.varvalue; @@ -3859,11 +3863,14 @@ static void valueFlowForwardConst(Token* start, } else { [&] { // Add the container size to iterators of the container (mirrors ContainerExpressionAnalyzer::match) - if (hasContainerSizeValue && astIsIterator(tok) && isAliasOf(tok, var->declarationId())) { + if (hasContainerSizeValue && isIteratorOf(tok, var->declarationId())) { for (const ValueFlow::Value& value : values) { if (!value.isContainerSizeValue()) continue; - setTokenValue(tok, value, settings); + ValueFlow::Value sizeValue = value; + if (!sizeValue.container) + sizeValue.container = var->nameToken(); + setTokenValue(tok, std::move(sizeValue), settings); } return; } @@ -4212,11 +4219,15 @@ static void valueFlowAfterAssign(const TokenList &tokenlist, values.remove_if([&](const ValueFlow::Value& value) { return types.count(value.valueType) > 0; }); - // Remove container size if its not a container - if (!astIsContainer(tok->astOperand2())) + // Remove container size if its not a container - unless the size records its container + // and flows into a pointer to the container data (e.g. p = v.data()) + if (!astIsContainer(tok->astOperand2())) { + const bool lhsIsPointer = astIsPointer(tok->astOperand1()); values.remove_if([&](const ValueFlow::Value& value) { - return value.valueType == ValueFlow::Value::ValueType::CONTAINER_SIZE; + return value.valueType == ValueFlow::Value::ValueType::CONTAINER_SIZE && + (!value.container || !lhsIsPointer); }); + } // Remove symbolic values that are the same as the LHS values.remove_if([&](const ValueFlow::Value& value) { if (value.isSymbolicValue() && value.tokvalue) @@ -6447,17 +6458,22 @@ static void valueFlowIterators(TokenList& tokenlist, const Settings& settings) const Library::Container::Yield yield = findIteratorYield(tok, ftok, settings.library); if (!ftok) continue; - if (yield == Library::Container::Yield::START_ITERATOR) { - ValueFlow::Value v(0); - v.setKnown(); - v.valueType = ValueFlow::Value::ValueType::ITERATOR_START; - setTokenValue(const_cast(ftok)->next(), std::move(v), settings); - } else if (yield == Library::Container::Yield::END_ITERATOR) { - ValueFlow::Value v(0); - v.setKnown(); - v.valueType = ValueFlow::Value::ValueType::ITERATOR_END; - setTokenValue(const_cast(ftok)->next(), std::move(v), settings); - } + if (yield != Library::Container::Yield::START_ITERATOR && yield != Library::Container::Yield::END_ITERATOR) + continue; + // The iterator value records the container it iterates. A pointer or a reference only + // transports the iterator, so record the container it refers to instead. + const Token* containerTok = tok; + if (astIsPointer(containerTok) || (containerTok->variable() && containerTok->variable()->isReference())) { + const ValueFlow::Value lifetime = ValueFlow::getLifetimeObjValue(containerTok); + if (lifetime.tokvalue && astIsContainer(lifetime.tokvalue) && !astIsPointer(lifetime.tokvalue)) + containerTok = lifetime.tokvalue; + } + ValueFlow::Value v(0); + v.setKnown(); + v.valueType = yield == Library::Container::Yield::START_ITERATOR ? ValueFlow::Value::ValueType::ITERATOR_START + : ValueFlow::Value::ValueType::ITERATOR_END; + v.container = containerTok; + setTokenValue(const_cast(ftok)->next(), std::move(v), settings); } } diff --git a/lib/vf_analyzers.cpp b/lib/vf_analyzers.cpp index cfba7d5f970..cc4a6a820cf 100644 --- a/lib/vf_analyzers.cpp +++ b/lib/vf_analyzers.cpp @@ -1299,6 +1299,12 @@ struct ExpressionAnalyzer : SingleValueFlowAnalyzer { dependOnThis |= exprDependsOnThis(value.tokvalue); setupExprVarIds(value.tokvalue); } + if (value.isContainerSizeValue() && value.container) { + // a container size tracked through another expression (e.g. a pointer obtained from + // data()) is invalidated by writes to the container it belongs to + dependOnThis |= exprDependsOnThis(value.container); + setupExprVarIds(value.container); + } uniqueExprId = expr->isUniqueExprId() && (Token::Match(expr, "%cop%") || !isVariableChanged(expr, 0, s)); } @@ -1503,15 +1509,22 @@ ValuePtr makeMemberExpressionAnalyzer(std::string varname, const Token struct ContainerExpressionAnalyzer : ExpressionAnalyzer { ContainerExpressionAnalyzer(const Token* expr, ValueFlow::Value val, const Settings& s) : ExpressionAnalyzer(expr, std::move(val), s) - {} + { + // The size of a container expression belongs to that expression. Through a pointer the + // size keeps belonging to the container the pointer was obtained from. + if (astIsContainer(expr) && !astIsPointer(expr)) + value.container = expr; + } bool match(const Token* tok) const override { - return tok->exprId() == expr->exprId() || (astIsIterator(tok) && isAliasOf(tok, expr->exprId())); + return tok->exprId() == expr->exprId() || isIteratorOf(tok, expr->exprId()); } Action isWritable(const Token* tok, Direction /*d*/) const override { - if (astIsIterator(tok)) + // only writes to the container itself change its size - not writes through an iterator + // or to a default-inserted element + if (tok->exprId() != expr->exprId()) return Action::None; if (!getValue(tok)) return Action::None; diff --git a/lib/vf_common.cpp b/lib/vf_common.cpp index ef48423f38a..f9eecc20fb9 100644 --- a/lib/vf_common.cpp +++ b/lib/vf_common.cpp @@ -404,8 +404,12 @@ namespace ValueFlow return Token::getStrLength(tok); if (astIsGenericChar(tok) || tok->tokType() == Token::eChar) return 1; - if (const Value* v = tok->getKnownValue(Value::ValueType::CONTAINER_SIZE)) - return v->intvalue; + if (const Value* v = tok->getKnownValue(Value::ValueType::CONTAINER_SIZE)) { + // on a pointer the size is the number of elements in the buffer (possibly including + // a null terminator), not the length of the string + if (!astIsPointer(tok)) + return v->intvalue; + } if (const Value* v = tok->getKnownValue(Value::ValueType::TOK)) { if (v->tokvalue != tok) return valueFlowGetStrLength(v->tokvalue, library); diff --git a/lib/vf_settokenvalue.cpp b/lib/vf_settokenvalue.cpp index aab64170890..9f56b57db0a 100644 --- a/lib/vf_settokenvalue.cpp +++ b/lib/vf_settokenvalue.cpp @@ -231,6 +231,11 @@ namespace ValueFlow if (!value.isImpossible() && value.isIntValue()) value = truncateImplicitConversion(tok->astParent(), value, settings); + // a container size value on a container expression belongs to that expression, while a + // pointer or an iterator only transports the size of the container it was obtained from + if (value.isContainerSizeValue() && !astIsPointer(tok) && astIsContainer(tok)) + value.container = tok; + if (settings.debugnormal) setSourceLocation(value, loc, tok); @@ -300,15 +305,32 @@ namespace ValueFlow } } } + // an empty associative container implies that its default-inserted elements are empty as well + if (Token::simpleMatch(parent, "[") && astIsLHS(tok) && astIsContainer(parent) && + tok->valueType()->container && tok->valueType()->container->stdAssociativeLike && + !value.isImpossible() && value.intvalue == 0) + setTokenValue(parent, value, settings); Token* next = nullptr; const Library::Container::Yield yields = getContainerYield(parent, settings.library, next); if (yields == Library::Container::Yield::SIZE) { value.valueType = Value::ValueType::INT; + value.container = nullptr; + setTokenValue(next, std::move(value), settings); + } else if (contains({Library::Container::Yield::BUFFER, + Library::Container::Yield::BUFFER_NT, + Library::Container::Yield::START_ITERATOR, + Library::Container::Yield::END_ITERATOR, + Library::Container::Yield::ITERATOR}, + yields)) { + // The returned pointer or iterator has as many elements available as the container + if (yields == Library::Container::Yield::BUFFER_NT) + value.intvalue += 1; // ..plus the null terminator setTokenValue(next, std::move(value), settings); } else if (yields == Library::Container::Yield::EMPTY) { const Value::Bound bound = value.bound; const long long intvalue = value.intvalue; value.valueType = Value::ValueType::INT; + value.container = nullptr; value.bound = Value::Bound::Point; if (value.isImpossible()) { if (intvalue == 0) diff --git a/lib/vfvalue.h b/lib/vfvalue.h index 8a473143b68..ce33f022e58 100644 --- a/lib/vfvalue.h +++ b/lib/vfvalue.h @@ -322,6 +322,10 @@ namespace ValueFlow /** token value - the token that has the value. this is used for pointer aliases, strings, etc. */ const Token* tokvalue{}; + /** For CONTAINER_SIZE values: the container the size belongs to, when the value is + * attached to a token that is not the container itself (an iterator or a pointer) */ + const Token* container = nullptr; + /** float value */ double floatValue{}; diff --git a/test/testbufferoverrun.cpp b/test/testbufferoverrun.cpp index 37ab7083902..8bac50a468c 100644 --- a/test/testbufferoverrun.cpp +++ b/test/testbufferoverrun.cpp @@ -197,6 +197,7 @@ class TestBufferOverrun : public TestFixture { TEST_CASE(array_index_function_parameter); TEST_CASE(array_index_enum_array); // #8439 TEST_CASE(array_index_container); // #9386 + TEST_CASE(array_index_container_data); // pointer from data()/c_str() carries the container size TEST_CASE(array_index_two_for_loops); TEST_CASE(array_index_new); // #7690 @@ -2902,6 +2903,69 @@ class TestBufferOverrun : public TestFixture { ASSERT_EQUALS("", errout_str()); } + void array_index_container_data() + { + check("void f() {\n" + " std::vector v(3);\n" + " int* p = v.data();\n" + " p[2] = 1;\n" + "}"); + ASSERT_EQUALS("", errout_str()); + + check("void f() {\n" + " std::vector v(3);\n" + " int* p = v.data();\n" + " p[5] = 1;\n" + "}"); + ASSERT_EQUALS( + "[test.cpp:4:6]: (error) Array 'p[3]' accessed at index 5, which is out of bounds. [arrayIndexOutOfBounds]\n", + errout_str()); + + check("void f() {\n" + " std::vector v(3);\n" + " memset(v.data(), 0, 12);\n" + " memset(v.data(), 0, 100);\n" + "}"); + ASSERT_EQUALS("[test.cpp:4:18]: (error) Buffer is accessed out of bounds: v.data() [bufferAccessOutOfBounds]\n", + errout_str()); + + check("void f() {\n" + " std::vector v(3);\n" + " int* p = v.data();\n" + " memset(p, 0, 100);\n" + "}"); + ASSERT_EQUALS("[test.cpp:4:12]: (error) Buffer is accessed out of bounds: p [bufferAccessOutOfBounds]\n", + errout_str()); + + // the size is not tracked past changes of the container size + check("void f() {\n" + " std::vector v(3);\n" + " v.reserve(100);\n" + " int* p = v.data();\n" + " v.resize(10);\n" + " memset(p, 0, 40);\n" + "}"); + ASSERT_EQUALS("", errout_str()); + + // ..or when the pointer is reassigned + check("void f(int* q) {\n" + " std::vector v(3);\n" + " int* p = v.data();\n" + " p = q;\n" + " memset(p, 0, 100);\n" + "}"); + ASSERT_EQUALS("", errout_str()); + + // the buffer of c_str() includes the null terminator + check("void f(char* dst) {\n" + " std::string s = \"abc\";\n" + " memcpy(dst, s.c_str(), 4);\n" + " memcpy(dst, s.c_str(), 5);\n" + "}"); + ASSERT_EQUALS("[test.cpp:4:24]: (error) Buffer is accessed out of bounds: s.c_str() [bufferAccessOutOfBounds]\n", + errout_str()); + } + void array_index_two_for_loops() { check("bool b();\n" "void f()\n" diff --git a/test/teststl.cpp b/test/teststl.cpp index c030fb4c6f6..2570059c19e 100644 --- a/test/teststl.cpp +++ b/test/teststl.cpp @@ -2798,6 +2798,21 @@ class TestStl : public TestFixture { ASSERT_EQUALS( "[test.cpp:4:24]: (error) The algorithm 'std::fill_n' accesses 10 elements through the iterator 'v.begin()' but only 5 elements are available. [algorithmOutOfBounds]\n", errout_str()); + + // an iterator into a nested container does not carry the outer container's size + check("std::array, 1> f(const std::array& a) {\n" + " std::array, 1> res;\n" + " std::copy(a.begin(), a.end(), res[0].begin());\n" + " return res;\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + + check("void f() {\n" + " const std::vector v0{1,2,3};\n" + " std::vector> v1(1, std::vector(5));\n" + " std::copy(v0.begin(), v0.end(), v1[0].begin());\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); } // Dereferencing invalid pointer diff --git a/test/testvalueflow.cpp b/test/testvalueflow.cpp index c98680b8180..f92ddee3685 100644 --- a/test/testvalueflow.cpp +++ b/test/testvalueflow.cpp @@ -517,6 +517,22 @@ class TestValueFlow : public TestFixture { return values; } + // The expression of the container recorded by the container size value of the token. The + // container token has to be resolved while the tokenizer is alive. +#define containerOfSizeValue(...) containerOfSizeValue_(__FILE__, __LINE__, __VA_ARGS__) + std::string containerOfSizeValue_(const char* file, int line, const char code[], const char tokstr[]) { + SimpleTokenizer tokenizer(settings, *this); + ASSERT_LOC(tokenizer.tokenize(code), file, line); + const Token* tok = Token::findmatch(tokenizer.tokens(), tokstr); + if (!tok) + return ""; + const std::list& values = tok->values(); + const auto it = std::find_if(values.cbegin(), values.cend(), [](const ValueFlow::Value& v) { + return v.isContainerSizeValue() && v.container; + }); + return it == values.cend() ? "" : it->container->expressionString(); + } + #define lifetimeValues(...) lifetimeValues_(__FILE__, __LINE__, __VA_ARGS__) template std::vector lifetimeValues_(const char* file, int line, const char (&code)[size], const char tokstr[]) { @@ -7682,6 +7698,93 @@ class TestValueFlow : public TestFixture { " if (m.empty()) {}\n" "}\n"; ASSERT(!isKnownContainerSizeValue(tokenValues(code, "m ."), 0).empty()); + + // the pointer returned by data() carries the container size + code = "int f() {\n" + " std::vector v(3);\n" + " int* p = v.data();\n" + " return p[1];\n" + "}"; + ASSERT_EQUALS("", + isKnownContainerSizeValue(tokenValues(code, "p [", ValueFlow::Value::ValueType::CONTAINER_SIZE), 3)); + + // ..which is invalidated when the container size changes + code = "int f() {\n" + " std::vector v(3);\n" + " int* p = v.data();\n" + " v.push_back(1);\n" + " return p[1];\n" + "}"; + ASSERT_EQUALS(0U, tokenValues(code, "p [", ValueFlow::Value::ValueType::CONTAINER_SIZE).size()); + + // the buffer of c_str() includes the null terminator + code = "const char* f() {\n" + " std::string s = \"abc\";\n" + " const char* p = s.c_str();\n" + " return p + 3;\n" + "}"; + ASSERT_EQUALS("", + isKnownContainerSizeValue(tokenValues(code, "p +", ValueFlow::Value::ValueType::CONTAINER_SIZE), 4)); + + code = "const char* f() {\n" + " std::string s = \"abc\";\n" + " return s.c_str();\n" + "}"; + ASSERT_EQUALS( + "", + isKnownContainerSizeValue(tokenValues(code, "( ) ;", ValueFlow::Value::ValueType::CONTAINER_SIZE), 4)); + + // the size value of a data() pointer records the container the size belongs to + code = "int* f() {\n" + " std::vector v(3);\n" + " return v.data();\n" + "}"; + ASSERT_EQUALS("", + isKnownContainerSizeValue(tokenValues(code, "( ) ;", ValueFlow::Value::ValueType::CONTAINER_SIZE), + 3)); + ASSERT_EQUALS("v", containerOfSizeValue(code, "( ) ;")); + + // an empty associative container implies that its default-inserted elements are empty as well + code = "void f(const std::string& k) {\n" + " std::map> m;\n" + " m[k].front();\n" + "}"; + ASSERT_EQUALS( + "", + isKnownContainerSizeValue(tokenValues(code, "[ k ] . front", ValueFlow::Value::ValueType::CONTAINER_SIZE), + 0)); + ASSERT_EQUALS("m[k]", containerOfSizeValue(code, "[ k ] . front")); + + // ..also for nested associative containers.. + code = "void f(int a, int b) {\n" + " std::map>> m;\n" + " m[a][b].front();\n" + "}"; + ASSERT_EQUALS( + "", + isKnownContainerSizeValue(tokenValues(code, "[ b ] . front", ValueFlow::Value::ValueType::CONTAINER_SIZE), 0)); + + // ..but not for non-associative containers.. + code = "void f(int i) {\n" + " std::vector> v;\n" + " v[i].front();\n" + "}"; + ASSERT_EQUALS(0U, tokenValues(code, "[ i ] . front", ValueFlow::Value::ValueType::CONTAINER_SIZE).size()); + + // ..nor when the container is not empty.. + code = "void f(std::map>& m, const std::string& k) {\n" + " if (m.size() == 1)\n" + " m[k].front();\n" + "}"; + ASSERT_EQUALS(0U, tokenValues(code, "[ k ] . front", ValueFlow::Value::ValueType::CONTAINER_SIZE).size()); + + // ..nor when the container was modified + code = "void f(const std::string& k) {\n" + " std::map> m;\n" + " m[\"a\"].push_back(1);\n" + " m[k].front();\n" + "}"; + ASSERT_EQUALS(0U, tokenValues(code, "[ k ] . front", ValueFlow::Value::ValueType::CONTAINER_SIZE).size()); } void valueFlowContainerSizeIterator() { @@ -7723,6 +7826,29 @@ class TestValueFlow : public TestFixture { " if (it != w.end()) {}\n" "}"; ASSERT(tokenValues(code, "it !=", ValueFlow::Value::ValueType::CONTAINER_SIZE).empty()); + + // iterators created from the container carry the container size + code = "bool f() {\n" + " std::vector v(3);\n" + " return v.begin() != v.end();\n" + "}"; + ASSERT_EQUALS( + "", + isKnownContainerSizeValue(tokenValues(code, "( ) !=", ValueFlow::Value::ValueType::CONTAINER_SIZE), 3)); + ASSERT_EQUALS( + "", + isKnownContainerSizeValue(tokenValues(code, "( ) ;", ValueFlow::Value::ValueType::CONTAINER_SIZE), 3)); + + // the size value records the container it belongs to + code = "void f() {\n" + " std::vector v(3);\n" + " auto it = v.begin();\n" + " if (it != v.end()) {}\n" + "}"; + ASSERT_EQUALS( + "", + isKnownContainerSizeValue(tokenValues(code, "it !=", ValueFlow::Value::ValueType::CONTAINER_SIZE), 3)); + ASSERT_EQUALS("v", containerOfSizeValue(code, "it !=")); } void valueFlowContainerElement() From dbde18971103bb5bcf87191c391f75486cd8ca12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludvig=20Gunne=20Lindstr=C3=B6m?= Date: Tue, 4 Aug 2026 16:45:22 +0200 Subject: [PATCH 141/165] Fix #14946: `originalName` in dumpfile missing for local typedefs (#8760) --- lib/tokenize.cpp | 1 + test/testincompletestatement.cpp | 2 +- test/testsimplifytypedef.cpp | 16 ++++++++++++++++ 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 07ffa4c666c..610877eec53 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -2044,6 +2044,7 @@ void Tokenizer::simplifyTypedefCpp() tok2->previous()->str("typedef"); tok2->insertToken(tok2->str()); } + tok2->originalName(tok2->str()); tok2->str(typeStart->str()); // restore qualification if it was removed diff --git a/test/testincompletestatement.cpp b/test/testincompletestatement.cpp index da238d304b2..72a13ee6c42 100644 --- a/test/testincompletestatement.cpp +++ b/test/testincompletestatement.cpp @@ -492,7 +492,7 @@ class TestIncompleteStatement : public TestFixture { "void f(int i) {\n" " (M::N::T)i;\n" "}\n"); - ASSERT_EQUALS("[test.cpp:5:5]: (warning) Redundant code: Found unused cast in expression '(char)i'. [constStatement]\n", errout_str()); + ASSERT_EQUALS("[test.cpp:5:5]: (warning) Redundant code: Found unused cast in expression '(T)i'. [constStatement]\n", errout_str()); check("void f(int (g)(int a, int b)) {\n" // #10873 " int p = 0, q = 1;\n" diff --git a/test/testsimplifytypedef.cpp b/test/testsimplifytypedef.cpp index 42718a2f99c..e83be343e01 100644 --- a/test/testsimplifytypedef.cpp +++ b/test/testsimplifytypedef.cpp @@ -256,6 +256,7 @@ class TestSimplifyTypedef : public TestFixture { TEST_CASE(simplifyTypedefOriginalName1); TEST_CASE(simplifyTypedefOriginalName2); + TEST_CASE(simplifyTypedefOriginalName3); TEST_CASE(simplifyTypedefTokenColumn1); TEST_CASE(simplifyTypedefTokenColumn2); @@ -4600,6 +4601,21 @@ class TestSimplifyTypedef : public TestFixture { ASSERT_EQUALS("A", token->originalName()); } + void simplifyTypedefOriginalName3() { + const char code[] = "void f(void) {\n" + " typedef int A;\n" + " A a;\n" + "}\n"; + TokenList tokenlist{ settings1, Standards::Language::C }; + ASSERT(TokenListHelper::createTokensFromString(tokenlist, code, "file.c")); + TokenizerTest tokenizer(std::move(tokenlist), *this); + tokenizer.createLinks(); + tokenizer.simplifyTypedef(); + ASSERT_NO_THROW(tokenizer.validate()); + const Token* token = Token::findsimplematch(tokenizer.list.front(), "int"); + ASSERT_EQUALS("A", token->originalName()); + } + void simplifyTypedefTokenColumn1() { // #13155 const char code[] = "void foo(void) {\n" " typedef signed int MY_INT;\n" From 1a96ce880c07919f85dce30fa02ffc3848f74721 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludvig=20Gunne=20Lindstr=C3=B6m?= Date: Tue, 4 Aug 2026 16:48:56 +0200 Subject: [PATCH 142/165] Fix #14918: fuzzing crash (stack-overflow) in findTokensSkipDeadCodeImpl() (#8732) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Daniel Marjamäki --- lib/tokenize.cpp | 3 +++ .../crash-9feb09f580c0cf101456c6c650ab4193b1009d07 | 1 + 2 files changed, 4 insertions(+) create mode 100644 test/cli/fuzz-crash_c/crash-9feb09f580c0cf101456c6c650ab4193b1009d07 diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 610877eec53..8382c09e785 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -8814,6 +8814,9 @@ void Tokenizer::findGarbageCode() const if (!cpp || mSettings.standards.cpp < Standards::CPP20 || !Token::Match(tok->previous(), "%name% : %num% =")) syntaxError(tok, tok->strAt(1) + " " + tok->strAt(2)); } + else if (!cpp && Token::Match(tok, "++|-- ++|--")) { + syntaxError(tok, tok->str() + tok->strAt(1)); + } else if (Token::simpleMatch(tok, ") return") && !Token::Match(tok->link()->previous(), "if|while|for (")) { if (tok->link()->previous() && tok->link()->previous()->isUpperCaseName()) unknownMacroError(tok->link()->previous()); diff --git a/test/cli/fuzz-crash_c/crash-9feb09f580c0cf101456c6c650ab4193b1009d07 b/test/cli/fuzz-crash_c/crash-9feb09f580c0cf101456c6c650ab4193b1009d07 new file mode 100644 index 00000000000..8577d6ccb7f --- /dev/null +++ b/test/cli/fuzz-crash_c/crash-9feb09f580c0cf101456c6c650ab4193b1009d07 @@ -0,0 +1 @@ +d(){e?&d=d++++F:a} \ No newline at end of file From 933246d2ad5b7972a2886608142be3e69df3f530 Mon Sep 17 00:00:00 2001 From: Paul Fultz II Date: Tue, 4 Aug 2026 10:08:26 -0500 Subject: [PATCH 143/165] Add unit tests for cppcheckdata.py (#8707) This adds unit tests for cppcheckdata.py which runs with pytest. It will also run these tests with cmake automatically if python is available, so this should run on the CI. The unit tests did surface a couple of problems, but I didnt fix it this PR to keep the scope smaller. Instead I just marked the test with `pytest.mark.xfail` for now. I can do a follow up PR to fix these issues: 1. `Token.isBoolean` is dead code. `Tokenizer::dump` (lib/tokenize.cpp:6179) checks `tok->isName()` before `isBoolean()`, and `eBoolean` tokens count as names (lib/token.h:397), so true/false are always dumped as `type="name"` and the `type="boolean"` branch at tokenize.cpp:6199 is unreachable for them(I see there is `TODO: "true"/"false" aren't really a name...`) 2. Line suppressions match every line. The final "other suppression" fallback in `Suppression.isMatch()` (cppcheckdata.py:1007) doesn't check that `lineNumber` is unset, so a suppression for line 5 also matches line 6. The fix would be a one-line `self.lineNumber is None` guard. 3. In C++ `Token::Match`, `!!x` also matches when there is no token at all (null), but Python `match()` fails when the token list ends: `match(last_brace, '} !!x')` returns false. --------- Co-authored-by: Your Name --- test/CMakeLists.txt | 2 + test/addon/CMakeLists.txt | 41 ++ test/addon/conftest.py | 201 +++++++ test/addon/requirements.txt | 1 + test/addon/test_cppcheckdata.py | 915 ++++++++++++++++++++++++++++++++ test/cli/performance_test.py | 2 +- 6 files changed, 1161 insertions(+), 1 deletion(-) create mode 100644 test/addon/CMakeLists.txt create mode 100644 test/addon/conftest.py create mode 100644 test/addon/requirements.txt create mode 100644 test/addon/test_cppcheckdata.py diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 14f3a8eac17..f1e59e17daf 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -47,6 +47,8 @@ if (BUILD_TESTING) if (REGISTER_TESTS) # CMAKE_MATCH_ usage for if (MATCHES) requires CMake 3.9 + add_subdirectory(addon) + find_package(Threads REQUIRED) include(ProcessorCount) ProcessorCount(N) diff --git a/test/addon/CMakeLists.txt b/test/addon/CMakeLists.txt new file mode 100644 index 00000000000..bb04afb6c51 --- /dev/null +++ b/test/addon/CMakeLists.txt @@ -0,0 +1,41 @@ +if (NOT Python_Interpreter_FOUND) + message(WARNING "Python interpreter not found - skipping addon tests.") + return() +endif() + +# creating a virtual environment needs the venv and ensurepip modules - some +# distributions ship them separately from the interpreter (e.g. the Debian/Ubuntu +# python3-venv package) +execute_process(COMMAND ${Python_EXECUTABLE} -c "import venv, ensurepip" + RESULT_VARIABLE PYTHON_VENV_RESULT + OUTPUT_QUIET + ERROR_QUIET) +if (NOT PYTHON_VENV_RESULT EQUAL 0) + message(WARNING "Python venv module not available (e.g. install the python3-venv package) - skipping addon tests.") + return() +endif() + +set(VENV_DIR ${CMAKE_CURRENT_BINARY_DIR}/venv) +if (WIN32) + set(VENV_PYTHON ${VENV_DIR}/Scripts/python.exe) +else() + set(VENV_PYTHON ${VENV_DIR}/bin/python) +endif() + +# fixture: create a virtual environment and install the python dependencies into it +add_test(NAME addon-venv-create + COMMAND ${Python_EXECUTABLE} -m venv ${VENV_DIR}) +set_tests_properties(addon-venv-create PROPERTIES + FIXTURES_SETUP addon-venv-dir) + +add_test(NAME addon-venv-install + COMMAND ${VENV_PYTHON} -m pip install -r ${CMAKE_CURRENT_SOURCE_DIR}/requirements.txt) +set_tests_properties(addon-venv-install PROPERTIES + FIXTURES_REQUIRED addon-venv-dir + FIXTURES_SETUP addon-venv + TIMEOUT 300) + +add_test(NAME addon-cppcheckdata + COMMAND ${VENV_PYTHON} -m pytest --cppcheck-binary=$ ${CMAKE_CURRENT_SOURCE_DIR}) +set_tests_properties(addon-cppcheckdata PROPERTIES + FIXTURES_REQUIRED addon-venv) diff --git a/test/addon/conftest.py b/test/addon/conftest.py new file mode 100644 index 00000000000..87012983951 --- /dev/null +++ b/test/addon/conftest.py @@ -0,0 +1,201 @@ +"""pytest configuration for the addon tests. + +The tests exercise addons/cppcheckdata.py against dump files that are +generated on the fly with the cppcheck binary given by --cppcheck-binary. +""" +import os +import shutil +import subprocess +import sys + +import pytest + +# Make 'import cppcheckdata' resolve to /addons/cppcheckdata.py +_ADDONS_DIR = os.path.normpath(os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', '..', 'addons')) +if _ADDONS_DIR not in sys.path: + sys.path.insert(0, _ADDONS_DIR) + + +def pytest_addoption(parser): + parser.addoption('--cppcheck-binary', + default='cppcheck', + help='path to the cppcheck binary used to generate dump files ' + '(default: cppcheck found in PATH)') + + +@pytest.fixture(scope='session') +def cppcheck_binary(request): + binary = request.config.getoption('--cppcheck-binary') + resolved = shutil.which(binary) + if resolved is None: + pytest.fail("cppcheck binary '%s' not found - point --cppcheck-binary at a cppcheck executable" % binary) + return os.path.abspath(resolved) + + +class DumpFactory: + """Runs 'cppcheck --dump' on a source snippet and parses the result.""" + + def __init__(self, binary, tmp_path_factory): + self.binary = binary + self.tmp_path_factory = tmp_path_factory + + def create(self, code, filename='test.c', extra_args=()): + """Write the code to a file, dump it and return the dump file path.""" + directory = self.tmp_path_factory.mktemp('cppcheckdata') + path = directory / filename + path.write_text(code) + cmd = [self.binary, '--dump', '--quiet', str(path)] + list(extra_args) + proc = subprocess.run(cmd, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + check=True, + universal_newlines=True) + assert proc.returncode == 0, \ + 'cppcheck failed with exit code %d:\n%s\n%s' % (proc.returncode, proc.stdout, proc.stderr) + return str(path) + '.dump' + + def parse(self, code, filename='test.c', extra_args=()): + """Write the code to a file, dump it and return the parsed CppcheckData.""" + import cppcheckdata + return cppcheckdata.parsedump(self.create(code, filename, extra_args)) + + +@pytest.fixture(scope='session') +def dump_factory(cppcheck_binary, tmp_path_factory): + return DumpFactory(cppcheck_binary, tmp_path_factory) + + +SAMPLE_C = """#define ANSWER 42 +static int add(int a, int b) +{ + return a + b; +} + +double half(double d) +{ + return d / 2.0; +} + +int main(void) +{ + int x = ANSWER; + int arr[10]; + arr[0] = add(x, 1); + int neg = -x; + return arr[0] + neg; +} +""" + +SAMPLE_CPP = """namespace ns { + int twice(int v) { return 2 * v; } +} + +class Shape { +public: + virtual ~Shape() {} + virtual double area() const = 0; +protected: + double mScale; +}; + +enum Color { RED, GREEN }; + +const int limit = 5; +bool flag = true; +const char *msg = "hello"; +char ch = 'x'; + +int run() +{ + Color color = RED; + if (flag && limit > 1) { + return ns::twice(21); + } + return static_cast(color); +} +""" + +MULTI_CFG_C = """typedef int myint; +typedef float myfloat; +#if defined(FOO) && FOO > 1 +int foo(void) { return 1; } +#endif +myint bar(void) { myint y = 3; return y; } +""" + +MATCH_C = """struct Point { + int x; + int y; +}; + +int calc(int a, int b) +{ + int bit_or = a | b; + int log_or = a || b; + int mod = a % b; + int mul = a * b; + int not_a = !a; + int neq = a != b; + int arr[3]; + arr[0] = a; + a += 1; + if (a > b) { + return a; + } + return calc(a, b); +} +""" + +MATCH_CPP = """class Widget {}; + +bool use(int i, int j) +{ + std::vector v; + bool less = i < j; + return less && v.empty(); +} +""" + + +@pytest.fixture(scope='session') +def sample_data(dump_factory): + """Parsed dump of the canonical C sample.""" + return dump_factory.parse(SAMPLE_C, filename='sample.c') + + +@pytest.fixture(scope='session') +def sample_cfg(sample_data): + cfgs = sample_data.configurations + assert len(cfgs) == 1 + return cfgs[0] + + +@pytest.fixture(scope='session') +def sample_cpp_data(dump_factory): + """Parsed dump of the canonical C++ sample.""" + return dump_factory.parse(SAMPLE_CPP, filename='sample.cpp') + + +@pytest.fixture(scope='session') +def sample_cpp_cfg(sample_cpp_data): + cfgs = sample_cpp_data.configurations + assert len(cfgs) == 1 + return cfgs[0] + + +@pytest.fixture(scope='session') +def multi_cfg_data(dump_factory): + """Parsed dump of a file with two preprocessor configurations.""" + return dump_factory.parse(MULTI_CFG_C, filename='multi.c') + + +@pytest.fixture(scope='session') +def match_cfg(dump_factory): + """Configuration of a C sample covering the match() pattern syntax.""" + return dump_factory.parse(MATCH_C, filename='match.c').configurations[0] + + +@pytest.fixture(scope='session') +def match_cpp_cfg(dump_factory): + """Configuration of a C++ sample with linked '<' tokens for match().""" + return dump_factory.parse(MATCH_CPP, filename='match.cpp').configurations[0] diff --git a/test/addon/requirements.txt b/test/addon/requirements.txt new file mode 100644 index 00000000000..e079f8a6038 --- /dev/null +++ b/test/addon/requirements.txt @@ -0,0 +1 @@ +pytest diff --git a/test/addon/test_cppcheckdata.py b/test/addon/test_cppcheckdata.py new file mode 100644 index 00000000000..0ff3f31a89d --- /dev/null +++ b/test/addon/test_cppcheckdata.py @@ -0,0 +1,915 @@ +"""Unit tests for addons/cppcheckdata.py + +Most tests parse dump files generated with the cppcheck binary +(see conftest.py); tests of pure helper classes construct the +objects directly from dicts (which provide the same .get() API +as the XML elements). +""" +import json +import sys + +import pytest + +import cppcheckdata + + +def find_tokens(cfg, token_str): + return [tok for tok in cfg.tokenlist if tok.str == token_str] + + +def find_token(cfg, token_str, skip=0): + tokens = find_tokens(cfg, token_str) + assert len(tokens) > skip, "token '%s' (skip=%d) not found" % (token_str, skip) + return tokens[skip] + + +def find_function(cfg, name): + for function in cfg.functions: + if function.name == name: + return function + assert False, "function '%s' not found" % name + + +def find_scope(cfg, scope_type, className=None): + for scope in cfg.scopes: + if scope.type == scope_type and (className is None or scope.className == className): + return scope + assert False, "scope '%s' not found" % scope_type + + +def find_variable(cfg, name): + for variable in cfg.variables: + if variable.nameToken and variable.nameToken.str == name: + return variable + assert False, "variable '%s' not found" % name + + +class TestCppcheckData: + def test_language(self, sample_data, sample_cpp_data): + assert sample_data.language == 'c' + assert sample_cpp_data.language == 'cpp' + + def test_platform(self, sample_data): + platform = sample_data.platform + assert platform.name + assert platform.char_bit == 8 + assert platform.short_bit >= 16 + assert platform.int_bit >= 16 + assert platform.long_bit >= 32 + assert platform.long_long_bit >= 64 + assert platform.pointer_bit > 0 + assert 'char_bit=8' in repr(platform) + + def test_files(self, sample_data): + assert len(sample_data.files) == 1 + assert sample_data.files[0].endswith('sample.c') + + def test_rawtokens(self, sample_data): + raw = sample_data.rawTokens + # the not yet preprocessed code contains the directive tokens + assert [tok.str for tok in raw[:4]] == ['#', 'define', 'ANSWER', '42'] + assert raw[-1].str == '}' + assert raw[0].file.endswith('sample.c') + assert raw[0].linenr == 1 + # next/previous chain + assert raw[0].previous is None + assert raw[-1].next is None + for i in range(len(raw) - 1): + assert raw[i].next is raw[i + 1] + assert raw[i + 1].previous is raw[i] + + def test_configurations(self, sample_data): + cfgs = sample_data.configurations + assert len(cfgs) == 1 + assert cfgs[0].name == '' + + def test_iterconfigurations(self, multi_cfg_data): + it = multi_cfg_data.iterconfigurations() + cfgs = list(it) + assert len(cfgs) == 2 + assert cfgs[0].name == '' + assert 'FOO' in cfgs[1].name + # 'foo()' is only tokenized in the FOO configuration + assert not find_tokens(cfgs[0], 'foo') + assert find_tokens(cfgs[1], 'foo') + + def test_standards(self, sample_cfg, sample_cpp_cfg): + assert sample_cfg.standards.c.startswith('c') + assert sample_cpp_cfg.standards.cpp.startswith('c++') + assert sample_cfg.standards.posix is False + assert 'c=' in repr(sample_cfg.standards) + + +class TestToken: + def test_tokenlist(self, sample_cfg): + code = ' '.join(tok.str for tok in sample_cfg.tokenlist) + assert 'static int add ( int a , int b )' in code + # the macro has been expanded + assert 'x = 42' in code + + def test_next_previous(self, sample_cfg): + tokens = sample_cfg.tokenlist + assert tokens[0].previous is None + assert tokens[-1].next is None + for i in range(len(tokens) - 1): + assert tokens[i].next is tokens[i + 1] + assert tokens[i + 1].previous is tokens[i] + + def test_location(self, sample_cfg): + tok = sample_cfg.tokenlist[0] + assert tok.str == 'static' + assert tok.file.endswith('sample.c') + assert tok.linenr == 2 + assert tok.column == 1 + + def test_link(self, sample_cfg): + parenthesis = find_token(sample_cfg, '(') + assert parenthesis.link.str == ')' + assert parenthesis.link.link is parenthesis + bracket = find_token(sample_cfg, '[') + assert bracket.link.str == ']' + brace = find_token(sample_cfg, '{') + assert brace.link.str == '}' + + def test_scope(self, sample_cfg): + assert sample_cfg.tokenlist[0].scope.type == 'Global' + return_tok = find_token(sample_cfg, 'return') + assert return_tok.scope.type == 'Function' + assert return_tok.scope.className == 'add' + + def test_name_number_flags(self, sample_cfg): + name_tok = find_token(sample_cfg, 'main') + assert name_tok.isName + assert not name_tok.isNumber + num_tok = find_token(sample_cfg, '42') + assert num_tok.isNumber + assert num_tok.isInt + assert not num_tok.isFloat + float_tok = find_token(sample_cfg, '2.0') + assert float_tok.isNumber + assert float_tok.isFloat + + def test_operator_flags(self, sample_cfg, sample_cpp_cfg): + plus = find_token(sample_cfg, '+') + assert plus.isOp + assert plus.isArithmeticalOp + assign = find_token(sample_cfg, '=') + assert assign.isOp + assert assign.isAssignmentOp + logical = find_token(sample_cpp_cfg, '&&') + assert logical.isOp + assert logical.isLogicalOp + comparison = find_token(sample_cpp_cfg, '>') + assert comparison.isOp + assert comparison.isComparisonOp + + def test_string_char(self, sample_cpp_cfg): + string_tok = find_token(sample_cpp_cfg, '"hello"') + assert string_tok.isString + assert string_tok.strlen == 5 + char_tok = find_token(sample_cpp_cfg, "'x'") + assert char_tok.isChar + + @pytest.mark.xfail(strict=False, + reason='Tokenizer::dump checks Token::isName() before Token::isBoolean() and ' + 'eBoolean tokens are names, so type="boolean" is never dumped') + def test_boolean(self, sample_cpp_cfg): + bool_tok = find_token(sample_cpp_cfg, 'true') + assert bool_tok.isBoolean + + def test_cast(self, sample_cpp_cfg): + # static_cast(...) is simplified to a C-style cast + assert any(tok.isCast for tok in sample_cpp_cfg.tokenlist) + + def test_macro_expansion(self, sample_cfg): + tok = find_token(sample_cfg, '42') + assert tok.isExpandedMacro + assert tok.macroName == 'ANSWER' + + def test_removed_void_parameter(self, sample_cfg): + main_tok = find_token(sample_cfg, 'main') + assert main_tok.next.isRemovedVoidParameter + + def test_splitted_var_decl(self, sample_cfg): + # 'int x = ANSWER;' is simplified to 'int x ; x = 42 ;' + assert any(tok.isSplittedVarDeclEq for tok in sample_cfg.tokenlist) + + def test_variable_and_var_id(self, sample_cfg): + x_decl = find_token(sample_cfg, 'x') + assert x_decl.varId + assert x_decl.variable.nameToken is x_decl + # all 'x' tokens refer to the same variable and varId + for tok in find_tokens(sample_cfg, 'x'): + assert tok.varId == x_decl.varId + assert tok.variable is x_decl.variable + + def test_function(self, sample_cfg): + add_call = find_token(sample_cfg, 'add', skip=1) + assert add_call.function + assert add_call.function.name == 'add' + + def test_value_type(self, sample_cfg): + x_tok = find_token(sample_cfg, 'x') + assert x_tok.valueType.type == 'int' + assert x_tok.valueType.sign == 'signed' + assert x_tok.valueType.pointer == 0 + assert x_tok.valueType.isIntegral() + assert not x_tok.valueType.isFloat() + assert not x_tok.valueType.isEnum() + d_tok = find_token(sample_cfg, 'd') + assert d_tok.valueType.type == 'double' + assert d_tok.valueType.isFloat() + # in 'arr[0] = ...' the array decays to a pointer + arr_use = find_token(sample_cfg, 'arr', skip=1) + assert arr_use.valueType.pointer == 1 + + def test_value_type_enum(self, sample_cpp_cfg): + color_tok = find_token(sample_cpp_cfg, 'color') + assert color_tok.valueType.isEnum() + assert color_tok.valueType.typeScope.className == 'Color' + + def test_ast(self, sample_cfg): + plus = find_token(sample_cfg, '+') + assert plus.astOperand1.str == 'a' + assert plus.astOperand2.str == 'b' + assert plus.astParent.str == 'return' + assert plus.isBinaryOp() + assert not plus.isUnaryOp('+') + + def test_ast_unary_op(self, sample_cfg): + # the '-' in 'int neg = -x;' + minus = find_token(sample_cfg, '-') + assert minus.isUnaryOp('-') + assert not minus.isBinaryOp() + assert minus.astOperand1.str == 'x' + assert minus.astOperand2 is None + + def test_ast_parents_top(self, sample_cfg): + a_tok = find_token(sample_cfg, 'a', skip=1) # the 'a' in 'return a + b;' + assert [tok.str for tok in a_tok.astParents()] == ['+', 'return'] + assert a_tok.astTop().str == 'return' + + def test_values(self, sample_cfg): + # 'x' has the known value 42 when it is used + x_use = find_token(sample_cfg, 'x', skip=2) + assert x_use.getKnownIntValue() == 42 + value = x_use.getValue(42) + assert value.intvalue == 42 + assert value.isKnown() + assert not value.isPossible() + assert x_use.getValue(43) is None + assert 'intvalue=42' in repr(value) + + def test_values_possible(self, sample_cfg): + # inside add() the argument 'a' has the possible value 42 + a_use = find_token(sample_cfg, 'a', skip=1) + assert a_use.getKnownIntValue() is None + value = a_use.getValue(42) + assert value is not None + assert value.isPossible() + + def test_impossible_values(self, sample_cfg): + # impossible values are separated from the possible/known ones + arr_tokens = find_tokens(sample_cfg, 'arr') + impossible = [v for tok in arr_tokens for v in tok.impossible_values] + assert impossible + assert all(v.isImpossible() for v in impossible) + possible_or_known = [v for tok in arr_tokens for v in tok.values] + assert all(not v.isImpossible() for v in possible_or_known) + + def test_forward_backward(self, sample_cfg): + add_def = find_token(sample_cfg, 'add') + strs = [tok.str for tok in add_def.forward()] + assert strs[:4] == ['add', '(', 'int', 'a'] + end = add_def.tokAt(2) + assert [tok.str for tok in add_def.forward(end=end)] == ['add', '('] + strs = [tok.str for tok in add_def.backward()] + assert strs[:3] == ['add', 'int', 'static'] + start = sample_cfg.tokenlist[0] + assert [tok.str for tok in add_def.backward(start=start)] == ['add', 'int'] + + def test_tokAt_linkAt(self, sample_cfg): + add_def = find_token(sample_cfg, 'add') + assert add_def.tokAt(0) is add_def + assert add_def.tokAt(1).str == '(' + assert add_def.tokAt(-1).str == 'int' + assert add_def.linkAt(1).str == ')' + + def test_repr(self, sample_cfg): + tok = sample_cfg.tokenlist[0] + assert "str='static'" in repr(tok) + + +class TestScope: + def test_scopes(self, sample_cfg): + types = [scope.type for scope in sample_cfg.scopes] + assert types.count('Global') == 1 + assert types.count('Function') == 3 + + def test_global_scope(self, sample_cfg): + global_scope = find_scope(sample_cfg, 'Global') + assert global_scope.nestedIn is None + assert not global_scope.isExecutable + assert len(global_scope.nestedList) == 3 + + def test_function_scope(self, sample_cfg): + scope = find_scope(sample_cfg, 'Function', className='add') + assert scope.bodyStart.str == '{' + assert scope.bodyEnd.str == '}' + assert scope.bodyStart.link is scope.bodyEnd + assert scope.nestedIn.type == 'Global' + assert scope.function.name == 'add' + assert scope.isExecutable + + def test_varlist(self, sample_cfg): + scope = find_scope(sample_cfg, 'Function', className='main') + names = [var.nameToken.str for var in scope.varlist] + assert names == ['x', 'arr', 'neg'] + + def test_cpp_scopes(self, sample_cpp_cfg): + types = {scope.type for scope in sample_cpp_cfg.scopes} + assert {'Global', 'Namespace', 'Class', 'Enum', 'Function', 'If'} <= types + assert find_scope(sample_cpp_cfg, 'Namespace', className='ns') + assert find_scope(sample_cpp_cfg, 'Class', className='Shape') + if_scope = find_scope(sample_cpp_cfg, 'If') + assert if_scope.isExecutable + class_scope = find_scope(sample_cpp_cfg, 'Class') + assert not class_scope.isExecutable + + +class TestFunction: + def test_functions(self, sample_cfg): + names = {function.name for function in sample_cfg.functions} + assert names == {'add', 'half', 'main'} + + def test_arguments(self, sample_cfg): + add = find_function(sample_cfg, 'add') + assert sorted(add.argument.keys()) == [1, 2] + assert add.argument[1].nameToken.str == 'a' + assert add.argument[2].nameToken.str == 'b' + main = find_function(sample_cfg, 'main') + assert main.argument == {} + + def test_attributes(self, sample_cfg): + add = find_function(sample_cfg, 'add') + assert add.isStatic + assert add.type == 'Function' + assert add.tokenDef.str == 'add' + assert add.token.str == 'add' + assert add.nestedIn.type == 'Global' + main = find_function(sample_cfg, 'main') + assert not main.isStatic + + def test_virtual(self, sample_cpp_cfg): + area = find_function(sample_cpp_cfg, 'area') + assert area.hasVirtualSpecifier + twice = find_function(sample_cpp_cfg, 'twice') + assert not twice.hasVirtualSpecifier + assert twice.nestedIn.className == 'ns' + + +class TestVariable: + def test_local(self, sample_cfg): + x = find_variable(sample_cfg, 'x') + assert x.access == 'Local' + assert x.isLocal + assert not x.isArgument + assert not x.isGlobal + assert not x.isArray + assert x.typeStartToken.str == 'int' + assert x.typeEndToken.str == 'int' + assert x.scope.className == 'main' + + def test_argument(self, sample_cfg): + a = find_variable(sample_cfg, 'a') + assert a.access == 'Argument' + assert a.isArgument + assert not a.isLocal + + def test_array(self, sample_cfg): + arr = find_variable(sample_cfg, 'arr') + assert arr.isArray + assert not arr.isPointer + + def test_global_const(self, sample_cpp_cfg): + limit = find_variable(sample_cpp_cfg, 'limit') + assert limit.access == 'Global' + assert limit.isGlobal + assert limit.isConst + assert not limit.isStatic + + def test_pointer(self, sample_cpp_cfg): + msg = find_variable(sample_cpp_cfg, 'msg') + assert msg.isPointer + assert not msg.isArray + + def test_class_member(self, sample_cpp_cfg): + member = find_variable(sample_cpp_cfg, 'mScale') + assert member.access == 'Protected' + assert member.isClass is False + + +class TestPreprocessor: + def test_directives(self, sample_cfg): + directives = sample_cfg.directives + assert len(directives) == 1 + assert directives[0].str == '#define ANSWER 42' + assert directives[0].file.endswith('sample.c') + assert directives[0].linenr == 1 + assert "#define ANSWER 42" in repr(directives[0]) + + def test_macro_usage(self, sample_cfg): + macros = sample_cfg.macro_usage + assert len(macros) == 1 + macro = macros[0] + assert macro.name == 'ANSWER' + assert macro.usefile.endswith('sample.c') + assert int(macro.useline) == 14 + assert macro.isKnownValue + assert "name='ANSWER'" in repr(macro) + + def test_if_conditions(self, multi_cfg_data): + cfgs = multi_cfg_data.configurations + for cfg in cfgs: + assert len(cfg.preprocessor_if_conditions) == 1 + assert cfg.preprocessor_if_conditions[0].linenr == 3 + assert cfgs[0].preprocessor_if_conditions[0].result == 0 + assert cfgs[1].preprocessor_if_conditions[0].result == 1 + assert 'result=' in repr(cfgs[0].preprocessor_if_conditions[0]) + + def test_typedef_info(self, multi_cfg_data): + cfg = multi_cfg_data.configurations[0] + typedefs = {info.name: info for info in cfg.typedefInfo} + assert set(typedefs.keys()) == {'myint', 'myfloat'} + assert typedefs['myint'].used + assert not typedefs['myfloat'].used + assert typedefs['myint'].linenr == 1 + + +class TestHelperFunctions: + def test_getArguments(self, sample_cfg): + add_call = find_token(sample_cfg, 'add', skip=1) + args = cppcheckdata.getArguments(add_call) + assert [tok.str for tok in args] == ['x', '1'] + + def test_getArguments_no_call(self, sample_cfg): + int_tok = find_token(sample_cfg, 'int') + assert cppcheckdata.getArguments(int_tok) is None + + def test_get_function_call_name_args(self, sample_cfg): + add_call = find_token(sample_cfg, 'add', skip=1) + name, args = cppcheckdata.get_function_call_name_args(add_call) + assert name == 'add' + assert [tok.str for tok in args] == ['x', '1'] + + def test_get_function_call_name_args_namespace(self, sample_cpp_cfg): + twice_call = find_token(sample_cpp_cfg, 'twice', skip=1) + name, args = cppcheckdata.get_function_call_name_args(twice_call) + assert name == 'ns::twice' + assert [tok.str for tok in args] == ['21'] + + def test_get_function_call_name_args_not_a_call(self, sample_cfg): + # the function definition is not a call + add_def = find_token(sample_cfg, 'add') + name, args = cppcheckdata.get_function_call_name_args(add_def) + assert name is None + assert args is None + + def test_astIsFloat(self, sample_cfg): + division = find_token(sample_cfg, '/') + assert cppcheckdata.astIsFloat(division) + plus = find_token(sample_cfg, '+') # a + b with int operands + assert not cppcheckdata.astIsFloat(plus) + assert not cppcheckdata.astIsFloat(None) + + +class TestMatch: + """Tests for the cppcheckdata.match()/simpleMatch() pattern matching.""" + + def test_simpleMatch(self, match_cfg): + calc_def = find_token(match_cfg, 'calc') + assert cppcheckdata.simpleMatch(calc_def, 'calc') + assert cppcheckdata.simpleMatch(calc_def, 'calc ( int a , int b )') + assert not cppcheckdata.simpleMatch(calc_def, 'calc ( int b') + assert not cppcheckdata.simpleMatch(None, 'calc') + + def test_literal_sequence(self, match_cfg): + calc_def = find_token(match_cfg, 'calc') + assert cppcheckdata.match(calc_def, 'calc ( int') + assert cppcheckdata.match(calc_def, 'calc ( int a , int b )') + assert not cppcheckdata.match(calc_def, 'calc ( char') + # the match is anchored at the given token + assert not cppcheckdata.match(calc_def, 'int calc') + + def test_empty_pattern_and_no_token(self, match_cfg): + calc_def = find_token(match_cfg, 'calc') + assert not cppcheckdata.match(calc_def, '') + assert not cppcheckdata.match(None, 'calc') + + def test_end(self, match_cfg): + calc_def = find_token(match_cfg, 'calc') + res = cppcheckdata.match(calc_def, 'calc') + assert res.end is calc_def + res = cppcheckdata.match(calc_def, 'calc ( int') + assert res.end.str == 'int' + + # ---- literal operator tokens ---- + + def test_literal_bitwise_or(self, match_cfg): + # a literal '|' in the pattern matches a '|' token ... + bit_or = find_token(match_cfg, '|') + assert cppcheckdata.match(bit_or, '|') + assert cppcheckdata.match(bit_or.previous, '%var% | %var% ;') + # ... but not a '||' token, and it is not an either-or alternation + log_or = find_token(match_cfg, '||') + assert not cppcheckdata.match(log_or, '|') + + def test_literal_logical_or(self, match_cfg): + log_or = find_token(match_cfg, '||') + assert cppcheckdata.match(log_or, '||') + assert cppcheckdata.match(log_or.previous, '%var% || %var% ;') + bit_or = find_token(match_cfg, '|') + assert not cppcheckdata.match(bit_or, '||') + + def test_literal_not(self, match_cfg): + not_tok = find_token(match_cfg, '!') + assert cppcheckdata.match(not_tok, '! %var% ;') + assert not cppcheckdata.match(find_token(match_cfg, '!='), '!') + + def test_literal_not_equal(self, match_cfg): + neq = find_token(match_cfg, '!=') + assert cppcheckdata.match(neq, '!=') + assert cppcheckdata.match(neq.previous, '%var% != %var% ;') + assert not cppcheckdata.match(find_token(match_cfg, '='), '!=') + assert not cppcheckdata.match(neq, '=') + + def test_literal_star(self, match_cfg): + mul = find_token(match_cfg, '*') + assert cppcheckdata.match(mul, '*') + assert cppcheckdata.match(mul.previous, '%var% * %var% ;') + + def test_literal_percent(self, match_cfg): + mod = find_token(match_cfg, '%') + assert cppcheckdata.match(mod, '%') + assert cppcheckdata.match(mod.previous, '%var% % %var% ;') + + def test_literal_parentheses(self, match_cfg): + calc_call = find_token(match_cfg, 'calc', skip=1) + assert cppcheckdata.match(calc_call, 'calc ( %var% , %var% ) ;') + + # ---- %keyword% patterns ---- + + def test_any(self, match_cfg): + for token_str in ('calc', '(', '3', ';', '|', '{'): + assert cppcheckdata.match(find_token(match_cfg, token_str), '%any%') + plus_assign = find_token(match_cfg, '+=') + assert cppcheckdata.match(plus_assign, '%assign% %any% ;') + + def test_assign(self, match_cfg): + assert cppcheckdata.match(find_token(match_cfg, '='), '%assign%') + assert cppcheckdata.match(find_token(match_cfg, '+='), '%assign%') + assert not cppcheckdata.match(find_token(match_cfg, '!='), '%assign%') + assert not cppcheckdata.match(find_token(match_cfg, '|'), '%assign%') + + def test_comp(self, match_cfg): + assert cppcheckdata.match(find_token(match_cfg, '>'), '%comp%') + assert cppcheckdata.match(find_token(match_cfg, '!='), '%comp%') + assert not cppcheckdata.match(find_token(match_cfg, '='), '%comp%') + assert not cppcheckdata.match(find_token(match_cfg, '|'), '%comp%') + + def test_name(self, match_cfg): + assert cppcheckdata.match(find_token(match_cfg, 'calc'), '%name%') + assert cppcheckdata.match(find_token(match_cfg, 'int'), '%name%') + assert not cppcheckdata.match(find_token(match_cfg, '3'), '%name%') + assert not cppcheckdata.match(find_token(match_cfg, '('), '%name%') + + def test_op(self, match_cfg): + for op in ('|', '||', '*', '%', '!=', '>', '=', '+='): + assert cppcheckdata.match(find_token(match_cfg, op), '%op%'), op + assert not cppcheckdata.match(find_token(match_cfg, ';'), '%op%') + assert not cppcheckdata.match(find_token(match_cfg, 'calc'), '%op%') + + def test_or(self, match_cfg): + assert cppcheckdata.match(find_token(match_cfg, '|'), '%or%') + assert not cppcheckdata.match(find_token(match_cfg, '||'), '%or%') + + def test_oror(self, match_cfg): + assert cppcheckdata.match(find_token(match_cfg, '||'), '%oror%') + assert not cppcheckdata.match(find_token(match_cfg, '|'), '%oror%') + + def test_var(self, match_cfg): + a_use = find_token(match_cfg, 'a', skip=1) + assert cppcheckdata.match(a_use, '%var%') + # a function name is a %name% but not a %var% + assert not cppcheckdata.match(find_token(match_cfg, 'calc'), '%var%') + assert not cppcheckdata.match(find_token(match_cfg, '3'), '%var%') + + # ---- link patterns ---- + + def test_link_parentheses(self, match_cfg): + calc_call = find_token(match_cfg, 'calc', skip=1) + res = cppcheckdata.match(calc_call.next, '(*)') + assert res + assert res.end.str == ')' + assert res.end is calc_call.next.link + # the pattern continues after the linked token + assert cppcheckdata.match(calc_call, '%name% (*) ;') + # '(*)' only matches at a '(' token + assert not cppcheckdata.match(calc_call, '(*)') + + def test_link_brackets(self, match_cfg): + arr_decl = find_token(match_cfg, 'arr') + assert cppcheckdata.match(arr_decl, 'arr [*] ;') + arr_use = find_token(match_cfg, 'arr', skip=1) + res = cppcheckdata.match(arr_use, '%name% [*] %assign% %var% ;') + assert res + + def test_link_braces(self, match_cfg): + if_scope = find_scope(match_cfg, 'If') + res = cppcheckdata.match(if_scope.bodyStart, '{*}') + assert res + assert res.end is if_scope.bodyEnd + + def test_link_combined(self, match_cfg): + if_tok = find_token(match_cfg, 'if') + res = cppcheckdata.match(if_tok, 'if (*) {*}') + assert res + assert res.end.str == '}' + + def test_link_angle_brackets(self, match_cpp_cfg): + # the '<' of 'std::vector' is linked to the '>' + template_lt = find_token(match_cpp_cfg, '<') + assert template_lt.link + res = cppcheckdata.match(template_lt, '<*>') + assert res + assert res.end.str == '>' + assert cppcheckdata.match(template_lt.previous, 'vector <*> %var%') + # the '<' in 'i < j' is a comparison without a link + comparison_lt = find_token(match_cpp_cfg, '<', skip=1) + assert comparison_lt.link is None + assert not cppcheckdata.match(comparison_lt, '<*>') + + # ---- either-or alternation ---- + + def test_alternatives(self, match_cfg): + struct_tok = find_token(match_cfg, 'struct') + assert cppcheckdata.match(struct_tok, 'struct|class %name% {') + assert not cppcheckdata.match(struct_tok, 'union|enum %name% {') + + def test_alternatives_cpp(self, match_cpp_cfg): + class_tok = find_token(match_cpp_cfg, 'class') + assert cppcheckdata.match(class_tok, 'struct|class %name% {') + + def test_alternatives_with_keyword(self, match_cfg): + struct_tok = find_token(match_cfg, 'struct') + assert cppcheckdata.match(struct_tok, '%op%|struct') + assert not cppcheckdata.match(struct_tok, '%op%|%comp%') + + # ---- negation ---- + + def test_negation(self, match_cfg): + struct_tok = find_token(match_cfg, 'struct') + assert cppcheckdata.match(struct_tok, 'struct !!;') + assert not cppcheckdata.match(struct_tok, 'struct !!Point') + + def test_negation_keyword(self, match_cfg): + calc_call = find_token(match_cfg, 'calc', skip=1) + assert cppcheckdata.match(calc_call, '%name% !!%op%') + assert not cppcheckdata.match(calc_call, '%name% !!(') + + @pytest.mark.xfail(strict=False, + reason='in the C++ Token::Match a negation also matches when there is no token, ' + 'in match() it does not') + def test_negation_no_token(self, match_cfg): + last = match_cfg.tokenlist[-1] + assert last.str == '}' + assert cppcheckdata.match(last, '} !!x') + + # ---- bindings ---- + + def test_bindings(self, match_cfg): + calc_call = find_token(match_cfg, 'calc', skip=1) + res = cppcheckdata.match(calc_call, '%name%@ftok (*)') + assert res + assert res.ftok is calc_call + assert res.ftok.str == 'calc' + assert res.end.str == ')' + + def test_multiple_bindings(self, match_cfg): + bit_or_lhs = find_token(match_cfg, 'bit_or', skip=1) + res = cppcheckdata.match(bit_or_lhs, '%var%@lhs = %var%@op1 | %var%@op2 ;') + assert res + assert res.lhs.str == 'bit_or' + assert res.op1.str == 'a' + assert res.op2.str == 'b' + + def test_binding_on_link_pattern(self, match_cfg): + calc_call = find_token(match_cfg, 'calc', skip=1) + # the binding is the '(' token, end is behind the linked ')' + res = cppcheckdata.match(calc_call, '%name% (*)@paren') + assert res + assert res.paren.str == '(' + assert res.paren.link is res.end + + def test_bindings_on_failure(self, match_cfg): + calc_call = find_token(match_cfg, 'calc', skip=1) + res = cppcheckdata.match(calc_call, '%name%@ftok [*]@brackets') + assert not res + # all bindings (including 'end') read as None on a failed match + assert res.ftok is None + assert res.brackets is None + assert res.end is None + + def test_unknown_binding_raises(self, match_cfg): + calc_call = find_token(match_cfg, 'calc', skip=1) + res = cppcheckdata.match(calc_call, '%name%@ftok (*)') + assert res + with pytest.raises(AttributeError): + res.nosuchbinding # pylint: disable=W0104 + res = cppcheckdata.match(calc_call, '%name%@ftok [*]') + assert not res + with pytest.raises(AttributeError): + res.nosuchbinding # pylint: disable=W0104 + + # ---- '**' forward search ---- + + def test_find_forward(self, match_cfg): + calc_def = find_token(match_cfg, 'calc') + # '**' searches forward, skipping linked groups: the '{' found here + # is the function body, not a '{' inside the parameter list + res = cppcheckdata.match(calc_def, 'calc **{') + assert res + assert res.end.str == '{' + assert not cppcheckdata.match(calc_def, 'calc **nosuchtoken') + + +class TestSuppressions: + def make_suppression(self, **kwargs): + return cppcheckdata.Suppression(kwargs) + + def test_line_suppression(self): + supp = self.make_suppression(errorId='zerodiv', lineNumber='5') + assert supp.isMatch('a.c', '5', 'msg', 'zerodiv') + assert not supp.isMatch('a.c', '5', 'msg', 'nullPointer') + + @pytest.mark.xfail(strict=False, + reason='the "other suppression" fallback in Suppression.isMatch() does not check ' + 'that lineNumber is unset, so a line suppression matches every line') + def test_line_suppression_other_line(self): + supp = self.make_suppression(errorId='zerodiv', lineNumber='5') + assert not supp.isMatch('a.c', '6', 'msg', 'zerodiv') + + def test_wildcard_errorId(self): + supp = self.make_suppression(errorId='*', lineNumber='5') + assert supp.isMatch('a.c', '5', 'msg', 'anything') + + def test_file_suppression(self): + supp = self.make_suppression(errorId='zerodiv', fileName='a.c', type='file') + assert supp.isMatch('a.c', '1', 'msg', 'zerodiv') + assert supp.isMatch('a.c', '99', 'msg', 'zerodiv') + assert not supp.isMatch('b.c', '1', 'msg', 'zerodiv') + + def test_block_suppression(self): + supp = self.make_suppression(errorId='zerodiv', type='block', lineBegin='3', lineEnd='7') + assert supp.isMatch('a.c', '5', 'msg', 'zerodiv') + assert not supp.isMatch('a.c', '3', 'msg', 'zerodiv') + assert not supp.isMatch('a.c', '7', 'msg', 'zerodiv') + + def test_global_suppression(self): + supp = self.make_suppression(errorId='zerodiv') + assert supp.isMatch('a.c', '1', 'msg', 'zerodiv') + assert supp.isMatch('b.c', '99', 'other', 'zerodiv') + + def test_symbolName(self): + supp = self.make_suppression(errorId='zerodiv', symbolName='xyz') + assert supp.isMatch('a.c', '1', 'error on xyz here', 'zerodiv') + assert not supp.isMatch('a.c', '1', 'other message', 'zerodiv') + + def test_dumpfile_suppressions(self, dump_factory): + code = ('void f(void)\n' + '{\n' + ' int a;\n' + ' // cppcheck-suppress uninitvar\n' + ' a++;\n' + '}\n') + data = dump_factory.parse(code, extra_args=['--inline-suppr']) + assert len(data.suppressions) == 1 + supp = data.suppressions[0] + assert supp.errorId == 'uninitvar' + assert supp.fileName.endswith('test.c') + assert int(supp.lineNumber) == 5 + # parsedump() also sets the suppressions used by is_suppressed() + location = cppcheckdata.Location({'file': supp.fileName, 'line': '5', 'column': '5'}) + assert cppcheckdata.is_suppressed(location, 'msg', 'uninitvar') + assert not cppcheckdata.is_suppressed(location, 'msg', 'nullPointer') + # NOTE: a non-matching line is not checked here - see test_line_suppression_other_line + + +class TestPureHelpers: + """Tests that construct objects from dicts and do not need a dump file.""" + + def test_location(self): + loc = cppcheckdata.Location({'file': 'a.c', 'line': '3', 'column': '7'}) + assert loc.file == 'a.c' + assert loc.linenr == 3 + assert loc.column == 7 + + def test_location_defaults(self): + loc = cppcheckdata.Location({'file': 'a.c'}) + assert loc.linenr == 0 + assert loc.column == 0 + + def test_location_linenr_alias(self): + loc = cppcheckdata.Location({'file': 'a.c', 'linenr': '4'}) + assert loc.linenr == 4 + + def test_value_kinds(self): + known = cppcheckdata.Value({'intvalue': '42', 'known': 'true'}) + assert known.intvalue == 42 + assert known.isKnown() + assert not known.isPossible() + possible = cppcheckdata.Value({'intvalue': '1', 'possible': 'true'}) + assert possible.isPossible() + impossible = cppcheckdata.Value({'intvalue': '0', 'impossible': 'true'}) + assert impossible.isImpossible() + inconclusive = cppcheckdata.Value({'intvalue': '2', 'inconclusive': 'true'}) + assert inconclusive.isInconclusive() + + def test_value_condition(self): + value = cppcheckdata.Value({'intvalue': '1', 'possible': 'true', 'condition-line': '12'}) + assert value.condition == 12 + + def test_argument_parser(self): + parser = cppcheckdata.ArgumentParser() + args = parser.parse_args(['a.dump', 'b.ctu-info', '--cli', '-q']) + assert args.dumpfile == ['a.dump', 'b.ctu-info'] + assert args.cli + assert args.quiet + assert args.file_list is None + assert '{severity}' in args.template + + def test_get_files(self, tmp_path): + file_list = tmp_path / 'files.txt' + file_list.write_text('c.dump\nd.ctu-info\n') + parser = cppcheckdata.ArgumentParser() + args = parser.parse_args(['a.dump', 'b.ctu-info', '--file-list', str(file_list)]) + dump_files, ctu_info_files = cppcheckdata.get_files(args) + assert dump_files == ['a.dump', 'c.dump'] + assert ctu_info_files == ['b.ctu-info', 'd.ctu-info'] + + +class TestReporting: + def test_reportError_cli(self, monkeypatch, capsys): + monkeypatch.setattr(sys, 'argv', ['myaddon.py', '--cli']) + location = cppcheckdata.Location({'file': 'a.c', 'line': '3', 'column': '7'}) + cppcheckdata.reportError(location, 'error', 'the message', 'myaddon', 'myid', extra='extra info') + msg = json.loads(capsys.readouterr().out) + assert msg == {'file': 'a.c', + 'linenr': 3, + 'column': 7, + 'severity': 'error', + 'message': 'the message', + 'addon': 'myaddon', + 'errorId': 'myid', + 'extra': 'extra info'} + + def test_reportError_cli_column_override(self, monkeypatch, capsys): + monkeypatch.setattr(sys, 'argv', ['myaddon.py', '--cli']) + location = cppcheckdata.Location({'file': 'a.c', 'line': '3', 'column': '7'}) + cppcheckdata.reportError(location, 'error', 'the message', 'myaddon', 'myid', columnOverride=42) + msg = json.loads(capsys.readouterr().out) + assert msg['column'] == 42 + + def test_reportError_stderr(self, monkeypatch, capsys): + monkeypatch.setattr(sys, 'argv', ['myaddon.py']) + monkeypatch.setattr(cppcheckdata, 'current_dumpfile_suppressions', []) + monkeypatch.setattr(cppcheckdata, 'EXIT_CODE', 0) + location = cppcheckdata.Location({'file': 'a.c', 'line': '3', 'column': '7'}) + cppcheckdata.reportError(location, 'style', 'the message', 'myaddon', 'myid') + stderr = capsys.readouterr().err + assert stderr == '[a.c:3] (style) the message [myaddon-myid]\n' + assert cppcheckdata.EXIT_CODE == 1 + + def test_reportError_stderr_suppressed(self, monkeypatch, capsys): + monkeypatch.setattr(sys, 'argv', ['myaddon.py']) + suppression = cppcheckdata.Suppression({'errorId': 'myaddon-myid'}) + monkeypatch.setattr(cppcheckdata, 'current_dumpfile_suppressions', [suppression]) + monkeypatch.setattr(cppcheckdata, 'EXIT_CODE', 0) + location = cppcheckdata.Location({'file': 'a.c', 'line': '3', 'column': '7'}) + cppcheckdata.reportError(location, 'style', 'the message', 'myaddon', 'myid') + assert capsys.readouterr().err == '' + assert cppcheckdata.EXIT_CODE == 0 + + def test_log_checker_cli(self, monkeypatch, capsys): + monkeypatch.setattr(sys, 'argv', ['myaddon.py', '--cli']) + cppcheckdata.log_checker('SomeChecker', 'myaddon') + msg = json.loads(capsys.readouterr().out) + assert msg == {'addon': 'myaddon', + 'severity': 'none', + 'message': 'SomeChecker', + 'errorId': 'logChecker'} + + def test_log_checker_no_cli(self, monkeypatch, capsys): + monkeypatch.setattr(sys, 'argv', ['myaddon.py']) + cppcheckdata.log_checker('SomeChecker', 'myaddon') + assert capsys.readouterr().out == '' diff --git a/test/cli/performance_test.py b/test/cli/performance_test.py index 5be958619fc..67ec3be09f6 100644 --- a/test/cli/performance_test.py +++ b/test/cli/performance_test.py @@ -268,7 +268,7 @@ def test_crash_array_in_namespace(tmpdir): @pytest.mark.skipif(sys.platform == 'darwin', reason='GitHub macOS runners are too slow') -@pytest.mark.timeout(20) +@pytest.mark.timeout(30) def test_crash_array_in_array(tmpdir): # 12861 filename = os.path.join(tmpdir, 'hang.cpp') From 569f3d6a38aa3afadc2e4791c0fce939a3ee379d Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Tue, 4 Aug 2026 18:14:48 +0200 Subject: [PATCH 144/165] Fix #14952 Stack overflow in ValueFlow::isLifetimeBorrowed() (#8770) --- lib/token.cpp | 1 + lib/valueflow.cpp | 2 +- test/testvalueflow.cpp | 11 +++++++++++ 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/lib/token.cpp b/lib/token.cpp index d8b438c5073..eac69decee7 100644 --- a/lib/token.cpp +++ b/lib/token.cpp @@ -2433,6 +2433,7 @@ std::pair Token::typeDecl(const Token* tok, bool poi varTok = varTok->next(); while (Token::Match(varTok, "%name% ::")) varTok = varTok->tokAt(2); + assert(varTok != tok); std::pair r = typeDecl(varTok); if (r.first) return r; diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index 29eb07bcc90..5efe698bf61 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -3146,7 +3146,7 @@ static void valueFlowLifetime(TokenList &tokenlist, ErrorLogger &errorLogger, co valueFlowLifetimeConstructor(tok->next(), tokenlist, errorLogger, settings); } // Check function calls - else if (Token::Match(tok, "%name% (") && !Token::simpleMatch(tok->linkAt(1), ") {")) { + else if (tok->scope()->isExecutable() && Token::Match(tok, "%name% (")) { valueFlowLifetimeFunction(tok, tokenlist, errorLogger, settings); } // Unique pointer lifetimes diff --git a/test/testvalueflow.cpp b/test/testvalueflow.cpp index f92ddee3685..945555b1b3c 100644 --- a/test/testvalueflow.cpp +++ b/test/testvalueflow.cpp @@ -8481,6 +8481,17 @@ class TestValueFlow : public TestFixture { " auto b = a;\n" "}\n"; (void)valueOfTok(code, "b"); + + code = "namespace O {}\n" // #14952 + "namespace N {\n" + " using namespace O;\n" + " enum class E { E0 };\n" + " auto E0 = E::E0;\n" + " struct S {\n" + " E f() const { return E0; }\n" + " };\n" + "}\n"; + (void)valueOfTok(code, "E0"); } void valueFlowHang() { From 9408a1d22dc8c2281d7ce1b370c273b9118cef60 Mon Sep 17 00:00:00 2001 From: Robert Reif Date: Tue, 4 Aug 2026 15:21:45 -0400 Subject: [PATCH 145/165] add support for vcxproj ExcludedFromBuild (#8771) CMake generates a vcxproj file for the cppcheck GUI that has generated files for all configurations but adds ExcludedFromBuild so the files only gets compiled for a specific configuration. ``` true true true ``` This patch adds support for ExcludedFromBuild so a file only gets checked for a specific configuration. --- lib/importproject.cpp | 69 +++++++++++++++++------ test/cli/exclude/DebugX64.cpp | 8 +++ test/cli/exclude/ReleaseX64.cpp | 8 +++ test/cli/exclude/exclude.cppcheck | 16 ++++++ test/cli/exclude/exclude.slnx | 6 ++ test/cli/exclude/exclude.vcxproj | 94 +++++++++++++++++++++++++++++++ test/cli/exclude/foo.h | 1 + test/cli/exclude_test.py | 20 +++++++ 8 files changed, 206 insertions(+), 16 deletions(-) create mode 100644 test/cli/exclude/DebugX64.cpp create mode 100644 test/cli/exclude/ReleaseX64.cpp create mode 100644 test/cli/exclude/exclude.cppcheck create mode 100644 test/cli/exclude/exclude.slnx create mode 100644 test/cli/exclude/exclude.vcxproj create mode 100644 test/cli/exclude/foo.h create mode 100644 test/cli/exclude_test.py diff --git a/lib/importproject.cpp b/lib/importproject.cpp index 242c1719ba9..5c9bcaadd3f 100644 --- a/lib/importproject.cpp +++ b/lib/importproject.cpp @@ -617,12 +617,13 @@ namespace { std::string platformStr; }; - struct ConditionalGroup { - explicit ConditionalGroup(const tinyxml2::XMLElement *idg){ + struct Conditional { + explicit Conditional(const tinyxml2::XMLElement *idg){ const char *condAttr = idg->Attribute("Condition"); if (condAttr) mCondition = condAttr; } + explicit Conditional(std::string condition) : mCondition(std::move(condition)) {} static void replaceAll(std::string &c, const std::string &from, const std::string &to) { std::string::size_type pos; @@ -751,8 +752,8 @@ namespace { std::string mCondition; }; - struct ItemDefinitionGroup : ConditionalGroup { - explicit ItemDefinitionGroup(const tinyxml2::XMLElement *idg, std::string includePaths) : ConditionalGroup(idg), additionalIncludePaths(std::move(includePaths)) { + struct ItemDefinitionGroup : Conditional { + explicit ItemDefinitionGroup(const tinyxml2::XMLElement *idg, std::string includePaths) : Conditional(idg), additionalIncludePaths(std::move(includePaths)) { for (const tinyxml2::XMLElement *e1 = idg->FirstChildElement(); e1; e1 = e1->NextSiblingElement()) { const char* name = e1->Name(); if (std::strcmp(name, "ClCompile") == 0) { @@ -802,8 +803,8 @@ namespace { Standards::cppstd_t cppstd = Standards::CPPLatest; }; - struct ConfigurationPropertyGroup : ConditionalGroup { - explicit ConfigurationPropertyGroup(const tinyxml2::XMLElement *idg) : ConditionalGroup(idg) { + struct ConfigurationPropertyGroup : Conditional { + explicit ConfigurationPropertyGroup(const tinyxml2::XMLElement *idg) : Conditional(idg) { for (const tinyxml2::XMLElement *e = idg->FirstChildElement(); e; e = e->NextSiblingElement()) { if (std::strcmp(e->Name(), "UseOfMfc") == 0) { useOfMfc = true; @@ -816,6 +817,37 @@ namespace { bool useOfMfc = false; bool useUnicode = false; }; + + struct ItemGroupClCompile { + explicit ItemGroupClCompile(std::string filename) : mFilename(std::move(filename)) {} + ItemGroupClCompile(const tinyxml2::XMLElement *element, std::string file) : mFilename(std::move(file)) { + for (const tinyxml2::XMLElement* childElement = element->FirstChildElement(); childElement; childElement = childElement->NextSiblingElement()) { + const char *name = childElement->Name(); + if (!name) + continue; + if (std::strcmp(name, "ExcludedFromBuild") == 0) { + const char *condition = childElement->Attribute("Condition"); + const char *text = childElement->GetText(); + if (!condition || !text || std::strcmp(text, "true") != 0) + continue; + mConditions.emplace_back(condition); + } + // TODO: ForcedIncludeFiles and PrecompiledHeaderFile + } + } + bool exclude(const ProjectConfiguration& p, std::vector& errors) const { + if (mConditions.empty()) + return false; + for (const std::string& condition : mConditions) { + Conditional conditional(condition); + if (conditional.conditionIsTrue(p, mFilename, errors)) + return true; + } + return false; + } + std::string mFilename; + std::list mConditions; + }; } static std::list toStringList(const std::string &s) @@ -923,7 +955,7 @@ bool ImportProject::importVcxproj(const std::string &filename, const tinyxml2::X variables["ProjectDir"] = Path::simplifyPath(Path::getPathFromFilename(filename)); std::list projectConfigurationList; - std::list compileList; + std::list compileList; std::list itemDefinitionGroupList; std::vector configurationPropertyGroups; std::string includePath; @@ -954,7 +986,8 @@ bool ImportProject::importVcxproj(const std::string &filename, const tinyxml2::X const char *include = e->Attribute("Include"); if (include && Path::acceptFile(include)) { std::string toInclude = Path::simplifyPath(Path::isAbsolute(include) ? include : Path::getPathFromFilename(filename) + include); - compileList.emplace_back(toInclude); + findAndReplace(toInclude, "$(MSBuildThisFileDirectory)", "./"); + compileList.emplace_back(e, toInclude); } } } @@ -1016,7 +1049,7 @@ bool ImportProject::importVcxproj(const std::string &filename, const tinyxml2::X for (const auto& sharedProject : sharedItemsProjects) { for (const auto &file : sharedProject.sourceFiles) { std::string pathToFile = Path::simplifyPath(Path::getPathFromFilename(sharedProject.pathToProjectFile) + file); - compileList.emplace_back(std::move(pathToFile)); + compileList.emplace_back(pathToFile); } for (const auto &p : sharedProject.includePaths) { std::string path = Path::simplifyPath(Path::getPathFromFilename(sharedProject.pathToProjectFile) + p); @@ -1026,8 +1059,8 @@ bool ImportProject::importVcxproj(const std::string &filename, const tinyxml2::X // Project files PathMatch filtermatcher(fileFilters, Path::getCurrentPath()); - for (const std::string &cfilename : compileList) { - if (!fileFilters.empty() && !filtermatcher.match(cfilename)) + for (const ItemGroupClCompile& compile : compileList) { + if (!fileFilters.empty() && !filtermatcher.match(compile.mFilename)) continue; for (const ProjectConfiguration &p : projectConfigurationList) { @@ -1040,7 +1073,11 @@ bool ImportProject::importVcxproj(const std::string &filename, const tinyxml2::X continue; } - FileSettings fs{cfilename, Standards::Language::None, 0}; // file will be identified later on + // check if the file should be excluded for this configuration + if (compile.exclude(p, errors)) + continue; + + FileSettings fs{ compile.mFilename, Standards::Language::None, 0}; // file will be identified later on fs.cfg = p.name; // TODO: detect actual MSC version fs.msc = true; @@ -1053,7 +1090,7 @@ bool ImportProject::importVcxproj(const std::string &filename, const tinyxml2::X } std::string additionalIncludePaths; for (const ItemDefinitionGroup &i : itemDefinitionGroupList) { - if (!i.conditionIsTrue(p, cfilename, errors)) + if (!i.conditionIsTrue(p, compile.mFilename, errors)) continue; fs.standard = Standards::getCPP(i.cppstd); fs.defines += ';' + i.preprocessorDefinitions; @@ -1071,7 +1108,7 @@ bool ImportProject::importVcxproj(const std::string &filename, const tinyxml2::X } bool useUnicode = false; for (const ConfigurationPropertyGroup &c : configurationPropertyGroups) { - if (!c.conditionIsTrue(p, cfilename, errors)) + if (!c.conditionIsTrue(p, compile.mFilename, errors)) continue; // in msbuild the last definition wins useUnicode = c.useUnicode; @@ -1081,7 +1118,7 @@ bool ImportProject::importVcxproj(const std::string &filename, const tinyxml2::X fs.defines += ";UNICODE=1;_UNICODE=1"; } fsSetDefines(fs, fs.defines); - fsSetIncludePaths(fs, Path::getPathFromFilename(filename), toStringList(includePath + ';' + additionalIncludePaths), variables); + fsSetIncludePaths(fs, Path::getPathFromFilename(compile.mFilename), toStringList(includePath + ';' + additionalIncludePaths), variables); for (const auto &path : sharedItemsIncludePaths) { fs.includePaths.emplace_back(path); } @@ -1754,5 +1791,5 @@ bool cppcheck::testing::evaluateVcxprojCondition(const std::string& condition, c ProjectConfiguration p; p.configuration = configuration; p.platformStr = platform; - return ConditionalGroup::evalCondition(condition, p); + return Conditional::evalCondition(condition, p); } diff --git a/test/cli/exclude/DebugX64.cpp b/test/cli/exclude/DebugX64.cpp new file mode 100644 index 00000000000..cfb1fce687a --- /dev/null +++ b/test/cli/exclude/DebugX64.cpp @@ -0,0 +1,8 @@ +#include + +int foo() +{ + std::cout << "DebugX64\n"; + int x = 3 / 0; (void)x; // ERROR + return 0; +} diff --git a/test/cli/exclude/ReleaseX64.cpp b/test/cli/exclude/ReleaseX64.cpp new file mode 100644 index 00000000000..8fa6e6d0f82 --- /dev/null +++ b/test/cli/exclude/ReleaseX64.cpp @@ -0,0 +1,8 @@ +#include + +int foo() +{ + std::cout << "ReleaseX64\n"; + int x = 3 / 0; (void)x; // ERROR + return 0; +} diff --git a/test/cli/exclude/exclude.cppcheck b/test/cli/exclude/exclude.cppcheck new file mode 100644 index 00000000000..50d7da84486 --- /dev/null +++ b/test/cli/exclude/exclude.cppcheck @@ -0,0 +1,16 @@ + + + exclude-cppcheck-build-dir + exclude.slnx + false + true + true + true + 2 + 100 + + Debug + + + exclude + diff --git a/test/cli/exclude/exclude.slnx b/test/cli/exclude/exclude.slnx new file mode 100644 index 00000000000..837662784ac --- /dev/null +++ b/test/cli/exclude/exclude.slnx @@ -0,0 +1,6 @@ + + + + + + diff --git a/test/cli/exclude/exclude.vcxproj b/test/cli/exclude/exclude.vcxproj new file mode 100644 index 00000000000..cc326aaec2f --- /dev/null +++ b/test/cli/exclude/exclude.vcxproj @@ -0,0 +1,94 @@ + + + + + Debug + x64 + + + Release + x64 + + + + 18.0 + Win32Proj + {c9d1dca1-d8ff-4c05-9159-f00816645319} + exclude + 10.0 + + + + StaticLibrary + true + v145 + Unicode + + + Application + false + v145 + true + Unicode + + + + + + + + + + + + + + + + Level3 + true + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + stdcpp20 + + + Console + true + + + true + + + + + Level3 + true + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + stdcpp20 + + + Console + true + + + true + + + + + true + + + true + + + + + + + + + \ No newline at end of file diff --git a/test/cli/exclude/foo.h b/test/cli/exclude/foo.h new file mode 100644 index 00000000000..5d5f8f0c9e7 --- /dev/null +++ b/test/cli/exclude/foo.h @@ -0,0 +1 @@ +int foo(); diff --git a/test/cli/exclude_test.py b/test/cli/exclude_test.py new file mode 100644 index 00000000000..4f674aac34e --- /dev/null +++ b/test/cli/exclude_test.py @@ -0,0 +1,20 @@ + +# python -m pytest exclude_test.py + +import os + +from testutils import cppcheck + +__script_dir = os.path.dirname(os.path.abspath(__file__)) +__proj_dir = os.path.join(__script_dir, 'exclude') + +def test_exclude(): + args = [ + '--template=cppcheck1', + '--project=exclude/exclude.cppcheck', + '--no-cppcheck-build-dir' + ] + ret, stdout, stderr = cppcheck(args, cwd=__script_dir) + filename = os.path.join('exclude', 'DebugX64.cpp') + assert ret == 0, stdout + assert stderr == '[%s:6]: (error) Division by zero.\n' % filename From 8276218b3da696bf96ff8986b7807aaf48e91ab1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20Gr=C3=BCninger?= Date: Wed, 5 Aug 2026 09:11:41 +0200 Subject: [PATCH 146/165] [ci] Update Github actions to latest major release (#8756) --- .github/workflows/CI-cygwin.yml | 2 +- .github/workflows/CI-mingw.yml | 2 +- .github/workflows/CI-unixish-docker.yml | 4 ++-- .github/workflows/CI-unixish.yml | 22 ++++++++++----------- .github/workflows/CI-windows.yml | 12 +++++------ .github/workflows/buildman.yml | 8 ++++---- .github/workflows/cifuzz.yml | 2 +- .github/workflows/clang-tidy.yml | 4 ++-- .github/workflows/codeql-analysis.yml | 6 +++--- .github/workflows/corpus.yml | 4 ++-- .github/workflows/coverage.yml | 6 +++--- .github/workflows/coverity.yml | 2 +- .github/workflows/cppcheck-premium.yml | 6 +++--- .github/workflows/format.yml | 4 ++-- .github/workflows/iwyu.yml | 14 ++++++------- .github/workflows/release-windows-mingw.yml | 4 ++-- .github/workflows/release-windows.yml | 12 +++++------ .github/workflows/sanitizers.yml | 4 ++-- .github/workflows/scriptcheck.yml | 12 +++++------ .github/workflows/selfcheck.yml | 6 +++--- .github/workflows/valgrind.yml | 4 ++-- 21 files changed, 70 insertions(+), 70 deletions(-) diff --git a/.github/workflows/CI-cygwin.yml b/.github/workflows/CI-cygwin.yml index bf67967c5f8..6b0ad2cc5bd 100644 --- a/.github/workflows/CI-cygwin.yml +++ b/.github/workflows/CI-cygwin.yml @@ -37,7 +37,7 @@ jobs: runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 with: persist-credentials: false diff --git a/.github/workflows/CI-mingw.yml b/.github/workflows/CI-mingw.yml index 1b0cf3e5672..f308cfa5110 100644 --- a/.github/workflows/CI-mingw.yml +++ b/.github/workflows/CI-mingw.yml @@ -33,7 +33,7 @@ jobs: timeout-minutes: 19 # max + 3*std of the last 7K runs steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 with: persist-credentials: false diff --git a/.github/workflows/CI-unixish-docker.yml b/.github/workflows/CI-unixish-docker.yml index 16c1615ed04..adf4a74c81b 100644 --- a/.github/workflows/CI-unixish-docker.yml +++ b/.github/workflows/CI-unixish-docker.yml @@ -43,7 +43,7 @@ jobs: image: ${{ matrix.image }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 with: persist-credentials: false @@ -96,7 +96,7 @@ jobs: image: ${{ matrix.image }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 with: persist-credentials: false diff --git a/.github/workflows/CI-unixish.yml b/.github/workflows/CI-unixish.yml index 8fb5c8d76d6..9bac980c853 100644 --- a/.github/workflows/CI-unixish.yml +++ b/.github/workflows/CI-unixish.yml @@ -30,7 +30,7 @@ jobs: CCACHE_SLOPPINESS: pch_defines,time_macros steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 with: persist-credentials: false @@ -85,7 +85,7 @@ jobs: CCACHE_SLOPPINESS: pch_defines,time_macros steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 with: persist-credentials: false @@ -97,7 +97,7 @@ jobs: # TODO: move latest compiler to separate step # TODO: bail out on warnings with latest GCC - name: Set up GCC - uses: egor-tensin/setup-gcc@v1 + uses: egor-tensin/setup-gcc@v2 if: false # matrix.os == 'ubuntu-22.04' with: version: 13 @@ -216,7 +216,7 @@ jobs: CCACHE_SLOPPINESS: pch_defines,time_macros steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 with: persist-credentials: false @@ -265,7 +265,7 @@ jobs: runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 with: persist-credentials: false @@ -299,7 +299,7 @@ jobs: runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 with: persist-credentials: false @@ -333,7 +333,7 @@ jobs: runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 with: persist-credentials: false @@ -361,7 +361,7 @@ jobs: CCACHE_SLOPPINESS: pch_defines,time_macros steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 with: persist-credentials: false @@ -417,7 +417,7 @@ jobs: CMAKE_VERSION_FULL: 3.22.6 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 with: persist-credentials: false @@ -461,7 +461,7 @@ jobs: runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 with: persist-credentials: false @@ -712,7 +712,7 @@ jobs: runs-on: ubuntu-22.04 # run on the latest image only steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 with: persist-credentials: false diff --git a/.github/workflows/CI-windows.yml b/.github/workflows/CI-windows.yml index a63be4e0ad9..66858c7afbe 100644 --- a/.github/workflows/CI-windows.yml +++ b/.github/workflows/CI-windows.yml @@ -31,7 +31,7 @@ jobs: runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 with: persist-credentials: false @@ -82,7 +82,7 @@ jobs: runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 with: persist-credentials: false @@ -108,7 +108,7 @@ jobs: CMAKE_VERSION_FULL: 3.22.6 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 with: persist-credentials: false @@ -154,13 +154,13 @@ jobs: PCRE_VERSION: 8.45 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 with: persist-credentials: false - name: Set up Python if: matrix.config == 'release' - uses: actions/setup-python@v5 + uses: actions/setup-python@v6 with: python-version: '3.14' check-latest: true @@ -172,7 +172,7 @@ jobs: - name: Cache PCRE id: cache-pcre - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: | externals\pcre.h diff --git a/.github/workflows/buildman.yml b/.github/workflows/buildman.yml index b0b399dd851..e84cf4bffd9 100644 --- a/.github/workflows/buildman.yml +++ b/.github/workflows/buildman.yml @@ -19,7 +19,7 @@ jobs: convert_via_pandoc: runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 with: persist-credentials: false @@ -38,7 +38,7 @@ jobs: with: args: --output=output/manual-premium.pdf man/manual-premium.md - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@v7 with: name: output path: output @@ -46,7 +46,7 @@ jobs: manpage: runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 with: persist-credentials: false @@ -59,7 +59,7 @@ jobs: run: | make man - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@v7 with: name: cppcheck.1 path: cppcheck.1 diff --git a/.github/workflows/cifuzz.yml b/.github/workflows/cifuzz.yml index c54d47da4f1..400fb929786 100644 --- a/.github/workflows/cifuzz.yml +++ b/.github/workflows/cifuzz.yml @@ -27,7 +27,7 @@ jobs: dry-run: false language: c++ - name: Upload Crash - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 if: failure() && steps.build.outcome == 'success' with: name: artifacts diff --git a/.github/workflows/clang-tidy.yml b/.github/workflows/clang-tidy.yml index 7a5b317693a..4f2db4ab113 100644 --- a/.github/workflows/clang-tidy.yml +++ b/.github/workflows/clang-tidy.yml @@ -27,7 +27,7 @@ jobs: QT_VERSION: 6.10.0 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 with: persist-credentials: false @@ -86,7 +86,7 @@ jobs: run: | cmake --build cmake.output --target run-clang-tidy-csa 2> /dev/null - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@v7 if: success() || failure() with: name: Compilation Database diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 12e758d2c9e..84d37423d2e 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -33,13 +33,13 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: persist-credentials: false # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@v3 + uses: github/codeql-action/init@v4 with: languages: ${{ matrix.language }} @@ -49,4 +49,4 @@ jobs: make -j$(nproc) CXXOPTS="-Werror" HAVE_RULES=yes CPPCHK_GLIBCXX_DEBUG= cppcheck - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v3 + uses: github/codeql-action/analyze@v4 diff --git a/.github/workflows/corpus.yml b/.github/workflows/corpus.yml index 0c1aeda94de..2d9f1424fad 100644 --- a/.github/workflows/corpus.yml +++ b/.github/workflows/corpus.yml @@ -16,7 +16,7 @@ jobs: if: ${{ github.repository_owner == 'cppcheck-opensource' }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 with: persist-credentials: false @@ -51,7 +51,7 @@ jobs: # print largest size ls -l ./store | cut -d' ' -f5 | sort -u -n -r | head -n1 - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@v7 if: success() with: name: corpus diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 13f56172a80..b5e496adcf6 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -21,7 +21,7 @@ jobs: runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 with: persist-credentials: false @@ -57,12 +57,12 @@ jobs: lcov --extract lcov_tmp.info "$(pwd)/*" --output-file lcov.info genhtml lcov.info -o coverage_report --frame --legend --demangle-cpp - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@v7 with: name: Coverage results path: coverage_report - - uses: codecov/codecov-action@v4 + - uses: codecov/codecov-action@v5 with: token: ${{ secrets.CODECOV_TOKEN }} # file: ./coverage.xml # optional diff --git a/.github/workflows/coverity.yml b/.github/workflows/coverity.yml index 006160c7779..4c62971e4c4 100644 --- a/.github/workflows/coverity.yml +++ b/.github/workflows/coverity.yml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-latest if: ${{ github.repository_owner == 'cppcheck-opensource' }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 with: persist-credentials: false - name: Install missing software on ubuntu diff --git a/.github/workflows/cppcheck-premium.yml b/.github/workflows/cppcheck-premium.yml index ed0f2a1bcd5..b99cccd69da 100644 --- a/.github/workflows/cppcheck-premium.yml +++ b/.github/workflows/cppcheck-premium.yml @@ -25,7 +25,7 @@ jobs: build: runs-on: ubuntu-24.04 # run on the latest image only steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 with: persist-credentials: false @@ -60,13 +60,13 @@ jobs: #sed -i 's|"security-severity":.*||' results.sarif cat results.sarif - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@v7 with: name: results path: results.sarif - name: Upload report - uses: github/codeql-action/upload-sarif@v3 + uses: github/codeql-action/upload-sarif@v4 with: sarif_file: results.sarif category: cppcheckpremium diff --git a/.github/workflows/format.yml b/.github/workflows/format.yml index fd491c0ec0e..4ec72f935fd 100644 --- a/.github/workflows/format.yml +++ b/.github/workflows/format.yml @@ -24,12 +24,12 @@ jobs: UNCRUSTIFY_VERSION: 0.80.1 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 with: persist-credentials: false - name: Cache uncrustify - uses: actions/cache@v4 + uses: actions/cache@v5 id: cache-uncrustify with: path: | diff --git a/.github/workflows/iwyu.yml b/.github/workflows/iwyu.yml index de047b8d10a..2e54b92541e 100644 --- a/.github/workflows/iwyu.yml +++ b/.github/workflows/iwyu.yml @@ -39,7 +39,7 @@ jobs: QT_VERSION: 6.10.0 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 with: persist-credentials: false @@ -160,13 +160,13 @@ jobs: IWYU: include-what-you-use IWYU_CLANG_INC: ${{ matrix.clang_inc }} - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@v7 if: success() || failure() with: name: Compilation Database (include-what-you-use - ${{ matrix.os }} ${{ matrix.stdlib }}) path: ./cmake.output/compile_commands.json - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@v7 if: ${{ contains(matrix.os, 'macos') && (success() || failure()) }} with: name: macOS Mappings @@ -174,7 +174,7 @@ jobs: ./iwyu-mapgen-apple-libc.py ./macos.imp - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@v7 if: success() || failure() with: name: Logs (include-what-you-use - ${{ matrix.os }} ${{ matrix.stdlib }}) @@ -199,7 +199,7 @@ jobs: QT_VERSION: 6.10.0 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 with: persist-credentials: false @@ -256,13 +256,13 @@ jobs: # TODO: run multi-threaded find $PWD/cli $PWD/lib $PWD/test $PWD/gui -maxdepth 1 -name "*.cpp" | xargs -t -n 1 clang-include-cleaner-22 --print=changes --extra-arg=-w --extra-arg=-stdlib=${{ matrix.stdlib }} -p cmake.output > clang-include-cleaner.log 2>&1 - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@v7 if: success() || failure() with: name: Compilation Database (clang-include-cleaner - ${{ matrix.stdlib }}) path: ./cmake.output/compile_commands.json - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@v7 if: success() || failure() with: name: Logs (clang-include-cleaner - ${{ matrix.stdlib }}) diff --git a/.github/workflows/release-windows-mingw.yml b/.github/workflows/release-windows-mingw.yml index 3b9b836347f..8085990e39d 100644 --- a/.github/workflows/release-windows-mingw.yml +++ b/.github/workflows/release-windows-mingw.yml @@ -33,7 +33,7 @@ jobs: timeout-minutes: 19 # max + 3*std of the last 7K runs steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 with: persist-credentials: false @@ -63,7 +63,7 @@ jobs: cp /mingw64/bin/libstdc*.dll cppcheck-mingw/ cp /mingw64/bin/libwinpthread-1.dll cppcheck-mingw/ - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@v7 with: name: cppcheck-mingw path: cppcheck-mingw diff --git a/.github/workflows/release-windows.yml b/.github/workflows/release-windows.yml index 8d09a55302e..aa467d7b875 100644 --- a/.github/workflows/release-windows.yml +++ b/.github/workflows/release-windows.yml @@ -32,7 +32,7 @@ jobs: BOOST_MINOR_VERSION: 89 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 with: persist-credentials: false @@ -95,7 +95,7 @@ jobs: del build\bin\Release\cppcheck-gui.ilk || exit /b !errorlevel! del build\bin\Release\cppcheck-gui.pdb || exit /b !errorlevel! - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@v7 with: name: deploy path: build\bin\Release @@ -109,7 +109,7 @@ jobs: env: _CL_: /WX - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@v7 with: name: bin path: bin @@ -158,7 +158,7 @@ jobs: :: copy libcrypto-3-x64.dll and libssl-3-x64.dll copy %RUNNER_WORKSPACE%\Qt\Tools\OpenSSLv3\Win_x64\bin\lib*.dll win_installer\files || exit /b !errorlevel! - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@v7 with: name: collect path: win_installer\files @@ -173,7 +173,7 @@ jobs: @echo ProductVersion="%PRODUCTVER%" || exit /b !errorlevel! msbuild -m cppcheck.wixproj -p:Platform=x64,ProductVersion=%PRODUCTVER%.${{ github.run_number }} || exit /b !errorlevel! - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@v7 with: name: installer path: win_installer/Build/ @@ -209,7 +209,7 @@ jobs: del win_installer\files\Qt6Svg.dll || exit /b !errorlevel! del win_installer\files\vc_redist.x64.exe || exit /b !errorlevel! - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@v7 with: name: portable path: win_installer\files diff --git a/.github/workflows/sanitizers.yml b/.github/workflows/sanitizers.yml index ea0a0276c99..6021d1237d2 100644 --- a/.github/workflows/sanitizers.yml +++ b/.github/workflows/sanitizers.yml @@ -50,7 +50,7 @@ jobs: CCACHE_SLOPPINESS: pch_defines,time_macros steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 with: persist-credentials: false @@ -60,7 +60,7 @@ jobs: key: ${{ github.workflow }}-${{ github.job }}-${{ matrix.os }}-${{ matrix.sanitizer }} - name: Set up Python - uses: actions/setup-python@v5 + uses: actions/setup-python@v6 with: python-version: '3.14' check-latest: true diff --git a/.github/workflows/scriptcheck.yml b/.github/workflows/scriptcheck.yml index 844b1d5c2f3..8cee3c5a5b4 100644 --- a/.github/workflows/scriptcheck.yml +++ b/.github/workflows/scriptcheck.yml @@ -21,7 +21,7 @@ jobs: runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 with: persist-credentials: false @@ -31,7 +31,7 @@ jobs: key: ${{ github.workflow }}-${{ runner.os }} - name: Cache Cppcheck - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: cppcheck key: ${{ runner.os }}-scriptcheck-cppcheck-${{ github.sha }} @@ -56,19 +56,19 @@ jobs: fail-fast: false steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 with: persist-credentials: false # TODO: bailout on error - name: Restore Cppcheck - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: cppcheck key: ${{ runner.os }}-scriptcheck-cppcheck-${{ github.sha }} - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v5 + uses: actions/setup-python@v6 with: python-version: ${{ matrix.python-version }} check-latest: true @@ -209,7 +209,7 @@ jobs: runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 with: persist-credentials: false diff --git a/.github/workflows/selfcheck.yml b/.github/workflows/selfcheck.yml index 3517486df31..f16ce8d8332 100644 --- a/.github/workflows/selfcheck.yml +++ b/.github/workflows/selfcheck.yml @@ -24,7 +24,7 @@ jobs: QT_VERSION: 6.10.0 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 with: persist-credentials: false @@ -215,7 +215,7 @@ jobs: env: DISABLE_VALUEFLOW: 1 - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@v7 with: name: Callgrind Output path: ./callgrind.* @@ -228,7 +228,7 @@ jobs: env: DISABLE_VALUEFLOW: 1 - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@v7 with: name: Memcheck Output path: ./memcheck.* diff --git a/.github/workflows/valgrind.yml b/.github/workflows/valgrind.yml index 3e4a02dbb48..25ef4dd63a2 100644 --- a/.github/workflows/valgrind.yml +++ b/.github/workflows/valgrind.yml @@ -21,7 +21,7 @@ jobs: runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 with: persist-credentials: false @@ -64,7 +64,7 @@ jobs: #env: # DEBUGINFOD_URLS: https://debuginfod.ubuntu.com - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@v7 if: success() || failure() with: name: Logs From 6a29b12ce24eb507c1cb1d2e6d5d50607655870f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludvig=20Gunne=20Lindstr=C3=B6m?= Date: Wed, 5 Aug 2026 11:22:04 +0200 Subject: [PATCH 147/165] Fix #14899: FP invalidPrintfArgType_float with _sprintf_s_l() (#8729) --- lib/checkio.cpp | 36 ++++++++++++++++++++++++++---------- test/testio.cpp | 12 ++++++++++++ 2 files changed, 38 insertions(+), 10 deletions(-) diff --git a/lib/checkio.cpp b/lib/checkio.cpp index 0a0ca70a833..f726cef0cc7 100644 --- a/lib/checkio.cpp +++ b/lib/checkio.cpp @@ -666,16 +666,20 @@ void CheckIOImpl::wrongfeofUsage(const Token * tok) // printf("", 1); // Too much arguments //--------------------------------------------------------------------------- -static bool findFormat(nonneg int arg, const Token *firstArg, +static bool findFormat(nonneg int arg, nonneg int argc, const Token *firstArg, const Token *&formatStringTok, const Token *&formatArgTok) { + formatArgTok = firstArg; + + for (int i = 0; i < argc && formatArgTok; ++i) + formatArgTok = formatArgTok->nextArgument(); + const Token* argTok = firstArg; for (int i = 0; i < arg && argTok; ++i) argTok = argTok->nextArgument(); if (Token::Match(argTok, "%str% [,)]")) { - formatArgTok = argTok->nextArgument(); formatStringTok = argTok; return true; } @@ -686,7 +690,6 @@ static bool findFormat(nonneg int arg, const Token *firstArg, (argTok->variable()->dimensions().size() == 1 && argTok->variable()->dimensionKnown(0) && argTok->variable()->dimension(0) != 0))) { - formatArgTok = argTok->nextArgument(); if (!argTok->values().empty()) { const auto value = std::find_if( argTok->values().cbegin(), argTok->values().cend(), std::mem_fn(&ValueFlow::Value::isTokValue)); @@ -706,6 +709,17 @@ static inline bool typesMatch(const std::string& iToTest, const std::string& iTy return (iToTest == iTypename) || (iToTest == iOptionalPrefix + iTypename); } +static int getMaxArgNo(const Library::Function *func) +{ + const auto &checks = func->argumentChecks; + return std::max_element(checks.cbegin(), checks.cend(), + [](const std::pair &lhs, + const std::pair &rhs) { + return lhs.first < rhs.first; + } + )->first; +} + void CheckIOImpl::checkWrongPrintfScanfArguments() { const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase(); @@ -723,8 +737,10 @@ void CheckIOImpl::checkWrongPrintfScanfArguments() bool scan = false; bool scanf_s = false; int formatStringArgNo = -1; + int argc = -1; if (tok->strAt(1) == "(" && mSettings.library.formatstr_function(tok)) { + argc = getMaxArgNo(mSettings.library.getFunction(tok)); formatStringArgNo = mSettings.library.formatstr_argno(tok); scan = mSettings.library.formatstr_scan(tok); scanf_s = mSettings.library.formatstr_secure(tok); @@ -732,37 +748,37 @@ void CheckIOImpl::checkWrongPrintfScanfArguments() if (formatStringArgNo >= 0) { // formatstring found in library. Find format string and first argument belonging to format string. - if (!findFormat(formatStringArgNo, tok->tokAt(2), formatStringTok, argListTok)) + if (!findFormat(formatStringArgNo, argc, tok->tokAt(2), formatStringTok, argListTok)) continue; } else if (Token::simpleMatch(tok, "swprintf (")) { if (Token::Match(tok->tokAt(2)->nextArgument(), "%str%")) { // Find third parameter and format string - if (!findFormat(1, tok->tokAt(2), formatStringTok, argListTok)) + if (!findFormat(1, 2, tok->tokAt(2), formatStringTok, argListTok)) continue; } else { // Find fourth parameter and format string - if (!findFormat(2, tok->tokAt(2), formatStringTok, argListTok)) + if (!findFormat(2, 3, tok->tokAt(2), formatStringTok, argListTok)) continue; } } else if (isWindows && Token::Match(tok, "sprintf_s|swprintf_s (")) { // template int sprintf_s(char (&buffer)[size], const char *format, ...); - if (findFormat(1, tok->tokAt(2), formatStringTok, argListTok)) { + if (findFormat(1, 2, tok->tokAt(2), formatStringTok, argListTok)) { if (!formatStringTok) continue; } // int sprintf_s(char *buffer, size_t sizeOfBuffer, const char *format, ...); - else if (findFormat(2, tok->tokAt(2), formatStringTok, argListTok)) { + else if (findFormat(2, 3, tok->tokAt(2), formatStringTok, argListTok)) { if (!formatStringTok) continue; } } else if (isWindows && Token::Match(tok, "_snprintf_s|_snwprintf_s (")) { // template int _snprintf_s(char (&buffer)[size], size_t count, const char *format, ...); - if (findFormat(2, tok->tokAt(2), formatStringTok, argListTok)) { + if (findFormat(2, 3, tok->tokAt(2), formatStringTok, argListTok)) { if (!formatStringTok) continue; } // int _snprintf_s(char *buffer, size_t sizeOfBuffer, size_t count, const char *format, ...); - else if (findFormat(3, tok->tokAt(2), formatStringTok, argListTok)) { + else if (findFormat(3, 4, tok->tokAt(2), formatStringTok, argListTok)) { if (!formatStringTok) continue; } diff --git a/test/testio.cpp b/test/testio.cpp index 2d191555ba6..16d770bb0bd 100644 --- a/test/testio.cpp +++ b/test/testio.cpp @@ -4791,6 +4791,18 @@ class TestIO : public TestFixture { "[test.cpp:17:5]: (warning) %s in format string (no. 5) requires 'char *' but the argument type is 'signed int'. [invalidPrintfArgType_s]\n" "[test.cpp:17:5]: (warning) sprintf_s format string requires 5 parameters but 6 are given. [wrongPrintfScanfArgNum]\n", errout_str()); + check("int main()\n" + "{\n" + " double value = 3.14;\n" + " const size_t buffer_size = 64;\n" + " char buffer[buffer_size];\n" + " int precision = 2;\n" + " _locale_t locale = _create_locale(LC_ALL, \"C\");\n" + " _sprintf_s_l(buffer, buffer_size, \"%.*f\", locale, precision, value);\n" + " _free_locale(locale);\n" + " return 0;\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); } void testMicrosoftSecureScanfArgument() { From cb6d92e86287d511476b579a9e50a7b08067ebc7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludvig=20Gunne=20Lindstr=C3=B6m?= Date: Wed, 5 Aug 2026 11:23:00 +0200 Subject: [PATCH 148/165] AUTHORS: Add aadanen [skip ci] (#8774) --- AUTHORS | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS b/AUTHORS index b4917d7d157..cda29aa6ef8 100644 --- a/AUTHORS +++ b/AUTHORS @@ -1,6 +1,7 @@ The cppcheck team, in alphabetical order: 0x41head +Aaron Danen Abhijit Sawant Abhishek Bharadwaj Abigail Buccaneer From 44b9221a78e6d67f31a70533cea089d74fecf260 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludvig=20Gunne=20Lindstr=C3=B6m?= Date: Wed, 5 Aug 2026 12:43:15 +0200 Subject: [PATCH 149/165] Fix #14955: Bad varid for enumerator with using namespace (#8773) --- lib/tokenize.cpp | 12 +++++++++++- test/testtokenize.cpp | 16 ++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 8382c09e785..033462ca2e2 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -5270,7 +5270,16 @@ void Tokenizer::setVarIdPass2() std::map endOfScope; std::list scope; std::list usingnamespaces; + const Token *enumEnd = nullptr; for (Token *tok = list.front(); tok; tok = tok->next()) { + if (isEnumStart(tok)) { + enumEnd = tok->link(); + continue; + } + if (tok == enumEnd) { + enumEnd = nullptr; + continue; + } if (!tok->previous() || Token::Match(tok->previous(), "[;{}]")) { if (Token::Match(tok, "using namespace %name% ::|;")) { Token *endtok = tok->tokAt(2); @@ -5300,7 +5309,8 @@ void Tokenizer::setVarIdPass2() tok = tok->next()->findClosingBracket()->next(); else if (usingnamespaces.empty() || tok->varId() || !tok->isName() || tok->isStandardType() || tok->tokType() == Token::eKeyword || tok->tokType() == Token::eBoolean || Token::Match(tok->previous(), ".|namespace|class|struct|&|&&|*|> %name%") || Token::Match(tok->previous(), "%type%| %name% ( %type%|)") || Token::Match(tok, "public:|private:|protected:") || - (!tok->next() && Token::Match(tok->previous(), "}|; %name%"))) + (!tok->next() && Token::Match(tok->previous(), "}|; %name%")) || + (enumEnd && Token::Match(tok->previous(), "{|, %name% =|,|}"))) continue; if (tok->strAt(-1) == "::" && tok->tokAt(-2) && tok->tokAt(-2)->isName()) diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp index 79da0177e19..600d457e944 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -93,6 +93,7 @@ class TestTokenizer : public TestFixture { TEST_CASE(tokenize41); // #13847 TEST_CASE(tokenize42); // #13861 TEST_CASE(tokenize43); // #13861 + TEST_CASE(tokenize44); // #14955 TEST_CASE(validate); @@ -949,6 +950,21 @@ class TestTokenizer : public TestFixture { (void)errout_str(); } + void tokenize44() { // #14955 + const char code[] = "namespace O {}\n" + "namespace N {\n" + " using namespace O;\n" + " enum class E { E0 };\n" + " E E0 = E::E0;\n" + "}\n"; + const char expected[] = "2: namespace N {\n" + "3: using namespace O ;\n" + "4: enum class E { E0 } ;\n" + "5: E E0@1 ; E0@1 = E :: E0 ;\n" + "6: }\n"; + ASSERT_EQUALS(expected, tokenizeDebugListing(code)); + } + void validate() { // C++ code in C file ASSERT_THROW_INTERNAL(tokenizeAndStringify(";using namespace std;",dinit(TokenizeOptions, $.expand = false, $.cpp = false)), SYNTAX); From b702eade4a164d6739818fc1c560113215cf4929 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Wed, 5 Aug 2026 13:26:37 +0200 Subject: [PATCH 150/165] partial fix #14851 (CI: run 'make test' with some old gcc versions) (#8663) --- .github/workflows/gcc-versions.yml | 39 ++++++++++++++++++++++++++++++ test/testpath.cpp | 3 ++- 2 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/gcc-versions.yml diff --git a/.github/workflows/gcc-versions.yml b/.github/workflows/gcc-versions.yml new file mode 100644 index 00000000000..3402bade743 --- /dev/null +++ b/.github/workflows/gcc-versions.yml @@ -0,0 +1,39 @@ +# the purpose of this github action is to test that cppcheck source code can be compiled using old gcc versions. +# the gcc images we use here are copied from the official gcc images on docker hub + +name: gcc-versions + +on: + push: + branches: + - 'main' + - 'releases/**' + - '2.*' + tags: + - '2.*' + pull_request: + +permissions: + contents: read + +jobs: + build: + + strategy: + matrix: + #image: ["ghcr.io/cppcheck-opensource/gcc:5.4", "ghcr.io/cppcheck-opensource/gcc:6.5", "ghcr.io/cppcheck-opensource/gcc:7.5", "ghcr.io/cppcheck-opensource/gcc:8.5", "ghcr.io/cppcheck-opensource/gcc:9.5"] + image: ["ghcr.io/cppcheck-opensource/gcc:5.4"] + fail-fast: false + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + with: + persist-credentials: false + + - name: Build cppcheck + run: | + # FIXME: simplecpp-1.8.0 can't be compiled with gcc 5.4, so we can't run 'make test' now + #docker run --rm -v ${{ github.workspace }}:/cppcheck -w /cppcheck ${{ matrix.image }} make -j$(nproc) CXXOPTS="-Werror" test + docker run --rm -v ${{ github.workspace }}:/cppcheck -w /cppcheck ${{ matrix.image }} g++ -fsyntax-only -Iexternals -Iexternals/picojson -Iexternals/simplecpp -Iexternals/tinyxml2 -std=c++11 -Wno-multichar lib/*.cpp diff --git a/test/testpath.cpp b/test/testpath.cpp index 69ee91fa391..0ebe343685f 100644 --- a/test/testpath.cpp +++ b/test/testpath.cpp @@ -516,7 +516,8 @@ class TestPath : public TestFixture { ASSERT_EQUALS(expected, Path::getAbsoluteFilePath(Path::join(cwd, "testabspath.txt"))); std::string cwd_up = Path::getPathFromFilename(cwd); - cwd_up.pop_back(); // remove trailing slash + if (cwd_up != "/") + cwd_up.pop_back(); // remove trailing slash ASSERT_EQUALS(cwd_up, Path::getAbsoluteFilePath(Path::join(cwd, ".."))); ASSERT_EQUALS(cwd_up, Path::getAbsoluteFilePath(Path::join(cwd, "../"))); ASSERT_EQUALS(cwd_up, Path::getAbsoluteFilePath(Path::join(cwd, "..\\"))); From baf5eaa0780c38dbf2a22740a5c08974d0165546 Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Thu, 6 Aug 2026 14:17:46 +0200 Subject: [PATCH 151/165] TestValueFlow: Remove redundant test configuration, make settings const (#8776) Co-authored-by: chrchr-github --- test/testvalueflow.cpp | 45 ++++++++++++++++-------------------------- 1 file changed, 17 insertions(+), 28 deletions(-) diff --git a/test/testvalueflow.cpp b/test/testvalueflow.cpp index 945555b1b3c..4fc47f63d86 100644 --- a/test/testvalueflow.cpp +++ b/test/testvalueflow.cpp @@ -43,16 +43,9 @@ class TestValueFlow : public TestFixture { TestValueFlow() : TestFixture("TestValueFlow") {} private: - /*const*/ Settings settings = settingsBuilder().library("std.cfg").build(); + const Settings settings = settingsBuilder().library("std.cfg").build(); void run() override { - // strcpy, abort cfg - constexpr char cfg[] = "\n" - "\n" - " \n" - " true \n" // abort is a noreturn function - ""; - settings = settingsBuilder(settings).libraryxml(cfg).build(); mNewTemplate = true; TEST_CASE(valueFlowNumber); @@ -437,9 +430,10 @@ class TestValueFlow : public TestFixture { return false; } - bool testValueOfX_(const char* file, int line, const char code[], unsigned int linenr, int value, ValueFlow::Value::ValueType type) { + bool testValueOfX_(const char* file, int line, const char code[], unsigned int linenr, int value, ValueFlow::Value::ValueType type, const Settings* s = nullptr) { + const Settings& curSettings = s ? *s : settings; // Tokenize.. - SimpleTokenizer tokenizer(settings, *this); + SimpleTokenizer tokenizer(curSettings, *this); ASSERT_LOC(tokenizer.tokenize(code), file, line); for (const Token *tok = tokenizer.tokens(); tok; tok = tok->next()) { @@ -5887,21 +5881,19 @@ class TestValueFlow : public TestFixture { ASSERT_EQUALS(false, value.isKnown()); // #13959 - const Settings settingsOld = settings; - settings.standards.c = Standards::C23; + const Settings settingsC23 = settingsBuilder(settings).c(Standards::C23).build(); code = "void f(int* p) {\n" " if (p == nullptr)\n" " return;\n" " if (p) {}\n" "}\n"; - value = valueOfTok(code, "p ) { }", &settings, /*cpp*/ false); + value = valueOfTok(code, "p ) { }", &settingsC23, /*cpp*/ false); ASSERT_EQUALS(1, value.intvalue); ASSERT_EQUALS(true, value.isKnown()); - settings.standards.c = Standards::C17; - value = valueOfTok(code, "p ) { }", &settings, /*cpp*/ false); + const Settings settingsC17 = settingsBuilder(settings).c(Standards::C17).build(); + value = valueOfTok(code, "p ) { }", &settingsC17, /*cpp*/ false); ASSERT(value == ValueFlow::Value()); - settings = settingsOld; } void valueFlowSizeofForwardDeclaredEnum() { @@ -7880,48 +7872,47 @@ class TestValueFlow : public TestFixture { void valueFlowDynamicBufferSize() { const char *code; - const Settings settingsOld = settings; // TODO: get rid of this - settings = settingsBuilder(settings).library("posix.cfg").library("bsd.cfg").build(); + const Settings settingsCfg = settingsBuilder(settings).library("posix.cfg").library("bsd.cfg").build(); code = "void* f() {\n" " void* x = malloc(10);\n" " return x;\n" "}"; - ASSERT_EQUALS(true, testValueOfX(code, 3U, 10, ValueFlow::Value::ValueType::BUFFER_SIZE)); + ASSERT_EQUALS(true, testValueOfX(code, 3U, 10, ValueFlow::Value::ValueType::BUFFER_SIZE, &settingsCfg)); code = "void* f() {\n" " void* x = calloc(4, 5);\n" " return x;\n" "}"; - ASSERT_EQUALS(true, testValueOfX(code, 3U, 20, ValueFlow::Value::ValueType::BUFFER_SIZE)); + ASSERT_EQUALS(true, testValueOfX(code, 3U, 20, ValueFlow::Value::ValueType::BUFFER_SIZE, &settingsCfg)); code = "void* f() {\n" " const char* y = \"abcd\";\n" " const char* x = strdup(y);\n" " return x;\n" "}"; - ASSERT_EQUALS(true, testValueOfX(code, 4U, 5, ValueFlow::Value::ValueType::BUFFER_SIZE)); + ASSERT_EQUALS(true, testValueOfX(code, 4U, 5, ValueFlow::Value::ValueType::BUFFER_SIZE, &settingsCfg)); code = "void* f() {\n" " void* y = malloc(10);\n" " void* x = realloc(y, 20);\n" " return x;\n" "}"; - ASSERT_EQUALS(true, testValueOfX(code, 4U, 20, ValueFlow::Value::ValueType::BUFFER_SIZE)); + ASSERT_EQUALS(true, testValueOfX(code, 4U, 20, ValueFlow::Value::ValueType::BUFFER_SIZE, &settingsCfg)); code = "void* f() {\n" " void* y = calloc(10, 4);\n" " void* x = reallocarray(y, 20, 5);\n" " return x;\n" "}"; - ASSERT_EQUALS(true, testValueOfX(code, 4U, 100, ValueFlow::Value::ValueType::BUFFER_SIZE)); + ASSERT_EQUALS(true, testValueOfX(code, 4U, 100, ValueFlow::Value::ValueType::BUFFER_SIZE, &settingsCfg)); code = "struct A {};\n" // #14305 "void* f() {\n" " A* x = new A();\n" " return x;\n" "}"; - ASSERT_EQUALS(true, testValueOfX(code, 4U, 1, ValueFlow::Value::ValueType::BUFFER_SIZE)); + ASSERT_EQUALS(true, testValueOfX(code, 4U, 1, ValueFlow::Value::ValueType::BUFFER_SIZE, &settingsCfg)); code = "struct A {};\n" "void* f() {\n" @@ -7929,7 +7920,7 @@ class TestValueFlow : public TestFixture { " return x;\n" "}"; { - auto values = tokenValues(code, "x ; }"); + auto values = tokenValues(code, "x ; }", &settingsCfg); ASSERT_EQUALS(1, values.size()); ASSERT(values.front().isSymbolicValue()); // TODO: add BUFFER_SIZE value = 1 @@ -7940,9 +7931,7 @@ class TestValueFlow : public TestFixture { " B* x = new B();\n" " return x;\n" "}"; - ASSERT_EQUALS(true, testValueOfX(code, 4U, 4, ValueFlow::Value::ValueType::BUFFER_SIZE)); - - settings = settingsOld; + ASSERT_EQUALS(true, testValueOfX(code, 4U, 4, ValueFlow::Value::ValueType::BUFFER_SIZE, &settingsCfg)); } void valueFlowSafeFunctionParameterValues() { From fecb3496f915944388356346dbab6dd4c08c740c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Fri, 7 Aug 2026 07:59:49 +0200 Subject: [PATCH 152/165] Fix #14959 (Warning hash for token-based warnings) (#8778) --- Makefile | 2 +- lib/errorlogger.cpp | 65 ++++++++++++++++++++++++++++++++++++++++-- lib/errorlogger.h | 2 ++ oss-fuzz/Makefile | 2 +- test/cli/other_test.py | 2 +- 5 files changed, 68 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index 42b754733ec..a7f3feefba6 100644 --- a/Makefile +++ b/Makefile @@ -600,7 +600,7 @@ $(libcppdir)/cppcheck.o: lib/cppcheck.cpp externals/picojson/picojson.h external $(libcppdir)/ctu.o: lib/ctu.cpp externals/tinyxml2/tinyxml2.h lib/astutils.h lib/check.h lib/config.h lib/ctu.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h lib/xml.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/ctu.cpp -$(libcppdir)/errorlogger.o: lib/errorlogger.cpp externals/tinyxml2/tinyxml2.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/cppcheck.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/smallvector.h lib/standards.h lib/suppressions.h lib/templatesimplifier.h lib/token.h lib/tokenlist.h lib/utils.h lib/vfvalue.h lib/xml.h +$(libcppdir)/errorlogger.o: lib/errorlogger.cpp externals/tinyxml2/tinyxml2.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/cppcheck.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/suppressions.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenlist.h lib/utils.h lib/vfvalue.h lib/xml.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/errorlogger.cpp $(libcppdir)/errortypes.o: lib/errortypes.cpp lib/config.h lib/errortypes.h lib/utils.h diff --git a/lib/errorlogger.cpp b/lib/errorlogger.cpp index d58c5abcbba..d57ad999734 100644 --- a/lib/errorlogger.cpp +++ b/lib/errorlogger.cpp @@ -23,6 +23,7 @@ #include "path.h" #include "settings.h" #include "suppressions.h" +#include "symboldatabase.h" #include "token.h" #include "tokenlist.h" #include "utils.h" @@ -35,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -106,6 +108,8 @@ ErrorMessage::ErrorMessage(const std::list& callstack, const Token file0 = list->getFiles()[0]; setmsg(msg); + + calculateWarningHash(callstack); } @@ -126,7 +130,7 @@ ErrorMessage::ErrorMessage(const std::list& callstack, const Token setmsg(msg); - // hash = calculateWarningHash(list, hashWarning.str()); + calculateWarningHash(callstack); } ErrorMessage::ErrorMessage(ErrorPath errorPath, const TokenList *tokenList, Severity severity, const char id[], const std::string &msg, const CWE &cwe, Certainty certainty) @@ -159,7 +163,12 @@ ErrorMessage::ErrorMessage(ErrorPath errorPath, const TokenList *tokenList, Seve setmsg(msg); - // hash = calculateWarningHash(tokenList, hashWarning.str()); + std::list tokens; + std::transform(errorPath.cbegin(), errorPath.cend(), std::back_inserter(tokens), + [](const ErrorPathItem& e) { + return e.first; + }); + calculateWarningHash(tokens); } // TODO: improve errorhandling? @@ -244,6 +253,58 @@ void ErrorMessage::setmsg(const std::string &msg) } } +void ErrorMessage::calculateWarningHash(const std::list& callstack) +{ + if (callstack.empty()) + return; + // Calculate a hash for this warning message + std::string hashString; + for (const Token* tok: callstack) { + if (!tok) + continue; + if (!tok->scope()) + return; // might be a syntax error before scope info has been set + if (tok->scope()->isExecutable()) { + // Executable scope => include all tokens in the function => if the + // function is changed the hash is changed + for (const Token* t = tok; t; t = t->previous()) { + if (!t->scope()->isExecutable()) + break; + hashString += " " + t->str(); + } + for (const Token* t = tok->next(); t; t = t->next()) { + if (!t->scope()->isExecutable()) + break; + hashString += " " + t->str(); + } + } else { + // Non executable scope => include tokens in current statement => if the current statement is changed the hash is changed + for (const Token* t = tok; t; t = t->previous()) { + if (t->str() == ";") + break; + if (t->scope() != tok->scope()) // stop on {} unless its an initializer + break; + hashString += " " + t->str(); + } + for (const Token* t = tok->next(); t; t = t->next()) { + hashString += " " + t->str(); + if (t->str() == ";") + break; + if (t->scope() != tok->scope()) // stop on {} unless its an initializer + break; + } + } + } + + hashString = id + '\n' + mShortMessage + '\n' + hashString; + + // hash algorithm: sdbm + // any hash algorithm can be used but it has to be the same hash on different platforms and compilers + hash = std::accumulate(hashString.cbegin(), hashString.cend(), std::size_t{0}, [](std::size_t h, unsigned char c) { + return static_cast(c) + (h << 6) + (h << 16) - h; + }); +} + static void serializeString(std::string &oss, const std::string & str) { oss += std::to_string(str.length()); diff --git a/lib/errorlogger.h b/lib/errorlogger.h index 97cc3e7f82e..b28fdba244e 100644 --- a/lib/errorlogger.h +++ b/lib/errorlogger.h @@ -209,6 +209,8 @@ class CPPCHECKLIB ErrorMessage { private: static std::string fixInvalidChars(const std::string& raw); + void calculateWarningHash(const std::list& callstack); + /** Short message */ std::string mShortMessage; diff --git a/oss-fuzz/Makefile b/oss-fuzz/Makefile index eeb795bd35c..e6966747958 100644 --- a/oss-fuzz/Makefile +++ b/oss-fuzz/Makefile @@ -270,7 +270,7 @@ $(libcppdir)/cppcheck.o: ../lib/cppcheck.cpp ../externals/picojson/picojson.h .. $(libcppdir)/ctu.o: ../lib/ctu.cpp ../externals/tinyxml2/tinyxml2.h ../lib/astutils.h ../lib/check.h ../lib/config.h ../lib/ctu.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/path.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h ../lib/xml.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/ctu.cpp -$(libcppdir)/errorlogger.o: ../lib/errorlogger.cpp ../externals/tinyxml2/tinyxml2.h ../lib/check.h ../lib/checkers.h ../lib/color.h ../lib/config.h ../lib/cppcheck.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/path.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/standards.h ../lib/suppressions.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h ../lib/xml.h +$(libcppdir)/errorlogger.o: ../lib/errorlogger.cpp ../externals/tinyxml2/tinyxml2.h ../lib/check.h ../lib/checkers.h ../lib/color.h ../lib/config.h ../lib/cppcheck.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/path.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/suppressions.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h ../lib/xml.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/errorlogger.cpp $(libcppdir)/errortypes.o: ../lib/errortypes.cpp ../lib/config.h ../lib/errortypes.h ../lib/utils.h diff --git a/test/cli/other_test.py b/test/cli/other_test.py index c48a0b50354..f5928c07de5 100644 --- a/test/cli/other_test.py +++ b/test/cli/other_test.py @@ -2666,7 +2666,7 @@ def test_xml_output(tmp_path): # #13391 / #13485 - + p From 5799d47ee5b641fbb962f4dedeff9f3d2a2a368f Mon Sep 17 00:00:00 2001 From: Swasti Shrivastava <37058682+swasti16@users.noreply.github.com> Date: Fri, 7 Aug 2026 11:41:04 +0530 Subject: [PATCH 153/165] Remove GUI compliance report instructions (feature removed) (#8781) The "Compliance report..." File menu option no longer exists in the Cppcheck Premium GUI. Compliance reports are still available via the command-line `compliance-report` tool, documented in the section immediately below. --- man/manual-premium.md | 5 ----- 1 file changed, 5 deletions(-) diff --git a/man/manual-premium.md b/man/manual-premium.md index c8e38666530..9175ef47c8a 100644 --- a/man/manual-premium.md +++ b/man/manual-premium.md @@ -1384,11 +1384,6 @@ If you want to check all files, you can append `:all` to the coding standard. Ex ## Compliance report -### Graphical user interface - -Run a analysis with some coding standards enabled. After that you can click on -the `Compliance report...` in the `File` menu. - ### Command line There is a tool `compliance-report` that is distributed with Cppcheck Premium. To see From dc9bd7fae838e0f374d89fa786cc5949752dd676 Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Fri, 7 Aug 2026 13:10:45 +0200 Subject: [PATCH 154/165] Fix #14966 internalError for valid typedef (#8783) --- lib/tokenize.cpp | 7 +++++++ test/testsimplifytypedef.cpp | 3 +++ 2 files changed, 10 insertions(+) diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 033462ca2e2..0076ce30875 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -566,11 +566,18 @@ namespace { const auto checkForRecursion = [this]() { if (Token::Match(mTypedefToken, "typedef %name% %name% ;")) return; + int nBraces = 0; for (const Token *tok = mTypedefToken; tok != mEndToken; tok = tok->next()) { + if (tok->str() == "{") + ++nBraces; + else if (tok->str() == "}") + --nBraces; if (tok == mNameToken) continue; if (tok->str() != mNameToken->str()) continue; + if (nBraces > 0 && Token::simpleMatch(tok->next(), ";")) + continue; if (Token::Match(tok->previous(), "struct|class|enum|union")) continue; throw InternalError(tok, "recursive typedef encountered"); diff --git a/test/testsimplifytypedef.cpp b/test/testsimplifytypedef.cpp index e83be343e01..f8e3eb1cdf6 100644 --- a/test/testsimplifytypedef.cpp +++ b/test/testsimplifytypedef.cpp @@ -3879,6 +3879,9 @@ class TestSimplifyTypedef : public TestFixture { void simplifyTypedef164() { const char code[] = "typedef struct D{x;}y y;"; ASSERT_THROW_INTERNAL(tok(code), INTERNAL); + + const char code2[] = "typedef struct { int t; } t;"; // #14966 + ASSERT_EQUALS("struct t { int t ; } ;", tok(code2)); } void simplifyTypedefFunction1() { From 14442692603640cf63098be3387e0f5226bc3faf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludvig=20Gunne=20Lindstr=C3=B6m?= Date: Fri, 7 Aug 2026 15:46:02 +0200 Subject: [PATCH 155/165] Fix #14962: False Positive: missingReturn: return expression misdiagnosed as missing return path (#8780) --- lib/checkfunctions.cpp | 7 ++++++- test/testfunctions.cpp | 11 +++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/lib/checkfunctions.cpp b/lib/checkfunctions.cpp index 1edfdfab6ac..1f17d0bbcdc 100644 --- a/lib/checkfunctions.cpp +++ b/lib/checkfunctions.cpp @@ -386,7 +386,12 @@ static const Token *checkMissingReturnScope(const Token *tok, const Library &lib if (!isExhaustiveSwitch(tok->link())) return tok->link(); } else if (tok->scope()->type == ScopeType::eIf) { - const Token *condition = tok->scope()->classDef->next()->astOperand2(); + const Token *paren = tok->link()->linkAt(-1); + if (!paren || !Token::simpleMatch(paren->astOperand1(), "if")) { + tok = tok->link(); + continue; + } + const Token *condition = paren->astOperand2(); if (condition && condition->hasKnownIntValue() && condition->getKnownIntValue() == 1) return checkMissingReturnScope(tok, library); return tok; diff --git a/test/testfunctions.cpp b/test/testfunctions.cpp index f5067bc31dc..d5a18f7d916 100644 --- a/test/testfunctions.cpp +++ b/test/testfunctions.cpp @@ -87,6 +87,7 @@ class TestFunctions : public TestFixture { TEST_CASE(checkMissingReturn6); // #13180 TEST_CASE(checkMissingReturn7); // #14370 - FN try/catch TEST_CASE(checkMissingReturn8); + TEST_CASE(checkMissingReturn9); TEST_CASE(checkMissingReturnStdInt); // #14482 - FN std::int32_t // std::move for locar variable @@ -1936,6 +1937,16 @@ class TestFunctions : public TestFixture { ASSERT_EQUALS("", errout_str()); } + void checkMissingReturn9() { + check("struct S { int v; };\n" + " S operator/(S x, S y) { return { x.v / y.v }; }\n" + " S f(int a, int b) {\n" + " if (b) { return S{ a } / S{ b }; }\n" + " else { return {}; }\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + } + void checkMissingReturnStdInt() {// #14482 - FN check("std::int32_t f() {}\n"); ASSERT_EQUALS("[test.cpp:1:19]: (error) Found an exit path from function with non-void return type that has missing return statement [missingReturn]\n", errout_str()); From 4b0c239a321ff12bd34627c0913d8712dd105456 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludvig=20Gunne=20Lindstr=C3=B6m?= Date: Sat, 8 Aug 2026 09:45:12 +0200 Subject: [PATCH 156/165] Fix #14017: Missing varid on namespace member (#8784) --- lib/tokenize.cpp | 6 ++++-- test/testvarid.cpp | 9 +++++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 0076ce30875..1a6d4a4e53f 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -5172,8 +5172,10 @@ static Token * matchMemberName(const std::list &scope, const Token // Current scope.. for (auto it = scope.cbegin(); it != scope.cend(); ++it) { - if (scopeIt == scopeInfo.cend() || scopeIt->name != *it) - return nullptr; + if (scopeIt == scopeInfo.cend() || scopeIt->name != *it) { + scopeIt = scopeInfo.cbegin(); + break; + } ++scopeIt; } diff --git a/test/testvarid.cpp b/test/testvarid.cpp index c8d16bc89a5..e30c613c0bc 100644 --- a/test/testvarid.cpp +++ b/test/testvarid.cpp @@ -102,6 +102,7 @@ class TestVarID : public TestFixture { TEST_CASE(varid70); // #12660 - function TEST_CASE(varid71); // #12676 - wrong varid in uninstantiated templated constructor TEST_CASE(varid72); + TEST_CASE(varid73); TEST_CASE(varid_for_1); TEST_CASE(varid_for_2); TEST_CASE(varid_for_3); @@ -1409,6 +1410,14 @@ class TestVarID : public TestFixture { ASSERT_EQUALS(expected1, tokenize(code1)); } + void varid73() { + const char code[] = "namespace a { int x; };\n" + "namespace b { int x = a::x; };\n"; + const char expected[] = "1: namespace a { int x@1 ; } ;\n" + "2: namespace b { int x@2 ; x@2 = a :: x@1 ; } ;\n"; + ASSERT_EQUALS(expected, tokenize(code)); + } + void varid_for_1() { const char code[] = "void foo(int a, int b) {\n" " for (int a=1,b=2;;) {}\n" From b1b7e3ccb5e14da331e45e086df3a73101a00513 Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Mon, 10 Aug 2026 09:03:31 +0200 Subject: [PATCH 157/165] Fix #14948 FP bufferAccessOutOfBounds after container size check (#8763) Co-authored-by: chrchr-github --- lib/checkbufferoverrun.cpp | 11 +++++++++-- test/testbufferoverrun.cpp | 17 +++++++++++++++++ 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/lib/checkbufferoverrun.cpp b/lib/checkbufferoverrun.cpp index 8c8912ed06d..f0a12efccec 100644 --- a/lib/checkbufferoverrun.cpp +++ b/lib/checkbufferoverrun.cpp @@ -68,7 +68,9 @@ static const ValueFlow::Value *getBufferSizeValue(const Token *tok) auto it = std::find_if(tokenValues.cbegin(), tokenValues.cend(), std::mem_fn(&ValueFlow::Value::isBufferSizeValue)); if (it != tokenValues.cend()) return &*it; - it = std::find_if(tokenValues.cbegin(), tokenValues.cend(), std::mem_fn(&ValueFlow::Value::isContainerSizeValue)); + it = std::find_if(tokenValues.cbegin(), tokenValues.cend(), [](const ValueFlow::Value& v) { + return v.isContainerSizeValue() && !v.isImpossible(); + }); return it == tokenValues.cend() ? nullptr : &*it; } @@ -597,6 +599,8 @@ ValueFlow::Value CheckBufferOverrunImpl::getBufferSize(const Token *bufTok, cons ValueFlow::Value bufSizeVal; bufSizeVal.valueType = ValueFlow::Value::ValueType::BUFFER_SIZE; bufSizeVal.intvalue = value->intvalue * elementSize; + bufSizeVal.valueKind = value->valueKind; + bufSizeVal.errorPath = value->errorPath; return bufSizeVal; } } @@ -730,7 +734,10 @@ void CheckBufferOverrunImpl::bufferOverflow() void CheckBufferOverrunImpl::bufferOverflowError(const Token *tok, const ValueFlow::Value *value, Certainty certainty) { - reportError(getErrorPath(tok, value, "Buffer overrun"), Severity::error, "bufferAccessOutOfBounds", "Buffer is accessed out of bounds: " + (tok ? getRealBufferTok(tok)->expressionString() : "buf"), CWE_BUFFER_OVERRUN, certainty); + const auto errorPath = getErrorPath(tok, value, "Buffer overrun"); + const auto severity = !value || value->isKnown() ? Severity::error : Severity::warning; + const std::string msg = "Buffer is accessed out of bounds: " + (tok ? getRealBufferTok(tok)->expressionString() : "buf"); + reportError(errorPath, severity, "bufferAccessOutOfBounds", msg, CWE_BUFFER_OVERRUN, certainty); } //--------------------------------------------------------------------------- diff --git a/test/testbufferoverrun.cpp b/test/testbufferoverrun.cpp index 8bac50a468c..3914f0ee828 100644 --- a/test/testbufferoverrun.cpp +++ b/test/testbufferoverrun.cpp @@ -3628,6 +3628,14 @@ class TestBufferOverrun : public TestFixture { " memset(&a[i], 0, sizeof(a));\n" "}\n"); ASSERT_EQUALS("[test.cpp:4:16]: (error) Buffer is accessed out of bounds: &a[i] [bufferAccessOutOfBounds]\n", errout_str()); + + check("void f(const std::vector& s) {\n" // #14948 + " if (s.size() < 4)\n" + " return;\n" + " uint32_t u = 0;\n" + " std::memcpy(&u, &s[0], sizeof(u));\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); } void buffer_overrun_errorpath() { @@ -3642,6 +3650,15 @@ class TestBufferOverrun : public TestFixture { ASSERT_EQUALS("[test.cpp:3:12]: error: Buffer is accessed out of bounds: p [bufferAccessOutOfBounds]\n" "[test.cpp:2:13]: note: Assign p, buffer with size 10\n" "[test.cpp:3:12]: note: Buffer overrun\n", errout_str()); + + check("void f(const std::vector& s) {\n" + " if (s.size() == 2) {}\n" + " uint32_t u = 0;\n" + " std::memcpy(&u, &s[0], sizeof(u));\n" + "}\n", s); + ASSERT_EQUALS("[test.cpp:4:21]: warning: Buffer is accessed out of bounds: &s[0] [bufferAccessOutOfBounds]\n" + "[test.cpp:2:18]: note: Assuming that condition 's.size()==2' is not redundant\n" + "[test.cpp:4:21]: note: Buffer overrun\n", errout_str()); } void buffer_overrun_bailoutIfSwitch() { From dfcec18902c43786c4e1ab5c01c302fbf718c52d Mon Sep 17 00:00:00 2001 From: correctmost <134317971+correctmost@users.noreply.github.com> Date: Mon, 10 Aug 2026 04:47:39 -0400 Subject: [PATCH 158/165] gtk.cfg: Remove pure annotation from g_str_has_prefix/suffix (#8788) `g_str_has_prefix` and `g_str_has_suffix` are not technically pure because they can log to the console if a precondition fails. This partially reverts commit 7cc7c0bb5. --- Some notes: The original `gtk.cfg` change hasn't been released yet, so the revert shouldn't cause any churn for users. GLib has code like this: ```c gboolean (g_str_has_prefix) (const gchar *str, const gchar *prefix) { g_return_val_if_fail (str != NULL, FALSE); g_return_val_if_fail (prefix != NULL, FALSE); return strncmp (str, prefix, strlen (prefix)) == 0; } ``` Most real-world code is treating this function as safe to call inside of an assert, even though it could technically have side effects if one of the preconditions fails. I removed the pure annotation to err on the side of correctness and pedantry, even though most projects would view the warnings as "false positives" from a practical perspective. Here is example usage from QEMU: ```c char *qemu_chr_get_filename(Chardev *chr) { ChardevClass *cc = CHARDEV_GET_CLASS(chr); const char *typename; if (cc->chr_get_filename) { return cc->chr_get_filename(chr); } typename = object_get_typename(OBJECT(chr)); assert(g_str_has_prefix(typename, "chardev-")); return g_strdup(typename + 8); } ``` --- cfg/gtk.cfg | 1 - test/cfg/gtk.c | 6 ++++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/cfg/gtk.cfg b/cfg/gtk.cfg index 5e94a0bbb5c..a1d7763670e 100644 --- a/cfg/gtk.cfg +++ b/cfg/gtk.cfg @@ -5221,7 +5221,6 @@ - false diff --git a/test/cfg/gtk.c b/test/cfg/gtk.c index 6b48bca2f9e..b923135e2d9 100644 --- a/test/cfg/gtk.c +++ b/test/cfg/gtk.c @@ -59,8 +59,14 @@ void validCode(int argInt, GHashTableIter * hash_table_iter, GHashTable * hash_t g_string_free(pGStr1, TRUE); gchar * pGchar1 = g_strconcat("a", "b", NULL); + + // g_str_has_prefix and g_str_has_suffix can have side effects because they use + // g_return_val_if_fail, which logs to the console upon failure + // cppcheck-suppress assertWithSideEffect g_assert_true(g_str_has_prefix(pGchar1, "a")); + // cppcheck-suppress assertWithSideEffect g_assert_true(g_str_has_suffix(pGchar1, "b")); + printf("%s", pGchar1); g_free(pGchar1); From 4184c39b50ab7443ce62ea617ed033cf6812a5df Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Thu, 13 Aug 2026 16:43:27 +0200 Subject: [PATCH 159/165] Fix #14971 [regression] internalError for valid typedef (#8790) Co-authored-by: chrchr-github --- lib/tokenize.cpp | 2 +- test/testsimplifytypedef.cpp | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 1a6d4a4e53f..27be2e544a2 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -576,7 +576,7 @@ namespace { continue; if (tok->str() != mNameToken->str()) continue; - if (nBraces > 0 && Token::simpleMatch(tok->next(), ";")) + if (nBraces > 0 && Token::Match(tok->next(), "[;(]")) continue; if (Token::Match(tok->previous(), "struct|class|enum|union")) continue; diff --git a/test/testsimplifytypedef.cpp b/test/testsimplifytypedef.cpp index f8e3eb1cdf6..78d7bd25f3d 100644 --- a/test/testsimplifytypedef.cpp +++ b/test/testsimplifytypedef.cpp @@ -3882,6 +3882,9 @@ class TestSimplifyTypedef : public TestFixture { const char code2[] = "typedef struct { int t; } t;"; // #14966 ASSERT_EQUALS("struct t { int t ; } ;", tok(code2)); + + const char code3[] = "typedef struct S { S() {} } S;"; // #14971 + ASSERT_EQUALS("struct S { S ( ) { } } ;", tok(code3)); } void simplifyTypedefFunction1() { From b3917652c0205dfa2cea97b868186364a0104ebb Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Fri, 14 Aug 2026 09:27:11 +0200 Subject: [PATCH 160/165] Fix #14725 FP redundantIfRemove when conditional code has extra code (#8789) --- lib/checkstl.cpp | 3 +++ test/teststl.cpp | 10 ++++++++++ 2 files changed, 13 insertions(+) diff --git a/lib/checkstl.cpp b/lib/checkstl.cpp index de1d82792ac..cf2b671606f 100644 --- a/lib/checkstl.cpp +++ b/lib/checkstl.cpp @@ -1867,6 +1867,9 @@ void CheckStlImpl::redundantCondition() const Token *var3 = var2->tokAt(7); const Token *any2 = var3->tokAt(4); + if (any2->tokAt(3) != scope.bodyEnd) + continue; + // Check if all the "%name%" fields are the same and if all the "%any%" are the same.. if (var1->str() == var2->str() && var2->str() == var3->str() && diff --git a/test/teststl.cpp b/test/teststl.cpp index 2570059c19e..1cc11029804 100644 --- a/test/teststl.cpp +++ b/test/teststl.cpp @@ -4556,6 +4556,16 @@ class TestStl : public TestFixture { " haystack.remove(needle);" "}"); ASSERT_EQUALS("[test.cpp:3:9]: (style) Redundant checking of STL container element existence before removing it. [redundantIfRemove]\n", errout_str()); + + check("void g(const std::string&);\n" // #14725 + "std::set g_s;\n" + "void f(const std::string& k) {\n" + " if (g_s.find(k) != g_s.end()) {\n" + " g_s.erase(k);\n" + " g(k);\n" + " }\n" + "}"); + ASSERT_EQUALS("", errout_str()); } void missingInnerComparison1() { From 2d75160cada40e58bd54afd77f730259e069f8c9 Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Fri, 14 Aug 2026 09:28:22 +0200 Subject: [PATCH 161/165] Fix #14973 FP assertWithSideEffect with function pointer comparison (#8792) --- lib/checkassert.cpp | 5 +++++ test/testassert.cpp | 11 +++++++++++ 2 files changed, 16 insertions(+) diff --git a/lib/checkassert.cpp b/lib/checkassert.cpp index 4578f7395ba..00bb95e319a 100644 --- a/lib/checkassert.cpp +++ b/lib/checkassert.cpp @@ -78,6 +78,11 @@ void CheckAssertImpl::assertWithSideEffects() continue; } + const Token* parent = tmp->astParent(); + while (Token::Match(parent, ".|::")) + parent = parent->astParent(); + if (!Token::simpleMatch(parent, "(")) + continue; const Function* f = tmp->function(); const Scope* scope = f->functionScope; if (!scope) { diff --git a/test/testassert.cpp b/test/testassert.cpp index ea170c43f2d..a76b8207445 100644 --- a/test/testassert.cpp +++ b/test/testassert.cpp @@ -147,6 +147,17 @@ class TestAssert : public TestFixture { " assert(g());\n" "}\n"); ASSERT_EQUALS("", errout_str()); + + check("int i;\n" // #14973 + "bool f() {\n" + " i = 0;\n" + " return true;\n" + "}\n" + "void g() {\n" + " bool (*fp)() = f;\n" + " assert(fp == f);\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); } void memberFunctionCallInAssert() { From 7d48e00b6da72ff56dbab8fc5c50a89affab237f Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Mon, 17 Aug 2026 09:53:39 +0200 Subject: [PATCH 162/165] Fix #14976 FP uninitvar (std::size() used on array) (#8795) Co-authored-by: chrchr-github --- cfg/std.cfg | 4 +--- test/cfg/std.cpp | 5 +++++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/cfg/std.cfg b/cfg/std.cfg index 4662d0a4632..6c434b8715c 100644 --- a/cfg/std.cfg +++ b/cfg/std.cfg @@ -8343,9 +8343,7 @@ initializer list (7) string& replace (const_iterator i1, const_iterator i2, init - - - + false diff --git a/test/cfg/std.cpp b/test/cfg/std.cpp index 850dd74b997..e4753a09f7c 100644 --- a/test/cfg/std.cpp +++ b/test/cfg/std.cpp @@ -5071,6 +5071,11 @@ int f_constVariable_std_begin() { return arr[0]; } +std::size_t uninitvar_std_size() { // #14976 + int a[3]; + return std::size(a); +} + void smartPtr_get() { std::unique_ptr p; From ab9989ca09bc7d5bc573e2e6214c422d998c4f38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludvig=20Gunne=20Lindstr=C3=B6m?= Date: Mon, 17 Aug 2026 14:47:44 +0200 Subject: [PATCH 163/165] Fix #14978: Valueflow: Missing buffer size for `::operator new` (#8799) --- lib/valueflow.cpp | 8 +++++++- test/testvalueflow.cpp | 7 +++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index 5efe698bf61..7acf7179723 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -7025,6 +7025,12 @@ static void valueFlowDynamicBufferSize(const TokenList& tokenlist, const SymbolD auto getBufferSizeFromNew = [&](const Token* newTok) -> MathLib::bigint { MathLib::bigint sizeValue = -1, numElem = -1; + // ::operator new(size_t size) + if (Token::Match(newTok->astOperand1(), "::| operatornew")) { + const Token *sizeTok = newTok->astOperand2(); + return sizeTok->hasKnownIntValue() ? sizeTok->getKnownIntValue() : -1; + } + if (newTok && newTok->astOperand1()) { // number of elements const Token* bracTok = nullptr, *typeTok = nullptr; if (newTok->astOperand1()->str() == "[") @@ -7071,7 +7077,7 @@ static void valueFlowDynamicBufferSize(const TokenList& tokenlist, const SymbolD if (!rhs) continue; - const bool isNew = rhs->isCpp() && rhs->str() == "new"; + const bool isNew = rhs->isCpp() && (rhs->str() == "new" || Token::Match(rhs->astOperand1(), "::| operatornew")); if (!isNew && !Token::Match(rhs->previous(), "%name% (")) continue; diff --git a/test/testvalueflow.cpp b/test/testvalueflow.cpp index 4fc47f63d86..39916ddeb43 100644 --- a/test/testvalueflow.cpp +++ b/test/testvalueflow.cpp @@ -7932,6 +7932,13 @@ class TestValueFlow : public TestFixture { " return x;\n" "}"; ASSERT_EQUALS(true, testValueOfX(code, 4U, 4, ValueFlow::Value::ValueType::BUFFER_SIZE, &settingsCfg)); + + code = "void f()\n" + "{\n" + " void *x = ::operator new(0);\n" + " (void) x;\n" + "}\n"; + ASSERT_EQUALS(true, testValueOfX(code, 4U, 0, ValueFlow::Value::ValueType::BUFFER_SIZE)); } void valueFlowSafeFunctionParameterValues() { From 777a112d9a8ddd3f77b206807cbbfb2ee1a1d202 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludvig=20Gunne=20Lindstr=C3=B6m?= Date: Mon, 17 Aug 2026 15:12:57 +0200 Subject: [PATCH 164/165] Fix #14946: `originalName` in dumpfile missing for local typedefs (#8793) --- lib/tokenize.cpp | 103 ++++++++++++++++++----------------- test/testsimplifytypedef.cpp | 32 +++++++++++ 2 files changed, 85 insertions(+), 50 deletions(-) diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 27be2e544a2..bc50979a04f 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -1187,21 +1187,23 @@ void Tokenizer::simplifyTypedef() simplifyTypedefCpp(); } -static Token* simplifyTypedefCopyTokens(Token* to, const Token* fromStart, const Token* toEnd, const Token* location) { +static Token* simplifyTypedefCopyTokens(Token* to, const Token* fromStart, const Token* toEnd, const Token* location, const std::string &originalName) { Token* ret = TokenList::copyTokens(to, fromStart, toEnd); for (Token* tok = to->next(); tok != ret->next(); tok = tok->next()) { tok->linenr(location->linenr()); tok->column(location->column()); tok->isSimplifiedTypedef(true); + tok->originalName(originalName); } return ret; } -static Token* simplifyTypedefInsertToken(Token* tok, const std::string& str, const Token* location) { +static Token* simplifyTypedefInsertToken(Token* tok, const std::string& str, const Token* location, const std::string &originalName) { tok = tok->insertToken(str); tok->linenr(location->linenr()); tok->column(location->column()); tok->isSimplifiedTypedef(true); + tok->originalName(originalName); return tok; } @@ -2037,12 +2039,13 @@ void Tokenizer::simplifyTypedefCpp() // start substituting at the typedef name by replacing it with the type const Token* location = tok2; + const std::string originalName = tok2->str(); for (Token* tok3 = typeStart; tok3 && (tok3->str() != ";"); tok3 = tok3->next()) tok3->isSimplifiedTypedef(true); if (isPointerTypeCall) { tok2->deleteThis(); - tok2 = simplifyTypedefInsertToken(tok2, "0", location); - simplifyTypedefInsertToken(tok2->next(), "0", location); + tok2 = simplifyTypedefInsertToken(tok2, "0", location, originalName); + simplifyTypedefInsertToken(tok2->next(), "0", location, originalName); } if (Token::Match(tok2->tokAt(-1), "class|struct|union") && tok2->strAt(-1) == typeStart->str()) tok2->deletePrevious(); @@ -2051,7 +2054,7 @@ void Tokenizer::simplifyTypedefCpp() tok2->previous()->str("typedef"); tok2->insertToken(tok2->str()); } - tok2->originalName(tok2->str()); + tok2->originalName(originalName); tok2->str(typeStart->str()); // restore qualification if it was removed @@ -2060,12 +2063,12 @@ void Tokenizer::simplifyTypedefCpp() tok2 = tok2->previous(); if (globalScope) { - tok2 = simplifyTypedefInsertToken(tok2, "::", location); + tok2 = simplifyTypedefInsertToken(tok2, "::", location, originalName); } for (std::size_t i = classLevel; i < spaceInfo.size(); ++i) { - tok2 = simplifyTypedefInsertToken(tok2, spaceInfo[i].className, location); - tok2 = simplifyTypedefInsertToken(tok2, "::", location); + tok2 = simplifyTypedefInsertToken(tok2, spaceInfo[i].className, location, originalName); + tok2 = simplifyTypedefInsertToken(tok2, "::", location, originalName); } } @@ -2082,11 +2085,11 @@ void Tokenizer::simplifyTypedefCpp() std::string::size_type spaceIdx = 0; std::string::size_type startIdx = 0; while ((spaceIdx = removed1.find(' ', startIdx)) != std::string::npos) { - simplifyTypedefInsertToken(tok2->previous(), removed1.substr(startIdx, spaceIdx - startIdx), location); + simplifyTypedefInsertToken(tok2->previous(), removed1.substr(startIdx, spaceIdx - startIdx), location, originalName); startIdx = spaceIdx + 1; } - simplifyTypedefInsertToken(tok2->previous(), removed1.substr(startIdx), location); - simplifyTypedefInsertToken(tok2->previous(), "::", location); + simplifyTypedefInsertToken(tok2->previous(), removed1.substr(startIdx), location, originalName); + simplifyTypedefInsertToken(tok2->previous(), "::", location, originalName); break; } idx = removed1.rfind(" ::"); @@ -2098,23 +2101,23 @@ void Tokenizer::simplifyTypedefCpp() } Token* constTok = Token::simpleMatch(tok2->previous(), "const") ? tok2->previous() : nullptr; // add remainder of type - tok2 = simplifyTypedefCopyTokens(tok2, typeStart->next(), typeEnd, location); + tok2 = simplifyTypedefCopyTokens(tok2, typeStart->next(), typeEnd, location, originalName); if (!pointers.empty()) { for (const std::string &p : pointers) // cppcheck-suppress useStlAlgorithm - tok2 = simplifyTypedefInsertToken(tok2, p, location); + tok2 = simplifyTypedefInsertToken(tok2, p, location, originalName); if (constTok && !functionPtr) { - tok2 = simplifyTypedefInsertToken(tok2, "const", location); + tok2 = simplifyTypedefInsertToken(tok2, "const", location, originalName); constTok->deleteThis(); location = constTok; } } if (funcStart && funcEnd) { - tok2 = simplifyTypedefInsertToken(tok2, "(", location); + tok2 = simplifyTypedefInsertToken(tok2, "(", location, originalName); Token *paren = tok2; - tok2 = simplifyTypedefCopyTokens(tok2, funcStart, funcEnd, location); + tok2 = simplifyTypedefCopyTokens(tok2, funcStart, funcEnd, location, originalName); if (!inCast) tok2 = processFunc(tok2, inOperator); @@ -2125,17 +2128,17 @@ void Tokenizer::simplifyTypedefCpp() while (Token::Match(tok2, "%name%|] [")) tok2 = tok2->linkAt(1); - tok2 = simplifyTypedefInsertToken(tok2, ")", location); + tok2 = simplifyTypedefInsertToken(tok2, ")", location, originalName); Token::createMutualLinks(tok2, paren); - tok2 = simplifyTypedefCopyTokens(tok2, argStart, argEnd, location); + tok2 = simplifyTypedefCopyTokens(tok2, argStart, argEnd, location, originalName); if (specStart) { Token *spec = specStart; - tok2 = simplifyTypedefInsertToken(tok2, spec->str(), location); + tok2 = simplifyTypedefInsertToken(tok2, spec->str(), location, originalName); while (spec != specEnd) { spec = spec->next(); - tok2 = simplifyTypedefInsertToken(tok2, spec->str(), location); + tok2 = simplifyTypedefInsertToken(tok2, spec->str(), location, originalName); } } } @@ -2147,20 +2150,20 @@ void Tokenizer::simplifyTypedefCpp() if (!inTemplate && function && tok2->next() && tok2->strAt(1) != "*") needParen = false; if (needParen) { - tok2 = simplifyTypedefInsertToken(tok2, "(", location); + tok2 = simplifyTypedefInsertToken(tok2, "(", location, originalName); } Token *tok3 = tok2; if (namespaceStart) { const Token *tok4 = namespaceStart; while (tok4 != namespaceEnd) { - tok2 = simplifyTypedefInsertToken(tok2, tok4->str(), location); + tok2 = simplifyTypedefInsertToken(tok2, tok4->str(), location, originalName); tok4 = tok4->next(); } - tok2 = simplifyTypedefInsertToken(tok2, namespaceEnd->str(), location); + tok2 = simplifyTypedefInsertToken(tok2, namespaceEnd->str(), location, originalName); } if (functionPtr) { - tok2 = simplifyTypedefInsertToken(tok2, "*", location); + tok2 = simplifyTypedefInsertToken(tok2, "*", location, originalName); } if (!inCast) @@ -2170,35 +2173,35 @@ void Tokenizer::simplifyTypedefCpp() if (!tok2) syntaxError(nullptr); - tok2 = simplifyTypedefInsertToken(tok2, ")", location); + tok2 = simplifyTypedefInsertToken(tok2, ")", location, originalName); Token::createMutualLinks(tok2, tok3); } if (!tok2) syntaxError(nullptr); - tok2 = simplifyTypedefCopyTokens(tok2, argStart, argEnd, location); + tok2 = simplifyTypedefCopyTokens(tok2, argStart, argEnd, location, originalName); if (inTemplate) { tok2 = tok2->next(); } if (specStart) { Token *spec = specStart; - tok2 = simplifyTypedefInsertToken(tok2, spec->str(), location); + tok2 = simplifyTypedefInsertToken(tok2, spec->str(), location, originalName); while (spec != specEnd) { spec = spec->next(); - tok2 = simplifyTypedefInsertToken(tok2, spec->str(), location); + tok2 = simplifyTypedefInsertToken(tok2, spec->str(), location, originalName); } } } else if (functionRetFuncPtr || functionPtrRetFuncPtr) { - tok2 = simplifyTypedefInsertToken(tok2, "(", location); + tok2 = simplifyTypedefInsertToken(tok2, "(", location, originalName); Token *tok3 = tok2; - tok2 = simplifyTypedefInsertToken(tok2, "*", location); + tok2 = simplifyTypedefInsertToken(tok2, "*", location, originalName); Token * tok4 = nullptr; if (functionPtrRetFuncPtr) { - tok2 = simplifyTypedefInsertToken(tok2, "(", location); + tok2 = simplifyTypedefInsertToken(tok2, "(", location, originalName); tok4 = tok2; - tok2 = simplifyTypedefInsertToken(tok2, "*", location); + tok2 = simplifyTypedefInsertToken(tok2, "*", location, originalName); } // skip over variable name if there @@ -2211,24 +2214,24 @@ void Tokenizer::simplifyTypedefCpp() } if (tok4 && functionPtrRetFuncPtr) { - tok2 = simplifyTypedefInsertToken(tok2,")", location); + tok2 = simplifyTypedefInsertToken(tok2,")", location, originalName); Token::createMutualLinks(tok2, tok4); } - tok2 = simplifyTypedefCopyTokens(tok2, argStart, argEnd, location); + tok2 = simplifyTypedefCopyTokens(tok2, argStart, argEnd, location, originalName); - tok2 = simplifyTypedefInsertToken(tok2, ")", location); + tok2 = simplifyTypedefInsertToken(tok2, ")", location, originalName); Token::createMutualLinks(tok2, tok3); - tok2 = simplifyTypedefCopyTokens(tok2, argFuncRetStart, argFuncRetEnd, location); + tok2 = simplifyTypedefCopyTokens(tok2, argFuncRetStart, argFuncRetEnd, location, originalName); } else if (ptrToArray || refToArray) { - tok2 = simplifyTypedefInsertToken(tok2, "(", location); + tok2 = simplifyTypedefInsertToken(tok2, "(", location, originalName); Token *tok3 = tok2; if (ptrToArray) - tok2 = simplifyTypedefInsertToken(tok2, "*", location); + tok2 = simplifyTypedefInsertToken(tok2, "*", location, originalName); else - tok2 = simplifyTypedefInsertToken(tok2, "&", location); + tok2 = simplifyTypedefInsertToken(tok2, "&", location, originalName); bool hasName = false; // skip over name @@ -2247,14 +2250,14 @@ void Tokenizer::simplifyTypedefCpp() tok2 = tok2->linkAt(1); } - simplifyTypedefInsertToken(tok2, ")", location); + simplifyTypedefInsertToken(tok2, ")", location, originalName); Token::createMutualLinks(tok2->next(), tok3); if (!hasName) tok2 = tok2->next(); } else if (ptrMember) { if (Token::simpleMatch(tok2, "* (")) { - tok2 = simplifyTypedefInsertToken(tok2, "*", location); + tok2 = simplifyTypedefInsertToken(tok2, "*", location, originalName); } else { // This is the case of casting operator. // Name is not available, and () should not be @@ -2263,7 +2266,7 @@ void Tokenizer::simplifyTypedefCpp() Token *openParenthesis = nullptr; if (!castOperator) { - tok2 = simplifyTypedefInsertToken(tok2, "(", location); + tok2 = simplifyTypedefInsertToken(tok2, "(", location, originalName); openParenthesis = tok2; } @@ -2271,25 +2274,25 @@ void Tokenizer::simplifyTypedefCpp() const Token *tok4 = namespaceStart; while (tok4 != namespaceEnd) { - tok2 = simplifyTypedefInsertToken(tok2, tok4->str(), location); + tok2 = simplifyTypedefInsertToken(tok2, tok4->str(), location, originalName); tok4 = tok4->next(); } - tok2 = simplifyTypedefInsertToken(tok2, namespaceEnd->str(), location); + tok2 = simplifyTypedefInsertToken(tok2, namespaceEnd->str(), location, originalName); - tok2 = simplifyTypedefInsertToken(tok2, "*", location); + tok2 = simplifyTypedefInsertToken(tok2, "*", location, originalName); if (openParenthesis) { // Skip over name, if any if (Token::Match(tok2->next(), "%name%")) tok2 = tok2->next(); - tok2 = simplifyTypedefInsertToken(tok2, ")", location); + tok2 = simplifyTypedefInsertToken(tok2, ")", location, originalName); Token::createMutualLinks(tok2, openParenthesis); } } } else if (typeOf) { - tok2 = simplifyTypedefCopyTokens(tok2, argStart, argEnd, location); + tok2 = simplifyTypedefCopyTokens(tok2, argStart, argEnd, location, originalName); } else if (Token::Match(tok2, "%name% [")) { while (Token::Match(tok2, "%name%|] [")) { tok2 = tok2->linkAt(1); @@ -2311,7 +2314,7 @@ void Tokenizer::simplifyTypedefCpp() // reference or pointer to array? if (Token::Match(tok2, "&|*|&&")) { tok2 = tok2->previous(); - Token *tok3 = simplifyTypedefInsertToken(tok2, "(", location); + Token *tok3 = simplifyTypedefInsertToken(tok2, "(", location, originalName); // handle missing variable name if (Token::Match(tok3, "( *|&|&& *|&|&& %name%")) @@ -2349,7 +2352,7 @@ void Tokenizer::simplifyTypedefCpp() tok2 = tok2->tokAt(3); } - tok2 = simplifyTypedefInsertToken(tok2, ")", location); + tok2 = simplifyTypedefInsertToken(tok2, ")", location, originalName); Token::createMutualLinks(tok2, tok3); } @@ -2360,7 +2363,7 @@ void Tokenizer::simplifyTypedefCpp() while (tok2->strAt(1) == "[") tok2 = tok2->linkAt(1); - tok2 = simplifyTypedefCopyTokens(tok2, arrayStart, arrayEnd, location); + tok2 = simplifyTypedefCopyTokens(tok2, arrayStart, arrayEnd, location, originalName); if (!tok2->next()) syntaxError(tok2); diff --git a/test/testsimplifytypedef.cpp b/test/testsimplifytypedef.cpp index 78d7bd25f3d..330808b7220 100644 --- a/test/testsimplifytypedef.cpp +++ b/test/testsimplifytypedef.cpp @@ -257,6 +257,8 @@ class TestSimplifyTypedef : public TestFixture { TEST_CASE(simplifyTypedefOriginalName1); TEST_CASE(simplifyTypedefOriginalName2); TEST_CASE(simplifyTypedefOriginalName3); + TEST_CASE(simplifyTypedefOriginalName4); + TEST_CASE(simplifyTypedefOriginalName5); TEST_CASE(simplifyTypedefTokenColumn1); TEST_CASE(simplifyTypedefTokenColumn2); @@ -4622,6 +4624,36 @@ class TestSimplifyTypedef : public TestFixture { ASSERT_EQUALS("A", token->originalName()); } + void simplifyTypedefOriginalName4() { + const char code[] = "void f(void) {\n" + " typedef unsigned int A;\n" + " A a;\n" + "}\n"; + TokenList tokenlist{ settings1, Standards::Language::C }; + ASSERT(TokenListHelper::createTokensFromString(tokenlist, code, "file.c")); + TokenizerTest tokenizer(std::move(tokenlist), *this); + tokenizer.createLinks(); + tokenizer.simplifyTypedef(); + ASSERT_NO_THROW(tokenizer.validate()); + const Token* token = Token::findsimplematch(tokenizer.list.front(), "int"); + ASSERT_EQUALS("A", token->originalName()); + } + + void simplifyTypedefOriginalName5() { + const char code[] = "void f(void) {\n" + " typedef void (*A)(int);\n" + " A a;\n" + "}\n"; + TokenList tokenlist{ settings1, Standards::Language::C }; + ASSERT(TokenListHelper::createTokensFromString(tokenlist, code, "file.c")); + TokenizerTest tokenizer(std::move(tokenlist), *this); + tokenizer.createLinks(); + tokenizer.simplifyTypedef(); + ASSERT_NO_THROW(tokenizer.validate()); + const Token* token = Token::findsimplematch(tokenizer.list.front(), "int"); + ASSERT_EQUALS("A", token->originalName()); + } + void simplifyTypedefTokenColumn1() { // #13155 const char code[] = "void foo(void) {\n" " typedef signed int MY_INT;\n" From 2e19539840f28d059b7e9fa2402e81994d9d0d23 Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Tue, 18 Aug 2026 17:04:48 +0200 Subject: [PATCH 165/165] Fix #14977 internalError for valid typedef (operator=) (#8798) Co-authored-by: chrchr-github --- lib/tokenize.cpp | 4 ++-- test/testsimplifytypedef.cpp | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index bc50979a04f..b22658db28c 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -572,12 +572,12 @@ namespace { ++nBraces; else if (tok->str() == "}") --nBraces; + if (nBraces > 0) + continue; if (tok == mNameToken) continue; if (tok->str() != mNameToken->str()) continue; - if (nBraces > 0 && Token::Match(tok->next(), "[;(]")) - continue; if (Token::Match(tok->previous(), "struct|class|enum|union")) continue; throw InternalError(tok, "recursive typedef encountered"); diff --git a/test/testsimplifytypedef.cpp b/test/testsimplifytypedef.cpp index 330808b7220..6e8b8820177 100644 --- a/test/testsimplifytypedef.cpp +++ b/test/testsimplifytypedef.cpp @@ -3887,6 +3887,9 @@ class TestSimplifyTypedef : public TestFixture { const char code3[] = "typedef struct S { S() {} } S;"; // #14971 ASSERT_EQUALS("struct S { S ( ) { } } ;", tok(code3)); + + const char code4[] = "typedef struct S { S& operator=(const S&) = delete; } S;"; // #14977 + ASSERT_EQUALS("struct S { S & operator= ( const S & ) = delete ; } ;", tok(code4)); } void simplifyTypedefFunction1() {