Fix 10491: Crash in unusedFunction on valid C++ code (#3465)

This commit is contained in:
Paul Fultz II 2021-09-22 06:03:46 -05:00 committed by GitHub
parent 4ad09f181a
commit edd435d5f0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 40 additions and 10 deletions

View File

@ -4482,6 +4482,7 @@ void Tokenizer::createLinks2()
bool isStruct = false; bool isStruct = false;
std::stack<Token*> type; std::stack<Token*> type;
std::stack<Token*> templateTokens;
for (Token *token = list.front(); token; token = token->next()) { for (Token *token = list.front(); token; token = token->next()) {
if (Token::Match(token, "%name%|> %name% [:<]")) if (Token::Match(token, "%name%|> %name% [:<]"))
isStruct = true; isStruct = true;
@ -4493,14 +4494,14 @@ void Tokenizer::createLinks2()
type.push(token); type.push(token);
else if (!type.empty() && Token::Match(token, "}|]|)")) { else if (!type.empty() && Token::Match(token, "}|]|)")) {
while (type.top()->str() == "<") { while (type.top()->str() == "<") {
if (templateToken && templateToken->next() == type.top()) if (!templateTokens.empty() && templateTokens.top()->next() == type.top())
templateToken = nullptr; templateTokens.pop();
type.pop(); type.pop();
} }
type.pop(); type.pop();
} else } else
token->link(nullptr); token->link(nullptr);
} else if (!templateToken && !isStruct && Token::Match(token, "%oror%|&&|;")) { } else if (templateTokens.empty() && !isStruct && Token::Match(token, "%oror%|&&|;")) {
if (Token::Match(token, "&& [,>]")) if (Token::Match(token, "&& [,>]"))
continue; continue;
// If there is some such code: A<B||C>.. // If there is some such code: A<B||C>..
@ -4548,8 +4549,8 @@ void Tokenizer::createLinks2()
(token->previous()->isName() && !token->previous()->varId()))) || (token->previous()->isName() && !token->previous()->varId()))) ||
Token::Match(token->next(), ">|>>"))) { Token::Match(token->next(), ">|>>"))) {
type.push(token); type.push(token);
if (!templateToken && (token->previous()->str() == "template")) if (token->previous()->str() == "template")
templateToken = token; templateTokens.push(token);
} else if (token->str() == ">" || token->str() == ">>") { } else if (token->str() == ">" || token->str() == ">>") {
if (type.empty() || type.top()->str() != "<") // < and > don't match. if (type.empty() || type.top()->str() != "<") // < and > don't match.
continue; continue;
@ -4580,15 +4581,18 @@ void Tokenizer::createLinks2()
type.pop(); type.pop();
type.pop(); type.pop();
Token::createMutualLinks(top2, token); Token::createMutualLinks(top2, token);
if (top1 == templateToken || top2 == templateToken) if (templateTokens.size() == 2 && (top1 == templateTokens.top() || top2 == templateTokens.top())) {
templateToken = nullptr; templateTokens.pop();
templateTokens.pop();
}
} else { } else {
type.pop(); type.pop();
if (Token::Match(token, "> %name%") && Token::Match(top1->tokAt(-2), "%op% %name% <")) if (Token::Match(token, "> %name%") && Token::Match(top1->tokAt(-2), "%op% %name% <") &&
(templateTokens.empty() || top1 != templateTokens.top()))
continue; continue;
Token::createMutualLinks(top1, token); Token::createMutualLinks(top1, token);
if (top1 == templateToken) if (!templateTokens.empty() && top1 == templateTokens.top())
templateToken = nullptr; templateTokens.pop();
} }
} }
} }

View File

@ -3304,6 +3304,32 @@ private:
tokenizer.tokenize(istr, "test.cpp"); tokenizer.tokenize(istr, "test.cpp");
ASSERT(nullptr != Token::findsimplematch(tokenizer.tokens(), "> . f (")->link()); ASSERT(nullptr != Token::findsimplematch(tokenizer.tokens(), "> . f (")->link());
} }
{
// #10491
const char code[] = "template <template <class> class> struct a;\n";
errout.str("");
Tokenizer tokenizer(&settings0, this);
std::istringstream istr(code);
tokenizer.tokenize(istr, "test.cpp");
const Token* tok1 = Token::findsimplematch(tokenizer.tokens(), "< class");
const Token* tok2 = Token::findsimplematch(tok1, "> class");
ASSERT_EQUALS(true, tok1->link() == tok2);
ASSERT_EQUALS(true, tok2->link() == tok1);
}
{
// #10491
const char code[] = "template <template <class> class> struct a;\n";
errout.str("");
Tokenizer tokenizer(&settings0, this);
std::istringstream istr(code);
tokenizer.tokenize(istr, "test.cpp");
const Token* tok1 = Token::findsimplematch(tokenizer.tokens(), "< template");
const Token* tok2 = Token::findsimplematch(tok1, "> struct");
ASSERT_EQUALS(true, tok1->link() == tok2);
ASSERT_EQUALS(true, tok2->link() == tok1);
}
} }
void simplifyString() { void simplifyString() {