Allow SSIZE_T in addition to ssize_t (#2263)

The Windows Data Type SSIZE_T is declared in BaseTsd.h
However, it is written in capital letters

- Fixes e.g. the following false positive:
  (portability) %zd in format string (no. 1) requires 'ssize_t' but the
  argument type is 'SSIZE_T {aka signed long long}'.
  [invalidPrintfArgType_sint]
This commit is contained in:
Wolfgang Stöggl 2019-10-24 21:51:20 +02:00 committed by Daniel Marjamäki
parent fbd59b2fc5
commit 1ea3fc8083
2 changed files with 80 additions and 2 deletions

View File

@ -566,6 +566,7 @@ void CheckIO::checkFormatString(const Token * const tok,
const bool scan, const bool scan,
const bool scanf_s) const bool scanf_s)
{ {
const bool isWindows = mSettings->isWindowsPlatform();
const bool printWarning = mSettings->isEnabled(Settings::WARNING); const bool printWarning = mSettings->isEnabled(Settings::WARNING);
const std::string &formatString = formatStringTok->str(); const std::string &formatString = formatStringTok->str();
@ -841,7 +842,8 @@ void CheckIO::checkFormatString(const Token * const tok,
invalidScanfArgTypeError_int(tok, numFormat, specifier, &argInfo, false); invalidScanfArgTypeError_int(tok, numFormat, specifier, &argInfo, false);
break; break;
case 'z': case 'z':
if (!typesMatch(argInfo.typeToken->originalName(), "ssize_t")) if (!(typesMatch(argInfo.typeToken->originalName(), "ssize_t") ||
(isWindows && typesMatch(argInfo.typeToken->originalName(), "SSIZE_T"))))
invalidScanfArgTypeError_int(tok, numFormat, specifier, &argInfo, false); invalidScanfArgTypeError_int(tok, numFormat, specifier, &argInfo, false);
break; break;
case 't': case 't':
@ -1095,7 +1097,8 @@ void CheckIO::checkFormatString(const Token * const tok,
invalidPrintfArgTypeError_sint(tok, numFormat, specifier, &argInfo); invalidPrintfArgTypeError_sint(tok, numFormat, specifier, &argInfo);
break; break;
case 'z': case 'z':
if (!typesMatch(argInfo.typeToken->originalName(), "ssize_t")) if (!(typesMatch(argInfo.typeToken->originalName(), "ssize_t") ||
(isWindows && typesMatch(argInfo.typeToken->originalName(), "SSIZE_T"))))
invalidPrintfArgTypeError_sint(tok, numFormat, specifier, &argInfo); invalidPrintfArgTypeError_sint(tok, numFormat, specifier, &argInfo);
break; break;
case 'L': case 'L':

View File

@ -4142,6 +4142,43 @@ private:
ASSERT_EQUALS("[test.cpp:2]: (warning) %d in format string (no. 1) requires 'int' but the argument type is 'const void *'.\n" ASSERT_EQUALS("[test.cpp:2]: (warning) %d in format string (no. 1) requires 'int' but the argument type is 'const void *'.\n"
"[test.cpp:2]: (warning) %d in format string (no. 2) requires 'int' but the argument type is 'const void *'.\n", errout.str()); "[test.cpp:2]: (warning) %d in format string (no. 2) requires 'int' but the argument type is 'const void *'.\n", errout.str());
check("void foo() {\n"
" SSIZE_T s = -2;\n" // In MSVC, SSIZE_T is available in capital letters using #include <BaseTsd.h>
" int i;\n"
" printf(\"%zd\", s);\n"
" printf(\"%zd%i\", s, i);\n"
" printf(\"%zu\", s);\n"
"}", false, true, Settings::Win32A);
ASSERT_EQUALS("[test.cpp:6]: (portability) %zu in format string (no. 1) requires 'size_t' but the argument type is 'SSIZE_T {aka signed long}'.\n", errout.str());
check("void foo() {\n"
" SSIZE_T s = -2;\n" // In MSVC, SSIZE_T is available in capital letters using #include <BaseTsd.h>
" int i;\n"
" printf(\"%zd\", s);\n"
" printf(\"%zd%i\", s, i);\n"
" printf(\"%zu\", s);\n"
"}", false, true, Settings::Win64);
ASSERT_EQUALS("[test.cpp:6]: (portability) %zu in format string (no. 1) requires 'size_t' but the argument type is 'SSIZE_T {aka signed long long}'.\n", errout.str());
check("void foo() {\n"
" SSIZE_T s = -2;\n" // Under Unix, ssize_t has to be written in small letters. Not Cppcheck, but the compiler will report this.
" int i;\n"
" printf(\"%zd\", s);\n"
" printf(\"%zd%i\", s, i);\n"
" printf(\"%zu\", s);\n"
"}", false, true, Settings::Unix64);
ASSERT_EQUALS("", errout.str());
check("void foo() {\n"
" typedef SSIZE_T ssize_t;\n" // Test using typedef
" ssize_t s = -2;\n"
" int i;\n"
" printf(\"%zd\", s);\n"
" printf(\"%zd%i\", s, i);\n"
" printf(\"%zu\", s);\n"
"}", false, true, Settings::Win64);
ASSERT_EQUALS("[test.cpp:7]: (portability) %zu in format string (no. 1) requires 'size_t' but the argument type is 'SSIZE_T {aka signed long long}'.\n", errout.str());
} }
void testMicrosoftScanfArgument() { void testMicrosoftScanfArgument() {
@ -4225,6 +4262,44 @@ private:
"[test.cpp:15]: (warning) 'I' in format string (no. 1) is a length modifier and cannot be used without a conversion specifier.\n" "[test.cpp:15]: (warning) 'I' in format string (no. 1) is a length modifier and cannot be used without a conversion specifier.\n"
"[test.cpp:16]: (warning) 'I32' in format string (no. 1) is a length modifier and cannot be used without a conversion specifier.\n" "[test.cpp:16]: (warning) 'I32' in format string (no. 1) is a length modifier and cannot be used without a conversion specifier.\n"
"[test.cpp:17]: (warning) 'I64' in format string (no. 1) is a length modifier and cannot be used without a conversion specifier.\n", errout.str()); "[test.cpp:17]: (warning) 'I64' in format string (no. 1) is a length modifier and cannot be used without a conversion specifier.\n", errout.str());
check("void foo() {\n"
" SSIZE_T s;\n" // In MSVC, SSIZE_T is available in capital letters using #include <BaseTsd.h>
" int i;\n"
" scanf(\"%zd\", &s);\n"
" scanf(\"%zd%i\", &s, &i);\n"
" scanf(\"%zu\", &s);\n"
"}", false, true, Settings::Win32A);
ASSERT_EQUALS("[test.cpp:6]: (portability) %zu in format string (no. 1) requires 'size_t *' but the argument type is 'SSIZE_T * {aka signed long *}'.\n", errout.str());
check("void foo() {\n"
" SSIZE_T s;\n" // In MSVC, SSIZE_T is available in capital letters using #include <BaseTsd.h>
" int i;\n"
" scanf(\"%zd\", &s);\n"
" scanf(\"%zd%i\", &s, &i);\n"
" scanf(\"%zu\", &s);\n"
"}", false, true, Settings::Win64);
ASSERT_EQUALS("[test.cpp:6]: (portability) %zu in format string (no. 1) requires 'size_t *' but the argument type is 'SSIZE_T * {aka signed long long *}'.\n", errout.str());
check("void foo() {\n"
" SSIZE_T s;\n" // Under Unix, ssize_t has to be written in small letters. Not Cppcheck, but the compiler will report this.
" int i;\n"
" scanf(\"%zd\", &s);\n"
" scanf(\"%zd%i\", &s, &i);\n"
" scanf(\"%zu\", &s);\n"
"}", false, true, Settings::Unix64);
ASSERT_EQUALS("", errout.str());
check("void foo() {\n"
" typedef SSIZE_T ssize_t;\n" // Test using typedef
" ssize_t s;\n"
" int i;\n"
" scanf(\"%zd\", &s);\n"
" scanf(\"%zd%i\", &s, &i);\n"
" scanf(\"%zu\", &s);\n"
"}", false, true, Settings::Win64);
ASSERT_EQUALS("[test.cpp:7]: (portability) %zu in format string (no. 1) requires 'size_t *' but the argument type is 'SSIZE_T * {aka signed long long *}'.\n", errout.str());
} }
void testMicrosoftCStringFormatArguments() { // ticket #4920 void testMicrosoftCStringFormatArguments() { // ticket #4920