From d3c8ffca1c05ecb1912118b86d4f48395c39e3d5 Mon Sep 17 00:00:00 2001 From: chrchr-github Date: Wed, 31 Dec 2025 15:01:11 +0100 Subject: [PATCH 01/10] Fix #14356 fuzzing crash (null-pointer-use) in ReverseTraversal::traverse() --- lib/tokenize.cpp | 2 ++ .../fuzz-crash_c/crash-24c217c96d177b8dff4028bce639756d6a8c6088 | 1 + 2 files changed, 3 insertions(+) create mode 100644 test/cli/fuzz-crash_c/crash-24c217c96d177b8dff4028bce639756d6a8c6088 diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 952ba4b6c00..652520039a5 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -8936,6 +8936,8 @@ void Tokenizer::findGarbageCode() const syntaxError(tok); if (Token::Match(tok, "& %comp%|&&|%oror%|&|%or%") && tok->strAt(1) != ">") syntaxError(tok); + if (Token::Match(tok, "%comp%|&&|%oror%|&|%or% }") && tok->str() != ">") + syntaxError(tok); if (Token::Match(tok, "^ %op%") && !Token::Match(tok->next(), "[>*+-!~]")) syntaxError(tok); if (Token::Match(tok, ": [)]=]")) diff --git a/test/cli/fuzz-crash_c/crash-24c217c96d177b8dff4028bce639756d6a8c6088 b/test/cli/fuzz-crash_c/crash-24c217c96d177b8dff4028bce639756d6a8c6088 new file mode 100644 index 00000000000..161962b6fe4 --- /dev/null +++ b/test/cli/fuzz-crash_c/crash-24c217c96d177b8dff4028bce639756d6a8c6088 @@ -0,0 +1 @@ +f(S=n){n*,n&&} \ No newline at end of file From bca62bc87dd05648e47451accb681cc3bba65be1 Mon Sep 17 00:00:00 2001 From: chrchr-github Date: Wed, 31 Dec 2025 23:40:49 +0100 Subject: [PATCH 02/10] Fix #13694 fuzzing crash (null-pointer-use) in isUnreachableOperand() --- lib/tokenize.cpp | 2 ++ .../fuzz-crash/crash-a03d001b1336e191debffcde652ce5fb63d0a7d6 | 1 + 2 files changed, 3 insertions(+) create mode 100644 test/cli/fuzz-crash/crash-a03d001b1336e191debffcde652ce5fb63d0a7d6 diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 652520039a5..f113e0af016 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -8944,6 +8944,8 @@ void Tokenizer::findGarbageCode() const syntaxError(tok); if (Token::Match(tok, "typedef [,;:]")) syntaxError(tok); + if (Token::Match(tok, "? %assign%")) + syntaxError(tok); if (Token::Match(tok, "!|~ %comp%") && !(cpp && tok->strAt(1) == ">" && Token::simpleMatch(tok->tokAt(-1), "operator"))) syntaxError(tok); diff --git a/test/cli/fuzz-crash/crash-a03d001b1336e191debffcde652ce5fb63d0a7d6 b/test/cli/fuzz-crash/crash-a03d001b1336e191debffcde652ce5fb63d0a7d6 new file mode 100644 index 00000000000..0a3ef8a3bb2 --- /dev/null +++ b/test/cli/fuzz-crash/crash-a03d001b1336e191debffcde652ce5fb63d0a7d6 @@ -0,0 +1 @@ +(c[?=3:4])p \ No newline at end of file From 06903d57e92e0a75d1005fdb7acf60227bf1ee9b Mon Sep 17 00:00:00 2001 From: chrchr-github Date: Thu, 1 Jan 2026 12:27:13 +0100 Subject: [PATCH 03/10] Fix #13502, #13708 fuzzing crashes --- lib/templatesimplifier.cpp | 4 ++++ .../fuzz-crash/crash-924d1c8815a87b27a5ddd16f5f1ac5fe1aa6ea5a | 1 + .../fuzz-crash/crash-9eb2c9e545b361a17d74ccd4e8c933ca65542b12 | 1 + 3 files changed, 6 insertions(+) create mode 100644 test/cli/fuzz-crash/crash-924d1c8815a87b27a5ddd16f5f1ac5fe1aa6ea5a create mode 100644 test/cli/fuzz-crash/crash-9eb2c9e545b361a17d74ccd4e8c933ca65542b12 diff --git a/lib/templatesimplifier.cpp b/lib/templatesimplifier.cpp index 1f90593560f..8799aada6df 100644 --- a/lib/templatesimplifier.cpp +++ b/lib/templatesimplifier.cpp @@ -690,6 +690,8 @@ bool TemplateSimplifier::getTemplateDeclarations() else if (Token::Match(tok2, "{|=|;")) { const int namepos = getTemplateNamePosition(parmEnd); if (namepos > 0) { + if (!tok->scopeInfo()) + mTokenizer.syntaxError(tok); TokenAndName decl(tok, tok->scopeInfo()->name, parmEnd->tokAt(namepos), parmEnd); if (decl.isForwardDeclaration()) { // Declaration => add to mTemplateForwardDeclarations @@ -3983,6 +3985,8 @@ void TemplateSimplifier::simplifyTemplates(const std::time_t maxtime) if (it->isSpecialization()) { // delete the "template < >" Token * tok = it->token(); + if (!tok) + mTokenizer.syntaxError(it->nameToken()); tok->deleteNext(2); tok->deleteThis(); } else { diff --git a/test/cli/fuzz-crash/crash-924d1c8815a87b27a5ddd16f5f1ac5fe1aa6ea5a b/test/cli/fuzz-crash/crash-924d1c8815a87b27a5ddd16f5f1ac5fe1aa6ea5a new file mode 100644 index 00000000000..05a2a5f3aa6 --- /dev/null +++ b/test/cli/fuzz-crash/crash-924d1c8815a87b27a5ddd16f5f1ac5fe1aa6ea5a @@ -0,0 +1 @@ +template<>et(){}}}>(){} \ No newline at end of file diff --git a/test/cli/fuzz-crash/crash-9eb2c9e545b361a17d74ccd4e8c933ca65542b12 b/test/cli/fuzz-crash/crash-9eb2c9e545b361a17d74ccd4e8c933ca65542b12 new file mode 100644 index 00000000000..8d7829b6343 --- /dev/null +++ b/test/cli/fuzz-crash/crash-9eb2c9e545b361a17d74ccd4e8c933ca65542b12 @@ -0,0 +1 @@ +{template<>i}template<>fact2(){fact2<3>()} \ No newline at end of file From dbec63d25721d6d5d86aad3dd459bcad7521f0c3 Mon Sep 17 00:00:00 2001 From: chrchr-github Date: Thu, 1 Jan 2026 12:29:52 +0100 Subject: [PATCH 04/10] Fix #13704 fuzzing crash (null-pointer-use) in TokenList::insertTokens() --- lib/tokenize.cpp | 2 ++ .../fuzz-crash/crash-c36b9a5f7fce91031cb578ef591f90d48d95a7f4 | 1 + 2 files changed, 3 insertions(+) create mode 100644 test/cli/fuzz-crash/crash-c36b9a5f7fce91031cb578ef591f90d48d95a7f4 diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index f113e0af016..fbbf8c5d4e6 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -7580,6 +7580,8 @@ void Tokenizer::simplifyVarDecl(Token * tokBegin, const Token * const tokEnd, co if (!varTok) syntaxError(tok2); // invalid code if (eq->str() == "=") { + if (varTok->index() + 1 > list.back()->index()) + syntaxError(tok2); TokenList::insertTokens(eq, varTok, 2); eq->str(";"); eq->isSplittedVarDeclEq(true); diff --git a/test/cli/fuzz-crash/crash-c36b9a5f7fce91031cb578ef591f90d48d95a7f4 b/test/cli/fuzz-crash/crash-c36b9a5f7fce91031cb578ef591f90d48d95a7f4 new file mode 100644 index 00000000000..094721301b9 --- /dev/null +++ b/test/cli/fuzz-crash/crash-c36b9a5f7fce91031cb578ef591f90d48d95a7f4 @@ -0,0 +1 @@ +cs=t,{;{}}>l \ No newline at end of file From e498dff2e18c758786441591e6eb0559400dd901 Mon Sep 17 00:00:00 2001 From: chrchr-github Date: Thu, 1 Jan 2026 14:03:59 +0100 Subject: [PATCH 05/10] Fix --- lib/tokenize.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index fbbf8c5d4e6..e7d9fecc97c 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -5813,6 +5813,8 @@ bool Tokenizer::simplifyTokenList1(const char FileName[]) // Change initialisation of variable to assignment simplifyInitVar(); + list.front()->assignIndexes(); + // Split up variable declarations. simplifyVarDecl(false); From 265caa5708298641dd3fa03f9af508e44719a0de Mon Sep 17 00:00:00 2001 From: chrchr-github Date: Thu, 1 Jan 2026 14:21:38 +0100 Subject: [PATCH 06/10] Fix --- lib/tokenize.cpp | 4 ---- lib/tokenlist.cpp | 2 ++ 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index e7d9fecc97c..f113e0af016 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -5813,8 +5813,6 @@ bool Tokenizer::simplifyTokenList1(const char FileName[]) // Change initialisation of variable to assignment simplifyInitVar(); - list.front()->assignIndexes(); - // Split up variable declarations. simplifyVarDecl(false); @@ -7582,8 +7580,6 @@ void Tokenizer::simplifyVarDecl(Token * tokBegin, const Token * const tokEnd, co if (!varTok) syntaxError(tok2); // invalid code if (eq->str() == "=") { - if (varTok->index() + 1 > list.back()->index()) - syntaxError(tok2); TokenList::insertTokens(eq, varTok, 2); eq->str(";"); eq->isSplittedVarDeclEq(true); diff --git a/lib/tokenlist.cpp b/lib/tokenlist.cpp index 2ed39b82f43..d48e7d810df 100644 --- a/lib/tokenlist.cpp +++ b/lib/tokenlist.cpp @@ -295,6 +295,8 @@ void TokenList::insertTokens(Token *dest, const Token *src, nonneg int n) std::stack link; while (n > 0) { + if (!src) + throw InternalError(dest, std::string(__func__) + ": invalid source range", InternalError::INTERNAL); dest->insertToken(src->str(), src->originalName()); dest = dest->next(); From ddcfa246dfe99880b8f278f25e64a98ecc05103a Mon Sep 17 00:00:00 2001 From: chrchr-github Date: Thu, 1 Jan 2026 14:22:46 +0100 Subject: [PATCH 07/10] Format --- lib/tokenlist.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/tokenlist.cpp b/lib/tokenlist.cpp index d48e7d810df..1e476a14ec5 100644 --- a/lib/tokenlist.cpp +++ b/lib/tokenlist.cpp @@ -296,7 +296,7 @@ void TokenList::insertTokens(Token *dest, const Token *src, nonneg int n) while (n > 0) { if (!src) - throw InternalError(dest, std::string(__func__) + ": invalid source range", InternalError::INTERNAL); + throw InternalError(dest, std::string(__func__) + ": invalid source range", InternalError::INTERNAL); dest->insertToken(src->str(), src->originalName()); dest = dest->next(); From 21e34a4588918d0a1928921d96016dde9b7cdf29 Mon Sep 17 00:00:00 2001 From: chrchr-github Date: Thu, 1 Jan 2026 14:46:32 +0100 Subject: [PATCH 08/10] Simplify --- lib/templatesimplifier.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/templatesimplifier.cpp b/lib/templatesimplifier.cpp index 8799aada6df..dc82db507c8 100644 --- a/lib/templatesimplifier.cpp +++ b/lib/templatesimplifier.cpp @@ -691,7 +691,7 @@ bool TemplateSimplifier::getTemplateDeclarations() const int namepos = getTemplateNamePosition(parmEnd); if (namepos > 0) { if (!tok->scopeInfo()) - mTokenizer.syntaxError(tok); + syntaxError(tok); TokenAndName decl(tok, tok->scopeInfo()->name, parmEnd->tokAt(namepos), parmEnd); if (decl.isForwardDeclaration()) { // Declaration => add to mTemplateForwardDeclarations @@ -3986,7 +3986,7 @@ void TemplateSimplifier::simplifyTemplates(const std::time_t maxtime) // delete the "template < >" Token * tok = it->token(); if (!tok) - mTokenizer.syntaxError(it->nameToken()); + syntaxError(it->nameToken()); tok->deleteNext(2); tok->deleteThis(); } else { From cc40a61e9314f9264593bd10c002ad4e84a95931 Mon Sep 17 00:00:00 2001 From: chrchr-github Date: Thu, 1 Jan 2026 19:28:37 +0100 Subject: [PATCH 09/10] Capture stderr --- test/cli/fuzz_test.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/cli/fuzz_test.py b/test/cli/fuzz_test.py index b8cf09a5657..f1dbcd2983e 100644 --- a/test/cli/fuzz_test.py +++ b/test/cli/fuzz_test.py @@ -11,9 +11,9 @@ def test_fuzz_crash(): fuzz_crash_dir = os.path.join(__script_dir, 'fuzz-crash') for f in os.listdir(fuzz_crash_dir): - ret, stdout, _ = cppcheck(['-q', '--language=c++', '--enable=all', '--inconclusive', f], cwd=fuzz_crash_dir) + ret, stdout, stderr = cppcheck(['-q', '--language=c++', '--enable=all', '--inconclusive', f], cwd=fuzz_crash_dir) if ret != 0: - failures[f] = stdout + failures[f] = stdout + stderr assert failures == {} @@ -26,9 +26,9 @@ def test_fuzz_crash_c(): if not os.path.exists(fuzz_crash_dir): return for f in os.listdir(fuzz_crash_dir): - ret, stdout, _ = cppcheck(['-q', '--language=c', '--enable=all', '--inconclusive', f], cwd=fuzz_crash_dir) + ret, stdout, stderr = cppcheck(['-q', '--language=c', '--enable=all', '--inconclusive', f], cwd=fuzz_crash_dir) if ret != 0: - failures[f] = stdout + failures[f] = stdout + stderr assert failures == {} From ec8649811267ed1ac37d2583a6317b5905258af9 Mon Sep 17 00:00:00 2001 From: chrchr-github Date: Thu, 1 Jan 2026 20:46:50 +0100 Subject: [PATCH 10/10] Undo --- lib/templatesimplifier.cpp | 2 -- .../fuzz-crash/crash-924d1c8815a87b27a5ddd16f5f1ac5fe1aa6ea5a | 1 - 2 files changed, 3 deletions(-) delete mode 100644 test/cli/fuzz-crash/crash-924d1c8815a87b27a5ddd16f5f1ac5fe1aa6ea5a diff --git a/lib/templatesimplifier.cpp b/lib/templatesimplifier.cpp index dc82db507c8..1291993990d 100644 --- a/lib/templatesimplifier.cpp +++ b/lib/templatesimplifier.cpp @@ -3985,8 +3985,6 @@ void TemplateSimplifier::simplifyTemplates(const std::time_t maxtime) if (it->isSpecialization()) { // delete the "template < >" Token * tok = it->token(); - if (!tok) - syntaxError(it->nameToken()); tok->deleteNext(2); tok->deleteThis(); } else { diff --git a/test/cli/fuzz-crash/crash-924d1c8815a87b27a5ddd16f5f1ac5fe1aa6ea5a b/test/cli/fuzz-crash/crash-924d1c8815a87b27a5ddd16f5f1ac5fe1aa6ea5a deleted file mode 100644 index 05a2a5f3aa6..00000000000 --- a/test/cli/fuzz-crash/crash-924d1c8815a87b27a5ddd16f5f1ac5fe1aa6ea5a +++ /dev/null @@ -1 +0,0 @@ -template<>et(){}}}>(){} \ No newline at end of file