Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 11 additions & 9 deletions lib/tokenize.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6814,21 +6814,23 @@ bool Tokenizer::simplifyAddBraces()
return true;
}

Token *Tokenizer::simplifyAddBracesToCommand(Token *tok)
Token *Tokenizer::simplifyAddBracesToCommand(Token *tok, int depth)
{
if (depth < 0)
return tok;
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(), "{"))
tokPossibleDo = nullptr;
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
Expand All @@ -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") {
Expand All @@ -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
Expand Down Expand Up @@ -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()!="}") {
Expand Down
4 changes: 2 additions & 2 deletions lib/tokenize.h
Original file line number Diff line number Diff line change
Expand Up @@ -211,15 +211,15 @@ 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 = 500);

/** Add pair of braces to an single if-block, else-block, for-block, etc.
* for command starting at token
* @return last token of command
* 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 = 500);

/**
* typedef A mytype;
Expand Down
25 changes: 25 additions & 0 deletions test/testtokenize.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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"
Expand Down
Loading