From 7f88b6684216617d6a6cb2672956e4f8ebc23397 Mon Sep 17 00:00:00 2001 From: Richard Quirk Date: Sun, 6 Nov 2011 15:32:28 +0100 Subject: [PATCH] Fix namespaced types for auto_ptr new[] errors This fixes false negatives for code such as: std::auto_ptr p(new foo::bar[10]); The idea is to find a "new", search for the end token ";", then see if the declaration ends in a closing square bracket. Also fixes other cases that checked for "new %type% [" so that they work with namespaces. --- lib/checkstl.cpp | 21 +++++++++++++++++---- test/teststl.cpp | 27 +++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 4 deletions(-) diff --git a/lib/checkstl.cpp b/lib/checkstl.cpp index 37e9d5c20..58d42ffac 100644 --- a/lib/checkstl.cpp +++ b/lib/checkstl.cpp @@ -1081,6 +1081,18 @@ void CheckStl::string_c_strError(const Token* tok, bool is_inconlusive) reportError(tok, Severity::error, "stlcstr", "Dangerous usage of c_str()"); } +static bool hasArrayEnd(const Token *tok1) +{ + const Token *end = Token::findsimplematch(tok1, ";"); + return (end && Token::simpleMatch(end->previous(), "] ;")); +} + +static bool hasArrayEndParen(const Token *tok1) +{ + const Token *end = Token::findsimplematch(tok1, ";"); + return (end && end->previous() && + Token::simpleMatch(end->previous()->previous(), "] ) ;")); +} //--------------------------------------------------------------------------- // @@ -1101,7 +1113,7 @@ void CheckStl::checkAutoPointer() while (tok2) { if (Token::Match(tok2, "> %var%")) { const Token *tok3 = tok2->next()->next(); - if (Token::Match(tok3, "( new %type% [")) { + if (Token::Match(tok3, "( new %type%") && hasArrayEndParen(tok3)) { autoPointerArrayError(tok2->next()); break; } @@ -1113,8 +1125,8 @@ void CheckStl::checkAutoPointer() if (Token::simpleMatch(tok3->previous(), "[ ] )")) { autoPointerArrayError(tok2->next()); } else if (tok3->varId()) { - const Token *decltok = Token::findmatch(_tokenizer->tokens(), "%varid% = new %type% [", tok3->varId()); - if (decltok) { + const Token *decltok = Token::findmatch(_tokenizer->tokens(), "%varid% = new %type%", tok3->varId()); + if (decltok && hasArrayEnd(decltok)) { autoPointerArrayError(tok2->next()); } } @@ -1135,7 +1147,8 @@ void CheckStl::checkAutoPointer() autoPointerError(tok->next()->next()); } } - } else if (Token::Match(tok, "%var% = new %type% [") || Token::Match(tok, "%var% . reset ( new %type% [")) { + } else if ((Token::Match(tok, "%var% = new %type% ") && hasArrayEnd(tok)) || + (Token::Match(tok, "%var% . reset ( new %type% ") && hasArrayEndParen(tok))) { iter = autoPtrVarId.find(tok->varId()); if (iter != autoPtrVarId.end()) { autoPointerArrayError(tok); diff --git a/test/teststl.cpp b/test/teststl.cpp index aa28e834a..f878c2d1b 100644 --- a/test/teststl.cpp +++ b/test/teststl.cpp @@ -1427,6 +1427,13 @@ private: "}\n"); ASSERT_EQUALS("[test.cpp:4]: (error) Object pointed by an 'auto_ptr' is destroyed using operator 'delete'. You should not use 'auto_ptr' for pointers obtained with operator 'new[]'.\n", errout.str()); + check("void f() \n" + "{\n" + " foo::bar::baz* var = new foo::bar::baz[10];\n" + " auto_ptr p2( var );\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:4]: (error) Object pointed by an 'auto_ptr' is destroyed using operator 'delete'. You should not use 'auto_ptr' for pointers obtained with operator 'new[]'.\n", errout.str()); + check("void f() \n" "{\n" " auto_ptr p2( new T[] );\n" @@ -1439,6 +1446,12 @@ private: "}\n"); ASSERT_EQUALS("[test.cpp:3]: (error) Object pointed by an 'auto_ptr' is destroyed using operator 'delete'. You should not use 'auto_ptr' for pointers obtained with operator 'new[]'.\n", errout.str()); + check("void f() \n" + "{\n" + " auto_ptr p(new foo::bar[10]);\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:3]: (error) Object pointed by an 'auto_ptr' is destroyed using operator 'delete'. You should not use 'auto_ptr' for pointers obtained with operator 'new[]'.\n", errout.str()); + check("void f() \n" "{\n" " auto_ptr p2;\n" @@ -1460,6 +1473,13 @@ private: "}\n"); ASSERT_EQUALS("[test.cpp:4]: (error) Object pointed by an 'auto_ptr' is destroyed using operator 'delete'. You should not use 'auto_ptr' for pointers obtained with operator 'new[]'.\n", errout.str()); + check("void f() \n" + "{\n" + " auto_ptr p2;\n" + " p2 = new T::B[10];\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:4]: (error) Object pointed by an 'auto_ptr' is destroyed using operator 'delete'. You should not use 'auto_ptr' for pointers obtained with operator 'new[]'.\n", errout.str()); + check("void f() \n" "{\n" " auto_ptr p2;\n" @@ -1467,6 +1487,13 @@ private: "}\n"); ASSERT_EQUALS("[test.cpp:4]: (error) Object pointed by an 'auto_ptr' is destroyed using operator 'delete'. You should not use 'auto_ptr' for pointers obtained with operator 'new[]'.\n", errout.str()); + check("void f() \n" + "{\n" + " auto_ptr p2;\n" + " p2.reset( new T::B[10] );\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:4]: (error) Object pointed by an 'auto_ptr' is destroyed using operator 'delete'. You should not use 'auto_ptr' for pointers obtained with operator 'new[]'.\n", errout.str()); + // ticket #2887 (infinite loop) check("A::A(std::auto_ptr e){}\n"); ASSERT_EQUALS("", errout.str());