From e28f7d641cf3ee87cf2f123c9e411749a102dc77 Mon Sep 17 00:00:00 2001 From: emptyiscolor Date: Wed, 25 Feb 2026 09:27:36 -0700 Subject: [PATCH 1/2] Fix Uncontrolled Recursion in `simplifyAddBracesToCommand` / `simplifyAddBracesPair` --- lib/tokenize.cpp | 20 +++++++++++--------- lib/tokenize.h | 4 ++-- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 9f07767edc7..8af57f6d52c 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -6814,11 +6814,13 @@ bool Tokenizer::simplifyAddBraces() return true; } -Token *Tokenizer::simplifyAddBracesToCommand(Token *tok) +Token *Tokenizer::simplifyAddBracesToCommand(Token *tok, int depth) { + if (depth > 500) + return tok; // bail out — extreme nesting/chaining, skip brace insertion Token * tokEnd=tok; if (Token::Match(tok,"for|switch|BOOST_FOREACH")) { - tokEnd=simplifyAddBracesPair(tok,true); + tokEnd=simplifyAddBracesPair(tok,true,depth+1); } else if (tok->str()=="while") { Token *tokPossibleDo=tok->previous(); if (Token::simpleMatch(tok->previous(), "{")) @@ -6826,9 +6828,9 @@ Token *Tokenizer::simplifyAddBracesToCommand(Token *tok) else if (Token::simpleMatch(tokPossibleDo,"}")) tokPossibleDo = tokPossibleDo->link(); if (!tokPossibleDo || tokPossibleDo->strAt(-1) != "do") - tokEnd=simplifyAddBracesPair(tok,true); + tokEnd=simplifyAddBracesPair(tok,true,depth+1); } else if (tok->str()=="do") { - tokEnd=simplifyAddBracesPair(tok,false); + tokEnd=simplifyAddBracesPair(tok,false,depth+1); if (tokEnd!=tok) { // walk on to next token, i.e. "while" // such that simplifyAddBracesPair does not close other braces @@ -6840,7 +6842,7 @@ Token *Tokenizer::simplifyAddBracesToCommand(Token *tok) } } } else if (tok->str()=="if" && !Token::simpleMatch(tok->tokAt(-2), "operator \"\"")) { - tokEnd=simplifyAddBracesPair(tok,true); + tokEnd=simplifyAddBracesPair(tok,true,depth+1); if (!tokEnd) return nullptr; if (tokEnd->strAt(1) == "else") { @@ -6849,16 +6851,16 @@ Token *Tokenizer::simplifyAddBracesToCommand(Token *tok) syntaxError(tokEndNextNext); if (tokEndNextNext->str() == "if") // do not change "else if ..." to "else { if ... }" - tokEnd=simplifyAddBracesToCommand(tokEndNextNext); + tokEnd=simplifyAddBracesToCommand(tokEndNextNext,depth+1); else - tokEnd=simplifyAddBracesPair(tokEnd->next(),false); + tokEnd=simplifyAddBracesPair(tokEnd->next(),false,depth+1); } } return tokEnd; } -Token *Tokenizer::simplifyAddBracesPair(Token *tok, bool commandWithCondition) +Token *Tokenizer::simplifyAddBracesPair(Token *tok, bool commandWithCondition, int depth) { Token * tokCondition=tok->next(); if (!tokCondition) // Missing condition @@ -6920,7 +6922,7 @@ Token *Tokenizer::simplifyAddBracesPair(Token *tok, bool commandWithCondition) Token::createMutualLinks(tokOpenBrace, tokCloseBrace); tokBracesEnd = tokCloseBrace; } else { - Token * tokEnd = simplifyAddBracesToCommand(tokStatement); + Token * tokEnd = simplifyAddBracesToCommand(tokStatement, depth+1); if (!tokEnd) // Ticket #4887 return tok; if (tokEnd->str()!="}") { diff --git a/lib/tokenize.h b/lib/tokenize.h index 61d1003f316..c1a11eb3252 100644 --- a/lib/tokenize.h +++ b/lib/tokenize.h @@ -211,7 +211,7 @@ class CPPCHECKLIB Tokenizer { * or input token in case of an error where no braces are added * or NULL when syntaxError is called */ - Token * simplifyAddBracesToCommand(Token * tok); + Token * simplifyAddBracesToCommand(Token * tok, int depth = 0); /** Add pair of braces to an single if-block, else-block, for-block, etc. * for command starting at token @@ -219,7 +219,7 @@ class CPPCHECKLIB Tokenizer { * or input token in case of an error where no braces are added * or NULL when syntaxError is called */ - Token * simplifyAddBracesPair(Token *tok, bool commandWithCondition); + Token * simplifyAddBracesPair(Token *tok, bool commandWithCondition, int depth = 0); /** * typedef A mytype; From d39fee4db36eac05aada9f51864e46e34fc0eb5a Mon Sep 17 00:00:00 2001 From: emptyiscolor Date: Wed, 25 Feb 2026 14:56:02 -0700 Subject: [PATCH 2/2] Fix recursion depth with count-down depth pattern and add test cases. --- lib/tokenize.cpp | 18 +++++++++--------- lib/tokenize.h | 4 ++-- test/testtokenize.cpp | 25 +++++++++++++++++++++++++ 3 files changed, 36 insertions(+), 11 deletions(-) diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 8af57f6d52c..f98fe8e24ac 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -6816,11 +6816,11 @@ bool Tokenizer::simplifyAddBraces() Token *Tokenizer::simplifyAddBracesToCommand(Token *tok, int depth) { - if (depth > 500) - return tok; // bail out — extreme nesting/chaining, skip brace insertion + if (depth < 0) + return tok; Token * tokEnd=tok; if (Token::Match(tok,"for|switch|BOOST_FOREACH")) { - tokEnd=simplifyAddBracesPair(tok,true,depth+1); + tokEnd=simplifyAddBracesPair(tok,true,depth-1); } else if (tok->str()=="while") { Token *tokPossibleDo=tok->previous(); if (Token::simpleMatch(tok->previous(), "{")) @@ -6828,9 +6828,9 @@ Token *Tokenizer::simplifyAddBracesToCommand(Token *tok, int depth) else if (Token::simpleMatch(tokPossibleDo,"}")) tokPossibleDo = tokPossibleDo->link(); if (!tokPossibleDo || tokPossibleDo->strAt(-1) != "do") - tokEnd=simplifyAddBracesPair(tok,true,depth+1); + tokEnd=simplifyAddBracesPair(tok,true,depth-1); } else if (tok->str()=="do") { - tokEnd=simplifyAddBracesPair(tok,false,depth+1); + tokEnd=simplifyAddBracesPair(tok,false,depth-1); if (tokEnd!=tok) { // walk on to next token, i.e. "while" // such that simplifyAddBracesPair does not close other braces @@ -6842,7 +6842,7 @@ Token *Tokenizer::simplifyAddBracesToCommand(Token *tok, int depth) } } } else if (tok->str()=="if" && !Token::simpleMatch(tok->tokAt(-2), "operator \"\"")) { - tokEnd=simplifyAddBracesPair(tok,true,depth+1); + tokEnd=simplifyAddBracesPair(tok,true,depth-1); if (!tokEnd) return nullptr; if (tokEnd->strAt(1) == "else") { @@ -6851,9 +6851,9 @@ Token *Tokenizer::simplifyAddBracesToCommand(Token *tok, int depth) syntaxError(tokEndNextNext); if (tokEndNextNext->str() == "if") // do not change "else if ..." to "else { if ... }" - tokEnd=simplifyAddBracesToCommand(tokEndNextNext,depth+1); + tokEnd=simplifyAddBracesToCommand(tokEndNextNext,depth-1); else - tokEnd=simplifyAddBracesPair(tokEnd->next(),false,depth+1); + tokEnd=simplifyAddBracesPair(tokEnd->next(),false,depth-1); } } @@ -6922,7 +6922,7 @@ Token *Tokenizer::simplifyAddBracesPair(Token *tok, bool commandWithCondition, i Token::createMutualLinks(tokOpenBrace, tokCloseBrace); tokBracesEnd = tokCloseBrace; } else { - Token * tokEnd = simplifyAddBracesToCommand(tokStatement, depth+1); + Token * tokEnd = simplifyAddBracesToCommand(tokStatement, depth-1); if (!tokEnd) // Ticket #4887 return tok; if (tokEnd->str()!="}") { diff --git a/lib/tokenize.h b/lib/tokenize.h index c1a11eb3252..7f257145ec7 100644 --- a/lib/tokenize.h +++ b/lib/tokenize.h @@ -211,7 +211,7 @@ class CPPCHECKLIB Tokenizer { * or input token in case of an error where no braces are added * or NULL when syntaxError is called */ - Token * simplifyAddBracesToCommand(Token * tok, int depth = 0); + Token * simplifyAddBracesToCommand(Token * tok, int depth = 500); /** Add pair of braces to an single if-block, else-block, for-block, etc. * for command starting at token @@ -219,7 +219,7 @@ class CPPCHECKLIB Tokenizer { * or input token in case of an error where no braces are added * or NULL when syntaxError is called */ - Token * simplifyAddBracesPair(Token *tok, bool commandWithCondition, int depth = 0); + Token * simplifyAddBracesPair(Token *tok, bool commandWithCondition, int depth = 500); /** * typedef A mytype; diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp index eff4a8d44f2..e26d6cdb43f 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -128,6 +128,7 @@ class TestTokenizer : public TestFixture { TEST_CASE(ifAddBraces18); // #3424 - if if { } else else TEST_CASE(ifAddBraces19); // #3928 - if for if else TEST_CASE(ifAddBraces20); // #5012 - syntax error 'else }' + TEST_CASE(ifAddBracesDepthLimit); TEST_CASE(ifAddBracesLabels); // #5332 - if (x) label: {} .. TEST_CASE(switchAddBracesLabels); @@ -1415,6 +1416,30 @@ class TestTokenizer : public TestFixture { ASSERT_THROW_INTERNAL(tokenizeAndStringify(code), SYNTAX); } + void ifAddBracesDepthLimit() { + // Ensure that a long else-if chain exceeding the recursion depth limit + // does not cause a stack overflow (CWE-674) + { + // Generate a chain of 1000 else-if clauses (exceeds depth limit of 500) + std::string code = "void f() { if(x) a();"; + for (int i = 0; i < 1000; i++) + code += " else if(x) a();"; + code += " else a(); }"; + // Should not crash — just verify tokenization completes + tokenizeAndStringify(code); + ignore_errout(); + } + { + // Generate deeply nested if statements (exceeds depth limit of 500) + std::string code = "void f() { "; + for (int i = 0; i < 1000; i++) + code += "if(x) "; + code += "a(); }"; + tokenizeAndStringify(code); + ignore_errout(); + } + } + void ifAddBracesLabels() { // Labels before statement ASSERT_EQUALS("int f ( int x ) {\n"