From abb0563cef6ad7555d48b2a184692d48ff587441 Mon Sep 17 00:00:00 2001 From: Paul Fultz II Date: Sun, 16 Jan 2022 05:35:51 -0600 Subject: [PATCH] Fix 10726: Crash in CheckExceptionSafety::checkRethrowCopy (#3711) --- lib/tokenize.cpp | 38 ++++++++++++++++++++++++++++++++++++-- lib/tokenlist.cpp | 37 ++++++++++++++++++++++++++++++++++--- test/cfg/windows.cpp | 4 ++-- test/testio.cpp | 9 ++++++--- test/teststl.cpp | 12 ++++++------ test/testtokenize.cpp | 7 +++++++ 6 files changed, 91 insertions(+), 16 deletions(-) diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index f7ec6b3f5..0acdbaec4 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -4824,8 +4824,6 @@ bool Tokenizer::simplifyTokenList1(const char FileName[]) // Simplify the C alternative tokens (and, or, etc.) simplifyCAlternativeTokens(); - reportUnknownMacros(); - simplifyFunctionTryCatch(); simplifyHeadersAndUnusedTemplates(); @@ -5020,6 +5018,8 @@ bool Tokenizer::simplifyTokenList1(const char FileName[]) // Split up variable declarations. simplifyVarDecl(false); + reportUnknownMacros(); + // typedef.. if (mTimerResults) { Timer t("Tokenizer::tokenize::simplifyTypedef", mSettings->showtime, mTimerResults); @@ -10068,6 +10068,17 @@ static const Token* skipCPPOrAlignAttribute(const Token * tok) return tok; } +static bool isNonMacro(const Token* tok) +{ + if (tok->isKeyword()) + return true; + if (cAlternativeTokens.count(tok->str()) > 0) + return true; + if (tok->str().compare(0, 2, "__") == 0) // attribute/annotation + return true; + return false; +} + void Tokenizer::reportUnknownMacros() const { // Report unknown macros used in expressions "%name% %num%" @@ -10161,6 +10172,29 @@ void Tokenizer::reportUnknownMacros() const unknownMacroError(tok->next()); } } + + // Report unknown macros without commas or operators inbetween statements: MACRO1() MACRO2() + for (const Token* tok = tokens(); tok; tok = tok->next()) { + if (!Token::Match(tok, "%name% (")) + continue; + if (isNonMacro(tok)) + continue; + + const Token* endTok = tok->linkAt(1); + if (!Token::Match(endTok, ") %name% (|.")) + continue; + + const Token* tok2 = endTok->next(); + if (isNonMacro(tok2)) + continue; + + if (tok2->next()->str() == "(") { + if (Token::Match(tok->previous(), "%name%|::|>")) + continue; + } + + unknownMacroError(tok); + } } void Tokenizer::findGarbageCode() const diff --git a/lib/tokenlist.cpp b/lib/tokenlist.cpp index dc2165347..f6430abdd 100644 --- a/lib/tokenlist.cpp +++ b/lib/tokenlist.cpp @@ -135,14 +135,17 @@ void TokenList::determineCppC() mKeywords.insert("mutable"); mKeywords.insert("namespace"); mKeywords.insert("new"); + mKeywords.insert("noexcept"); mKeywords.insert("operator"); mKeywords.insert("private"); mKeywords.insert("protected"); mKeywords.insert("public"); mKeywords.insert("reinterpret_cast"); + mKeywords.insert("static_assert"); mKeywords.insert("static_cast"); mKeywords.insert("template"); mKeywords.insert("this"); + mKeywords.insert("thread_local"); mKeywords.insert("throw"); //mKeywords.insert("true"); // literal mKeywords.insert("try"); @@ -152,6 +155,19 @@ void TokenList::determineCppC() mKeywords.insert("using"); mKeywords.insert("virtual"); //mKeywords.insert("wchar_t"); // type + if (!mSettings || mSettings->standards.cpp >= Standards::CPP20) { + mKeywords.insert("alignas"); + mKeywords.insert("alignof"); + mKeywords.insert("axiom"); + mKeywords.insert("co_await"); + mKeywords.insert("co_return"); + mKeywords.insert("co_yield"); + mKeywords.insert("concept"); + mKeywords.insert("synchronized"); + mKeywords.insert("consteval"); + mKeywords.insert("reflexpr"); + mKeywords.insert("requires"); + } } } @@ -613,7 +629,8 @@ static bool iscpp11init_impl(const Token * const tok) nameToken = nameToken->link()->previous(); const Token *endtok = nullptr; - if (Token::Match(nameToken, "%name%|return {") && (!Token::simpleMatch(nameToken->tokAt(2), "[") || findLambdaEndScope(nameToken->tokAt(2)))) + if (Token::Match(nameToken, "%name%|return|: {") && + (!Token::simpleMatch(nameToken->tokAt(2), "[") || findLambdaEndScope(nameToken->tokAt(2)))) endtok = nameToken->linkAt(1); else if (Token::Match(nameToken,"%name% <") && Token::simpleMatch(nameToken->linkAt(1),"> {")) endtok = nameToken->linkAt(1)->linkAt(1); @@ -625,7 +642,7 @@ static bool iscpp11init_impl(const Token * const tok) return false; if (Token::simpleMatch(nameToken->previous(), "namespace")) return false; - if (Token::Match(nameToken, "%any% {")) { + if (Token::Match(nameToken, "%any% {") && !Token::Match(nameToken, "return|:")) { // If there is semicolon between {..} this is not a initlist for (const Token *tok2 = nameToken->next(); tok2 != endtok; tok2 = tok2->next()) { if (tok2->str() == ";") @@ -819,7 +836,7 @@ static void compileTerm(Token *&tok, AST_state& state) } } else compileBinOp(tok, state, compileExpression); - if (Token::Match(tok, "} ,|:")) + if (Token::Match(tok, "} ,|:|)")) tok = tok->next(); } else if (state.cpp && Token::Match(tok->tokAt(-2), "%name% ( {") && !Token::findsimplematch(tok, ";", tok->link())) { if (Token::simpleMatch(tok, "{ }")) @@ -1678,6 +1695,20 @@ void TokenList::validateAst() const "' doesn't have two operands.", InternalError::AST); } + + // Check member access + if (Token::Match(tok, "%var% .")) { + if (!tok->astParent()) { + throw InternalError( + tok, "Syntax Error: AST broken, '" + tok->str() + "' doesn't have a parent.", InternalError::AST); + } + if (!tok->next()->astOperand1() || !tok->next()->astOperand2()) { + const std::string& op = + tok->next()->originalName().empty() ? tok->next()->str() : tok->next()->originalName(); + throw InternalError( + tok, "Syntax Error: AST broken, '" + op + "' doesn't have two operands.", InternalError::AST); + } + } } } diff --git a/test/cfg/windows.cpp b/test/cfg/windows.cpp index fc4d5d494..25a2981d3 100644 --- a/test/cfg/windows.cpp +++ b/test/cfg/windows.cpp @@ -212,7 +212,7 @@ void validCode() PSID pEveryoneSID = NULL; SID_IDENTIFIER_AUTHORITY SIDAuthWorld = SECURITY_WORLD_SID_AUTHORITY; - AllocateAndInitializeSid(&SIDAuthWorld, 1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, &pEveryoneSID) + AllocateAndInitializeSid(&SIDAuthWorld, 1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, &pEveryoneSID); FreeSid(pEveryoneSID); LPVOID pMem = HeapAlloc(GetProcessHeap(), 0, 10); @@ -629,7 +629,7 @@ void ignoredReturnValue() GetLastError(); // cppcheck-suppress ignoredReturnValue - GetProcessHeap() + GetProcessHeap(); // cppcheck-suppress ignoredReturnValue // cppcheck-suppress leakReturnValNotUsed HeapAlloc(GetProcessHeap(), 0, 10); diff --git a/test/testio.cpp b/test/testio.cpp index fc013d883..775568d78 100644 --- a/test/testio.cpp +++ b/test/testio.cpp @@ -4626,9 +4626,12 @@ private: check("void f() {\n" " char str[8];\n" - " scanf_s(\"%8c\", str, sizeof(str))\n" - " scanf_s(\"%9c\", str, sizeof(str))\n" - "}\n", false, false, Settings::Win32A); + " scanf_s(\"%8c\", str, sizeof(str));\n" + " scanf_s(\"%9c\", str, sizeof(str));\n" + "}\n", + false, + false, + Settings::Win32A); ASSERT_EQUALS("[test.cpp:4]: (error) Width 9 given in format string (no. 1) is larger than destination buffer 'str[8]', use %8c to prevent overflowing it.\n", errout.str()); check("void foo() {\n" diff --git a/test/teststl.cpp b/test/teststl.cpp index 4357c5049..95343ca96 100644 --- a/test/teststl.cpp +++ b/test/teststl.cpp @@ -1658,12 +1658,12 @@ private: "std::vector& g();\n" "void foo() {\n" " auto it = f().end() - 1;\n" - " f().begin() - it\n" - " f().begin()+1 - it\n" - " f().begin() - (it + 1)\n" - " f().begin() - f().end()\n" - " f().begin()+1 - f().end()\n" - " f().begin() - (f().end() + 1)\n" + " f().begin() - it;\n" + " f().begin()+1 - it;\n" + " f().begin() - (it + 1);\n" + " f().begin() - f().end();\n" + " f().begin()+1 - f().end();\n" + " f().begin() - (f().end() + 1);\n" " (void)std::find(f().begin(), it, 0);\n" " (void)std::find(f().begin(), it + 1, 0);\n" " (void)std::find(f().begin() + 1, it + 1, 0);\n" diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp index 3f3907301..bacc6e553 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -5905,6 +5905,7 @@ private: ASSERT_EQUALS("foryz:(", testAst("for (decltype(x) *y : z);")); ASSERT_EQUALS("for(tmpNULL!=tmptmpnext.=;;( tmpa=", testAst("for ( ({ tmp = a; }) ; tmp != NULL; tmp = tmp->next ) {}")); ASSERT_EQUALS("forx0=x;;(", testAst("for (int x=0; x;);")); + ASSERT_EQUALS("forae*bc.({:(", testAst("for (a *e : {b->c()});")); // for with initializer (c++20) ASSERT_EQUALS("forab=ca:;(", testAst("for(a=b;int c:a)")); @@ -6500,6 +6501,12 @@ private: const char code8[] = "void foo() { a = [](int x, decltype(vec) y){}; }"; ASSERT_NO_THROW(tokenizeAndStringify(code8)); + + const char code9[] = "void f(std::exception c) { b(M() c.what()); }"; + ASSERT_THROW(tokenizeAndStringify(code9), InternalError); + + const char code10[] = "void f(std::exception c) { b(M() M() + N(c.what())); }"; + ASSERT_THROW(tokenizeAndStringify(code10), InternalError); } void findGarbageCode() { // Test Tokenizer::findGarbageCode()