Skip to content

Commit edd435d

Browse files
authored
Fix 10491: Crash in unusedFunction on valid C++ code (#3465)
1 parent 4ad09f1 commit edd435d

2 files changed

Lines changed: 40 additions & 10 deletions

File tree

lib/tokenize.cpp

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4482,6 +4482,7 @@ void Tokenizer::createLinks2()
44824482
bool isStruct = false;
44834483

44844484
std::stack<Token*> type;
4485+
std::stack<Token*> templateTokens;
44854486
for (Token *token = list.front(); token; token = token->next()) {
44864487
if (Token::Match(token, "%name%|> %name% [:<]"))
44874488
isStruct = true;
@@ -4493,14 +4494,14 @@ void Tokenizer::createLinks2()
44934494
type.push(token);
44944495
else if (!type.empty() && Token::Match(token, "}|]|)")) {
44954496
while (type.top()->str() == "<") {
4496-
if (templateToken && templateToken->next() == type.top())
4497-
templateToken = nullptr;
4497+
if (!templateTokens.empty() && templateTokens.top()->next() == type.top())
4498+
templateTokens.pop();
44984499
type.pop();
44994500
}
45004501
type.pop();
45014502
} else
45024503
token->link(nullptr);
4503-
} else if (!templateToken && !isStruct && Token::Match(token, "%oror%|&&|;")) {
4504+
} else if (templateTokens.empty() && !isStruct && Token::Match(token, "%oror%|&&|;")) {
45044505
if (Token::Match(token, "&& [,>]"))
45054506
continue;
45064507
// If there is some such code: A<B||C>..
@@ -4548,8 +4549,8 @@ void Tokenizer::createLinks2()
45484549
(token->previous()->isName() && !token->previous()->varId()))) ||
45494550
Token::Match(token->next(), ">|>>"))) {
45504551
type.push(token);
4551-
if (!templateToken && (token->previous()->str() == "template"))
4552-
templateToken = token;
4552+
if (token->previous()->str() == "template")
4553+
templateTokens.push(token);
45534554
} else if (token->str() == ">" || token->str() == ">>") {
45544555
if (type.empty() || type.top()->str() != "<") // < and > don't match.
45554556
continue;
@@ -4580,15 +4581,18 @@ void Tokenizer::createLinks2()
45804581
type.pop();
45814582
type.pop();
45824583
Token::createMutualLinks(top2, token);
4583-
if (top1 == templateToken || top2 == templateToken)
4584-
templateToken = nullptr;
4584+
if (templateTokens.size() == 2 && (top1 == templateTokens.top() || top2 == templateTokens.top())) {
4585+
templateTokens.pop();
4586+
templateTokens.pop();
4587+
}
45854588
} else {
45864589
type.pop();
4587-
if (Token::Match(token, "> %name%") && Token::Match(top1->tokAt(-2), "%op% %name% <"))
4590+
if (Token::Match(token, "> %name%") && Token::Match(top1->tokAt(-2), "%op% %name% <") &&
4591+
(templateTokens.empty() || top1 != templateTokens.top()))
45884592
continue;
45894593
Token::createMutualLinks(top1, token);
4590-
if (top1 == templateToken)
4591-
templateToken = nullptr;
4594+
if (!templateTokens.empty() && top1 == templateTokens.top())
4595+
templateTokens.pop();
45924596
}
45934597
}
45944598
}

test/testtokenize.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3304,6 +3304,32 @@ class TestTokenizer : public TestFixture {
33043304
tokenizer.tokenize(istr, "test.cpp");
33053305
ASSERT(nullptr != Token::findsimplematch(tokenizer.tokens(), "> . f (")->link());
33063306
}
3307+
3308+
{
3309+
// #10491
3310+
const char code[] = "template <template <class> class> struct a;\n";
3311+
errout.str("");
3312+
Tokenizer tokenizer(&settings0, this);
3313+
std::istringstream istr(code);
3314+
tokenizer.tokenize(istr, "test.cpp");
3315+
const Token* tok1 = Token::findsimplematch(tokenizer.tokens(), "< class");
3316+
const Token* tok2 = Token::findsimplematch(tok1, "> class");
3317+
ASSERT_EQUALS(true, tok1->link() == tok2);
3318+
ASSERT_EQUALS(true, tok2->link() == tok1);
3319+
}
3320+
3321+
{
3322+
// #10491
3323+
const char code[] = "template <template <class> class> struct a;\n";
3324+
errout.str("");
3325+
Tokenizer tokenizer(&settings0, this);
3326+
std::istringstream istr(code);
3327+
tokenizer.tokenize(istr, "test.cpp");
3328+
const Token* tok1 = Token::findsimplematch(tokenizer.tokens(), "< template");
3329+
const Token* tok2 = Token::findsimplematch(tok1, "> struct");
3330+
ASSERT_EQUALS(true, tok1->link() == tok2);
3331+
ASSERT_EQUALS(true, tok2->link() == tok1);
3332+
}
33073333
}
33083334

33093335
void simplifyString() {

0 commit comments

Comments
 (0)