Fixed #6460 (Library: better function/type matching)
This commit is contained in:
parent
bfa16ec258
commit
3285f85ebf
|
@ -322,6 +322,8 @@
|
|||
<arg nr="4">
|
||||
<not-uninit/>
|
||||
</arg>
|
||||
<arg nr="5"/>
|
||||
<arg nr="6"/>
|
||||
</function>
|
||||
<function name="send">
|
||||
<arg nr="1">
|
||||
|
@ -350,6 +352,8 @@
|
|||
<arg nr="4">
|
||||
<not-uninit/>
|
||||
</arg>
|
||||
<arg nr="5"/>
|
||||
<arg nr="6"/>
|
||||
</function>
|
||||
<!-- void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset); -->
|
||||
<function name="mmap">
|
||||
|
|
|
@ -5520,5 +5520,6 @@
|
|||
<arg nr="2">
|
||||
<not-null/>
|
||||
</arg>
|
||||
<arg nr="3"/>
|
||||
</function>
|
||||
</def>
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
|
||||
// Test library configuration for std.cfg
|
||||
//
|
||||
// Usage:
|
||||
// $ cppcheck --check-library --enable=information --error-exitcode=1 --inline-suppr cfg/test/std.c
|
||||
// =>
|
||||
// No warnings about bad library configuration, unmatched suppressions, etc. exitcode=0
|
||||
//
|
||||
|
||||
#include <string.h>
|
||||
|
||||
void strcpy_ok(char *a, char *b) {
|
||||
strcpy(a,b);
|
||||
}
|
||||
|
||||
void strcpy_bad() {
|
||||
char a[10];
|
||||
// cppcheck-suppress bufferAccessOutOfBounds
|
||||
strcpy(a, "hello world!");
|
||||
}
|
||||
|
||||
|
|
@ -2890,3 +2890,23 @@ void CheckOther::redundantPointerOpError(const Token* tok, const std::string &va
|
|||
reportError(tok, Severity::style, "redundantPointerOp",
|
||||
"Redundant pointer operation on " + varname + " - it's already a pointer.", inconclusive);
|
||||
}
|
||||
|
||||
void CheckOther::checkLibraryMatchFunctions()
|
||||
{
|
||||
if (!_settings->checkLibrary || !_settings->isEnabled("information"))
|
||||
return;
|
||||
|
||||
for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) {
|
||||
if (Token::Match(tok, "%var% (") &&
|
||||
!tok->function() &&
|
||||
tok->astParent() == tok->next() &&
|
||||
_settings->library.isNotLibraryFunction(tok)) {
|
||||
reportError(tok,
|
||||
Severity::information,
|
||||
"checkLibraryFunction",
|
||||
"--check-library: There is no matching configuration for function " + tok->str() + "()");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -75,6 +75,9 @@ public:
|
|||
checkOther.checkCommaSeparatedReturn();
|
||||
checkOther.checkIgnoredReturnValue();
|
||||
checkOther.checkRedundantPointerOp();
|
||||
|
||||
// --check-library : functions with nonmatching configuration
|
||||
checkOther.checkLibraryMatchFunctions();
|
||||
}
|
||||
|
||||
/** @brief Run checks against the simplified token list */
|
||||
|
@ -237,6 +240,9 @@ public:
|
|||
/** @brief %Check for redundant pointer operations */
|
||||
void checkRedundantPointerOp();
|
||||
|
||||
/** @brief --check-library: warn for unconfigured function calls */
|
||||
void checkLibraryMatchFunctions();
|
||||
|
||||
private:
|
||||
// Error messages..
|
||||
void checkComparisonFunctionIsAlwaysTrueOrFalseError(const Token* tok, const std::string &strFunctionName, const std::string &varName, const bool result);
|
||||
|
|
|
@ -678,3 +678,32 @@ const Library::Container* Library::detectContainer(const Token* typeStart) const
|
|||
}
|
||||
return nullptr;
|
||||
}
|
||||
// returns true if ftok is not a library function
|
||||
bool Library::isNotLibraryFunction(const Token *ftok) const
|
||||
{
|
||||
if (!ftok->astParent())
|
||||
return false;
|
||||
if (ftok->astParent()->str() != "(")
|
||||
return true;
|
||||
|
||||
int callargs = 0;
|
||||
for (const Token *tok = ftok->tokAt(2); tok && tok->str() != ")"; tok = tok->next()) {
|
||||
if (callargs == 0)
|
||||
callargs = 1;
|
||||
if (tok->str() == ",")
|
||||
callargs++;
|
||||
else if (tok->link() && Token::Match(tok, "<|(|["))
|
||||
tok = tok->link();
|
||||
}
|
||||
const std::map<std::string, std::map<int, ArgumentChecks> >::const_iterator it = argumentChecks.find(ftok->str());
|
||||
if (it == argumentChecks.end())
|
||||
return (callargs != 0);
|
||||
int args = 0;
|
||||
for (std::map<int, ArgumentChecks>::const_iterator it2 = it->second.begin(); it2 != it->second.end(); ++it2) {
|
||||
if (it2->first > args)
|
||||
args = it2->first;
|
||||
if (it2->second.formatstr)
|
||||
return args > callargs;
|
||||
}
|
||||
return args != callargs;
|
||||
}
|
||||
|
|
|
@ -127,9 +127,7 @@ public:
|
|||
std::set<std::string> useretval;
|
||||
|
||||
// returns true if ftok is not a library function
|
||||
static bool isNotLibraryFunction(const Token *ftok) {
|
||||
return ftok->astParent() ? ftok->astParent()->str() != "(" : false;
|
||||
}
|
||||
bool isNotLibraryFunction(const Token *ftok) const;
|
||||
|
||||
bool isnoreturn(const Token *ftok) const {
|
||||
if (ftok->function() && ftok->function()->isAttributeNoreturn())
|
||||
|
|
|
@ -31,6 +31,7 @@ private:
|
|||
void run() {
|
||||
TEST_CASE(empty);
|
||||
TEST_CASE(function);
|
||||
TEST_CASE(function_match);
|
||||
TEST_CASE(function_arg);
|
||||
TEST_CASE(function_arg_any);
|
||||
TEST_CASE(function_arg_valid);
|
||||
|
@ -78,6 +79,26 @@ private:
|
|||
ASSERT(library.isnotnoreturn(tokenList.front()));
|
||||
}
|
||||
|
||||
void function_match() const {
|
||||
const char xmldata[] = "<?xml version=\"1.0\"?>\n"
|
||||
"<def>\n"
|
||||
" <function name=\"foo\">\n"
|
||||
" <arg nr=\"1\"/>"
|
||||
" </function>\n"
|
||||
"</def>";
|
||||
tinyxml2::XMLDocument doc;
|
||||
doc.Parse(xmldata, sizeof(xmldata));
|
||||
|
||||
TokenList tokenList(nullptr);
|
||||
std::istringstream istr("foo();"); // <- too few arguments, not library function
|
||||
tokenList.createTokens(istr);
|
||||
tokenList.front()->next()->astOperand1(tokenList.front());
|
||||
|
||||
Library library;
|
||||
library.load(doc);
|
||||
ASSERT(library.isNotLibraryFunction(tokenList.front()));
|
||||
}
|
||||
|
||||
void function_arg() const {
|
||||
const char xmldata[] = "<?xml version=\"1.0\"?>\n"
|
||||
"<def>\n"
|
||||
|
@ -134,7 +155,7 @@ private:
|
|||
library.load(doc);
|
||||
|
||||
TokenList tokenList(nullptr);
|
||||
std::istringstream istr("foo();");
|
||||
std::istringstream istr("foo(a,b,c,d,e);");
|
||||
tokenList.createTokens(istr);
|
||||
tokenList.front()->next()->astOperand1(tokenList.front());
|
||||
|
||||
|
@ -177,6 +198,7 @@ private:
|
|||
" <function name=\"foo\">\n"
|
||||
" <arg nr=\"1\"><minsize type=\"strlen\" arg=\"2\"/></arg>\n"
|
||||
" <arg nr=\"2\"><minsize type=\"argvalue\" arg=\"3\"/></arg>\n"
|
||||
" <arg nr=\"3\"/>\n"
|
||||
" </function>\n"
|
||||
"</def>";
|
||||
tinyxml2::XMLDocument doc;
|
||||
|
@ -186,7 +208,7 @@ private:
|
|||
library.load(doc);
|
||||
|
||||
TokenList tokenList(nullptr);
|
||||
std::istringstream istr("foo();");
|
||||
std::istringstream istr("foo(a,b,c);");
|
||||
tokenList.createTokens(istr);
|
||||
tokenList.front()->next()->astOperand1(tokenList.front());
|
||||
|
||||
|
|
|
@ -2865,6 +2865,7 @@ private:
|
|||
|
||||
Settings settings;
|
||||
settings.library.setnoreturn("exit", true);
|
||||
settings.library.argumentChecks["exit"][1] = Library::ArgumentChecks();
|
||||
check("void foo() {\n"
|
||||
" exit(0);\n"
|
||||
" break;\n"
|
||||
|
|
Loading…
Reference in New Issue