Skip to content

Commit 0f754d1

Browse files
authored
fix #13585 & #13578: Stack overflow in findTokensSkipDeadAndUnevaluatedCode() / Bad AST for function calls with parentheses (#7262)
1 parent a7e9e68 commit 0f754d1

File tree

5 files changed

+98
-49
lines changed

5 files changed

+98
-49
lines changed

lib/tokenize.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3712,6 +3712,22 @@ void Tokenizer::simplifySQL()
37123712
}
37133713
}
37143714

3715+
void Tokenizer::simplifyParenthesizedLibraryFunctions()
3716+
{
3717+
for (Token *tok = list.front(); tok; tok = tok->next()) {
3718+
if (!Token::simpleMatch(tok, ") ("))
3719+
continue;
3720+
Token *rpar = tok, *lpar = tok->link();
3721+
if (!lpar)
3722+
continue;
3723+
const Token *ftok = rpar->previous();
3724+
if (mSettings.library.isNotLibraryFunction(ftok))
3725+
continue;
3726+
lpar->deleteThis();
3727+
rpar->deleteThis();
3728+
}
3729+
}
3730+
37153731
void Tokenizer::simplifyArrayAccessSyntax()
37163732
{
37173733
// 0[a] -> a[0]
@@ -5528,6 +5544,9 @@ bool Tokenizer::simplifyTokenList1(const char FileName[])
55285544

55295545
createLinks();
55305546

5547+
// replace library function calls such as (std::min)(a, b) with std::min(a, b)
5548+
simplifyParenthesizedLibraryFunctions();
5549+
55315550
// Simplify debug intrinsics
55325551
simplifyDebug();
55335552

lib/tokenize.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,8 @@ class CPPCHECKLIB Tokenizer {
317317

318318
void simplifySQL();
319319

320+
void simplifyParenthesizedLibraryFunctions();
321+
320322
void checkForEnumsWithTypedef();
321323

322324
void findComplicatedSyntaxErrorsInTemplates();

lib/tokenlist.cpp

Lines changed: 42 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -452,8 +452,7 @@ namespace {
452452
bool inCase{}; // true from case to :
453453
bool stopAtColon{}; // help to properly parse ternary operators
454454
const Token* functionCallEndPar{};
455-
const Library &library;
456-
explicit AST_state(bool cpp, const Library &library) : cpp(cpp), library(library) {}
455+
explicit AST_state(bool cpp) : cpp(cpp) {}
457456
};
458457
}
459458

@@ -491,7 +490,7 @@ static Token* skipDecl(Token* tok, std::vector<Token*>* inner = nullptr)
491490
return tok;
492491
}
493492

494-
static bool iscast(const Token *tok, const AST_state &state)
493+
static bool iscast(const Token *tok, bool cpp)
495494
{
496495
if (!Token::Match(tok, "( ::| %name%"))
497496
return false;
@@ -503,7 +502,7 @@ static bool iscast(const Token *tok, const AST_state &state)
503502
return false;
504503

505504
if (tok->previous() && tok->previous()->isName() && tok->strAt(-1) != "return" &&
506-
(!state.cpp || !Token::Match(tok->previous(), "delete|throw")))
505+
(!cpp || !Token::Match(tok->previous(), "delete|throw")))
507506
return false;
508507

509508
if (Token::simpleMatch(tok->previous(), ">") && tok->linkAt(-1))
@@ -528,10 +527,7 @@ static bool iscast(const Token *tok, const AST_state &state)
528527
for (const Token *tok2 = tok->next(); tok2; tok2 = tok2->next()) {
529528
if (tok2->varId() != 0)
530529
return false;
531-
if (state.cpp && !type && tok2->str() == "new")
532-
return false;
533-
534-
if (!state.library.isNotLibraryFunction(tok2))
530+
if (cpp && !type && tok2->str() == "new")
535531
return false;
536532

537533
while (tok2->link() && Token::Match(tok2, "(|[|<"))
@@ -804,7 +800,7 @@ static void compileTerm(Token *&tok, AST_state& state)
804800
std::vector<Token*> inner;
805801
tok = skipDecl(tok, &inner);
806802
for (Token* tok3 : inner) {
807-
AST_state state1(state.cpp, state.library);
803+
AST_state state1(state.cpp);
808804
compileExpression(tok3, state1);
809805
}
810806
bool repeat = true;
@@ -834,7 +830,7 @@ static void compileTerm(Token *&tok, AST_state& state)
834830
}
835831
} else if (tok->str() == "{") {
836832
const Token *prev = tok->previous();
837-
if (Token::simpleMatch(prev, ") {") && iscast(prev->link(), state))
833+
if (Token::simpleMatch(prev, ") {") && iscast(prev->link(), state.cpp))
838834
prev = prev->link()->previous();
839835
if (Token::simpleMatch(tok->link(),"} [")) {
840836
tok = tok->next();
@@ -906,9 +902,9 @@ static void compileScope(Token *&tok, AST_state& state)
906902
}
907903
}
908904

