From 423dcfd005d2ba1eff75039d77c18601328c4090 Mon Sep 17 00:00:00 2001 From: Paul Date: Wed, 15 Jul 2020 12:22:36 -0500 Subject: [PATCH 1/2] Fix issue 9796: False positive: lifetime, pointer item is not deallocated by pop_back --- lib/valueflow.cpp | 8 +++++++- test/teststl.cpp | 12 ++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index 271429172..57dadab82 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -3623,11 +3623,17 @@ static void valueFlowLifetime(TokenList *tokenlist, SymbolDatabase*, ErrorLogger if (!Token::Match(parent, ". %name% (")) continue; + bool isContainerOfPointers = true; + const Token* containerTypeToken = tok->valueType()->containerTypeToken; + if (containerTypeToken && Token::simpleMatch(containerTypeToken->previous(), "<") && containerTypeToken->previous()->link()) { + isContainerOfPointers = Token::simpleMatch(containerTypeToken->previous()->link()->previous(), "*"); + } + LifetimeStore ls; if (astIsIterator(parent->tokAt(2))) ls = LifetimeStore{tok, "Iterator to container is created here.", ValueFlow::Value::LifetimeKind::Iterator}; - else if (astIsPointer(parent->tokAt(2)) || Token::Match(parent->next(), "data|c_str")) + else if ((astIsPointer(parent->tokAt(2)) && !isContainerOfPointers) || Token::Match(parent->next(), "data|c_str")) ls = LifetimeStore{tok, "Pointer to container is created here.", ValueFlow::Value::LifetimeKind::Object}; else continue; diff --git a/test/teststl.cpp b/test/teststl.cpp index e9e929a92..ca054dfaf 100644 --- a/test/teststl.cpp +++ b/test/teststl.cpp @@ -4164,6 +4164,18 @@ private: " v.push_back(\"y\");\n" "}\n",true); ASSERT_EQUALS("", errout.str()); + + // #9796 + check("struct A {};\n" + "void f() {\n" + " std::vector v;\n" + " A *a = new A();\n" + " v.push_back(a);\n" + " A *b = v.back();\n" + " v.pop_back();\n" + " delete b;\n" + "}\n" ,true); + ASSERT_EQUALS("", errout.str()); } void invalidContainerLoop() { From 831690f89b178d7bc47a25f1794bfd9633cad1ec Mon Sep 17 00:00:00 2001 From: Paul Date: Thu, 16 Jul 2020 14:33:39 -0500 Subject: [PATCH 2/2] Use parseDecl instead --- lib/valueflow.cpp | 5 +++-- test/teststl.cpp | 22 ++++++++++++++++++++++ 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index 57dadab82..e06bada7c 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -3625,8 +3625,9 @@ static void valueFlowLifetime(TokenList *tokenlist, SymbolDatabase*, ErrorLogger bool isContainerOfPointers = true; const Token* containerTypeToken = tok->valueType()->containerTypeToken; - if (containerTypeToken && Token::simpleMatch(containerTypeToken->previous(), "<") && containerTypeToken->previous()->link()) { - isContainerOfPointers = Token::simpleMatch(containerTypeToken->previous()->link()->previous(), "*"); + if (containerTypeToken) { + ValueType vt = ValueType::parseDecl(containerTypeToken, settings); + isContainerOfPointers = vt.pointer > 0; } LifetimeStore ls; diff --git a/test/teststl.cpp b/test/teststl.cpp index ca054dfaf..d243f0cd7 100644 --- a/test/teststl.cpp +++ b/test/teststl.cpp @@ -4176,6 +4176,28 @@ private: " delete b;\n" "}\n" ,true); ASSERT_EQUALS("", errout.str()); + + check("struct A {};\n" + "void f() {\n" + " std::vector> v;\n" + " A *a = new A();\n" + " v.push_back(a);\n" + " A *b = v.back();\n" + " v.pop_back();\n" + " delete b;\n" + "}\n" ,true); + ASSERT_EQUALS("", errout.str()); + + check("struct A {};\n" + "void f() {\n" + " std::vector> v;\n" + " std::shared_ptr a = std::make_shared();\n" + " v.push_back(a);\n" + " std::shared_ptr b = v.back();\n" + " v.pop_back();\n" + " delete b;\n" + "}\n" ,true); + ASSERT_EQUALS("", errout.str()); } void invalidContainerLoop() {