Find iterator mismatch when using temporary containers (#3579)

This commit is contained in:
Paul Fultz II 2021-12-04 05:55:56 -06:00 committed by GitHub
parent c14920218c
commit 8dcea26c10
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 29 additions and 8 deletions

View File

@ -344,9 +344,14 @@ void CheckStl::iteratorsError(const Token* tok, const Token* containerTok, const
void CheckStl::iteratorsError(const Token* tok, const Token* containerTok, const std::string& containerName) void CheckStl::iteratorsError(const Token* tok, const Token* containerTok, const std::string& containerName)
{ {
std::list<const Token*> callstack = { tok, containerTok }; std::list<const Token*> callstack = { tok, containerTok };
reportError(callstack, Severity::error, "iterators3", reportError(callstack,
"$symbol:" + containerName + "\n" Severity::error,
"Same iterator is used with containers '" + containerName + "' that are defined in different scopes.", CWE664, Certainty::normal); "iterators3",
"$symbol:" + containerName +
"\n"
"Same iterator is used with containers '$symbol' that are temporaries or defined in different scopes.",
CWE664,
Certainty::normal);
} }
// Error message used when dereferencing an iterator that has been erased.. // Error message used when dereferencing an iterator that has been erased..
@ -709,8 +714,11 @@ static bool isSameIteratorContainerExpression(const Token* tok1,
const Library& library, const Library& library,
ValueFlow::Value::LifetimeKind kind = ValueFlow::Value::LifetimeKind::Iterator) ValueFlow::Value::LifetimeKind kind = ValueFlow::Value::LifetimeKind::Iterator)
{ {
if (isSameExpression(true, false, tok1, tok2, library, false, false)) if (isSameExpression(true, false, tok1, tok2, library, false, false)) {
if (astIsContainerOwned(tok1) && isTemporary(true, tok1, &library))
return false;
return true; return true;
}
if (kind == ValueFlow::Value::LifetimeKind::Address) { if (kind == ValueFlow::Value::LifetimeKind::Address) {
return isSameExpression(true, false, getAddressContainer(tok1), getAddressContainer(tok2), library, false, false); return isSameExpression(true, false, getAddressContainer(tok1), getAddressContainer(tok2), library, false, false);
} }

View File

@ -1305,7 +1305,9 @@ private:
" }\n" " }\n"
" }\n" " }\n"
"}"); "}");
ASSERT_EQUALS("[test.cpp:7] -> [test.cpp:4]: (error) Same iterator is used with containers 'l1' that are defined in different scopes.\n", errout.str()); ASSERT_EQUALS(
"[test.cpp:7] -> [test.cpp:4]: (error) Same iterator is used with containers 'l1' that are temporaries or defined in different scopes.\n",
errout.str());
check("void foo()\n" check("void foo()\n"
"{\n" "{\n"
@ -1320,7 +1322,7 @@ private:
"}"); "}");
TODO_ASSERT_EQUALS( TODO_ASSERT_EQUALS(
"[test.cpp:7] -> [test.cpp:4]: (error) Same iterator is used with containers 'l1' that are defined in different scopes.\n", "[test.cpp:7] -> [test.cpp:4]: (error) Same iterator is used with containers 'l1' that are defined in different scopes.\n",
"[test.cpp:7] -> [test.cpp:7]: (error) Same iterator is used with containers 'l1' that are defined in different scopes.\n[test.cpp:7]: (error) Dangerous comparison using operator< on iterator.\n", "[test.cpp:7] -> [test.cpp:7]: (error) Same iterator is used with containers 'l1' that are temporaries or defined in different scopes.\n[test.cpp:7]: (error) Dangerous comparison using operator< on iterator.\n",
errout.str()); errout.str());
check("void foo()\n" check("void foo()\n"
@ -1336,7 +1338,7 @@ private:
" }\n" " }\n"
"}"); "}");
ASSERT_EQUALS( ASSERT_EQUALS(
"[test.cpp:8] -> [test.cpp:4]: (error) Same iterator is used with containers 'l1' that are defined in different scopes.\n", "[test.cpp:8] -> [test.cpp:4]: (error) Same iterator is used with containers 'l1' that are temporaries or defined in different scopes.\n",
errout.str()); errout.str());
check("void foo()\n" check("void foo()\n"
@ -1352,7 +1354,18 @@ private:
" }\n" " }\n"
"}"); "}");
ASSERT_EQUALS( ASSERT_EQUALS(
"[test.cpp:8] -> [test.cpp:7]: (error) Same iterator is used with containers 'l1' that are defined in different scopes.\n", "[test.cpp:8] -> [test.cpp:7]: (error) Same iterator is used with containers 'l1' that are temporaries or defined in different scopes.\n",
errout.str());
check("std::set<int> g() {\n"
" static const std::set<int> s = {1};\n"
" return s;\n"
"}\n"
"void f() {\n"
" if (g().find(2) == g().end()) {}\n"
"}\n");
ASSERT_EQUALS(
"[test.cpp:6] -> [test.cpp:6]: (error) Same iterator is used with containers 'g()' that are temporaries or defined in different scopes.\n",
errout.str()); errout.str());
} }