Fixed #4948 (check printf %l and %ll arguments for long and long long)

This commit is contained in:
Robert Reif 2013-08-10 12:33:55 +02:00 committed by Daniel Marjamäki
parent 64733d9e63
commit 5aa79198e6
2 changed files with 41 additions and 15 deletions

View File

@ -591,36 +591,38 @@ void CheckIO::checkWrongPrintfScanfArguments()
case 'x': case 'x':
case 'X': case 'X':
case 'o': case 'o':
if (varTypeTok && isKnownType(variableInfo, varTypeTok) && !Token::Match(varTypeTok, "bool|short|long|int|char|size_t") && !variableInfo->isPointer() && !variableInfo->isArray()) { specifier += *i;
specifier += *i; if (varTypeTok && isKnownType(variableInfo, varTypeTok) && !variableInfo->isPointer() && !variableInfo->isArray()) {
invalidPrintfArgTypeError_int(tok, numFormat, specifier); if (!Token::Match(varTypeTok, "bool|short|long|int|char|size_t") ||
(specifier[0] == 'l' && (varTypeTok->str() != "long" || (specifier[1] == 'l' && !varTypeTok->isLong())))) {
invalidPrintfArgTypeError_int(tok, numFormat, specifier);
}
} else if (argListTok->type() == Token::eString) { } else if (argListTok->type() == Token::eString) {
specifier += *i;
invalidPrintfArgTypeError_int(tok, numFormat, specifier); invalidPrintfArgTypeError_int(tok, numFormat, specifier);
} }
done = true; done = true;
break; break;
case 'd': case 'd':
case 'i': case 'i':
specifier += *i;
if (varTypeTok && isKnownType(variableInfo, varTypeTok) && !variableInfo->isPointer() && !variableInfo->isArray()) { if (varTypeTok && isKnownType(variableInfo, varTypeTok) && !variableInfo->isPointer() && !variableInfo->isArray()) {
if ((varTypeTok->isUnsigned() || !Token::Match(varTypeTok, "bool|short|long|int")) && varTypeTok->str() != "char") { if (((varTypeTok->isUnsigned() || !Token::Match(varTypeTok, "bool|short|long|int")) && varTypeTok->str() != "char") ||
specifier += *i; (specifier[0] == 'l' && (varTypeTok->str() != "long" || (specifier[1] == 'l' && !varTypeTok->isLong())))) {
invalidPrintfArgTypeError_sint(tok, numFormat, specifier); invalidPrintfArgTypeError_sint(tok, numFormat, specifier);
} }
} else if (argListTok->type() == Token::eString) { } else if (argListTok->type() == Token::eString) {
specifier += *i;
invalidPrintfArgTypeError_sint(tok, numFormat, specifier); invalidPrintfArgTypeError_sint(tok, numFormat, specifier);
} }
done = true; done = true;
break; break;
case 'u': case 'u':
specifier += *i;
if (varTypeTok && isKnownType(variableInfo, varTypeTok) && !variableInfo->isPointer() && !variableInfo->isArray()) { if (varTypeTok && isKnownType(variableInfo, varTypeTok) && !variableInfo->isPointer() && !variableInfo->isArray()) {
if ((!varTypeTok->isUnsigned() || !Token::Match(varTypeTok, "char|short|long|int|size_t")) && varTypeTok->str() != "bool") { if (((!varTypeTok->isUnsigned() || !Token::Match(varTypeTok, "char|short|long|int|size_t")) && varTypeTok->str() != "bool") ||
specifier += *i; (specifier[0] == 'l' && (varTypeTok->str() != "long" || (specifier[1] == 'l' && !varTypeTok->isLong())))) {
invalidPrintfArgTypeError_uint(tok, numFormat, specifier); invalidPrintfArgTypeError_uint(tok, numFormat, specifier);
} }
} else if (argListTok->type() == Token::eString) { } else if (argListTok->type() == Token::eString) {
specifier += *i;
invalidPrintfArgTypeError_uint(tok, numFormat, specifier); invalidPrintfArgTypeError_uint(tok, numFormat, specifier);
} }
done = true; done = true;
@ -803,19 +805,29 @@ void CheckIO::invalidPrintfArgTypeError_p(const Token* tok, unsigned int numForm
void CheckIO::invalidPrintfArgTypeError_int(const Token* tok, unsigned int numFormat, const std::string& specifier) void CheckIO::invalidPrintfArgTypeError_int(const Token* tok, unsigned int numFormat, const std::string& specifier)
{ {
std::ostringstream errmsg; std::ostringstream errmsg;
errmsg << "%" << specifier << " in format string (no. " << numFormat << ") requires an integer given in the argument list."; errmsg << "%" << specifier << " in format string (no. " << numFormat << ") requires a"
<< (specifier[0] != 'l' ? "n" : "")
<< (specifier[0] == 'l' ? " long" : "")
<< (specifier[0] == 'l' && specifier[1] == 'l' ? " long" : "")
<< " integer given in the argument list.";
reportError(tok, Severity::warning, "invalidPrintfArgType_int", errmsg.str()); reportError(tok, Severity::warning, "invalidPrintfArgType_int", errmsg.str());
} }
void CheckIO::invalidPrintfArgTypeError_uint(const Token* tok, unsigned int numFormat, const std::string& specifier) void CheckIO::invalidPrintfArgTypeError_uint(const Token* tok, unsigned int numFormat, const std::string& specifier)
{ {
std::ostringstream errmsg; std::ostringstream errmsg;
errmsg << "%" << specifier << " in format string (no. " << numFormat << ") requires an unsigned integer given in the argument list."; errmsg << "%" << specifier << " in format string (no. " << numFormat << ") requires an unsigned "
<< (specifier[0] == 'l' ? "long " : "")
<< (specifier[0] == 'l' && specifier[1] == 'l' ? "long " : "")
<< "integer given in the argument list.";
reportError(tok, Severity::warning, "invalidPrintfArgType_uint", errmsg.str()); reportError(tok, Severity::warning, "invalidPrintfArgType_uint", errmsg.str());
} }
void CheckIO::invalidPrintfArgTypeError_sint(const Token* tok, unsigned int numFormat, const std::string& specifier) void CheckIO::invalidPrintfArgTypeError_sint(const Token* tok, unsigned int numFormat, const std::string& specifier)
{ {
std::ostringstream errmsg; std::ostringstream errmsg;
errmsg << "%" << specifier << " in format string (no. " << numFormat << ") requires a signed integer given in the argument list."; errmsg << "%" << specifier << " in format string (no. " << numFormat << ") requires a signed "
<< (specifier[0] == 'l' ? "long " : "")
<< (specifier[0] == 'l' && specifier[1] == 'l' ? "long " : "")
<< "integer given in the argument list.";
reportError(tok, Severity::warning, "invalidPrintfArgType_sint", errmsg.str()); reportError(tok, Severity::warning, "invalidPrintfArgType_sint", errmsg.str());
} }
void CheckIO::invalidPrintfArgTypeError_float(const Token* tok, unsigned int numFormat, const std::string& specifier) void CheckIO::invalidPrintfArgTypeError_float(const Token* tok, unsigned int numFormat, const std::string& specifier)

View File

@ -769,8 +769,8 @@ private:
"}"); "}");
ASSERT_EQUALS("[test.cpp:2]: (warning) %hd in format string (no. 1) requires a signed integer given in the argument list.\n" ASSERT_EQUALS("[test.cpp:2]: (warning) %hd in format string (no. 1) requires a signed integer given in the argument list.\n"
"[test.cpp:3]: (warning) %hhd in format string (no. 1) requires a signed integer given in the argument list.\n" "[test.cpp:3]: (warning) %hhd in format string (no. 1) requires a signed integer given in the argument list.\n"
"[test.cpp:4]: (warning) %ld in format string (no. 1) requires a signed integer given in the argument list.\n" "[test.cpp:4]: (warning) %ld in format string (no. 1) requires a signed long integer given in the argument list.\n"
"[test.cpp:5]: (warning) %lld in format string (no. 1) requires a signed integer given in the argument list.\n" , errout.str()); "[test.cpp:5]: (warning) %lld in format string (no. 1) requires a signed long long integer given in the argument list.\n" , errout.str());
check("void foo(size_t s, ptrdiff_t p) {\n" check("void foo(size_t s, ptrdiff_t p) {\n"
" printf(\"%zd\", s);\n" " printf(\"%zd\", s);\n"
@ -779,6 +779,20 @@ private:
ASSERT_EQUALS("[test.cpp:2]: (warning) %zd in format string (no. 1) requires a signed integer given in the argument list.\n" ASSERT_EQUALS("[test.cpp:2]: (warning) %zd in format string (no. 1) requires a signed integer given in the argument list.\n"
"[test.cpp:3]: (warning) %tu in format string (no. 1) requires an unsigned integer given in the argument list.\n", errout.str()); "[test.cpp:3]: (warning) %tu in format string (no. 1) requires an unsigned integer given in the argument list.\n", errout.str());
check("void foo(unsigned int i) {\n"
" printf(\"%ld\", i);\n"
" printf(\"%lld\", i);\n"
" printf(\"%lu\", i);\n"
" printf(\"%llu\", i);\n"
" printf(\"%lx\", i);\n"
" printf(\"%llx\", i);\n"
"}");
ASSERT_EQUALS("[test.cpp:2]: (warning) %ld in format string (no. 1) requires a signed long integer given in the argument list.\n"
"[test.cpp:3]: (warning) %lld in format string (no. 1) requires a signed long long integer given in the argument list.\n"
"[test.cpp:4]: (warning) %lu in format string (no. 1) requires an unsigned long integer given in the argument list.\n"
"[test.cpp:5]: (warning) %llu in format string (no. 1) requires an unsigned long long integer given in the argument list.\n"
"[test.cpp:6]: (warning) %lx in format string (no. 1) requires a long integer given in the argument list.\n"
"[test.cpp:7]: (warning) %llx in format string (no. 1) requires a long long integer given in the argument list.\n", errout.str());
} }
void testPosixPrintfScanfParameterPosition() { // #4900 - No support for parameters in format strings void testPosixPrintfScanfParameterPosition() { // #4900 - No support for parameters in format strings