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() {