diff --git a/cfg/std.cfg b/cfg/std.cfg
index e3e73f13e..441e44378 100644
--- a/cfg/std.cfg
+++ b/cfg/std.cfg
@@ -1872,6 +1872,7 @@
+
diff --git a/lib/checkfunctions.cpp b/lib/checkfunctions.cpp
index 7b4d2befb..2ef3e258a 100644
--- a/lib/checkfunctions.cpp
+++ b/lib/checkfunctions.cpp
@@ -94,7 +94,7 @@ void CheckFunctions::checkProhibitedFunctions()
}
//---------------------------------------------------------------------------
-// Check and
+// Check , and
//---------------------------------------------------------------------------
void CheckFunctions::invalidFunctionUsage()
{
@@ -125,7 +125,7 @@ void CheckFunctions::invalidFunctionUsage()
else if (!mSettings->library.isIntArgValid(functionToken, argnr, 1))
invalidFunctionArgError(argtok, functionToken->str(), argnr, nullptr, mSettings->library.validarg(functionToken, argnr));
}
-
+// check
if (mSettings->library.isargstrz(functionToken, argnr)) {
if (Token::Match(argtok, "& %var% !![") && argtok->next() && argtok->next()->valueType()) {
const ValueType * valueType = argtok->next()->valueType();
@@ -135,6 +135,33 @@ void CheckFunctions::invalidFunctionUsage()
invalidFunctionArgStrError(argtok, functionToken->str(), argnr);
}
}
+ const ValueType* const valueType = argtok->valueType();
+ const Variable* const variable = argtok->variable();
+ // Is non-null terminated local variable of type char (e.g. char buf[] = {'x'};) ?
+ if (variable && variable->isLocal()
+ && valueType->type == ValueType::Type::CHAR) {
+ const Token* varTok = variable->declEndToken();
+ auto count = -1; // Find out explicitly set count, e.g.: char buf[3] = {...}. Variable 'count' is set to 3 then.
+ if (varTok && Token::simpleMatch(varTok->previous(), "]"))
+ {
+ const Token* countTok = varTok->previous()->tokAt(-1);
+ if (countTok && countTok->hasKnownIntValue())
+ count = countTok->getKnownIntValue();
+ }
+ if (Token::simpleMatch(varTok, "=") && Token::simpleMatch(varTok->next(), "{")) {
+ varTok = varTok->next();
+ auto actualCharCount = 0;
+ while (varTok && !Token::simpleMatch(varTok->next(), "}")) {
+ if (!Token::simpleMatch(varTok->next(), ","))
+ ++actualCharCount;
+ varTok = varTok->next();
+ }
+ if (varTok && varTok->hasKnownIntValue() && varTok->getKnownIntValue() != 0
+ && (count == -1 || (count > 0 && count <= actualCharCount))) {
+ invalidFunctionArgStrError(argtok, functionToken->str(), argnr);
+ }
+ }
+ }
}
}
}
diff --git a/test/cfg/std.cpp b/test/cfg/std.cpp
index 4803f90e7..927c865c3 100644
--- a/test/cfg/std.cpp
+++ b/test/cfg/std.cpp
@@ -36,6 +36,18 @@
#include
#include
+void invalidFunctionArgStr_fopen(const char * const fileName, const char * const mode)
+{
+ const char fileNameBuf[] = {'f','i','l','e'};
+ const char modeBuf[] = {'r'};
+ // cppcheck-suppress invalidFunctionArgStr
+ FILE *fp = fopen(fileName, modeBuf);
+ fclose(fp);
+ // cppcheck-suppress invalidFunctionArgStr
+ fp = fopen(fileNameBuf, mode);
+ fclose(fp);
+}
+
float invalidFunctionArg_remquo (float x, float y, int* quo )
{
// cppcheck-suppress invalidFunctionArg
diff --git a/test/testfunctions.cpp b/test/testfunctions.cpp
index 85115dba1..cd0125850 100644
--- a/test/testfunctions.cpp
+++ b/test/testfunctions.cpp
@@ -613,6 +613,42 @@ private:
" return 0;\n"
"}");
ASSERT_EQUALS("[test.cpp:5]: (error) Invalid strcat() argument nr 2. A nul-terminated string is required.\n", errout.str());
+
+ check("FILE* f(void) {\n"
+ " const char fileName[1] = { \'x\' };\n"
+ " return fopen(fileName, \"r\"); \n"
+ "}");
+ ASSERT_EQUALS("[test.cpp:3]: (error) Invalid fopen() argument nr 1. A nul-terminated string is required.\n", errout.str());
+
+ check("FILE* f(void) {\n"
+ " const char fileName[2] = { \'x\', \'y\' };\n"
+ " return fopen(fileName, \"r\"); \n"
+ "}");
+ ASSERT_EQUALS("[test.cpp:3]: (error) Invalid fopen() argument nr 1. A nul-terminated string is required.\n", errout.str());
+
+ check("FILE* f(void) {\n"
+ " const char fileName[3] = { \'x\', \'y\' ,\'\\0\' };\n"
+ " return fopen(fileName, \"r\"); \n"
+ "}");
+ ASSERT_EQUALS("", errout.str());
+
+ check("FILE* f(void) {\n"
+ " const char fileName[3] = { \'x\', \'y\' };\n" // implicit '\0' added at the end
+ " return fopen(fileName, \"r\"); \n"
+ "}");
+ ASSERT_EQUALS("", errout.str());
+
+ check("FILE* f(void) {\n"
+ " const char fileName[] = { \'\\0\' };\n"
+ " return fopen(fileName, \"r\"); \n"
+ "}");
+ ASSERT_EQUALS("", errout.str());
+
+ check("FILE* f(void) {\n"
+ " const char fileName[] = { };\n"
+ " return fopen(fileName, \"r\"); \n"
+ "}");
+ ASSERT_EQUALS("", errout.str());
}
void mathfunctionCall_sqrt() {