Skip to content

Commit 0608ef7

Browse files
authored
fix #13554 AST: function name in parentheses is not a cast 'result = (strtod)("NAN", NULL);' (#7227)
1 parent 54a9ba4 commit 0608ef7

File tree

2 files changed

+59
-42
lines changed

2 files changed

+59
-42
lines changed

Diff for: lib/tokenlist.cpp

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

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

493-
static bool iscast(const Token *tok, bool cpp)
494+
static bool iscast(const Token *tok, const AST_state &state)
494495
{
495496
if (!Token::Match(tok, "( ::| %name%"))
496497
return false;
@@ -502,7 +503,7 @@ static bool iscast(const Token *tok, bool cpp)
502503
return false;
503504

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

508509
if (Token::simpleMatch(tok->previous(), ">") && tok->linkAt(-1))
@@ -527,7 +528,10 @@ static bool iscast(const Token *tok, bool cpp)
527528
for (const Token *tok2 = tok->next(); tok2; tok2 = tok2->next()) {
528529
if (tok2->varId() != 0)
529530
return false;
530-
if (cpp && !type && tok2->str() == "new")
531+
if (state.cpp && !type && tok2->str() == "new")
532+
return false;
533+
534+
if (!state.library.isNotLibraryFunction(tok2))
531535
return false;
532536

533537
while (tok2->link() && Token::Match(tok2, "(|[|<"))
@@ -802,7 +806,7 @@ static void compileTerm(Token *&tok, AST_state& state)
802806
std::vector<Token*> inner;
803807
tok = skipDecl(tok, &inner);
804808
for (Token* tok3 : inner) {
805-
AST_state state1(state.cpp);
809+
AST_state state1(state.cpp, state.library);
806810
compileExpression(tok3, state1);
807811
}
808812
bool repeat = true;
@@ -832,7 +836,7 @@ static void compileTerm(Token *&tok, AST_state& state)
832836
}
833837
} else if (tok->str() == "{") {
834838
const Token *prev = tok->previous();
835-
if (Token::simpleMatch(prev, ") {") && iscast(prev->link(), state.cpp))
839+
if (Token::simpleMatch(prev, ") {") && iscast(prev->link(), state))
836840
prev = prev->link()->previous();
837841
if (Token::simpleMatch(tok->link(),"} [")) {
838842
tok = tok->next();
@@ -904,9 +908,9 @@ static void compileScope(Token *&tok, AST_state& state)
904908
}
905909
}
906910

