From d4705ca8ab4c76f8d47abf3d8f6a092308eb2f3f Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Sat, 10 Jun 2023 07:41:52 +0200 Subject: [PATCH] Fix #10809 cppcheckError Cyclic reverse analysis (#5137) * Fix #10809 cppcheckError Cyclic reverse analysis * Handle fixed AST in ValueFlow, fix FN * Remove --- lib/tokenlist.cpp | 17 +++++++++++------ lib/valueflow.cpp | 7 ++----- test/testbufferoverrun.cpp | 8 ++++++++ test/testtokenize.cpp | 4 ++++ 4 files changed, 25 insertions(+), 11 deletions(-) diff --git a/lib/tokenlist.cpp b/lib/tokenlist.cpp index b4849ee5a..f7e79170c 100644 --- a/lib/tokenlist.cpp +++ b/lib/tokenlist.cpp @@ -560,9 +560,9 @@ static bool iscpp11init_impl(const Token * const tok) return true; if (nameToken->str() == ">" && nameToken->link()) nameToken = nameToken->link()->previous(); - if (nameToken->str() == "]") { - const Token* newTok = nameToken->link()->previous(); - while (Token::Match(newTok, "%type%|::") && !newTok->isKeyword()) + if (Token::Match(nameToken, "]|*")) { + const Token* newTok = nameToken->link() ? nameToken->link()->previous() : nameToken->previous(); + while (Token::Match(newTok, "%type%|::|*") && !newTok->isKeyword()) newTok = newTok->previous(); if (Token::simpleMatch(newTok, "new")) return true; @@ -880,8 +880,10 @@ static void compilePrecedence2(Token *&tok, AST_state& state) { auto doCompileScope = [&](const Token* tok) -> bool { const bool isStartOfCpp11Init = state.cpp && tok && tok->str() == "{" && iscpp11init(tok); - if (isStartOfCpp11Init) { + if (isStartOfCpp11Init || Token::simpleMatch(tok, "(")) { tok = tok->previous(); + while (Token::simpleMatch(tok, "*")) + tok = tok->previous(); while (tok && Token::Match(tok->previous(), ":: %type%")) tok = tok->tokAt(-2); if (tok && !tok->isKeyword()) @@ -891,8 +893,11 @@ static void compilePrecedence2(Token *&tok, AST_state& state) return !findLambdaEndTokenWithoutAST(tok); }; - if (doCompileScope(tok)) + bool isNew = true; + if (doCompileScope(tok)) { compileScope(tok, state); + isNew = false; + } while (tok) { if (tok->tokType() == Token::eIncDecOp && !isPrefixUnary(tok, state.cpp)) { compileUnaryOp(tok, state, compileScope); @@ -982,7 +987,7 @@ static void compilePrecedence2(Token *&tok, AST_state& state) const std::size_t oldOpSize = state.op.size(); compileExpression(tok, state); tok = tok2; - if ((oldOpSize > 0 && Token::simpleMatch(tok->previous(), "} (")) + if ((oldOpSize > 0 && (isNew || Token::simpleMatch(tok->previous(), "} ("))) || (tok->previous() && tok->previous()->isName() && !Token::Match(tok->previous(), "return|case") && (!state.cpp || !Token::Match(tok->previous(), "throw|delete"))) || (tok->strAt(-1) == "]" && (!state.cpp || !Token::Match(tok->linkAt(-1)->previous(), "new|delete"))) || (tok->strAt(-1) == ">" && tok->linkAt(-1)) diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index 60446f315..4d93771e7 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -8941,17 +8941,14 @@ static void valueFlowDynamicBufferSize(const TokenList* tokenlist, const SymbolD const Token* bracTok = nullptr, *typeTok = nullptr; if (newTok->astOperand1()->str() == "[") bracTok = newTok->astOperand1(); - else if (newTok->astOperand1()->str() == "(") { + else if (Token::Match(newTok->astOperand1(), "(|{")) { if (newTok->astOperand1()->astOperand1() && newTok->astOperand1()->astOperand1()->str() == "[") bracTok = newTok->astOperand1()->astOperand1(); else typeTok = newTok->astOperand1()->astOperand1(); } - else { + else typeTok = newTok->astOperand1(); - if (typeTok->str() == "{") - typeTok = typeTok->astOperand1(); - } if (bracTok && bracTok->astOperand2() && bracTok->astOperand2()->hasKnownIntValue()) numElem = bracTok->astOperand2()->getKnownIntValue(); else if (Token::Match(typeTok, "%type%")) diff --git a/test/testbufferoverrun.cpp b/test/testbufferoverrun.cpp index 4c2560ecc..45af74ac8 100644 --- a/test/testbufferoverrun.cpp +++ b/test/testbufferoverrun.cpp @@ -2880,6 +2880,14 @@ private: " delete[] z;\n" "}\n"); ASSERT_EQUALS("[test.cpp:4]: (error) Array 'z[5]' accessed at index 7, which is out of bounds.\n", errout.str()); + + check("void h() {\n" + " int** z = new int* [5]{ 0 };\n" + " for (int n = 0; n < 8; ++n)\n" + " z[n] = nullptr;\n" + " delete[] z;\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:4]: (error) Array 'z[5]' accessed at index 7, which is out of bounds.\n", errout.str()); } void buffer_overrun_2_struct() { diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp index e93dd76a3..4a3829ba1 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -6178,6 +6178,10 @@ private: ASSERT_EQUALS("intnewdelete", testAst("void f() { delete new int; }")); ASSERT_EQUALS("pint3[new1+=", testAst("p = (new int[3]) + 1;")); // #11327 ASSERT_EQUALS("aType2[T1T2,{new=", testAst("a = new Type *[2] {T1, T2};")); // #11745 + ASSERT_EQUALS("pSthis(new=", testAst("p = new S*(this);")); // #10809 + ASSERT_EQUALS("pint0{new=", testAst("p = new int*{ 0 };")); + ASSERT_EQUALS("pint5[{new=", testAst("p = new int* [5]{};")); + ASSERT_EQUALS("pint5[0{new=", testAst("p = new int* [5]{ 0 };")); // placement new ASSERT_EQUALS("X12,3,(new ab,c,", testAst("new (a,b,c) X(1,2,3);"));