diff --git a/cfg/posix.cfg b/cfg/posix.cfg
new file mode 100644
index 000000000..1302533a2
--- /dev/null
+++ b/cfg/posix.cfg
@@ -0,0 +1,5 @@
+
+
+ false 0-999999
+
+
diff --git a/cfg/std.cfg b/cfg/std.cfg
index 39fa8feb5..e3bb60e2a 100644
--- a/cfg/std.cfg
+++ b/cfg/std.cfg
@@ -25,10 +25,11 @@
false
false
- false
- false
- false
- false
+ false 0-
+ false 0-
+ false 0-
+ false 0-
+ false 0-
false
false
@@ -36,9 +37,18 @@
false
false
false
- false
- false
- false
+ false 0-
+ false 0-
+ false 0-
false
+
+ 0,2-36
+ 0,2-36
+ 0,2-36
+ 0,2-36
+ 0,2-36
+ 0,2-36
+ 0,2-36
+ 0,2-36
diff --git a/cli/cppcheckexecutor.cpp b/cli/cppcheckexecutor.cpp
index 0187d7026..ccfadfdf7 100644
--- a/cli/cppcheckexecutor.cpp
+++ b/cli/cppcheckexecutor.cpp
@@ -157,6 +157,9 @@ int CppCheckExecutor::check(int argc, const char* const argv[])
return EXIT_FAILURE;
}
+ if (settings.standards.posix)
+ settings.library.load(argv[0], "posix");
+
if (settings.reportProgress)
time1 = std::time(0);
diff --git a/gui/mainwindow.cpp b/gui/mainwindow.cpp
index 15e51c003..70b0d6374 100644
--- a/gui/mainwindow.cpp
+++ b/gui/mainwindow.cpp
@@ -516,9 +516,6 @@ Settings MainWindow::GetCppcheckSettings()
{
Settings result;
- const QString applicationFilePath = QCoreApplication::applicationFilePath();
- result.library.load(applicationFilePath.toLatin1(), "std");
-
// If project file loaded, read settings from it
if (mProject) {
ProjectFile *pfile = mProject->GetProjectFile();
@@ -567,6 +564,11 @@ Settings MainWindow::GetCppcheckSettings()
result.standards.c = mSettings->value(SETTINGS_STD_C99, true).toBool() ? Standards::C99 : (mSettings->value(SETTINGS_STD_C11, false).toBool() ? Standards::C11 : Standards::C89);
result.standards.posix = mSettings->value(SETTINGS_STD_POSIX, false).toBool();
+ const QString applicationFilePath = QCoreApplication::applicationFilePath();
+ result.library.load(applicationFilePath.toLatin1(), "std");
+ if (result.standards.posix)
+ result.library.load(applicationFilePath.toLatin1(), "posix");
+
if (result._jobs <= 1) {
result._jobs = 1;
}
diff --git a/lib/checkother.cpp b/lib/checkother.cpp
index 33f93e591..99fff7e31 100644
--- a/lib/checkother.cpp
+++ b/lib/checkother.cpp
@@ -579,40 +579,6 @@ void CheckOther::checkPipeParameterSizeError(const Token *tok, const std::string
"The variable '" + strVarName + "' is an array of size " + strDim + ", which does not match.");
}
-//-----------------------------------------------------------------------------
-// check usleep(), which is allowed to be called with in a range of [0,999999]
-//
-// Reference:
-// - http://man7.org/linux/man-pages/man3/usleep.3.html
-//-----------------------------------------------------------------------------
-void CheckOther::checkSleepTimeInterval()
-{
- if (!_settings->standards.posix)
- return;
-
- const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase();
- const std::size_t functions = symbolDatabase->functionScopes.size();
- for (std::size_t i = 0; i < functions; ++i) {
- const Scope * scope = symbolDatabase->functionScopes[i];
- for (const Token* tok = scope->classStart->next(); tok != scope->classEnd; tok = tok->next()) {
- if (Token::Match(tok, "usleep ( %num% )")) {
- const Token * const numTok = tok->tokAt(2);
- MathLib::bigint value = MathLib::toLongNumber(numTok->str());
- if (value > 999999) { // less than 1 million
- checkSleepTimeError(numTok, numTok->str());
- }
- }
- }
- }
-}
-
-void CheckOther::checkSleepTimeError(const Token *tok, const std::string &strDim)
-{
- reportError(tok, Severity::error,
- "tooBigSleepTime", "The argument of usleep must be less than 1000000.\n"
- "The argument of usleep must be less than 1000000, but " + strDim + " is provided.");
-}
-
//---------------------------------------------------------------------------
// Detect redundant assignments: x = 0; x = 4;
//---------------------------------------------------------------------------
@@ -1472,24 +1438,40 @@ void CheckOther::redundantConditionError(const Token *tok, const std::string &te
//---------------------------------------------------------------------------
void CheckOther::invalidFunctionUsage()
{
- // strtol and strtoul..
- for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) {
- if (!Token::Match(tok, "strtol|strtoul|strtoll|strtoull|wcstol|wcstoul|wcstoll|wcstoull ("))
- continue;
+ const SymbolDatabase* symbolDatabase = _tokenizer->getSymbolDatabase();
+ const std::size_t functions = symbolDatabase->functionScopes.size();
+ for (std::size_t i = 0; i < functions; ++i) {
+ const Scope * scope = symbolDatabase->functionScopes[i];
+ for (const Token* tok = scope->classStart->next(); tok != scope->classEnd; tok = tok->next()) {
+ if (!Token::Match(tok, "%var% ( !!)"))
+ continue;
+ const std::string functionName = tok->str();
+ int argnr = 1;
+ const Token *argtok = tok->tokAt(2);
+ while (argtok && argtok->str() != ")") {
+ if (Token::Match(argtok,"%num% [,)]")) {
+ if (MathLib::isInt(argtok->str()) &&
+ !_settings->library.isargvalid(functionName, argnr, MathLib::toLongNumber(argtok->str())))
+ invalidFunctionArgError(argtok,functionName,argnr,_settings->library.validarg(functionName,argnr));
+ } else {
+ const Token *top = argtok;
+ while (top->astParent() && top->astParent()->str() != "," && top->astParent() != tok->next())
+ top = top->astParent();
+ if (top->isComparisonOp() || Token::Match(top, "%oror%|&&")) {
+ if (_settings->library.isboolargbad(functionName, argnr))
+ invalidFunctionArgBoolError(top, functionName, argnr);
- const std::string& funcname = tok->str();
- tok = tok->tokAt(2);
- // Locate the third parameter of the function call..
- for (int i = 0; i < 2 && tok; i++)
- tok = tok->nextArgument();
-
- if (Token::Match(tok, "%num% )")) {
- const MathLib::bigint radix = MathLib::toLongNumber(tok->str());
- if (!(radix == 0 || (radix >= 2 && radix <= 36))) {
- dangerousUsageStrtolError(tok, funcname);
+ // Are the values 0 and 1 valid?
+ else if (!_settings->library.isargvalid(functionName, argnr, 0))
+ invalidFunctionArgError(top, functionName, argnr, _settings->library.validarg(functionName,argnr));
+ else if (!_settings->library.isargvalid(functionName, argnr, 1))
+ invalidFunctionArgError(top, functionName, argnr, _settings->library.validarg(functionName,argnr));
+ }
+ }
+ argnr++;
+ argtok = argtok->nextArgument();
}
- } else
- break;
+ }
}
// sprintf|snprintf overlapping data
@@ -1529,11 +1511,6 @@ void CheckOther::invalidFunctionUsage()
}
}
-void CheckOther::dangerousUsageStrtolError(const Token *tok, const std::string& funcname)
-{
- reportError(tok, Severity::error, "dangerousUsageStrtol", "Invalid radix in call to " + funcname + "(). It must be 0 or 2-36.");
-}
-
void CheckOther::sprintfOverlappingDataError(const Token *tok, const std::string &varname)
{
reportError(tok, Severity::error, "sprintfOverlappingData",
@@ -1545,6 +1522,26 @@ void CheckOther::sprintfOverlappingDataError(const Token *tok, const std::string
"to sprintf() or snprintf(), the results are undefined.\"");
}
+void CheckOther::invalidFunctionArgError(const Token *tok, const std::string &functionName, int argnr, const std::string &validstr)
+{
+ std::ostringstream errmsg;
+ errmsg << "Invalid " << functionName << "() argument nr " << argnr;
+ if (!tok)
+ ;
+ else if (tok->isNumber())
+ errmsg << ". The value is " << tok->str() << " but the valid values are '" << validstr << "'.";
+ else if (tok->isComparisonOp())
+ errmsg << ". The value is 0 or 1 (comparison result) but the valid values are '" << validstr << "'.";
+ reportError(tok, Severity::error, "invalidFunctionArg", errmsg.str());
+}
+
+void CheckOther::invalidFunctionArgBoolError(const Token *tok, const std::string &functionName, int argnr)
+{
+ std::ostringstream errmsg;
+ errmsg << "Invalid " << functionName << "() argument nr " << argnr << ". A non-boolean value is required.";
+ reportError(tok, Severity::error, "invalidFunctionArgBool", errmsg.str());
+}
+
//---------------------------------------------------------------------------
// Find consecutive return, break, continue, goto or throw statements. e.g.:
// break; break;
diff --git a/lib/checkother.h b/lib/checkother.h
index c4cab33c2..a8a95b945 100644
--- a/lib/checkother.h
+++ b/lib/checkother.h
@@ -109,7 +109,6 @@ public:
checkOther.checkRedundantCopy();
checkOther.checkNegativeBitwiseShift();
checkOther.checkSuspiciousEqualityComparison();
- checkOther.checkSleepTimeInterval();
checkOther.checkComparisonFunctionIsAlwaysTrueOrFalse();
}
@@ -132,11 +131,12 @@ public:
void invalidPointerCast();
/**
- * @brief Invalid function usage (invalid radix / overlapping data)
+ * @brief Invalid function usage (invalid input value / overlapping data)
*
* %Check that given function parameters are valid according to the standard
* - wrong radix given for strtol/strtoul
* - overlapping data when using sprintf/snprintf
+ * - wrong input value according to library
*/
void invalidFunctionUsage();
@@ -263,9 +263,6 @@ public:
/** @brief %Check to avoid casting a return value to unsigned char and then back to integer type. */
void checkCastIntToCharAndBack();
- /** @brief %Check providing too big sleep time intervals on POSIX systems. */
- void checkSleepTimeInterval();
-
/** @brief %Check for using of comparison functions evaluating always to true or false. */
void checkComparisonFunctionIsAlwaysTrueOrFalse(void);
@@ -275,7 +272,6 @@ private:
// Error messages..
void checkComparisonFunctionIsAlwaysTrueOrFalseError(const Token* tok, const std::string &strFunctionName, const std::string &varName, const bool result);
- void checkSleepTimeError(const Token *tok, const std::string &strDim);
void checkCastIntToCharAndBackError(const Token *tok, const std::string &strFunctionName);
void checkPipeParameterSizeError(const Token *tok, const std::string &strVarName, const std::string &strDim);
void oppositeInnerConditionError(const Token *tok);
@@ -285,8 +281,9 @@ private:
void redundantGetAndSetUserIdError(const Token *tok);
void cstyleCastError(const Token *tok);
void invalidPointerCastError(const Token* tok, const std::string& from, const std::string& to, bool inconclusive);
- void dangerousUsageStrtolError(const Token *tok, const std::string& funcname);
void sprintfOverlappingDataError(const Token *tok, const std::string &varname);
+ void invalidFunctionArgError(const Token *tok, const std::string &functionName, int argnr, const std::string &validstr);
+ void invalidFunctionArgBoolError(const Token *tok, const std::string &functionName, int argnr);
void udivError(const Token *tok, bool inconclusive);
void passedByValueError(const Token *tok, const std::string &parname);
void constStatementError(const Token *tok, const std::string &type);
@@ -340,6 +337,8 @@ private:
// error
c.sprintfOverlappingDataError(0, "varname");
+ c.invalidFunctionArgError(0, "func_name", 1, "1-4");
+ c.invalidFunctionArgBoolError(0, "func_name", 1);
c.udivError(0, false);
c.zerodivError(0);
c.zerodivcondError(0,0);
@@ -349,7 +348,6 @@ private:
c.invalidPointerCastError(0, "float", "double", false);
c.negativeBitwiseShiftError(0);
c.checkPipeParameterSizeError(0, "varname", "dimension");
- c.checkSleepTimeError(0,"dimension");
//performance
c.redundantCopyError(0, "varname");
@@ -361,7 +359,6 @@ private:
c.checkCastIntToCharAndBackError(0,"func_name");
c.oppositeInnerConditionError(0);
c.cstyleCastError(0);
- c.dangerousUsageStrtolError(0, "strtol");
c.passedByValueError(0, "parametername");
c.constStatementError(0, "type");
c.charArrayIndexError(0);
@@ -421,7 +418,7 @@ private:
"* bitwise operation with negative right operand\n"
"* provide wrong dimensioned array to pipe() system command (--std=posix)\n"
"* cast the return values of getc(),fgetc() and getchar() to character and compare it to EOF\n"
- "* provide too big sleep times on POSIX systems\n"
+ "* invalid input values for functions\n"
// warning
"* either division by zero or useless condition\n"
@@ -435,7 +432,6 @@ private:
"* C-style pointer cast in cpp file\n"
"* casting between incompatible pointer types\n"
"* redundant if\n"
- "* bad usage of the function 'strtol'\n"
"* [[CheckUnsignedDivision|unsigned division]]\n"
"* passing parameter by value\n"
"* [[IncompleteStatement|Incomplete statement]]\n"
diff --git a/lib/library.cpp b/lib/library.cpp
index 78a3835cc..c810f4069 100644
--- a/lib/library.cpp
+++ b/lib/library.cpp
@@ -19,6 +19,9 @@
#include "library.h"
#include "path.h"
#include "tinyxml2.h"
+#include "tokenlist.h"
+#include "mathlib.h"
+#include "token.h"
#include
#include
@@ -108,13 +111,16 @@ bool Library::load(const tinyxml2::XMLDocument &doc)
leakignore.insert(name);
else if (strcmp(functionnode->Name(), "arg") == 0 && functionnode->Attribute("nr") != NULL) {
const int nr = atoi(functionnode->Attribute("nr"));
+ bool notbool = false;
bool notnull = false;
bool notuninit = false;
bool formatstr = false;
bool strz = false;
std::string valid;
for (const tinyxml2::XMLElement *argnode = functionnode->FirstChildElement(); argnode; argnode = argnode->NextSiblingElement()) {
- if (strcmp(argnode->Name(), "not-null") == 0)
+ if (strcmp(argnode->Name(), "not-bool") == 0)
+ notbool = true;
+ else if (strcmp(argnode->Name(), "not-null") == 0)
notnull = true;
else if (strcmp(argnode->Name(), "not-uninit") == 0)
notuninit = true;
@@ -144,6 +150,7 @@ bool Library::load(const tinyxml2::XMLDocument &doc)
else
return false;
}
+ argumentChecks[name][nr].notbool = notbool;
argumentChecks[name][nr].notnull = notnull;
argumentChecks[name][nr].notuninit = notuninit;
argumentChecks[name][nr].formatstr = formatstr;
@@ -249,3 +256,24 @@ bool Library::load(const tinyxml2::XMLDocument &doc)
}
return true;
}
+
+bool Library::isargvalid(const std::string &functionName, int argnr, const MathLib::bigint argvalue) const
+{
+ const ArgumentChecks *ac = getarg(functionName, argnr);
+ if (!ac || ac->valid.empty())
+ return true;
+ TokenList tokenList(0);
+ std::istringstream istr(ac->valid + ',');
+ tokenList.createTokens(istr,"");
+ for (const Token *tok = tokenList.front(); tok; tok = tok->next()) {
+ if (tok->isNumber() && argvalue == MathLib::toLongNumber(tok->str()))
+ return true;
+ if (Token::Match(tok, "%num% - %num%") && argvalue >= MathLib::toLongNumber(tok->str()) && argvalue <= MathLib::toLongNumber(tok->strAt(2)))
+ return true;
+ if (Token::Match(tok, "%num% - ,") && argvalue >= MathLib::toLongNumber(tok->str()))
+ return true;
+ if ((!tok->previous() || tok->previous()->str() == ",") && Token::Match(tok,"- %num%") && argvalue <= MathLib::toLongNumber(tok->strAt(1)))
+ return true;
+ }
+ return false;
+}
diff --git a/lib/library.h b/lib/library.h
index b325c6335..36ce11978 100644
--- a/lib/library.h
+++ b/lib/library.h
@@ -23,6 +23,7 @@
#include "config.h"
#include "path.h"
+#include "mathlib.h"
#include
#include