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:
parent
bb640c4879
commit
09c8cfb2ae
|
@ -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)
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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() {
|
||||
|
|
Loading…
Reference in New Issue