CheckStl: validation of iterators returned from functions

This commit is contained in:
Daniel Marjamäki 2016-11-01 14:08:42 +01:00
parent 892a81055d
commit 0e9810b7f6
6 changed files with 65 additions and 7 deletions

View File

@ -4038,12 +4038,44 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun
<!-- InputIterator std::find(InputIterator first, InputIterator last, T val) -->
<!-- InputIterator std::find_if(InputIterator first, InputIterator last, UnaryPredicate val) -->
<!-- InputIterator std::find_if_not(InputIterator first, InputIterator last, UnaryPredicate val) -->
<function name="std::find,std::find_if,std::find_if_not">
<use-retval/>
<noreturn>false</noreturn>
<returnValue type="iterator" container="1"/>
<arg nr="1">
<not-uninit/>
<iterator container="1" type="first"/>
</arg>
<arg nr="2">
<not-uninit/>
<iterator container="1" type="last"/>
</arg>
<arg nr="3">
<not-uninit/>
</arg>
</function>
<!-- bool std::all_of(InputIterator first, InputIterator last, UnaryPredicate pred) -->
<!-- bool std::any_of(InputIterator first, InputIterator last, UnaryPredicate pred) -->
<!-- bool std::none_of(InputIterator first, InputIterator last, UnaryPredicate pred) -->
<!-- InputIterator std::count(InputIterator first, InputIterator last, T val) -->
<!-- InputIterator std::count_if(InputIterator first, InputIterator last, UnaryPredicate val) -->
<function name="std::find,std::find_if,std::find_if_not,std::count,std::count_if,std::all_of,std::any_of,std::none_of">
<use-retval/>
<noreturn>false</noreturn>
<returnValue type="bool"/>
<arg nr="1">
<not-uninit/>
<iterator container="1" type="first"/>
</arg>
<arg nr="2">
<not-uninit/>
<iterator container="1" type="last"/>
</arg>
<arg nr="3">
<not-uninit/>
</arg>
</function>
<!-- difference_type std::count(InputIterator first, InputIterator last, T val) -->
<!-- difference_type std::count_if(InputIterator first, InputIterator last, UnaryPredicate val) -->
<function name="std::count,std::count_if">
<use-retval/>
<noreturn>false</noreturn>
<arg nr="1">

View File

@ -298,6 +298,8 @@ static const std::string pattern2 = pattern1x1_1 + pattern1x1_2;
static const Variable *getContainer(const Token *argtok)
{
while (argtok && argtok->astOperand1())
argtok = argtok->astOperand1();
if (!Token::Match(argtok, "%var% . begin|end|rbegin|rend ( )")) // TODO: use Library yield
return nullptr;
const Variable *var = argtok->variable();
@ -341,6 +343,17 @@ void CheckStl::mismatchingContainers()
mismatchingContainersError(argTok);
}
}
int ret = _settings->library.returnValueContainer(ftok);
if (ret != -1 && Token::Match(ftok->next()->astParent(), "==|!=")) {
const Token *parent = ftok->next()->astParent();
const Token *other = (parent->astOperand1() == ftok->next()) ? parent->astOperand2() : parent->astOperand1();
const Variable *c = getContainer(other);
if (c) {
std::map<const Variable *, unsigned int>::const_iterator it = containerNr.find(c);
if (it == containerNr.end() || it->second != ret)
mismatchingContainersError(other);
}
}
}
}
for (unsigned int varid = 0; varid < symbolDatabase->getVariableListSize(); varid++) {

View File

@ -550,12 +550,14 @@ Library::Error Library::loadFunction(const tinyxml2::XMLElement * const node, co
_returnValue[name] = expr;
if (const char *type = functionnode->Attribute("type"))
_returnValueType[name] = type;
if (const char *container = functionnode->Attribute("container"))
_returnValueContainer[name] = std::atoi(container);
} else if (functionnodename == "arg") {
const char* argNrString = functionnode->Attribute("nr");
if (!argNrString)
return Error(MISSING_ATTRIBUTE, "nr");
const bool bAnyArg = strcmp(argNrString, "any")==0;
const int nr = (bAnyArg) ? -1 : atoi(argNrString);
const int nr = bAnyArg ? -1 : std::atoi(argNrString);
ArgumentChecks &ac = argumentChecks[name][nr];
ac.optional = functionnode->Attribute("default") != nullptr;
for (const tinyxml2::XMLElement *argnode = functionnode->FirstChildElement(); argnode; argnode = argnode->NextSiblingElement()) {
@ -1000,6 +1002,14 @@ std::string Library::returnValueType(const Token *ftok) const
return it != _returnValueType.end() ? it->second : std::string();
}
int Library::returnValueContainer(const Token *ftok) const
{
if (isNotLibraryFunction(ftok))
return -1;
std::map<std::string, int>::const_iterator it = _returnValueContainer.find(getFunctionName(ftok));
return it != _returnValueContainer.end() ? it->second : -1;
}
bool Library::isnoreturn(const Token *ftok) const
{
if (ftok->function() && ftok->function()->isAttributeNoreturn())

View File

@ -168,6 +168,7 @@ public:
std::string returnValue(const Token *ftok) const;
std::string returnValueType(const Token *ftok) const;
int returnValueContainer(const Token *ftok) const;
bool isnoreturn(const Token *ftok) const;
bool isnotnoreturn(const Token *ftok) const;
@ -510,6 +511,7 @@ private:
std::map<std::string, bool> _noreturn; // is function noreturn?
std::map<std::string, std::string> _returnValue;
std::map<std::string, std::string> _returnValueType;
std::map<std::string, int> _returnValueContainer;
std::set<std::string> _ignorefunction; // ignore functions/macros from a library (gtk, qt etc)
std::map<std::string, bool> _reporterrors;
std::map<std::string, bool> _processAfterCode;

View File

@ -4619,7 +4619,7 @@ void SymbolDatabase::setValueTypeInTokenList(Token *tokens, bool cpp, const Sett
// library function
else if (tok->previous()) {
const std::string typestr(settings->library.returnValueType(tok->previous()));
if (typestr.empty())
if (typestr.empty() || typestr == "iterator")
continue;
TokenList tokenList(settings);
std::istringstream istr(typestr+";");

View File

@ -3165,10 +3165,11 @@ void nullPointer_wmemcmp(wchar_t *p)
#include <algorithm>
#include <list>
void stdfind(const std::list<int> &ints1, const std::list<int> &ints2) {
void stdfind(const std::list<int> &ints1, const std::list<int> &ints2)
{
// cppcheck-suppress mismatchingContainers
// cppcheck-suppress ignoredReturnValue
std::find(ints1.begin(), ints2.end(), 123);
// TODO cppcheck-suppress mismatchingContainers
// cppcheck-suppress mismatchingContainers
if (std::find(ints1.begin(), ints1.end(), 123) == ints2.end()) {}
}