Improved check: Sign checking in printf format string (#3511)
Removed some redundant code (already covered by token list simplifications and symboldatabase)
This commit is contained in:
parent
4f4be79f20
commit
2bd1f1d8dc
|
@ -519,23 +519,31 @@ void CheckIO::checkWrongPrintfScanfArguments()
|
|||
invalidPrintfArgTypeError_n(tok, numFormat);
|
||||
break;
|
||||
case 'c':
|
||||
case 'd':
|
||||
case 'i':
|
||||
case 'u':
|
||||
case 'x':
|
||||
case 'X':
|
||||
case 'o':
|
||||
if (varTypeTok && varTypeTok->str() == "const")
|
||||
varTypeTok = varTypeTok->next();
|
||||
if ((varTypeTok && isKnownType(variableInfo, varTypeTok) && !Token::Match(varTypeTok, "unsigned|signed| bool|short|long|int|char|size_t|unsigned|signed") && !variableInfo->isPointer() && !variableInfo->isArray()))
|
||||
if (varTypeTok && isKnownType(variableInfo, varTypeTok) && !Token::Match(varTypeTok, "bool|short|long|int|char|size_t") && !variableInfo->isPointer() && !variableInfo->isArray())
|
||||
invalidPrintfArgTypeError_int(tok, numFormat, *i);
|
||||
else if (argListTok->type() == Token::eString)
|
||||
invalidPrintfArgTypeError_int(tok, numFormat, *i);
|
||||
break;
|
||||
case 'd':
|
||||
case 'i':
|
||||
if (varTypeTok && isKnownType(variableInfo, varTypeTok) && !variableInfo->isPointer() && !variableInfo->isArray()) {
|
||||
if ((varTypeTok->isUnsigned() || !Token::Match(varTypeTok, "bool|short|long|int")) && varTypeTok->str() != "char")
|
||||
invalidPrintfArgTypeError_sint(tok, numFormat, *i);
|
||||
} else if (argListTok->type() == Token::eString)
|
||||
invalidPrintfArgTypeError_sint(tok, numFormat, *i);
|
||||
break;
|
||||
case 'u':
|
||||
if (varTypeTok && isKnownType(variableInfo, varTypeTok) && !variableInfo->isPointer() && !variableInfo->isArray()) {
|
||||
if ((!varTypeTok->isUnsigned() || !Token::Match(varTypeTok, "short|long|int|size_t")) && varTypeTok->str() != "bool")
|
||||
invalidPrintfArgTypeError_uint(tok, numFormat, *i);
|
||||
} else if (argListTok->type() == Token::eString)
|
||||
invalidPrintfArgTypeError_uint(tok, numFormat, *i);
|
||||
break;
|
||||
case 'p':
|
||||
if (varTypeTok && varTypeTok->str() == "const")
|
||||
varTypeTok = varTypeTok->next();
|
||||
if (varTypeTok && isKnownType(variableInfo, varTypeTok) && !Token::Match(varTypeTok, "unsigned|signed| short|long|int|size_t|unsigned|signed") && !variableInfo->isPointer() && !variableInfo->isArray())
|
||||
if (varTypeTok && isKnownType(variableInfo, varTypeTok) && !Token::Match(varTypeTok, "short|long|int|size_t") && !variableInfo->isPointer() && !variableInfo->isArray())
|
||||
invalidPrintfArgTypeError_p(tok, numFormat);
|
||||
else if (argListTok->type() == Token::eString)
|
||||
invalidPrintfArgTypeError_p(tok, numFormat);
|
||||
|
@ -545,8 +553,6 @@ void CheckIO::checkWrongPrintfScanfArguments()
|
|||
case 'f':
|
||||
case 'g':
|
||||
case 'G':
|
||||
if (varTypeTok && varTypeTok->str() == "const")
|
||||
varTypeTok = varTypeTok->next();
|
||||
if (varTypeTok && ((isKnownType(variableInfo, varTypeTok) && !Token::Match(varTypeTok, "float|double")) || variableInfo->isPointer() || variableInfo->isArray()))
|
||||
invalidPrintfArgTypeError_float(tok, numFormat, *i);
|
||||
else if (argListTok->type() == Token::eString)
|
||||
|
@ -628,6 +634,18 @@ void CheckIO::invalidPrintfArgTypeError_int(const Token* tok, unsigned int numFo
|
|||
errmsg << "%" << c << " in format string (no. " << numFormat << ") requires an integer given in the argument list";
|
||||
reportError(tok, Severity::warning, "invalidPrintfArgType_int", errmsg.str());
|
||||
}
|
||||
void CheckIO::invalidPrintfArgTypeError_uint(const Token* tok, unsigned int numFormat, char c)
|
||||
{
|
||||
std::ostringstream errmsg;
|
||||
errmsg << "%" << c << " in format string (no. " << numFormat << ") requires an unsigned integer given in the argument list";
|
||||
reportError(tok, Severity::warning, "invalidPrintfArgType_uint", errmsg.str());
|
||||
}
|
||||
void CheckIO::invalidPrintfArgTypeError_sint(const Token* tok, unsigned int numFormat, char c)
|
||||
{
|
||||
std::ostringstream errmsg;
|
||||
errmsg << "%" << c << " in format string (no. " << numFormat << ") requires a signed integer given in the argument list";
|
||||
reportError(tok, Severity::warning, "invalidPrintfArgType_sint", errmsg.str());
|
||||
}
|
||||
void CheckIO::invalidPrintfArgTypeError_float(const Token* tok, unsigned int numFormat, char c)
|
||||
{
|
||||
std::ostringstream errmsg;
|
||||
|
|
|
@ -87,6 +87,8 @@ private:
|
|||
void invalidPrintfArgTypeError_n(const Token* tok, unsigned int numFormat);
|
||||
void invalidPrintfArgTypeError_p(const Token* tok, unsigned int numFormat);
|
||||
void invalidPrintfArgTypeError_int(const Token* tok, unsigned int numFormat, char c);
|
||||
void invalidPrintfArgTypeError_uint(const Token* tok, unsigned int numFormat, char c);
|
||||
void invalidPrintfArgTypeError_sint(const Token* tok, unsigned int numFormat, char c);
|
||||
void invalidPrintfArgTypeError_float(const Token* tok, unsigned int numFormat, char c);
|
||||
void invalidScanfFormatWidthError(const Token* tok, const std::string &functionName, unsigned int numFormat, int width, const Variable *var);
|
||||
|
||||
|
@ -105,7 +107,9 @@ private:
|
|||
c.invalidPrintfArgTypeError_s(0, 1);
|
||||
c.invalidPrintfArgTypeError_n(0, 1);
|
||||
c.invalidPrintfArgTypeError_p(0, 1);
|
||||
c.invalidPrintfArgTypeError_int(0, 1, 'u');
|
||||
c.invalidPrintfArgTypeError_int(0, 1, 'X');
|
||||
c.invalidPrintfArgTypeError_uint(0, 1, 'u');
|
||||
c.invalidPrintfArgTypeError_sint(0, 1, 'i');
|
||||
c.invalidPrintfArgTypeError_float(0, 1, 'f');
|
||||
c.invalidScanfFormatWidthError(0, "scanf", 10, 5, NULL);
|
||||
}
|
||||
|
|
|
@ -531,18 +531,52 @@ private:
|
|||
"[test.cpp:7]: (warning) %n in format string (no. 1) requires a pointer to an non-const integer given in the argument list\n", errout.str());
|
||||
|
||||
check("class foo {};\n"
|
||||
"void foo(const int* cpi, foo f, bar b, bar* bp, double d) {\n"
|
||||
" printf(\"%i\", f);\n"
|
||||
"void foo(const int* cpi, foo f, bar b, bar* bp, double d, int i, unsigned int u) {\n"
|
||||
" printf(\"%X\", f);\n"
|
||||
" printf(\"%c\", \"s4\");\n"
|
||||
" printf(\"%o\", d);\n"
|
||||
" printf(\"%i\", cpi);\n"
|
||||
" printf(\"%u\", b);\n"
|
||||
" printf(\"%u\", bp);\n"
|
||||
" printf(\"%x\", cpi);\n"
|
||||
" printf(\"%o\", b);\n"
|
||||
" printf(\"%X\", bp);\n"
|
||||
" printf(\"%X\", u);\n"
|
||||
" printf(\"%X\", i);\n"
|
||||
"}");
|
||||
ASSERT_EQUALS("[test.cpp:3]: (warning) %i in format string (no. 1) requires an integer given in the argument list\n"
|
||||
ASSERT_EQUALS("[test.cpp:3]: (warning) %X in format string (no. 1) requires an integer given in the argument list\n"
|
||||
"[test.cpp:4]: (warning) %c in format string (no. 1) requires an integer given in the argument list\n"
|
||||
"[test.cpp:5]: (warning) %o in format string (no. 1) requires an integer given in the argument list\n", errout.str());
|
||||
|
||||
check("class foo {};\n"
|
||||
"void foo(const int* cpi, foo f, bar b, bar* bp, double d, unsigned int u, unsigned char uc) {\n"
|
||||
" printf(\"%i\", f);\n"
|
||||
" printf(\"%d\", \"s4\");\n"
|
||||
" printf(\"%d\", d);\n"
|
||||
" printf(\"%d\", u);\n"
|
||||
" printf(\"%d\", cpi);\n"
|
||||
" printf(\"%i\", b);\n"
|
||||
" printf(\"%i\", bp);\n"
|
||||
" printf(\"%i\", uc);\n" // char is smaller than int, so there shouldn't be a problem
|
||||
"}");
|
||||
ASSERT_EQUALS("[test.cpp:3]: (warning) %i in format string (no. 1) requires a signed integer given in the argument list\n"
|
||||
"[test.cpp:4]: (warning) %d in format string (no. 1) requires a signed integer given in the argument list\n"
|
||||
"[test.cpp:5]: (warning) %d in format string (no. 1) requires a signed integer given in the argument list\n"
|
||||
"[test.cpp:6]: (warning) %d in format string (no. 1) requires a signed integer given in the argument list\n", errout.str());
|
||||
|
||||
check("class foo {};\n"
|
||||
"void foo(const int* cpi, foo f, bar b, bar* bp, double d, int i, bool bo) {\n"
|
||||
" printf(\"%u\", f);\n"
|
||||
" printf(\"%u\", \"s4\");\n"
|
||||
" printf(\"%u\", d);\n"
|
||||
" printf(\"%u\", i);\n"
|
||||
" printf(\"%u\", cpi);\n"
|
||||
" printf(\"%u\", b);\n"
|
||||
" printf(\"%u\", bp);\n"
|
||||
" printf(\"%u\", bo);\n" // bool shouldn't have a negative sign
|
||||
"}");
|
||||
ASSERT_EQUALS("[test.cpp:3]: (warning) %u in format string (no. 1) requires an unsigned integer given in the argument list\n"
|
||||
"[test.cpp:4]: (warning) %u in format string (no. 1) requires an unsigned integer given in the argument list\n"
|
||||
"[test.cpp:5]: (warning) %u in format string (no. 1) requires an unsigned integer given in the argument list\n"
|
||||
"[test.cpp:6]: (warning) %u in format string (no. 1) requires an unsigned integer given in the argument list\n", errout.str());
|
||||
|
||||
check("class foo {};\n"
|
||||
"void foo(const int* cpi, foo f, bar b, bar* bp, char c) {\n"
|
||||
" printf(\"%p\", f);\n"
|
||||
|
|
Loading…
Reference in New Issue