907-
static bool isPrefixUnary(const Token* tok, bool cpp)
911+
static bool isPrefixUnary(const Token* tok, const AST_state &state)
908912
{
909-
if (cpp && Token::simpleMatch(tok->previous(), "* [") && Token::simpleMatch(tok->link(), "] {")) {
913+
if (state.cpp && Token::simpleMatch(tok->previous(), "* [") && Token::simpleMatch(tok->link(), "] {")) {
910914
for (const Token* prev = tok->previous(); Token::Match(prev, "%name%|::|*|&|>|>>"); prev = prev->previous()) {
911915
if (Token::Match(prev, ">|>>")) {
912916
if (!prev->link())
@@ -918,7 +922,7 @@ static bool isPrefixUnary(const Token* tok, bool cpp)
918922
}
919923
}
920924
if (!tok->previous()
921-
|| ((Token::Match(tok->previous(), "(|[|{|%op%|;|?|:|,|.|case|return|::") || (cpp && tok->strAt(-1) == "throw"))
925+
|| ((Token::Match(tok->previous(), "(|[|{|%op%|;|?|:|,|.|case|return|::") || (state.cpp && tok->strAt(-1) == "throw"))
922926
&& (tok->previous()->tokType() != Token::eIncDecOp || tok->tokType() == Token::eIncDecOp)))
923927
return true;
924928

@@ -927,10 +931,10 @@ static bool isPrefixUnary(const Token* tok, bool cpp)
927931
return !Token::Match(parent, "%type%") || parent->isKeyword();
928932
}
929933

930-
if (tok->str() == "*" && tok->previous()->tokType() == Token::eIncDecOp && isPrefixUnary(tok->previous(), cpp))
934+
if (tok->str() == "*" && tok->previous()->tokType() == Token::eIncDecOp && isPrefixUnary(tok->previous(), state))
931935
return true;
932936

933-
return tok->strAt(-1) == ")" && iscast(tok->linkAt(-1), cpp);
937+
return tok->strAt(-1) == ")" && iscast(tok->linkAt(-1), state);
934938
}
935939

936940
static void compilePrecedence2(Token *&tok, AST_state& state)
@@ -956,7 +960,7 @@ static void compilePrecedence2(Token *&tok, AST_state& state)
956960
isNew = false;
957961
}
958962
while (tok) {
959-
if (tok->tokType() == Token::eIncDecOp && !isPrefixUnary(tok, state.cpp)) {
963+
if (tok->tokType() == Token::eIncDecOp && !isPrefixUnary(tok, state)) {
960964
compileUnaryOp(tok, state, compileScope);
961965
} else if (tok->str() == "...") {
962966
if (!Token::simpleMatch(tok->previous(), ")"))
@@ -974,7 +978,7 @@ static void compilePrecedence2(Token *&tok, AST_state& state)
974978
else
975979
compileUnaryOp(tok, state, compileScope);
976980
} else if (tok->str() == "[") {
977-
if (state.cpp && isPrefixUnary(tok, /*cpp*/ true) && Token::Match(tok->link(), "] (|{|<")) { // Lambda
981+
if (state.cpp && isPrefixUnary(tok, state) && Token::Match(tok->link(), "] (|{|<")) { // Lambda
978982
// What we do here:
979983
// - Nest the round bracket under the square bracket.
980984
// - Nest what follows the lambda (if anything) with the lambda opening [
@@ -984,7 +988,7 @@ static void compilePrecedence2(Token *&tok, AST_state& state)
984988
// Parse arguments in the capture list
985989
if (tok->strAt(1) != "]") {
986990
Token* tok2 = tok->next();
987-
AST_state state2(state.cpp);
991+
AST_state state2(state.cpp, state.library);
988992
compileExpression(tok2, state2);
989993
if (!state2.op.empty()) {
990994
squareBracket->astOperand2(state2.op.top());
@@ -1048,7 +1052,7 @@ static void compilePrecedence2(Token *&tok, AST_state& state)
10481052
tok = tok->link()->next();
10491053
continue;
10501054
} else if (tok->str() == "(" &&
1051-
(!iscast(tok, state.cpp) || Token::Match(tok->previous(), "if|while|for|switch|catch"))) {
1055+
(!iscast(tok, state) || Token::Match(tok->previous(), "if|while|for|switch|catch"))) {
10521056
Token* tok2 = tok;
10531057
tok = tok->next();
10541058
const bool opPrevTopSquare = !state.op.empty() && state.op.top() && state.op.top()->str() == "[";
@@ -1059,7 +1063,7 @@ static void compilePrecedence2(Token *&tok, AST_state& state)
10591063
|| (tok->previous() && tok->previous()->isName() && !Token::Match(tok->previous(), "return|case") && (!state.cpp || !Token::Match(tok->previous(), "throw|delete")))
10601064
|| (tok->strAt(-1) == "]" && (!state.cpp || !Token::Match(tok->linkAt(-1)->previous(), "new|delete")))
10611065
|| (tok->strAt(-1) == ">" && tok->linkAt(-1))
1062-
|| (tok->strAt(-1) == ")" && !iscast(tok->linkAt(-1), state.cpp)) // Don't treat brackets to clarify precedence as function calls
1066+
|| (tok->strAt(-1) == ")" && !iscast(tok->linkAt(-1), state)) // Don't treat brackets to clarify precedence as function calls
10631067
|| (tok->strAt(-1) == "}" && opPrevTopSquare)) {
10641068
const bool operandInside = oldOpSize < state.op.size();
10651069
if (operandInside)
@@ -1070,7 +1074,7 @@ static void compilePrecedence2(Token *&tok, AST_state& state)
10701074
tok = tok->link()->next();
10711075
if (Token::simpleMatch(tok, "::"))
10721076
compileBinOp(tok, state, compileTerm);
1073-
} else if (iscast(tok, state.cpp) && Token::simpleMatch(tok->link(), ") {") &&
1077+
} else if (iscast(tok, state) && Token::simpleMatch(tok->link(), ") {") &&
10741078
Token::simpleMatch(tok->link()->linkAt(1), "} [")) {
10751079
Token *cast = tok;
10761080
tok = tok->link()->next();
@@ -1103,7 +1107,7 @@ static void compilePrecedence3(Token *&tok, AST_state& state)
11031107
compilePrecedence2(tok, state);
11041108
while (tok) {
11051109
if ((Token::Match(tok, "[+-!~*&]") || tok->tokType() == Token::eIncDecOp) &&
1106-
isPrefixUnary(tok, state.cpp)) {
1110+
isPrefixUnary(tok, state)) {
11071111
if (Token::Match(tok, "* [*,)]")) {
11081112
Token* tok2 = tok->next();
11091113
while (tok2->next() && tok2->str() == "*")
@@ -1114,7 +1118,7 @@ static void compilePrecedence3(Token *&tok, AST_state& state)
11141118
}
11151119
}
11161120
compileUnaryOp(tok, state, compilePrecedence3);
1117-
} else if (tok->str() == "(" && iscast(tok, state.cpp)) {
1121+
} else if (tok->str() == "(" && iscast(tok, state)) {
11181122
Token* castTok = tok;
11191123
castTok->isCast(true);
11201124
tok = tok->link()->next();
@@ -1134,7 +1138,7 @@ static void compilePrecedence3(Token *&tok, AST_state& state)
11341138
if (Token::Match(tok->link(), ") ::| %type%")) {
11351139
if (Token::Match(tok, "( !!)")) {
11361140
Token *innerTok = tok->next();
1137-
AST_state innerState(true);
1141+
AST_state innerState(true, state.library);
11381142
compileExpression(innerTok, innerState);
11391143
}
11401144
tok = tok->link()->next();
@@ -1459,10 +1463,10 @@ const Token* findLambdaEndTokenWithoutAST(const Token* tok) {
14591463
return tok->link()->next();
14601464
}
14611465

1462-
static Token * createAstAtToken(Token *tok);
1466+
static Token * createAstAtToken(Token *tok, const Library &library);
14631467

14641468
// Compile inner expressions inside inner ({..}) and lambda bodies
1465-
static void createAstAtTokenInner(Token * const tok1, const Token *endToken, bool cpp)
1469+
static void createAstAtTokenInner(Token * const tok1, const Token *endToken, bool cpp, const Library &library)
14661470
{
14671471
for (Token* tok = tok1; precedes(tok, endToken); tok = tok ? tok->next() : nullptr) {
14681472
if (tok->str() == "{" && !iscpp11init(tok)) {
@@ -1480,7 +1484,7 @@ static void createAstAtTokenInner(Token * const tok1, const Token *endToken, boo
14801484
}
14811485
if (!hasAst) {
14821486
for (; tok && tok != endToken && tok != endToken2; tok = tok ? tok->next() : nullptr)
1483-
tok = createAstAtToken(tok);
1487+
tok = createAstAtToken(tok, library);
14841488
}
14851489
} else if (cpp && tok->str() == "[") {
14861490
if (isLambdaCaptureList(tok)) {
@@ -1490,7 +1494,7 @@ static void createAstAtTokenInner(Token * const tok1, const Token *endToken, boo
14901494
const Token * const endToken2 = tok->link();
14911495
tok = tok->next();
14921496
for (; tok && tok != endToken && tok != endToken2; tok = tok ? tok->next() : nullptr)
1493-
tok = createAstAtToken(tok);
1497+
tok = createAstAtToken(tok, library);
14941498
}
14951499
}
14961500
else if (Token::simpleMatch(tok, "( * ) [")) {
@@ -1504,9 +1508,9 @@ static void createAstAtTokenInner(Token * const tok1, const Token *endToken, boo
15041508
if (!hasAst) {
15051509
Token *const startTok = tok = tok->tokAt(4);
15061510
const Token* const endtok = startTok->linkAt(-1);
1507-
AST_state state(cpp);
1511+
AST_state state(cpp, library);
15081512
compileExpression(tok, state);
1509-
createAstAtTokenInner(startTok, endtok, cpp);
1513+
createAstAtTokenInner(startTok, endtok, cpp, library);
15101514
}
15111515
}
15121516
}
@@ -1532,7 +1536,7 @@ static Token * findAstTop(Token *tok1, const Token *tok2)
15321536
return nullptr;
15331537
}
15341538

1535-
static Token * createAstAtToken(Token *tok)
1539+
static Token * createAstAtToken(Token *tok, const Library &library)
15361540
{
15371541
const bool cpp = tok->isCpp();
15381542
// skip function pointer declaration
@@ -1570,7 +1574,7 @@ static Token * createAstAtToken(Token *tok)
15701574
if (cpp && Token::Match(tok, "for ( const| auto &|&&| [")) {
15711575
Token *decl = Token::findsimplematch(tok, "[");
15721576
if (Token::simpleMatch(decl->link(), "] :")) {
1573-
AST_state state1(cpp);
1577+
AST_state state1(cpp, library);
15741578
while (decl->str() != "]") {
15751579
if (Token::Match(decl, "%name% ,|]")) {
15761580
state1.op.push(decl);
@@ -1607,14 +1611,14 @@ static Token * createAstAtToken(Token *tok)
16071611
std::vector<Token*> inner;
16081612
Token* tok2 = skipDecl(tok->tokAt(2), &inner);
16091613
for (Token* tok3 : inner) {
1610-
AST_state state1(cpp);
1614+
AST_state state1(cpp, library);
16111615
compileExpression(tok3, state1);
16121616
}
16131617
Token *init1 = nullptr;
16141618
Token * const endPar = tok->linkAt(1);
16151619
if (tok2 == tok->tokAt(2) && Token::Match(tok2, "%op%|(")) {
16161620
init1 = tok2;
1617-
AST_state state1(cpp);
1621+
AST_state state1(cpp, library);
16181622
compileExpression(tok2, state1);
16191623
if (Token::Match(init1, "( !!{")) {
16201624
for (Token *tok3 = init1; tok3 && tok3 != tok3->link(); tok3 = tok3->next()) {
@@ -1634,7 +1638,7 @@ static Token * createAstAtToken(Token *tok)
16341638
tok2 = tok2->link();
16351639
} else if (Token::Match(tok2, "%name% )| %op%|(|[|{|.|:|::") || Token::Match(tok2->previous(), "[(;{}] %cop%|(")) {
16361640
init1 = tok2;
1637-
AST_state state1(cpp);
1641+
AST_state state1(cpp, library);
16381642
compileExpression(tok2, state1);
16391643
if (Token::Match(tok2, ";|)"))
16401644
break;
@@ -1647,7 +1651,7 @@ static Token * createAstAtToken(Token *tok)
16471651
}
16481652
if (!tok2 || tok2->str() != ";") {
16491653
if (tok2 == endPar && init1) {
1650-
createAstAtTokenInner(init1->next(), endPar, cpp);
1654+
createAstAtTokenInner(init1->next(), endPar, cpp, library);
16511655
tok->next()->astOperand2(init1);
16521656
tok->next()->astOperand1(tok);
16531657
}
@@ -1658,7 +1662,7 @@ static Token * createAstAtToken(Token *tok)
16581662

16591663
Token * const semicolon1 = tok2;
16601664
tok2 = tok2->next();
1661-
AST_state state2(cpp);
1665+
AST_state state2(cpp, library);
16621666
compileExpression(tok2, state2);
16631667

16641668
Token * const semicolon2 = tok2;
@@ -1667,7 +1671,7 @@ static Token * createAstAtToken(Token *tok)
16671671

16681672
if (semicolon2->str() == ";") {
16691673
tok2 = tok2->next();
1670-
AST_state state3(cpp);
1674+
AST_state state3(cpp, library);
16711675
if (Token::simpleMatch(tok2, "( {")) {
16721676
state3.op.push(tok2->next());
16731677
tok2 = tok2->link()->next();
@@ -1695,7 +1699,7 @@ static Token * createAstAtToken(Token *tok)
16951699
tok->next()->astOperand1(tok);
16961700
tok->next()->astOperand2(semicolon1);
16971701

1698-
createAstAtTokenInner(endPar->link(), endPar, cpp);
1702+
createAstAtTokenInner(endPar->link(), endPar, cpp, library);
16991703

17001704
return endPar;
17011705
}
@@ -1718,9 +1722,9 @@ static Token * createAstAtToken(Token *tok)
17181722
}
17191723
if (Token::Match(tok2, "%name%|> %name% {") && tok2->next()->varId() && iscpp11init(tok2->tokAt(2))) {
17201724
Token *const tok1 = tok = tok2->next();
1721-
AST_state state(cpp);
1725+
AST_state state(cpp, library);
17221726
compileExpression(tok, state);
1723-
createAstAtTokenInner(tok1->next(), tok1->linkAt(1), cpp);
1727+
createAstAtTokenInner(tok1->next(), tok1->linkAt(1), cpp, library);
17241728
return tok;
17251729
}
17261730
}
@@ -1760,7 +1764,7 @@ static Token * createAstAtToken(Token *tok)
17601764
tok = tok->previous();
17611765

17621766
Token * const tok1 = tok;
1763-
AST_state state(cpp);
1767+
AST_state state(cpp, library);
17641768
if (Token::Match(tok, "%name% ("))
17651769
state.functionCallEndPar = tok->linkAt(1);
17661770
if (Token::simpleMatch(tok->tokAt(-1), "::") && (!tok->tokAt(-2) || !tok->tokAt(-2)->isName()))
@@ -1770,20 +1774,20 @@ static Token * createAstAtToken(Token *tok)
17701774
if (endToken == tok1 || !endToken)
17711775
return tok1;
17721776

1773-
createAstAtTokenInner(tok1->next(), endToken, cpp);
1777+
createAstAtTokenInner(tok1->next(), endToken, cpp, library);
17741778

17751779
return endToken->previous();
17761780
}
17771781

17781782
if (cpp && tok->str() == "{" && iscpp11init(tok)) {
17791783
Token * const tok1 = tok;
1780-
AST_state state(cpp);
1784+
AST_state state(cpp, library);
17811785
compileExpression(tok, state);
17821786
Token* const endToken = tok;
17831787
if (endToken == tok1 || !endToken)
17841788
return tok1;
17851789

1786-
createAstAtTokenInner(tok1->next(), endToken, cpp);
1790+
createAstAtTokenInner(tok1->next(), endToken, cpp, library);
17871791
return endToken->previous();
17881792
}
17891793

@@ -1793,7 +1797,7 @@ static Token * createAstAtToken(Token *tok)
17931797
void TokenList::createAst() const
17941798
{
17951799
for (Token *tok = mTokensFrontBack.front; tok; tok = tok ? tok->next() : nullptr) {
1796-
Token* const nextTok = createAstAtToken(tok);
1800+
Token* const nextTok = createAstAtToken(tok, mSettings->library);
17971801
if (precedes(nextTok, tok))
17981802
throw InternalError(tok, "Syntax Error: Infinite loop when creating AST.", InternalError::AST);
17991803
tok = nextTok;

Diff for: test/testtokenize.cpp

+13
Original file line numberDiff line numberDiff line change
@@ -460,6 +460,8 @@ class TestTokenizer : public TestFixture {
460460
TEST_CASE(testDirectiveIncludeLocations);
461461
TEST_CASE(testDirectiveIncludeComments);
462462
TEST_CASE(testDirectiveRelativePath);
463+
464+
TEST_CASE(funcnameInParenthesis); // #13554
463465
}
464466

465467
#define tokenizeAndStringify(...) tokenizeAndStringify_(__FILE__, __LINE__, __VA_ARGS__)
@@ -8344,6 +8346,17 @@ class TestTokenizer : public TestFixture {
83448346
directiveDump(filedata, "/some/path/test.c", s, ostr);
83458347
ASSERT_EQUALS(dumpdata, ostr.str());
83468348
}
8349+
8350+
void funcnameInParenthesis() { // #13554
8351+
const char code[] = "void f(void) {\n"
8352+
" double result = (strtod)(\"NAN\", NULL);\n"
8353+
"}\n";
8354+
SimpleTokenizer tokenizer(settings1, *this);
8355+
ASSERT_LOC(tokenizer.tokenize(code, false), __FILE__, __LINE__);
8356+
const Token *f = Token::findsimplematch(tokenizer.tokens(), "strtod");
8357+
ASSERT(f);
8358+
ASSERT(!f->previous()->isCast());
8359+
}
83478360
};
83488361

83498362
REGISTER_TEST(TestTokenizer)

0 commit comments

Comments
 (0)