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(InputIterator first, InputIterator last, T val) -->
|
||||||
<!-- InputIterator std::find_if(InputIterator first, InputIterator last, UnaryPredicate val) -->
|
<!-- InputIterator std::find_if(InputIterator first, InputIterator last, UnaryPredicate val) -->
|
||||||
<!-- InputIterator std::find_if_not(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::all_of(InputIterator first, InputIterator last, UnaryPredicate pred) -->
|
||||||
<!-- bool std::any_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) -->
|
<!-- 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">
|
<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/>
|
<use-retval/>
|
||||||
<noreturn>false</noreturn>
|
<noreturn>false</noreturn>
|
||||||
<arg nr="1">
|
<arg nr="1">
|
||||||
|
|
|
@ -298,6 +298,8 @@ static const std::string pattern2 = pattern1x1_1 + pattern1x1_2;
|
||||||
|
|
||||||
static const Variable *getContainer(const Token *argtok)
|
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
|
if (!Token::Match(argtok, "%var% . begin|end|rbegin|rend ( )")) // TODO: use Library yield
|
||||||
return nullptr;
|
return nullptr;
|
||||||
const Variable *var = argtok->variable();
|
const Variable *var = argtok->variable();
|
||||||
|
@ -341,6 +343,17 @@ void CheckStl::mismatchingContainers()
|
||||||
mismatchingContainersError(argTok);
|
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++) {
|
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;
|
_returnValue[name] = expr;
|
||||||
if (const char *type = functionnode->Attribute("type"))
|
if (const char *type = functionnode->Attribute("type"))
|
||||||
_returnValueType[name] = type;
|
_returnValueType[name] = type;
|
||||||
|
if (const char *container = functionnode->Attribute("container"))
|
||||||
|
_returnValueContainer[name] = std::atoi(container);
|
||||||
} else if (functionnodename == "arg") {
|
} else if (functionnodename == "arg") {
|
||||||
const char* argNrString = functionnode->Attribute("nr");
|
const char* argNrString = functionnode->Attribute("nr");
|
||||||
if (!argNrString)
|
if (!argNrString)
|
||||||
return Error(MISSING_ATTRIBUTE, "nr");
|
return Error(MISSING_ATTRIBUTE, "nr");
|
||||||
const bool bAnyArg = strcmp(argNrString, "any")==0;
|
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];
|
ArgumentChecks &ac = argumentChecks[name][nr];
|
||||||
ac.optional = functionnode->Attribute("default") != nullptr;
|
ac.optional = functionnode->Attribute("default") != nullptr;
|
||||||
for (const tinyxml2::XMLElement *argnode = functionnode->FirstChildElement(); argnode; argnode = argnode->NextSiblingElement()) {
|
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();
|
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
|
bool Library::isnoreturn(const Token *ftok) const
|
||||||
{
|
{
|
||||||
if (ftok->function() && ftok->function()->isAttributeNoreturn())
|
if (ftok->function() && ftok->function()->isAttributeNoreturn())
|
||||||
|
|
|
@ -168,6 +168,7 @@ public:
|
||||||
|
|
||||||
std::string returnValue(const Token *ftok) const;
|
std::string returnValue(const Token *ftok) const;
|
||||||
std::string returnValueType(const Token *ftok) const;
|
std::string returnValueType(const Token *ftok) const;
|
||||||
|
int returnValueContainer(const Token *ftok) const;
|
||||||
|
|
||||||
bool isnoreturn(const Token *ftok) const;
|
bool isnoreturn(const Token *ftok) const;
|
||||||
bool isnotnoreturn(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, bool> _noreturn; // is function noreturn?
|
||||||
std::map<std::string, std::string> _returnValue;
|
std::map<std::string, std::string> _returnValue;
|
||||||
std::map<std::string, std::string> _returnValueType;
|
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::set<std::string> _ignorefunction; // ignore functions/macros from a library (gtk, qt etc)
|
||||||
std::map<std::string, bool> _reporterrors;
|
std::map<std::string, bool> _reporterrors;
|
||||||
std::map<std::string, bool> _processAfterCode;
|
std::map<std::string, bool> _processAfterCode;
|
||||||
|
|
|
@ -4619,7 +4619,7 @@ void SymbolDatabase::setValueTypeInTokenList(Token *tokens, bool cpp, const Sett
|
||||||
// library function
|
// library function
|
||||||
else if (tok->previous()) {
|
else if (tok->previous()) {
|
||||||
const std::string typestr(settings->library.returnValueType(tok->previous()));
|
const std::string typestr(settings->library.returnValueType(tok->previous()));
|
||||||
if (typestr.empty())
|
if (typestr.empty() || typestr == "iterator")
|
||||||
continue;
|
continue;
|
||||||
TokenList tokenList(settings);
|
TokenList tokenList(settings);
|
||||||
std::istringstream istr(typestr+";");
|
std::istringstream istr(typestr+";");
|
||||||
|
|
|
@ -3165,10 +3165,11 @@ void nullPointer_wmemcmp(wchar_t *p)
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <list>
|
#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 mismatchingContainers
|
||||||
// cppcheck-suppress ignoredReturnValue
|
// cppcheck-suppress ignoredReturnValue
|
||||||
std::find(ints1.begin(), ints2.end(), 123);
|
std::find(ints1.begin(), ints2.end(), 123);
|
||||||
// TODO cppcheck-suppress mismatchingContainers
|
// cppcheck-suppress mismatchingContainers
|
||||||
if (std::find(ints1.begin(), ints1.end(), 123) == ints2.end()){}
|
if (std::find(ints1.begin(), ints1.end(), 123) == ints2.end()) {}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue