Improved invalidFunctionArgStr checking and detect more cases where a NON-null-terminated string is used to call functions, configured with <strz/>.
This commit is contained in:
parent
cd7362e0e7
commit
886b5d1039
|
@ -1872,6 +1872,7 @@
|
||||||
<arg nr="2" direction="in">
|
<arg nr="2" direction="in">
|
||||||
<not-null/>
|
<not-null/>
|
||||||
<not-uninit/>
|
<not-uninit/>
|
||||||
|
<strz/>
|
||||||
</arg>
|
</arg>
|
||||||
</function>
|
</function>
|
||||||
<!-- errno_t fopen_s(FILE *restrict *restrict streamptr,-->
|
<!-- errno_t fopen_s(FILE *restrict *restrict streamptr,-->
|
||||||
|
|
|
@ -94,7 +94,7 @@ void CheckFunctions::checkProhibitedFunctions()
|
||||||
}
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
// Check <valid> and <not-bool>
|
// Check <valid>, <strz> and <not-bool>
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
void CheckFunctions::invalidFunctionUsage()
|
void CheckFunctions::invalidFunctionUsage()
|
||||||
{
|
{
|
||||||
|
@ -125,7 +125,7 @@ void CheckFunctions::invalidFunctionUsage()
|
||||||
else if (!mSettings->library.isIntArgValid(functionToken, argnr, 1))
|
else if (!mSettings->library.isIntArgValid(functionToken, argnr, 1))
|
||||||
invalidFunctionArgError(argtok, functionToken->str(), argnr, nullptr, mSettings->library.validarg(functionToken, argnr));
|
invalidFunctionArgError(argtok, functionToken->str(), argnr, nullptr, mSettings->library.validarg(functionToken, argnr));
|
||||||
}
|
}
|
||||||
|
// check <strz>
|
||||||
if (mSettings->library.isargstrz(functionToken, argnr)) {
|
if (mSettings->library.isargstrz(functionToken, argnr)) {
|
||||||
if (Token::Match(argtok, "& %var% !![") && argtok->next() && argtok->next()->valueType()) {
|
if (Token::Match(argtok, "& %var% !![") && argtok->next() && argtok->next()->valueType()) {
|
||||||
const ValueType * valueType = argtok->next()->valueType();
|
const ValueType * valueType = argtok->next()->valueType();
|
||||||
|
@ -135,6 +135,33 @@ void CheckFunctions::invalidFunctionUsage()
|
||||||
invalidFunctionArgStrError(argtok, functionToken->str(), argnr);
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,6 +36,18 @@
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
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 )
|
float invalidFunctionArg_remquo (float x, float y, int* quo )
|
||||||
{
|
{
|
||||||
// cppcheck-suppress invalidFunctionArg
|
// cppcheck-suppress invalidFunctionArg
|
||||||
|
|
|
@ -613,6 +613,42 @@ private:
|
||||||
" return 0;\n"
|
" return 0;\n"
|
||||||
"}");
|
"}");
|
||||||
ASSERT_EQUALS("[test.cpp:5]: (error) Invalid strcat() argument nr 2. A nul-terminated string is required.\n", errout.str());
|
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() {
|
void mathfunctionCall_sqrt() {
|
||||||
|
|
Loading…
Reference in New Issue