CheckIO: This patch adds support for fprintf_s, fscanf_s and %I. Ticket: #5051

This commit is contained in:
Robert Reif 2013-10-03 06:37:40 +02:00 committed by Daniel Marjamäki
parent 022e7a0f0f
commit 59de30823e
3 changed files with 218 additions and 11 deletions

View File

@ -454,7 +454,7 @@ void CheckIO::checkWrongPrintfScanfArguments()
} }
} else if (Token::Match(tok, "sprintf|fprintf|sscanf|fscanf|swscanf|fwprintf|fwscanf ( %any%") || } else if (Token::Match(tok, "sprintf|fprintf|sscanf|fscanf|swscanf|fwprintf|fwscanf ( %any%") ||
(Token::simpleMatch(tok, "swprintf (") && Token::Match(tok->tokAt(2)->nextArgument(), "%str%")) || (Token::simpleMatch(tok, "swprintf (") && Token::Match(tok->tokAt(2)->nextArgument(), "%str%")) ||
(windows && Token::Match(tok, "sscanf_s|swscanf_s ( %any%"))) { (windows && Token::Match(tok, "sscanf_s|swscanf_s|fscanf_s|fwscanf_s|fprintf_s|fwprintf_s ( %any%"))) {
const Token* formatStringTok = tok->tokAt(2)->nextArgument(); // Find second parameter (format string) const Token* formatStringTok = tok->tokAt(2)->nextArgument(); // Find second parameter (format string)
if (Token::Match(formatStringTok, "%str% [,)]")) { if (Token::Match(formatStringTok, "%str% [,)]")) {
argListTok = formatStringTok->nextArgument(); // Find third parameter (first argument of va_args) argListTok = formatStringTok->nextArgument(); // Find third parameter (first argument of va_args)
@ -492,7 +492,7 @@ void CheckIO::checkWrongPrintfScanfArguments()
} }
// Count format string parameters.. // Count format string parameters..
bool scanf_s = windows ? Token::Match(tok, "scanf_s|wscanf_s|sscanf_s|swscanf_s") : false; bool scanf_s = windows ? Token::Match(tok, "scanf_s|wscanf_s|sscanf_s|swscanf_s|fscanf_s|fwscanf_s") : false;
bool scan = Token::Match(tok, "sscanf|fscanf|scanf|swscanf|fwscanf|wscanf") || scanf_s; bool scan = Token::Match(tok, "sscanf|fscanf|scanf|swscanf|fwscanf|wscanf") || scanf_s;
unsigned int numFormat = 0; unsigned int numFormat = 0;
unsigned int numSecure = 0; unsigned int numSecure = 0;
@ -661,7 +661,14 @@ void CheckIO::checkWrongPrintfScanfArguments()
invalidScanfArgTypeError_int(tok, numFormat, specifier, &argInfo, true); invalidScanfArgTypeError_int(tok, numFormat, specifier, &argInfo, true);
break; break;
case 'I': case 'I':
if (argInfo.typeToken->str() != "long" || !argInfo.typeToken->isLong()) if (specifier.find("I64") != std::string::npos) {
if (argInfo.typeToken->str() != "long" || !argInfo.typeToken->isLong())
invalidScanfArgTypeError_int(tok, numFormat, specifier, &argInfo, true);
} else if (specifier.find("I32") != std::string::npos) {
if (argInfo.typeToken->str() != "int" || argInfo.typeToken->isLong())
invalidScanfArgTypeError_int(tok, numFormat, specifier, &argInfo, true);
} else if (argInfo.typeToken->originalName() != "ptrdiff_t" &&
argInfo.typeToken->originalName() != "size_t")
invalidScanfArgTypeError_int(tok, numFormat, specifier, &argInfo, true); invalidScanfArgTypeError_int(tok, numFormat, specifier, &argInfo, true);
break; break;
case 'j': case 'j':
@ -726,7 +733,13 @@ void CheckIO::checkWrongPrintfScanfArguments()
invalidScanfArgTypeError_int(tok, numFormat, specifier, &argInfo, false); invalidScanfArgTypeError_int(tok, numFormat, specifier, &argInfo, false);
break; break;
case 'I': case 'I':
if (argInfo.typeToken->str() != "long" || !argInfo.typeToken->isLong()) if (specifier.find("I64") != std::string::npos) {
if (argInfo.typeToken->str() != "long" || !argInfo.typeToken->isLong())
invalidScanfArgTypeError_int(tok, numFormat, specifier, &argInfo, false);
} else if (specifier.find("I32") != std::string::npos) {
if (argInfo.typeToken->str() != "int" || argInfo.typeToken->isLong())
invalidScanfArgTypeError_int(tok, numFormat, specifier, &argInfo, false);
} else if (argInfo.typeToken->originalName() != "ptrdiff_t")
invalidScanfArgTypeError_int(tok, numFormat, specifier, &argInfo, false); invalidScanfArgTypeError_int(tok, numFormat, specifier, &argInfo, false);
break; break;
case 'j': case 'j':
@ -787,7 +800,13 @@ void CheckIO::checkWrongPrintfScanfArguments()
invalidScanfArgTypeError_int(tok, numFormat, specifier, &argInfo, true); invalidScanfArgTypeError_int(tok, numFormat, specifier, &argInfo, true);
break; break;
case 'I': case 'I':
if (argInfo.typeToken->str() != "long" || !argInfo.typeToken->isLong()) if (specifier.find("I64") != std::string::npos) {
if (argInfo.typeToken->str() != "long" || !argInfo.typeToken->isLong())
invalidScanfArgTypeError_int(tok, numFormat, specifier, &argInfo, true);
} else if (specifier.find("I32") != std::string::npos) {
if (argInfo.typeToken->str() != "int" || argInfo.typeToken->isLong())
invalidScanfArgTypeError_int(tok, numFormat, specifier, &argInfo, true);
} else if (argInfo.typeToken->originalName() != "size_t")
invalidScanfArgTypeError_int(tok, numFormat, specifier, &argInfo, true); invalidScanfArgTypeError_int(tok, numFormat, specifier, &argInfo, true);
break; break;
case 'j': case 'j':
@ -853,8 +872,10 @@ void CheckIO::checkWrongPrintfScanfArguments()
done = true; done = true;
break; break;
case 'I': case 'I':
if (i+1 != formatString.end() && *(i+1) == '6' && if ((i+1 != formatString.end() && *(i+1) == '6' &&
i+2 != formatString.end() && *(i+2) == '4') { i+2 != formatString.end() && *(i+2) == '4') ||
(i+1 != formatString.end() && *(i+1) == '3' &&
i+2 != formatString.end() && *(i+2) == '2')) {
specifier += *i++; specifier += *i++;
specifier += *i++; specifier += *i++;
if ((i+1) != formatString.end() && !isalpha(*(i+1))) { if ((i+1) != formatString.end() && !isalpha(*(i+1))) {
@ -865,9 +886,13 @@ void CheckIO::checkWrongPrintfScanfArguments()
specifier += *i++; specifier += *i++;
} }
} else { } else {
specifier += *i; if ((i+1) != formatString.end() && !isalpha(*(i+1))) {
invalidLengthModifierError(tok, numFormat, specifier); specifier += *i;
done = true; invalidLengthModifierError(tok, numFormat, specifier);
done = true;
} else {
specifier += *i++;
}
} }
break; break;
case 'h': case 'h':
@ -1497,8 +1522,12 @@ void CheckIO::invalidScanfArgTypeError_int(const Token* tok, unsigned int numFor
errmsg << (isUnsigned ? "unsigned " : "") << "long long"; errmsg << (isUnsigned ? "unsigned " : "") << "long long";
else else
errmsg << (isUnsigned ? "unsigned " : "") << "long"; errmsg << (isUnsigned ? "unsigned " : "") << "long";
} else if (specifier[0] == 'I') { } else if (specifier.find("I32") != std::string::npos) {
errmsg << (isUnsigned ? "unsigned " : "") << "__int32";
} else if (specifier.find("I64") != std::string::npos) {
errmsg << (isUnsigned ? "unsigned " : "") << "__int64"; errmsg << (isUnsigned ? "unsigned " : "") << "__int64";
} else if (specifier[0] == 'I') {
errmsg << (isUnsigned ? "size_t" : "ptrdiff_t");
} else if (specifier[0] == 'j') { } else if (specifier[0] == 'j') {
if (isUnsigned) if (isUnsigned)
errmsg << "uintmax_t"; errmsg << "uintmax_t";

View File

@ -9604,6 +9604,9 @@ void Tokenizer::simplifyMicrosoftStringFunctions()
tok->str("strstr"); tok->str("strstr");
} else if (Token::simpleMatch(tok, "_tcstok (")) { } else if (Token::simpleMatch(tok, "_tcstok (")) {
tok->str("strtok"); tok->str("strtok");
} else if (Token::simpleMatch(tok, "_ftprintf (")) {
tok->str("fprintf");
tok->originalName("_ftprintf");
} else if (Token::simpleMatch(tok, "_tprintf (")) { } else if (Token::simpleMatch(tok, "_tprintf (")) {
tok->str("printf"); tok->str("printf");
tok->originalName("_tprintf"); tok->originalName("_tprintf");
@ -9613,12 +9616,18 @@ void Tokenizer::simplifyMicrosoftStringFunctions()
} else if (Token::simpleMatch(tok, "_sntprintf (")) { } else if (Token::simpleMatch(tok, "_sntprintf (")) {
tok->str("snprintf"); tok->str("snprintf");
tok->originalName("_sntprintf"); tok->originalName("_sntprintf");
} else if (Token::simpleMatch(tok, "_ftscanf (")) {
tok->str("fscanf");
tok->originalName("_ftscanf");
} else if (Token::simpleMatch(tok, "_tscanf (")) { } else if (Token::simpleMatch(tok, "_tscanf (")) {
tok->str("scanf"); tok->str("scanf");
tok->originalName("_tscanf"); tok->originalName("_tscanf");
} else if (Token::simpleMatch(tok, "_stscanf (")) { } else if (Token::simpleMatch(tok, "_stscanf (")) {
tok->str("sscanf"); tok->str("sscanf");
tok->originalName("_stscanf"); tok->originalName("_stscanf");
} else if (Token::simpleMatch(tok, "_ftprintf_s (")) {
tok->str("fprintf_s");
tok->originalName("_ftprintf_s");
} else if (Token::simpleMatch(tok, "_tprintf_s (")) { } else if (Token::simpleMatch(tok, "_tprintf_s (")) {
tok->str("printf_s"); tok->str("printf_s");
tok->originalName("_tprintf_s"); tok->originalName("_tprintf_s");
@ -9628,6 +9637,9 @@ void Tokenizer::simplifyMicrosoftStringFunctions()
} else if (Token::simpleMatch(tok, "_sntprintf_s (")) { } else if (Token::simpleMatch(tok, "_sntprintf_s (")) {
tok->str("_snprintf_s"); tok->str("_snprintf_s");
tok->originalName("_sntprintf_s"); tok->originalName("_sntprintf_s");
} else if (Token::simpleMatch(tok, "_ftscanf_s (")) {
tok->str("fscanf_s");
tok->originalName("_ftscanf_s");
} else if (Token::simpleMatch(tok, "_tscanf_s (")) { } else if (Token::simpleMatch(tok, "_tscanf_s (")) {
tok->str("scanf_s"); tok->str("scanf_s");
tok->originalName("_tscanf_s"); tok->originalName("_tscanf_s");
@ -9674,6 +9686,9 @@ void Tokenizer::simplifyMicrosoftStringFunctions()
tok->str("wcsstr"); tok->str("wcsstr");
} else if (Token::simpleMatch(tok, "_tcstok (")) { } else if (Token::simpleMatch(tok, "_tcstok (")) {
tok->str("wcstok"); tok->str("wcstok");
} else if (Token::simpleMatch(tok, "_ftprintf (")) {
tok->str("fwprintf");
tok->originalName("_ftprintf");
} else if (Token::simpleMatch(tok, "_tprintf (")) { } else if (Token::simpleMatch(tok, "_tprintf (")) {
tok->str("wprintf"); tok->str("wprintf");
tok->originalName("_tprintf"); tok->originalName("_tprintf");
@ -9683,12 +9698,18 @@ void Tokenizer::simplifyMicrosoftStringFunctions()
} else if (Token::simpleMatch(tok, "_sntprintf (")) { } else if (Token::simpleMatch(tok, "_sntprintf (")) {
tok->str("snwprintf"); tok->str("snwprintf");
tok->originalName("_sntprintf"); tok->originalName("_sntprintf");
} else if (Token::simpleMatch(tok, "_ftscanf (")) {
tok->str("fwscanf");
tok->originalName("_ftscanf");
} else if (Token::simpleMatch(tok, "_tscanf (")) { } else if (Token::simpleMatch(tok, "_tscanf (")) {
tok->str("wscanf"); tok->str("wscanf");
tok->originalName("_tscanf"); tok->originalName("_tscanf");
} else if (Token::simpleMatch(tok, "_stscanf (")) { } else if (Token::simpleMatch(tok, "_stscanf (")) {
tok->str("swscanf"); tok->str("swscanf");
tok->originalName("_stscanf"); tok->originalName("_stscanf");
} else if (Token::simpleMatch(tok, "_ftprintf_s (")) {
tok->str("fwprintf_s");
tok->originalName("_ftprintf_s");
} else if (Token::simpleMatch(tok, "_tprintf_s (")) { } else if (Token::simpleMatch(tok, "_tprintf_s (")) {
tok->str("wprintf_s"); tok->str("wprintf_s");
tok->originalName("_tprintf_s"); tok->originalName("_tprintf_s");
@ -9698,6 +9719,9 @@ void Tokenizer::simplifyMicrosoftStringFunctions()
} else if (Token::simpleMatch(tok, "_sntprintf_s (")) { } else if (Token::simpleMatch(tok, "_sntprintf_s (")) {
tok->str("_snwprintf_s"); tok->str("_snwprintf_s");
tok->originalName("_sntprintf_s"); tok->originalName("_sntprintf_s");
} else if (Token::simpleMatch(tok, "_ftscanf_s (")) {
tok->str("fwscanf_s");
tok->originalName("_ftscanf_s");
} else if (Token::simpleMatch(tok, "_tscanf_s (")) { } else if (Token::simpleMatch(tok, "_tscanf_s (")) {
tok->str("wscanf_s"); tok->str("wscanf_s");
tok->originalName("_tscanf_s"); tok->originalName("_tscanf_s");

View File

@ -49,6 +49,7 @@ private:
TEST_CASE(testPosixPrintfScanfParameterPosition); // #4900 TEST_CASE(testPosixPrintfScanfParameterPosition); // #4900
TEST_CASE(testMicrosoftPrintfArgument); // ticket #4902 TEST_CASE(testMicrosoftPrintfArgument); // ticket #4902
TEST_CASE(testMicrosoftScanfArgument);
TEST_CASE(testMicrosoftCStringFormatArguments); // ticket #4920 TEST_CASE(testMicrosoftCStringFormatArguments); // ticket #4920
TEST_CASE(testMicrosoftSecurePrintfArgument); TEST_CASE(testMicrosoftSecurePrintfArgument);
TEST_CASE(testMicrosoftSecureScanfArgument); TEST_CASE(testMicrosoftSecureScanfArgument);
@ -2146,6 +2147,83 @@ private:
"[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());
} }
void testMicrosoftScanfArgument() {
check("void foo() {\n"
" size_t s;\n"
" ptrdiff_t p;\n"
" __int32 i32;\n"
" unsigned __int32 u32;\n"
" __int64 i64;\n"
" unsigned __int64 u64;\n"
" scanf(\"%Id %Iu %Ix\", &s, &s, &s);\n"
" scanf(\"%Id %Iu %Ix\", &p, &p, &p);\n"
" scanf(\"%I32d %I32u %I32x\", &i32, &i32, &i32);\n"
" scanf(\"%I32d %I32u %I32x\", &u32, &u32, &u32);\n"
" scanf(\"%I64d %I64u %I64x\", &i64, &i64, &i64);\n"
" scanf(\"%I64d %I64u %I64x\", &u64, &u64, &u64);\n"
"}", false, false, Settings::Win32A);
ASSERT_EQUALS("[test.cpp:8]: (warning) %Id in format string (no. 1) requires 'ptrdiff_t *' but the argument type is 'size_t * {aka unsigned long *}'.\n"
"[test.cpp:9]: (warning) %Iu in format string (no. 2) requires 'size_t *' but the argument type is 'ptrdiff_t * {aka long *}'.\n"
"[test.cpp:10]: (warning) %I32u in format string (no. 2) requires 'unsigned __int32 *' but the argument type is '__int32 * {aka int *}'.\n"
"[test.cpp:11]: (warning) %I32d in format string (no. 1) requires '__int32 *' but the argument type is 'unsigned __int32 * {aka unsigned int *}'.\n"
"[test.cpp:12]: (warning) %I64u in format string (no. 2) requires 'unsigned __int64 *' but the argument type is '__int64 * {aka long long *}'.\n"
"[test.cpp:13]: (warning) %I64d in format string (no. 1) requires '__int64 *' but the argument type is 'unsigned __int64 * {aka unsigned long long *}'.\n", errout.str());
check("void foo() {\n"
" size_t s;\n"
" ptrdiff_t p;\n"
" __int32 i32;\n"
" unsigned __int32 u32;\n"
" __int64 i64;\n"
" unsigned __int64 u64;\n"
" scanf(\"%Id %Iu %Ix\", &s, &s, &s);\n"
" scanf(\"%Id %Iu %Ix\", &p, &p, &p);\n"
" scanf(\"%I32d %I32u %I32x\", &i32, &i32, &i32);\n"
" scanf(\"%I32d %I32u %I32x\", &u32, &u32, &u32);\n"
" scanf(\"%I64d %I64u %I64x\", &i64, &i64, &i64);\n"
" scanf(\"%I64d %I64u %I64x\", &u64, &u64, &u64);\n"
"}", false, false, Settings::Win64);
ASSERT_EQUALS("[test.cpp:8]: (warning) %Id in format string (no. 1) requires 'ptrdiff_t *' but the argument type is 'size_t * {aka unsigned long long *}'.\n"
"[test.cpp:9]: (warning) %Iu in format string (no. 2) requires 'size_t *' but the argument type is 'ptrdiff_t * {aka long long *}'.\n"
"[test.cpp:10]: (warning) %I32u in format string (no. 2) requires 'unsigned __int32 *' but the argument type is '__int32 * {aka int *}'.\n"
"[test.cpp:11]: (warning) %I32d in format string (no. 1) requires '__int32 *' but the argument type is 'unsigned __int32 * {aka unsigned int *}'.\n"
"[test.cpp:12]: (warning) %I64u in format string (no. 2) requires 'unsigned __int64 *' but the argument type is '__int64 * {aka long long *}'.\n"
"[test.cpp:13]: (warning) %I64d in format string (no. 1) requires '__int64 *' but the argument type is 'unsigned __int64 * {aka unsigned long long *}'.\n", errout.str());
check("void foo() {\n"
" size_t s;\n"
" int i;\n"
" scanf(\"%I\", &s);\n"
" scanf(\"%I6\", &s);\n"
" scanf(\"%I6x\", &s);\n"
" scanf(\"%I16\", &s);\n"
" scanf(\"%I16x\", &s);\n"
" scanf(\"%I32\", &s);\n"
" scanf(\"%I64\", &s);\n"
" scanf(\"%I%i\", &s, &i);\n"
" scanf(\"%I6%i\", &s, &i);\n"
" scanf(\"%I6x%i\", &s, &i);\n"
" scanf(\"%I16%i\", &s, &i);\n"
" scanf(\"%I16x%i\", &s, &i);\n"
" scanf(\"%I32%i\", &s, &i);\n"
" scanf(\"%I64%i\", &s, &i);\n"
"}");
ASSERT_EQUALS("[test.cpp:4]: (warning) 'I' in format string (no. 1) is a length modifier and cannot be used without a conversion specifier.\n"
"[test.cpp:5]: (warning) 'I' in format string (no. 1) is a length modifier and cannot be used without a conversion specifier.\n"
"[test.cpp:6]: (warning) 'I' in format string (no. 1) is a length modifier and cannot be used without a conversion specifier.\n"
"[test.cpp:7]: (warning) 'I' in format string (no. 1) is a length modifier and cannot be used without a conversion specifier.\n"
"[test.cpp:8]: (warning) 'I' in format string (no. 1) is a length modifier and cannot be used without a conversion specifier.\n"
"[test.cpp:9]: (warning) 'I32' in format string (no. 1) is a length modifier and cannot be used without a conversion specifier.\n"
"[test.cpp:10]: (warning) 'I64' in format string (no. 1) is a length modifier and cannot be used without a conversion specifier.\n"
"[test.cpp:11]: (warning) 'I' in format string (no. 1) is a length modifier and cannot be used without a conversion specifier.\n"
"[test.cpp:12]: (warning) 'I' in format string (no. 1) is a length modifier and cannot be used without a conversion specifier.\n"
"[test.cpp:13]: (warning) 'I' in format string (no. 1) is a length modifier and cannot be used without a conversion specifier.\n"
"[test.cpp:14]: (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:17]: (warning) 'I64' in format string (no. 1) is a length modifier and cannot be used without a conversion specifier.\n", errout.str());
}
void testMicrosoftCStringFormatArguments() { // ticket #4920 void testMicrosoftCStringFormatArguments() { // ticket #4920
check("void foo() {\n" check("void foo() {\n"
" unsigned __int32 u32;\n" " unsigned __int32 u32;\n"
@ -2289,6 +2367,42 @@ private:
ASSERT_EQUALS("[test.cpp:5]: (warning) %d in format string (no. 1) requires 'int' but the argument type is 'unsigned int'.\n" ASSERT_EQUALS("[test.cpp:5]: (warning) %d in format string (no. 1) requires 'int' but the argument type is 'unsigned int'.\n"
"[test.cpp:5]: (warning) %u in format string (no. 2) requires 'unsigned int' but the argument type is 'int'.\n" "[test.cpp:5]: (warning) %u in format string (no. 2) requires 'unsigned int' but the argument type is 'int'.\n"
"[test.cpp:5]: (warning) _snwprintf_s format string requires 2 parameters but 3 are given.\n", errout.str()); "[test.cpp:5]: (warning) _snwprintf_s format string requires 2 parameters but 3 are given.\n", errout.str());
check("void foo(FILE * fp) {\n"
" int i;\n"
" unsigned int u;\n"
" _ftprintf_s(fp, _T(\"%d %u\"), u, i, 0);\n"
"}\n", false, false, Settings::Win32A);
ASSERT_EQUALS("[test.cpp:4]: (warning) %d in format string (no. 1) requires 'int' but the argument type is 'unsigned int'.\n"
"[test.cpp:4]: (warning) %u in format string (no. 2) requires 'unsigned int' but the argument type is 'int'.\n"
"[test.cpp:4]: (warning) _ftprintf_s format string requires 2 parameters but 3 are given.\n", errout.str());
check("void foo(FILE * fp) {\n"
" int i;\n"
" unsigned int u;\n"
" _ftprintf_s(fp, _T(\"%d %u\"), u, i, 0);\n"
"}\n", false, false, Settings::Win32W);
ASSERT_EQUALS("[test.cpp:4]: (warning) %d in format string (no. 1) requires 'int' but the argument type is 'unsigned int'.\n"
"[test.cpp:4]: (warning) %u in format string (no. 2) requires 'unsigned int' but the argument type is 'int'.\n"
"[test.cpp:4]: (warning) _ftprintf_s format string requires 2 parameters but 3 are given.\n", errout.str());
check("void foo(FILE * fp) {\n"
" int i;\n"
" unsigned int u;\n"
" fprintf_s(fp, \"%d %u\", u, i, 0);\n"
"}\n", false, false, Settings::Win32A);
ASSERT_EQUALS("[test.cpp:4]: (warning) %d in format string (no. 1) requires 'int' but the argument type is 'unsigned int'.\n"
"[test.cpp:4]: (warning) %u in format string (no. 2) requires 'unsigned int' but the argument type is 'int'.\n"
"[test.cpp:4]: (warning) fprintf_s format string requires 2 parameters but 3 are given.\n", errout.str());
check("void foo(FILE * fp) {\n"
" int i;\n"
" unsigned int u;\n"
" fwprintf_s(fp, L\"%d %u\", u, i, 0);\n"
"}\n", false, false, Settings::Win32W);
ASSERT_EQUALS("[test.cpp:4]: (warning) %d in format string (no. 1) requires 'int' but the argument type is 'unsigned int'.\n"
"[test.cpp:4]: (warning) %u in format string (no. 2) requires 'unsigned int' but the argument type is 'int'.\n"
"[test.cpp:4]: (warning) fwprintf_s format string requires 2 parameters but 3 are given.\n", errout.str());
} }
void testMicrosoftSecureScanfArgument() { void testMicrosoftSecureScanfArgument() {
@ -2376,6 +2490,46 @@ private:
"[test.cpp:6]: (warning) %u in format string (no. 3) requires 'unsigned int *' but the argument type is 'int *'.\n" "[test.cpp:6]: (warning) %u in format string (no. 3) requires 'unsigned int *' but the argument type is 'int *'.\n"
"[test.cpp:6]: (warning) swscanf_s format string requires 6 parameters but 7 are given.\n", errout.str()); "[test.cpp:6]: (warning) swscanf_s format string requires 6 parameters but 7 are given.\n", errout.str());
check("void foo(FILE * fp) {\n"
" int i;\n"
" unsigned int u;\n"
" TCHAR str[10];\n"
" _ftscanf_s(fp, _T(\"%s %d %u %[a-z]\"), str, 10, &u, &i, str, 10, 0)\n"
"}\n", false, false, Settings::Win32A);
ASSERT_EQUALS("[test.cpp:5]: (warning) %d in format string (no. 2) requires 'int *' but the argument type is 'unsigned int *'.\n"
"[test.cpp:5]: (warning) %u in format string (no. 3) requires 'unsigned int *' but the argument type is 'int *'.\n"
"[test.cpp:5]: (warning) _ftscanf_s format string requires 6 parameters but 7 are given.\n", errout.str());
check("void foo(FILE * fp) {\n"
" int i;\n"
" unsigned int u;\n"
" TCHAR str[10];\n"
" _ftscanf_s(fp, _T(\"%s %d %u %[a-z]\"), str, 10, &u, &i, str, 10, 0)\n"
"}\n", false, false, Settings::Win32W);
ASSERT_EQUALS("[test.cpp:5]: (warning) %d in format string (no. 2) requires 'int *' but the argument type is 'unsigned int *'.\n"
"[test.cpp:5]: (warning) %u in format string (no. 3) requires 'unsigned int *' but the argument type is 'int *'.\n"
"[test.cpp:5]: (warning) _ftscanf_s format string requires 6 parameters but 7 are given.\n", errout.str());
check("void foo(FILE * fp) {\n"
" int i;\n"
" unsigned int u;\n"
" char str[10];\n"
" fscanf_s(fp, \"%s %d %u %[a-z]\", str, 10, &u, &i, str, 10, 0)\n"
"}\n", false, false, Settings::Win32A);
ASSERT_EQUALS("[test.cpp:5]: (warning) %d in format string (no. 2) requires 'int *' but the argument type is 'unsigned int *'.\n"
"[test.cpp:5]: (warning) %u in format string (no. 3) requires 'unsigned int *' but the argument type is 'int *'.\n"
"[test.cpp:5]: (warning) fscanf_s format string requires 6 parameters but 7 are given.\n", errout.str());
check("void foo(FILE * fp) {\n"
" int i;\n"
" unsigned int u;\n"
" wchar_t str[10];\n"
" fwscanf_s(fp, L\"%s %d %u %[a-z]\", str, 10, &u, &i, str, 10, 0)\n"
"}\n", false, false, Settings::Win32W);
ASSERT_EQUALS("[test.cpp:5]: (warning) %d in format string (no. 2) requires 'int *' but the argument type is 'unsigned int *'.\n"
"[test.cpp:5]: (warning) %u in format string (no. 3) requires 'unsigned int *' but the argument type is 'int *'.\n"
"[test.cpp:5]: (warning) fwscanf_s format string requires 6 parameters but 7 are given.\n", errout.str());
check("void foo() {\n" check("void foo() {\n"
" WCHAR msStr1[5] = {0};\n" " WCHAR msStr1[5] = {0};\n"
" wscanf_s(L\"%4[^-]\", msStr1, _countof(msStr1));\n" " wscanf_s(L\"%4[^-]\", msStr1, _countof(msStr1));\n"