diff --git a/cfg/posix.cfg b/cfg/posix.cfg
index 29d83f563..e45eb0fab 100644
--- a/cfg/posix.cfg
+++ b/cfg/posix.cfg
@@ -322,6 +322,8 @@
+
+
@@ -350,6 +352,8 @@
+
+
diff --git a/cfg/std.cfg b/cfg/std.cfg
index 199e4f8c1..929e03ee5 100644
--- a/cfg/std.cfg
+++ b/cfg/std.cfg
@@ -5520,5 +5520,6 @@
+
diff --git a/cfg/test/std.c b/cfg/test/std.c
new file mode 100644
index 000000000..a54483274
--- /dev/null
+++ b/cfg/test/std.c
@@ -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
+
+void strcpy_ok(char *a, char *b) {
+ strcpy(a,b);
+}
+
+void strcpy_bad() {
+ char a[10];
+ // cppcheck-suppress bufferAccessOutOfBounds
+ strcpy(a, "hello world!");
+}
+
+
diff --git a/lib/checkother.cpp b/lib/checkother.cpp
index 7df3690de..3f86553da 100644
--- a/lib/checkother.cpp
+++ b/lib/checkother.cpp
@@ -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() + "()");
+ }
+ }
+}
+
+
diff --git a/lib/checkother.h b/lib/checkother.h
index 9665f4227..69b25e4ae 100644
--- a/lib/checkother.h
+++ b/lib/checkother.h
@@ -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);
diff --git a/lib/library.cpp b/lib/library.cpp
index d7308f30a..67b5e8311 100644
--- a/lib/library.cpp
+++ b/lib/library.cpp
@@ -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 >::const_iterator it = argumentChecks.find(ftok->str());
+ if (it == argumentChecks.end())
+ return (callargs != 0);
+ int args = 0;
+ for (std::map::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;
+}
diff --git a/lib/library.h b/lib/library.h
index 3948eff31..78aa64079 100644
--- a/lib/library.h
+++ b/lib/library.h
@@ -127,9 +127,7 @@ public:
std::set 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())
diff --git a/test/testlibrary.cpp b/test/testlibrary.cpp
index 550a0fcfe..3774c8b48 100644
--- a/test/testlibrary.cpp
+++ b/test/testlibrary.cpp
@@ -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[] = "\n"
+ "\n"
+ " \n"
+ " "
+ " \n"
+ "";
+ 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[] = "\n"
"\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:
" \n"
" \n"
" \n"
+ " \n"
" \n"
"";
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());
diff --git a/test/testother.cpp b/test/testother.cpp
index 8e55a4bed..d3622ce59 100644
--- a/test/testother.cpp
+++ b/test/testother.cpp
@@ -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"