Fix issue 4693: Diagnostic when using the same iterators to an algorithm (#1326)

* Fix issue 4693: Diagnostic when using the same iterators to an algorithm

* Update classinfo
This commit is contained in:
Paul Fultz II 2018-08-05 02:10:54 -05:00 committed by Daniel Marjamäki
parent aa831ce972
commit ed197f235a
3 changed files with 51 additions and 3 deletions

View File

@ -314,6 +314,11 @@ void CheckStl::mismatchingContainerExpressionError(const Token *tok1, const Toke
expr1 + "' and '" + expr2 + "' are used together.", CWE664, false); expr1 + "' and '" + expr2 + "' are used together.", CWE664, false);
} }
void CheckStl::sameIteratorExpressionError(const Token *tok)
{
reportError(tok, Severity::style, "sameIteratorExpression", "Same iterators expression are used for algorithm.", CWE664, false);
}
static const std::set<std::string> algorithm2 = { // func(begin1, end1 static const std::set<std::string> algorithm2 = { // func(begin1, end1
"binary_search", "copy", "copy_if", "equal_range" "binary_search", "copy", "copy_if", "equal_range"
, "generate", "is_heap", "is_heap_until", "is_partitioned" , "generate", "is_heap", "is_heap_until", "is_partitioned"
@ -392,6 +397,12 @@ void CheckStl::mismatchingContainers()
if (!i) if (!i)
continue; continue;
const Token * const argTok = args[argnr - 1]; const Token * const argTok = args[argnr - 1];
if (i->first) {
firstArg = argTok;
}
if(i->last && firstArg && argTok && isSameExpression(true, false, firstArg, argTok, mSettings->library, false)) {
sameIteratorExpressionError(firstArg);
}
const Variable *c = getContainer(argTok); const Variable *c = getContainer(argTok);
if (c) { if (c) {
std::map<const Variable *, unsigned int>::const_iterator it = containerNr.find(c); std::map<const Variable *, unsigned int>::const_iterator it = containerNr.find(c);
@ -407,9 +418,7 @@ void CheckStl::mismatchingContainers()
mismatchingContainersError(argTok); mismatchingContainersError(argTok);
} }
} else { } else {
if (i->first) { if (i->last && firstArg && argTok) {
firstArg = argTok;
} else if (i->last && firstArg && argTok) {
const Token * iter1 = getIteratorExpression(firstArg); const Token * iter1 = getIteratorExpression(firstArg);
const Token * iter2 = getIteratorExpression(argTok); const Token * iter2 = getIteratorExpression(argTok);
if (iter1 && iter2 && !isSameExpression(true, false, iter1, iter2, mSettings->library, false)) { if (iter1 && iter2 && !isSameExpression(true, false, iter1, iter2, mSettings->library, false)) {

View File

@ -184,6 +184,7 @@ private:
void iteratorsError(const Token* tok, const std::string& container1, const std::string& container2); void iteratorsError(const Token* tok, const std::string& container1, const std::string& container2);
void mismatchingContainersError(const Token* tok); void mismatchingContainersError(const Token* tok);
void mismatchingContainerExpressionError(const Token *tok1, const Token *tok2); void mismatchingContainerExpressionError(const Token *tok1, const Token *tok2);
void sameIteratorExpressionError(const Token *tok);
void invalidIteratorError(const Token* tok, const std::string& func, const std::string& iterator_name); void invalidIteratorError(const Token* tok, const std::string& func, const std::string& iterator_name);
void invalidPointerError(const Token* tok, const std::string& func, const std::string& pointer_name); void invalidPointerError(const Token* tok, const std::string& func, const std::string& pointer_name);
void stlBoundariesError(const Token* tok); void stlBoundariesError(const Token* tok);
@ -212,6 +213,7 @@ private:
c.iteratorsError(nullptr, "container1", "container2"); c.iteratorsError(nullptr, "container1", "container2");
c.mismatchingContainersError(nullptr); c.mismatchingContainersError(nullptr);
c.mismatchingContainerExpressionError(nullptr, nullptr); c.mismatchingContainerExpressionError(nullptr, nullptr);
c.sameIteratorExpressionError(nullptr);
c.dereferenceErasedError(nullptr, nullptr, "iter", false); c.dereferenceErasedError(nullptr, nullptr, "iter", false);
c.stlOutOfBoundsError(nullptr, "i", "foo", false); c.stlOutOfBoundsError(nullptr, "i", "foo", false);
c.negativeIndexError(nullptr, ValueFlow::Value(-1)); c.negativeIndexError(nullptr, ValueFlow::Value(-1));
@ -249,6 +251,7 @@ private:
"- out of bounds errors\n" "- out of bounds errors\n"
"- misuse of iterators when iterating through a container\n" "- misuse of iterators when iterating through a container\n"
"- mismatching containers in calls\n" "- mismatching containers in calls\n"
"- same iterators in calls\n"
"- dereferencing an erased iterator\n" "- dereferencing an erased iterator\n"
"- for vectors: using iterator/pointer after push_back has been used\n" "- for vectors: using iterator/pointer after push_back has been used\n"
"- optimisation: use empty() instead of size() to guarantee fast code\n" "- optimisation: use empty() instead of size() to guarantee fast code\n"

View File

@ -55,6 +55,7 @@ private:
TEST_CASE(iterator13); TEST_CASE(iterator13);
TEST_CASE(iterator14); // #8191 TEST_CASE(iterator14); // #8191
TEST_CASE(iteratorExpression); TEST_CASE(iteratorExpression);
TEST_CASE(iteratorSameExpression);
TEST_CASE(dereference); TEST_CASE(dereference);
TEST_CASE(dereference_break); // #3644 - handle "break" TEST_CASE(dereference_break); // #3644 - handle "break"
@ -595,6 +596,41 @@ private:
ASSERT_EQUALS("", errout.str()); ASSERT_EQUALS("", errout.str());
} }
void iteratorSameExpression() {
check("void f(std::vector<int> v) {\n"
" std::for_each(v.begin(), v.begin(), [](int){});\n"
"}\n");
ASSERT_EQUALS("[test.cpp:2]: (style) Same iterators expression are used for algorithm.\n", errout.str());
check("std::vector<int>& g();\n"
"void f() {\n"
" std::for_each(g().begin(), g().begin(), [](int){});\n"
"}\n");
ASSERT_EQUALS("[test.cpp:3]: (style) Same iterators expression are used for algorithm.\n", errout.str());
check("void f(std::vector<int> v) {\n"
" std::for_each(v.end(), v.end(), [](int){});\n"
"}\n");
ASSERT_EQUALS("[test.cpp:2]: (style) Same iterators expression are used for algorithm.\n", errout.str());
check("std::vector<int>& g();\n"
"void f() {\n"
" std::for_each(g().end(), g().end(), [](int){});\n"
"}\n");
ASSERT_EQUALS("[test.cpp:3]: (style) Same iterators expression are used for algorithm.\n", errout.str());
check("std::vector<int>::iterator g();\n"
"void f(std::vector<int> v) {\n"
" std::for_each(g(), g(), [](int){});\n"
"}\n");
ASSERT_EQUALS("[test.cpp:3]: (style) Same iterators expression are used for algorithm.\n", errout.str());
check("void f(std::vector<int>::iterator it) {\n"
" std::for_each(it, it, [](int){});\n"
"}\n");
ASSERT_EQUALS("[test.cpp:2]: (style) Same iterators expression are used for algorithm.\n", errout.str());
}
// Dereferencing invalid pointer // Dereferencing invalid pointer
void dereference() { void dereference() {
check("void f()\n" check("void f()\n"