CheckStl: validation of iterators returned from functions
This commit is contained in:
parent
892a81055d
commit
0e9810b7f6
36
cfg/std.cfg
36
cfg/std.cfg
|
@ -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">
|
||||
|
|
|
@ -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++) {
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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+";");
|
||||
|
|
|
@ -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()) {}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue