Fix 6624: false negative: std::vector out of bounds access not detected (#3980)

* Fix 6624: false negative: std::vector out of bounds access not detected

* Format

* Add test for auto

* Fix tests

* Format
This commit is contained in:
Paul Fultz II 2022-04-06 23:47:15 -05:00 committed by GitHub
parent bb640c4879
commit 09c8cfb2ae
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 54 additions and 18 deletions

View File

@ -1198,6 +1198,20 @@ const Library::Container* Library::detectContainer(const Token* typeStart, bool
return nullptr;
}
const Library::Container* Library::detectContainerOrIterator(const Token* typeStart, bool* isIterator) const
{
const Library::Container* c = detectContainer(typeStart);
if (c) {
if (isIterator)
*isIterator = false;
return c;
}
c = detectContainer(typeStart, true);
if (c && isIterator)
*isIterator = true;
return c;
}
bool Library::isContainerYield(const Token * const cond, Library::Container::Yield y, const std::string& fallback)
{
if (!cond)

View File

@ -285,6 +285,7 @@ public:
};
std::map<std::string, Container> containers;
const Container* detectContainer(const Token* typeStart, bool iterator = false) const;
const Container* detectContainerOrIterator(const Token* typeStart, bool* isIterator = nullptr) const;
class ArgumentChecks {
public:

View File

@ -6324,6 +6324,7 @@ static const Token * parsedecl(const Token *type, ValueType * const valuetype, V
bool par = false;
while (Token::Match(type, "%name%|*|&|&&|::|(") && !Token::Match(type, "typename|template") && type->varId() == 0 &&
!type->variable() && !type->function()) {
bool isIterator = false;
if (type->str() == "(") {
if (Token::Match(type->link(), ") const| {"))
break;
@ -6364,8 +6365,12 @@ static const Token * parsedecl(const Token *type, ValueType * const valuetype, V
typeTokens.addtoken("::", 0, 0, 0, false);
pos1 = pos2 + 2;
} while (pos1 < type->str().size());
const Library::Container *container = settings->library.detectContainer(typeTokens.front());
const Library::Container* container =
settings->library.detectContainerOrIterator(typeTokens.front(), &isIterator);
if (container) {
if (isIterator)
valuetype->type = ValueType::Type::ITERATOR;
else
valuetype->type = ValueType::Type::CONTAINER;
valuetype->container = container;
} else {
@ -6374,7 +6379,10 @@ static const Token * parsedecl(const Token *type, ValueType * const valuetype, V
if (valuetype->typeScope)
valuetype->type = (scope->type == Scope::ScopeType::eClass) ? ValueType::Type::RECORD : ValueType::Type::NONSTD;
}
} else if (const Library::Container *container = settings->library.detectContainer(type)) {
} else if (const Library::Container* container = settings->library.detectContainerOrIterator(type, &isIterator)) {
if (isIterator)
valuetype->type = ValueType::Type::ITERATOR;
else
valuetype->type = ValueType::Type::CONTAINER;
valuetype->container = container;
while (Token::Match(type, "%type%|::|<") && type->str() != "const") {
@ -6696,7 +6704,7 @@ void SymbolDatabase::setValueTypeInTokenList(bool reportDebugWarnings, Token *to
const Token *typeStartToken = tok->astOperand1();
while (typeStartToken && typeStartToken->str() == "::")
typeStartToken = typeStartToken->astOperand1();
if (mSettings->library.detectContainer(typeStartToken) ||
if (mSettings->library.detectContainerOrIterator(typeStartToken) ||
mSettings->library.detectSmartPointer(typeStartToken)) {
ValueType vt;
if (parsedecl(typeStartToken, &vt, mDefaultSignedness, mSettings)) {
@ -6800,11 +6808,12 @@ void SymbolDatabase::setValueTypeInTokenList(bool reportDebugWarnings, Token *to
const Token *typeTok = tok->next();
if (Token::Match(typeTok, "( std| ::| nothrow )"))
typeTok = typeTok->link()->next();
if (const Library::Container *c = mSettings->library.detectContainer(typeTok)) {
bool isIterator = false;
if (const Library::Container* c = mSettings->library.detectContainerOrIterator(typeTok, &isIterator)) {
ValueType vt;
vt.pointer = 1;
vt.container = c;
vt.type = ValueType::Type::CONTAINER;
vt.type = isIterator ? ValueType::Type::ITERATOR : ValueType::Type::CONTAINER;
setValueType(tok, vt);
continue;
}

View File

@ -904,6 +904,22 @@ private:
" }\n"
"}\n");
ASSERT_EQUALS("", errout.str());
check("void f() {\n"
" std::vector<int> vec;\n"
" std::vector<int>::iterator it = vec.begin();\n"
" *it = 1;\n"
"}\n");
ASSERT_EQUALS("[test.cpp:4]: (error) Out of bounds access in expression 'it' because 'vec' is empty.\n",
errout.str());
check("void f() {\n"
" std::vector<int> vec;\n"
" auto it = vec.begin();\n"
" *it = 1;\n"
"}\n");
ASSERT_EQUALS("[test.cpp:4]: (error) Out of bounds access in expression 'it' because 'vec' is empty.\n",
errout.str());
}
void iterator1() {
@ -984,7 +1000,9 @@ private:
" std::list<int>::iterator it = l1.begin();\n"
" l2.insert(it, 0);\n"
"}");
ASSERT_EQUALS("[test.cpp:6]: (error) Same iterator is used with different containers 'l1' and 'l2'.\n", errout.str());
ASSERT_EQUALS("[test.cpp:6]: (error) Same iterator is used with different containers 'l1' and 'l2'.\n"
"[test.cpp:6]: (error) Iterator 'it' from different container 'l2' are used together.\n",
errout.str());
check("void foo() {\n" // #5803
" std::list<int> l1;\n"
@ -1416,10 +1434,8 @@ private:
}
void iterator18() {
check("void foo()\n"
check("void foo(std::list<int> l1, std::list<int> l2)\n"
"{\n"
" std::list<int> l1;\n"
" std::list<int> l2;\n"
" std::list<int>::iterator it1 = l1.begin();\n"
" std::list<int>::iterator it2 = l1.end();\n"
" while (++it1 != --it2)\n"
@ -1428,10 +1444,8 @@ private:
"}");
ASSERT_EQUALS("", errout.str());
check("void foo()\n"
check("void foo(std::list<int> l1, std::list<int> l2)\n"
"{\n"
" std::list<int> l1;\n"
" std::list<int> l2;\n"
" std::list<int>::iterator it1 = l1.begin();\n"
" std::list<int>::iterator it2 = l1.end();\n"
" while (it1++ != --it2)\n"
@ -1440,17 +1454,15 @@ private:
"}");
ASSERT_EQUALS("", errout.str());
check("void foo()\n"
check("void foo(std::list<int> l1, std::list<int> l2)\n"
"{\n"
" std::list<int> l1;\n"
" std::list<int> l2;\n"
" std::list<int>::iterator it1 = l1.begin();\n"
" std::list<int>::iterator it2 = l1.end();\n"
" if (--it2 > it1++)\n"
" {\n"
" }\n"
"}");
TODO_ASSERT_EQUALS("", "[test.cpp:7]: (error) Dangerous comparison using operator< on iterator.\n", errout.str());
TODO_ASSERT_EQUALS("", "[test.cpp:5]: (error) Dangerous comparison using operator< on iterator.\n", errout.str());
}
void iterator19() {