Skip to content

Commit d39fee4

Browse files
committed
Fix recursion depth with count-down depth pattern and add test cases.
1 parent e28f7d6 commit d39fee4

File tree

3 files changed

+36
-11
lines changed

3 files changed

+36
-11
lines changed

lib/tokenize.cpp

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6816,21 +6816,21 @@ bool Tokenizer::simplifyAddBraces()
68166816

68176817
Token *Tokenizer::simplifyAddBracesToCommand(Token *tok, int depth)
68186818
{
6819-
if (depth > 500)
6820-
return tok; // bail out — extreme nesting/chaining, skip brace insertion
6819+
if (depth < 0)
6820+
return tok;
68216821
Token * tokEnd=tok;
68226822
if (Token::Match(tok,"for|switch|BOOST_FOREACH")) {
6823-
tokEnd=simplifyAddBracesPair(tok,true,depth+1);
6823+
tokEnd=simplifyAddBracesPair(tok,true,depth-1);
68246824
} else if (tok->str()=="while") {
68256825
Token *tokPossibleDo=tok->previous();
68266826
if (Token::simpleMatch(tok->previous(), "{"))
68276827
tokPossibleDo = nullptr;
68286828
else if (Token::simpleMatch(tokPossibleDo,"}"))
68296829
tokPossibleDo = tokPossibleDo->link();
68306830
if (!tokPossibleDo || tokPossibleDo->strAt(-1) != "do")
6831-
tokEnd=simplifyAddBracesPair(tok,true,depth+1);
6831+
tokEnd=simplifyAddBracesPair(tok,true,depth-1);
68326832
} else if (tok->str()=="do") {
6833-
tokEnd=simplifyAddBracesPair(tok,false,depth+1);
6833+
tokEnd=simplifyAddBracesPair(tok,false,depth-1);
68346834
if (tokEnd!=tok) {
68356835
// walk on to next token, i.e. "while"
68366836
// such that simplifyAddBracesPair does not close other braces
@@ -6842,7 +6842,7 @@ Token *Tokenizer::simplifyAddBracesToCommand(Token *tok, int depth)
68426842
}
68436843
}
68446844
} else if (tok->str()=="if" && !Token::simpleMatch(tok->tokAt(-2), "operator \"\"")) {
6845-
tokEnd=simplifyAddBracesPair(tok,true,depth+1);
6845+
tokEnd=simplifyAddBracesPair(tok,true,depth-1);
68466846
if (!tokEnd)
68476847
return nullptr;
68486848
if (tokEnd->strAt(1) == "else") {
@@ -6851,9 +6851,9 @@ Token *Tokenizer::simplifyAddBracesToCommand(Token *tok, int depth)
68516851
syntaxError(tokEndNextNext);
68526852
if (tokEndNextNext->str() == "if")
68536853
// do not change "else if ..." to "else { if ... }"
6854-
tokEnd=simplifyAddBracesToCommand(tokEndNextNext,depth+1);
6854+
tokEnd=simplifyAddBracesToCommand(tokEndNextNext,depth-1);
68556855
else
6856-
tokEnd=simplifyAddBracesPair(tokEnd->next(),false,depth+1);
6856+
tokEnd=simplifyAddBracesPair(tokEnd->next(),false,depth-1);
68576857
}
68586858
}
68596859

@@ -6922,7 +6922,7 @@ Token *Tokenizer::simplifyAddBracesPair(Token *tok, bool commandWithCondition, i
69226922
Token::createMutualLinks(tokOpenBrace, tokCloseBrace);
69236923
tokBracesEnd = tokCloseBrace;
69246924
} else {
6925-
Token * tokEnd = simplifyAddBracesToCommand(tokStatement, depth+1);
6925+
Token * tokEnd = simplifyAddBracesToCommand(tokStatement, depth-1);
69266926
if (!tokEnd) // Ticket #4887
69276927
return tok;
69286928
if (tokEnd->str()!="}") {

lib/tokenize.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -211,15 +211,15 @@ class CPPCHECKLIB Tokenizer {
211211
* or input token in case of an error where no braces are added
212212
* or NULL when syntaxError is called
213213
*/
214-
Token * simplifyAddBracesToCommand(Token * tok, int depth = 0);
214+
Token * simplifyAddBracesToCommand(Token * tok, int depth = 500);
215215

216216
/** Add pair of braces to an single if-block, else-block, for-block, etc.
217217
* for command starting at token
218218
* @return last token of command
219219
* or input token in case of an error where no braces are added
220220
* or NULL when syntaxError is called
221221
*/
222-
Token * simplifyAddBracesPair(Token *tok, bool commandWithCondition, int depth = 0);
222+
Token * simplifyAddBracesPair(Token *tok, bool commandWithCondition, int depth = 500);
223223

224224
/**
225225
* typedef A mytype;

test/testtokenize.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@ class TestTokenizer : public TestFixture {
128128
TEST_CASE(ifAddBraces18); // #3424 - if if { } else else
129129
TEST_CASE(ifAddBraces19); // #3928 - if for if else
130130
TEST_CASE(ifAddBraces20); // #5012 - syntax error 'else }'
131+
TEST_CASE(ifAddBracesDepthLimit);
131132
TEST_CASE(ifAddBracesLabels); // #5332 - if (x) label: {} ..
132133

133134
TEST_CASE(switchAddBracesLabels);
@@ -1415,6 +1416,30 @@ class TestTokenizer : public TestFixture {
14151416
ASSERT_THROW_INTERNAL(tokenizeAndStringify(code), SYNTAX);
14161417
}
14171418

1419+
void ifAddBracesDepthLimit() {
1420+
// Ensure that a long else-if chain exceeding the recursion depth limit
1421+
// does not cause a stack overflow (CWE-674)
1422+
{
1423+
// Generate a chain of 1000 else-if clauses (exceeds depth limit of 500)
1424+
std::string code = "void f() { if(x) a();";
1425+
for (int i = 0; i < 1000; i++)
1426+
code += " else if(x) a();";
1427+
code += " else a(); }";
1428+
// Should not crash — just verify tokenization completes
1429+
tokenizeAndStringify(code);
1430+
ignore_errout();
1431+
}
1432+
{
1433+
// Generate deeply nested if statements (exceeds depth limit of 500)
1434+
std::string code = "void f() { ";
1435+
for (int i = 0; i < 1000; i++)
1436+
code += "if(x) ";
1437+
code += "a(); }";
1438+
tokenizeAndStringify(code);
1439+
ignore_errout();
1440+
}
1441+
}
1442+
14181443
void ifAddBracesLabels() {
14191444
// Labels before statement
14201445
ASSERT_EQUALS("int f ( int x ) {\n"

0 commit comments

Comments
 (0)