Fixed #4189 (Improve check (printf('%l') not detected))

This commit is contained in:
Baris Demiray 2012-10-21 08:50:29 +02:00 committed by Daniel Marjamäki
parent f0f216390e
commit 0e100f7563
3 changed files with 79 additions and 0 deletions

View File

@ -560,6 +560,35 @@ void CheckIO::checkWrongPrintfScanfArguments()
else if (argListTok->type() == Token::eString) else if (argListTok->type() == Token::eString)
invalidPrintfArgTypeError_float(tok, numFormat, *i); invalidPrintfArgTypeError_float(tok, numFormat, *i);
break; break;
case 'h': // Can be 'hh' (signed char or unsigned char) or 'h' (short int or unsigned short int)
case 'l': // Can be 'll' (long long int or unsigned long long int) or 'l' (long int or unsigned long int)
// If the next character is the same (which makes 'hh' or 'll') then expect another alphabetical character
if (i != formatString.end() && *(i+1) == *i) {
if (i+1 != formatString.end() && !isalpha(*(i+2))) {
std::string modifier;
modifier += *i;
modifier += *(i+1);
invalidLengthModifierError(tok, numFormat, modifier);
}
} else {
if (i != formatString.end() && !isalpha(*(i+1))) {
std::string modifier;
modifier += *i;
invalidLengthModifierError(tok, numFormat, modifier);
}
}
break;
case 'j': // intmax_t or uintmax_t
case 'z': // size_t
case 't': // ptrdiff_t
case 'L': // long double
// Expect an alphabetical character after these specifiers
if (i != formatString.end() && !isalpha(*(i+1))) {
std::string modifier;
modifier += *i;
invalidLengthModifierError(tok, numFormat, modifier);
}
break;
default: default:
break; break;
} }
@ -654,6 +683,13 @@ void CheckIO::invalidPrintfArgTypeError_float(const Token* tok, unsigned int num
errmsg << "%" << c << " in format string (no. " << numFormat << ") requires a floating point number given in the argument list."; errmsg << "%" << c << " in format string (no. " << numFormat << ") requires a floating point number given in the argument list.";
reportError(tok, Severity::warning, "invalidPrintfArgType_float", errmsg.str()); reportError(tok, Severity::warning, "invalidPrintfArgType_float", errmsg.str());
} }
void CheckIO::invalidLengthModifierError(const Token* tok, unsigned int numFormat, std::string& modifier)
{
std::ostringstream errmsg;
errmsg << "'" << modifier << "' in format string (no. " << numFormat << ") is a length modifier and cannot be used without a conversion specifier.";
reportError(tok, Severity::warning, "invalidLengthModifierError", errmsg.str());
}
void CheckIO::invalidScanfFormatWidthError(const Token* tok, unsigned int numFormat, int width, const Variable *var) void CheckIO::invalidScanfFormatWidthError(const Token* tok, unsigned int numFormat, int width, const Variable *var)
{ {
std::ostringstream errmsg; std::ostringstream errmsg;

View File

@ -90,6 +90,7 @@ private:
void invalidPrintfArgTypeError_uint(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_sint(const Token* tok, unsigned int numFormat, char c);
void invalidPrintfArgTypeError_float(const Token* tok, unsigned int numFormat, char c); void invalidPrintfArgTypeError_float(const Token* tok, unsigned int numFormat, char c);
void invalidLengthModifierError(const Token* tok, unsigned int numFormat, std::string& modifier);
void invalidScanfFormatWidthError(const Token* tok, unsigned int numFormat, int width, const Variable *var); void invalidScanfFormatWidthError(const Token* tok, unsigned int numFormat, int width, const Variable *var);
void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const { void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const {

View File

@ -640,6 +640,48 @@ private:
TODO_ASSERT_EQUALS("[test.cpp:3]: (warning) %u in format string (no. 1) requires an integer given in the argument list.\n" TODO_ASSERT_EQUALS("[test.cpp:3]: (warning) %u in format string (no. 1) requires an integer given in the argument list.\n"
"[test.cpp:4]: (warning) %f in format string (no. 1) requires an integer given in the argument list.\n" "[test.cpp:4]: (warning) %f in format string (no. 1) requires an integer given in the argument list.\n"
"[test.cpp:5]: (warning) %p in format string (no. 1) requires an integer given in the argument list.\n", "", errout.str()); "[test.cpp:5]: (warning) %p in format string (no. 1) requires an integer given in the argument list.\n", "", errout.str());
// Ticket #4189 (Improve check (printf("%l") not detected)) tests (according to C99 7.19.6.1.7)
// False positive tests
check("void foo(signed char sc, unsigned char uc, short int si, unsigned short int usi) {\n"
" printf(\"%hhx %hhd\", sc, uc);\n"
" printf(\"%hd %hi\", si, usi);\n"
"}");
ASSERT_EQUALS("", errout.str());
check("void foo(long long int lli, unsigned long long int ulli, long int li, unsigned long int uli) {\n"
" printf(\"%llo %llx\", lli, ulli);\n"
" printf(\"%ld %lu\", li, uli);\n"
"}");
ASSERT_EQUALS("", errout.str());
check("void foo(intmax_t im, uintmax_t uim, size_t s, ptrdiff_t p, long double ld) {\n"
" printf(\"%jd %jo\", im, uim);\n"
" printf(\"%zx\", s);\n"
" printf(\"%ti\", p);\n"
" printf(\"%La\", ld);\n"
"}");
ASSERT_EQUALS("", errout.str());
// False negative test
check("void foo(unsigned int i) {\n"
" printf(\"%h\", i);\n"
" printf(\"%hh\", i);\n"
" printf(\"%l\", i);\n"
" printf(\"%ll\", i);\n"
" printf(\"%j\", i);\n"
" printf(\"%z\", i);\n"
" printf(\"%t\", i);\n"
" printf(\"%L\", i);\n"
"}");
ASSERT_EQUALS("[test.cpp:2]: (warning) 'h' in format string (no. 1) is a length modifier and cannot be used without a conversion specifier.\n"
"[test.cpp:3]: (warning) 'hh' in format string (no. 1) is a length modifier and cannot be used without a conversion specifier.\n"
"[test.cpp:4]: (warning) 'l' in format string (no. 1) is a length modifier and cannot be used without a conversion specifier.\n"
"[test.cpp:5]: (warning) 'll' in format string (no. 1) is a length modifier and cannot be used without a conversion specifier.\n"
"[test.cpp:6]: (warning) 'j' in format string (no. 1) is a length modifier and cannot be used without a conversion specifier.\n"
"[test.cpp:7]: (warning) 'z' in format string (no. 1) is a length modifier and cannot be used without a conversion specifier.\n"
"[test.cpp:8]: (warning) 't' in format string (no. 1) is a length modifier and cannot be used without a conversion specifier.\n"
"[test.cpp:9]: (warning) 'L' in format string (no. 1) is a length modifier and cannot be used without a conversion specifier.\n", errout.str());
} }
}; };