909-
static bool isPrefixUnary(const Token* tok, const AST_state &state)
905+
static bool isPrefixUnary(const Token* tok, bool cpp)
910906
{
911-
if (state.cpp && Token::simpleMatch(tok->previous(), "* [") && Token::simpleMatch(tok->link(), "] {")) {
907+
if (cpp && Token::simpleMatch(tok->previous(), "* [") && Token::simpleMatch(tok->link(), "] {")) {
912908
for (const Token* prev = tok->previous(); Token::Match(prev, "%name%|::|*|&|>|>>"); prev = prev->previous()) {
913909
if (Token::Match(prev, ">|>>")) {
914910
if (!prev->link())
@@ -920,7 +916,7 @@ static bool isPrefixUnary(const Token* tok, const AST_state &state)
920916
}
921917
}
922918
if (!tok->previous()
923-
|| ((Token::Match(tok->previous(), "(|[|{|%op%|;|?|:|,|.|case|return|::") || (state.cpp && tok->strAt(-1) == "throw"))
919+
|| ((Token::Match(tok->previous(), "(|[|{|%op%|;|?|:|,|.|case|return|::") || (cpp && tok->strAt(-1) == "throw"))
924920
&& (tok->previous()->tokType() != Token::eIncDecOp || tok->tokType() == Token::eIncDecOp)))
925921
return true;
926922

@@ -929,10 +925,10 @@ static bool isPrefixUnary(const Token* tok, const AST_state &state)
929925
return !Token::Match(parent, "%type%") || parent->isKeyword();
930926
}
931927

932-
if (tok->str() == "*" && tok->previous()->tokType() == Token::eIncDecOp && isPrefixUnary(tok->previous(), state))
928+
if (tok->str() == "*" && tok->previous()->tokType() == Token::eIncDecOp && isPrefixUnary(tok->previous(), cpp))
933929
return true;
934930

935-
return tok->strAt(-1) == ")" && iscast(tok->linkAt(-1), state);
931+
return tok->strAt(-1) == ")" && iscast(tok->linkAt(-1), cpp);
936932
}
937933

938934
static void compilePrecedence2(Token *&tok, AST_state& state)
@@ -958,7 +954,7 @@ static void compilePrecedence2(Token *&tok, AST_state& state)
958954
isNew = false;
959955
}
960956
while (tok) {
961-
if (tok->tokType() == Token::eIncDecOp && !isPrefixUnary(tok, state)) {
957+
if (tok->tokType() == Token::eIncDecOp && !isPrefixUnary(tok, state.cpp)) {
962958
compileUnaryOp(tok, state, compileScope);
963959
} else if (tok->str() == "...") {
964960
if (!Token::simpleMatch(tok->previous(), ")"))
@@ -976,7 +972,7 @@ static void compilePrecedence2(Token *&tok, AST_state& state)
976972
else
977973
compileUnaryOp(tok, state, compileScope);
978974
} else if (tok->str() == "[") {
979-
if (state.cpp && isPrefixUnary(tok, state) && Token::Match(tok->link(), "] (|{|<")) { // Lambda
975+
if (state.cpp && isPrefixUnary(tok, /*cpp*/ true) && Token::Match(tok->link(), "] (|{|<")) { // Lambda
980976
// What we do here:
981977
// - Nest the round bracket under the square bracket.
982978
// - Nest what follows the lambda (if anything) with the lambda opening [
@@ -986,7 +982,7 @@ static void compilePrecedence2(Token *&tok, AST_state& state)
986982
// Parse arguments in the capture list
987983
if (tok->strAt(1) != "]") {
988984
Token* tok2 = tok->next();
989-
AST_state state2(state.cpp, state.library);
985+
AST_state state2(state.cpp);
990986
compileExpression(tok2, state2);
991987
if (!state2.op.empty()) {
992988
squareBracket->astOperand2(state2.op.top());
@@ -1050,7 +1046,7 @@ static void compilePrecedence2(Token *&tok, AST_state& state)
10501046
tok = tok->link()->next();
10511047
continue;
10521048
} else if (tok->str() == "(" &&
1053-
(!iscast(tok, state) || Token::Match(tok->previous(), "if|while|for|switch|catch"))) {
1049+
(!iscast(tok, state.cpp) || Token::Match(tok->previous(), "if|while|for|switch|catch"))) {
10541050
Token* tok2 = tok;
10551051
tok = tok->next();
10561052
const bool opPrevTopSquare = !state.op.empty() && state.op.top() && state.op.top()->str() == "[";
@@ -1061,7 +1057,7 @@ static void compilePrecedence2(Token *&tok, AST_state& state)
10611057
|| (tok->previous() && tok->previous()->isName() && !Token::Match(tok->previous(), "return|case") && (!state.cpp || !Token::Match(tok->previous(), "throw|delete")))
10621058
|| (tok->strAt(-1) == "]" && (!state.cpp || !Token::Match(tok->linkAt(-1)->previous(), "new|delete")))
10631059
|| (tok->strAt(-1) == ">" && tok->linkAt(-1))
1064-
|| (tok->strAt(-1) == ")" && !iscast(tok->linkAt(-1), state)) // Don't treat brackets to clarify precedence as function calls
1060+
|| (tok->strAt(-1) == ")" && !iscast(tok->linkAt(-1), state.cpp)) // Don't treat brackets to clarify precedence as function calls
10651061
|| (tok->strAt(-1) == "}" && opPrevTopSquare)) {
10661062
const bool operandInside = oldOpSize < state.op.size();
10671063
if (operandInside)
@@ -1072,7 +1068,7 @@ static void compilePrecedence2(Token *&tok, AST_state& state)
10721068
tok = tok->link()->next();
10731069
if (Token::simpleMatch(tok, "::"))
10741070
compileBinOp(tok, state, compileTerm);
1075-
} else if (iscast(tok, state) && Token::simpleMatch(tok->link(), ") {") &&
1071+
} else if (iscast(tok, state.cpp) && Token::simpleMatch(tok->link(), ") {") &&
10761072
Token::simpleMatch(tok->link()->linkAt(1), "} [")) {
10771073
Token *cast = tok;
10781074
tok = tok->link()->next();
@@ -1105,7 +1101,7 @@ static void compilePrecedence3(Token *&tok, AST_state& state)
11051101
compilePrecedence2(tok, state);
11061102
while (tok) {
11071103
if ((Token::Match(tok, "[+-!~*&]") || tok->tokType() == Token::eIncDecOp) &&
1108-
isPrefixUnary(tok, state)) {
1104+
isPrefixUnary(tok, state.cpp)) {
11091105
if (Token::Match(tok, "* [*,)]")) {
11101106
Token* tok2 = tok->next();
11111107
while (tok2->next() && tok2->str() == "*")
@@ -1116,7 +1112,7 @@ static void compilePrecedence3(Token *&tok, AST_state& state)
11161112
}
11171113
}
11181114
compileUnaryOp(tok, state, compilePrecedence3);
1119-
} else if (tok->str() == "(" && iscast(tok, state)) {
1115+
} else if (tok->str() == "(" && iscast(tok, state.cpp)) {
11201116
Token* castTok = tok;
11211117
castTok->isCast(true);
11221118
tok = tok->link()->next();
@@ -1136,7 +1132,7 @@ static void compilePrecedence3(Token *&tok, AST_state& state)
11361132
if (Token::Match(tok->link(), ") ::| %type%")) {
11371133
if (Token::Match(tok, "( !!)")) {
11381134
Token *innerTok = tok->next();
1139-
AST_state innerState(true, state.library);
1135+
AST_state innerState(true);
11401136
compileExpression(innerTok, innerState);
11411137
}
11421138
tok = tok->link()->next();
@@ -1461,10 +1457,10 @@ const Token* findLambdaEndTokenWithoutAST(const Token* tok) {
14611457
return tok->link()->next();
14621458
}
14631459

1464-
static Token * createAstAtToken(Token *tok, const Library &library);
1460+
static Token * createAstAtToken(Token *tok);
14651461

14661462
// Compile inner expressions inside inner ({..}) and lambda bodies
1467-
static void createAstAtTokenInner(Token * const tok1, const Token *endToken, bool cpp, const Library &library)
1463+
static void createAstAtTokenInner(Token * const tok1, const Token *endToken, bool cpp)
14681464
{
14691465
for (Token* tok = tok1; precedes(tok, endToken); tok = tok ? tok->next() : nullptr) {
14701466
if (tok->str() == "{" && !iscpp11init(tok)) {
@@ -1482,7 +1478,7 @@ static void createAstAtTokenInner(Token * const tok1, const Token *endToken, boo
14821478
}
14831479
if (!hasAst) {
14841480
for (; tok && tok != endToken && tok != endToken2; tok = tok ? tok->next() : nullptr)
1485-
tok = createAstAtToken(tok, library);
1481+
tok = createAstAtToken(tok);
14861482
}
14871483
} else if (cpp && tok->str() == "[") {
14881484
if (isLambdaCaptureList(tok)) {
@@ -1492,7 +1488,7 @@ static void createAstAtTokenInner(Token * const tok1, const Token *endToken, boo
14921488
const Token * const endToken2 = tok->link();
14931489
tok = tok->next();
14941490
for (; tok && tok != endToken && tok != endToken2; tok = tok ? tok->next() : nullptr)
1495-
tok = createAstAtToken(tok, library);
1491+
tok = createAstAtToken(tok);
14961492
}
14971493
}
14981494
else if (Token::simpleMatch(tok, "( * ) [")) {
@@ -1506,9 +1502,9 @@ static void createAstAtTokenInner(Token * const tok1, const Token *endToken, boo
15061502
if (!hasAst) {
15071503
Token *const startTok = tok = tok->tokAt(4);
15081504
const Token* const endtok = startTok->linkAt(-1);
1509-
AST_state state(cpp, library);
1505+
AST_state state(cpp);
15101506
compileExpression(tok, state);
1511-
createAstAtTokenInner(startTok, endtok, cpp, library);
1507+
createAstAtTokenInner(startTok, endtok, cpp);
15121508
}
15131509
}
15141510
}
@@ -1534,7 +1530,7 @@ static Token * findAstTop(Token *tok1, const Token *tok2)
15341530
return nullptr;
15351531
}
15361532

1537-
static Token * createAstAtToken(Token *tok, const Library &library)
1533+
static Token * createAstAtToken(Token *tok)
15381534
{
15391535
const bool cpp = tok->isCpp();
15401536
// skip function pointer declaration
@@ -1572,7 +1568,7 @@ static Token * createAstAtToken(Token *tok, const Library &library)
15721568
if (cpp && Token::Match(tok, "for ( const| auto &|&&| [")) {
15731569
Token *decl = Token::findsimplematch(tok, "[");
15741570
if (Token::simpleMatch(decl->link(), "] :")) {
1575-
AST_state state1(cpp, library);
1571+
AST_state state1(cpp);
15761572
while (decl->str() != "]") {
15771573
if (Token::Match(decl, "%name% ,|]")) {
15781574
state1.op.push(decl);
@@ -1609,14 +1605,14 @@ static Token * createAstAtToken(Token *tok, const Library &library)
16091605
std::vector<Token*> inner;
16101606
Token* tok2 = skipDecl(tok->tokAt(2), &inner);
16111607
for (Token* tok3 : inner) {
1612-
AST_state state1(cpp, library);
1608+
AST_state state1(cpp);
16131609
compileExpression(tok3, state1);
16141610
}
16151611
Token *init1 = nullptr;
16161612
Token * const endPar = tok->linkAt(1);
16171613
if (tok2 == tok->tokAt(2) && Token::Match(tok2, "%op%|(")) {
16181614
init1 = tok2;
1619-
AST_state state1(cpp, library);
1615+
AST_state state1(cpp);
16201616
compileExpression(tok2, state1);
16211617
if (Token::Match(init1, "( !!{")) {
16221618
for (Token *tok3 = init1; tok3 && tok3 != tok3->link(); tok3 = tok3->next()) {
@@ -1636,7 +1632,7 @@ static Token * createAstAtToken(Token *tok, const Library &library)
16361632
tok2 = tok2->link();
16371633
} else if (Token::Match(tok2, "%name% )| %op%|(|[|{|.|:|::") || Token::Match(tok2->previous(), "[(;{}] %cop%|(")) {
16381634
init1 = tok2;
1639-
AST_state state1(cpp, library);
1635+
AST_state state1(cpp);
16401636
compileExpression(tok2, state1);
16411637
if (Token::Match(tok2, ";|)"))
16421638
break;
@@ -1649,7 +1645,7 @@ static Token * createAstAtToken(Token *tok, const Library &library)
16491645
}
16501646
if (!tok2 || tok2->str() != ";") {
16511647
if (tok2 == endPar && init1) {
1652-
createAstAtTokenInner(init1->next(), endPar, cpp, library);
1648+
createAstAtTokenInner(init1->next(), endPar, cpp);
16531649
tok->next()->astOperand2(init1);
16541650
tok->next()->astOperand1(tok);
16551651
}
@@ -1660,7 +1656,7 @@ static Token * createAstAtToken(Token *tok, const Library &library)
16601656

16611657
Token * const semicolon1 = tok2;
16621658
tok2 = tok2->next();
1663-
AST_state state2(cpp, library);
1659+
AST_state state2(cpp);
16641660
compileExpression(tok2, state2);
16651661

16661662
Token * const semicolon2 = tok2;
@@ -1669,7 +1665,7 @@ static Token * createAstAtToken(Token *tok, const Library &library)
16691665

16701666
if (semicolon2->str() == ";") {
16711667
tok2 = tok2->next();
1672-
AST_state state3(cpp, library);
1668+
AST_state state3(cpp);
16731669
if (Token::simpleMatch(tok2, "( {")) {
16741670
state3.op.push(tok2->next());
16751671
tok2 = tok2->link()->next();
@@ -1697,7 +1693,7 @@ static Token * createAstAtToken(Token *tok, const Library &library)
16971693
tok->next()->astOperand1(tok);
16981694
tok->next()->astOperand2(semicolon1);
16991695

1700-
createAstAtTokenInner(endPar->link(), endPar, cpp, library);
1696+
createAstAtTokenInner(endPar->link(), endPar, cpp);
17011697

17021698
return endPar;
17031699
}
@@ -1720,9 +1716,9 @@ static Token * createAstAtToken(Token *tok, const Library &library)
17201716
}
17211717
if (Token::Match(tok2, "%name%|> %name% {") && tok2->next()->varId() && iscpp11init(tok2->tokAt(2))) {
17221718
Token *const tok1 = tok = tok2->next();
1723-
AST_state state(cpp, library);
1719+
AST_state state(cpp);
17241720
compileExpression(tok, state);
1725-
createAstAtTokenInner(tok1->next(), tok1->linkAt(1), cpp, library);
1721+
createAstAtTokenInner(tok1->next(), tok1->linkAt(1), cpp);
17261722
return tok;
17271723
}
17281724
}
@@ -1762,7 +1758,7 @@ static Token * createAstAtToken(Token *tok, const Library &library)
17621758
tok = tok->previous();
17631759

17641760
Token * const tok1 = tok;
1765-
AST_state state(cpp, library);
1761+
AST_state state(cpp);
17661762
if (Token::Match(tok, "%name% ("))
17671763
state.functionCallEndPar = tok->linkAt(1);
17681764
if (Token::simpleMatch(tok->tokAt(-1), "::") && (!tok->tokAt(-2) || !tok->tokAt(-2)->isName()))
@@ -1772,20 +1768,20 @@ static Token * createAstAtToken(Token *tok, const Library &library)
17721768
if (endToken == tok1 || !endToken)
17731769
return tok1;
17741770

1775-
createAstAtTokenInner(tok1->next(), endToken, cpp, library);
1771+
createAstAtTokenInner(tok1->next(), endToken, cpp);
17761772

17771773
return endToken->previous();
17781774
}
17791775

17801776
if (cpp && tok->str() == "{" && iscpp11init(tok)) {
17811777
Token * const tok1 = tok;
1782-
AST_state state(cpp, library);
1778+
AST_state state(cpp);
17831779
compileExpression(tok, state);
17841780
Token* const endToken = tok;
17851781
if (endToken == tok1 || !endToken)
17861782
return tok1;
17871783

1788-
createAstAtTokenInner(tok1->next(), endToken, cpp, library);
1784+
createAstAtTokenInner(tok1->next(), endToken, cpp);
17891785
return endToken->previous();
17901786
}
17911787

@@ -1795,7 +1791,7 @@ static Token * createAstAtToken(Token *tok, const Library &library)
17951791
void TokenList::createAst() const
17961792
{
17971793
for (Token *tok = mTokensFrontBack.front; tok; tok = tok ? tok->next() : nullptr) {
1798-
Token* const nextTok = createAstAtToken(tok, mSettings->library);
1794+
Token* const nextTok = createAstAtToken(tok);
17991795
if (precedes(nextTok, tok))
18001796
throw InternalError(tok, "Syntax Error: Infinite loop when creating AST.", InternalError::AST);
18011797
tok = nextTok;

0 commit comments

Comments
 (0)