From 3819c66f3649135af9550578dc1266acadb2eec2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Sun, 3 May 2009 07:37:39 +0200 Subject: [PATCH] stl: Fixed ticket #277 - dereferencing an iterator that has been erased --- src/checkstl.cpp | 14 +++++++++++++- src/checkstl.h | 4 ++++ test/teststl.cpp | 33 ++++++++++++++++++--------------- 3 files changed, 35 insertions(+), 16 deletions(-) diff --git a/src/checkstl.cpp b/src/checkstl.cpp index 2c989f471..6f1baedea 100644 --- a/src/checkstl.cpp +++ b/src/checkstl.cpp @@ -35,18 +35,24 @@ void CheckStl::iteratorsError(const Token *tok, const std::string &container1, c reportError(tok, "error", "iterators", "Same iterator is used with both " + container1 + " and " + container2); } +// Error message used when dereferencing an iterator that has been erased.. +void CheckStl::dereferenceErasedError(const Token *tok, const std::string &itername) +{ + reportError(tok, "error", "eraseDereference", "Dereferenced iterator '" + itername + "' has been erased"); +} void CheckStl::iterators() { for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) { - if (Token::Match(tok, "%var% = %var% . begin ( ) ;")) + if (Token::Match(tok, "%var% = %var% . begin ( ) ;|+")) { const unsigned int iteratorId(tok->varId()); const unsigned int containerId(tok->tokAt(2)->varId()); if (iteratorId == 0 || containerId == 0) continue; + bool validIterator = true; for (const Token *tok2 = tok->tokAt(6); tok2; tok2 = tok2->next()) { if (tok2->str() == "}") @@ -60,6 +66,12 @@ void CheckStl::iterators() { if (tok2->varId() != containerId) iteratorsError(tok2, tok->strAt(2), tok2->str()); + else if (tok2->strAt(2) == std::string("erase")) + validIterator = false; + } + else if (!validIterator && tok2->Match(tok2, "* %varid%", iteratorId)) + { + dereferenceErasedError(tok2, tok2->strAt(1)); } } } diff --git a/src/checkstl.h b/src/checkstl.h index 8d3e207b1..846cc25ab 100644 --- a/src/checkstl.h +++ b/src/checkstl.h @@ -63,6 +63,9 @@ public: */ void iterators(); + /** Dereferencing an erased iterator */ + void dereferenceErasedError(const Token *tok, const std::string &itername); + /** * Dangerous usage of erase */ @@ -97,6 +100,7 @@ private: void getErrorMessages() { iteratorsError(0, "container1", "container2"); + dereferenceErasedError(0, "iter"); stlOutOfBoundsError(0, "i", "foo"); eraseError(0); pushbackError(0, "iterator"); diff --git a/test/teststl.cpp b/test/teststl.cpp index c0c4c2700..fce35b64d 100644 --- a/test/teststl.cpp +++ b/test/teststl.cpp @@ -39,6 +39,8 @@ private: TEST_CASE(iterator2); TEST_CASE(iterator3); + TEST_CASE(dereference); + TEST_CASE(STLSize); TEST_CASE(STLSizeNoErr); TEST_CASE(erase); @@ -46,7 +48,6 @@ private: TEST_CASE(eraseReturn); TEST_CASE(eraseGoto); TEST_CASE(eraseAssign); - TEST_CASE(eraseDereference); TEST_CASE(eraseErase); TEST_CASE(pushback1); @@ -118,6 +119,22 @@ private: } + // Dereferencing invalid pointer + void dereference() + { + check("void f()\n" + "{\n" + " std::vector ints;" + " std::vector::iterator iter;\n" + " iter = ints.begin() + 2;\n" + " ints.erase(iter);\n" + " std::cout << (*iter) << std::endl;\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:6]: (error) Dereferenced iterator 'iter' has been erased\n", errout.str()); + } + + + void STLSize() { check("void foo()\n" @@ -258,20 +275,6 @@ private: ASSERT_EQUALS("", errout.str()); } - void eraseDereference() - { - check("void f(std::vector &ints)\n" - "{\n" - " std::vector::iterator iter;\n" - " iter = ints.begin() + 2;\n" - " ints.erase(iter);\n" - " std::cout << (*iter) << std::endl;\n" - "}\n"); - - // Ticket #277 - STL: Dereferencing an erased iterator - TODO_ASSERT_EQUALS("[test.cpp:6]: (error) Dereferencing invalid iterator\n", errout.str()); - } - void eraseErase() { check("void f(std::vector &ints)\n"