CheckIO: Fixed false positives when using _snprintf_s and _snwprintf_s. Ticket: #5057

This commit is contained in:
Robert Reif 2013-10-01 05:49:44 +02:00 committed by Daniel Marjamäki
parent f0cbeb5233
commit cc6745fef6
3 changed files with 149 additions and 12 deletions

View File

@ -475,7 +475,7 @@ void CheckIO::checkWrongPrintfScanfArguments()
} else { } else {
continue; continue;
} }
} else if (windows && Token::Match(tok, "snprintf_s|snwprintf_s (")) { } else if (windows && Token::Match(tok, "_snprintf_s|_snwprintf_s (")) {
const Token* formatStringTok = tok->tokAt(2); const Token* formatStringTok = tok->tokAt(2);
for (int i = 0; i < 3 && formatStringTok; i++) { for (int i = 0; i < 3 && formatStringTok; i++) {
formatStringTok = formatStringTok->nextArgument(); // Find forth parameter (format string) formatStringTok = formatStringTok->nextArgument(); // Find forth parameter (format string)
@ -513,17 +513,25 @@ void CheckIO::checkWrongPrintfScanfArguments()
} }
++i; ++i;
} }
if (scanf_s) {
numSecure++;
if (argListTok) {
argListTok = argListTok->nextArgument();
}
}
if (i == formatString.end()) if (i == formatString.end())
break; break;
} else if (percent) { } else if (percent) {
percent = false; percent = false;
bool _continue = false; bool _continue = false;
bool skip = false;
std::string width; std::string width;
unsigned int parameterPosition = 0; unsigned int parameterPosition = 0;
bool hasParameterPosition = false; bool hasParameterPosition = false;
while (i != formatString.end() && *i != ']' && !std::isalpha(*i)) { while (i != formatString.end() && *i != '[' && !std::isalpha(*i)) {
if (*i == '*') { if (*i == '*') {
skip = true;
if (scan) if (scan)
_continue = true; _continue = true;
else { else {
@ -540,6 +548,26 @@ void CheckIO::checkWrongPrintfScanfArguments()
} }
++i; ++i;
} }
if (*i == '[') {
while (i != formatString.end()) {
if (*i == ']') {
if (!skip) {
numFormat++;
if (argListTok)
argListTok = argListTok->nextArgument();
}
break;
}
++i;
}
if (scanf_s && !skip) {
numSecure++;
if (argListTok) {
argListTok = argListTok->nextArgument();
}
}
_continue = true;
}
if (i == formatString.end()) if (i == formatString.end())
break; break;
if (_continue) if (_continue)

View File

@ -5587,6 +5587,9 @@ void Tokenizer::simplifyPlatformTypes()
tok->str("const"); tok->str("const");
tok->insertToken("*"); tok->insertToken("*");
tok->insertToken("wchar_t"); tok->insertToken("wchar_t");
} else if (tok->str() == "WCHAR") {
tok->originalName(tok->str());
tok->str("wchar_t");
} }
} }
} }
@ -9612,7 +9615,7 @@ void Tokenizer::simplifyMicrosoftStringFunctions()
tok->str("sprintf_s"); tok->str("sprintf_s");
tok->originalName("_stprintf_s"); tok->originalName("_stprintf_s");
} 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, "_tscanf_s (")) { } else if (Token::simpleMatch(tok, "_tscanf_s (")) {
tok->str("scanf_s"); tok->str("scanf_s");
@ -9682,7 +9685,7 @@ void Tokenizer::simplifyMicrosoftStringFunctions()
tok->str("swprintf_s"); tok->str("swprintf_s");
tok->originalName("_stprintf_s"); tok->originalName("_stprintf_s");
} 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, "_tscanf_s (")) { } else if (Token::simpleMatch(tok, "_tscanf_s (")) {
tok->str("wscanf_s"); tok->str("wscanf_s");

View File

@ -2185,6 +2185,24 @@ private:
"[test.cpp:4]: (warning) %u in format string (no. 2) requires 'unsigned int' but the argument type is '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) _tprintf_s format string requires 2 parameters but 3 are given.\n", errout.str()); "[test.cpp:4]: (warning) _tprintf_s format string requires 2 parameters but 3 are given.\n", errout.str());
check("void foo() {\n"
" int i;\n"
" unsigned int u;\n"
" printf_s(\"%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) printf_s format string requires 2 parameters but 3 are given.\n", errout.str());
check("void foo() {\n"
" int i;\n"
" unsigned int u;\n"
" wprintf_s(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) wprintf_s format string requires 2 parameters but 3 are given.\n", errout.str());
check("void foo() {\n" check("void foo() {\n"
" TCHAR str[10];\n" " TCHAR str[10];\n"
" int i;\n" " int i;\n"
@ -2205,6 +2223,26 @@ private:
"[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) _stprintf_s format string requires 2 parameters but 3 are given.\n", errout.str()); "[test.cpp:5]: (warning) _stprintf_s format string requires 2 parameters but 3 are given.\n", errout.str());
check("void foo() {\n"
" char str[10];\n"
" int i;\n"
" unsigned int u;\n"
" sprintf_s(str, sizeof(str), \"%d %u\", u, i, 0);\n"
"}\n", false, false, Settings::Win32A);
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) sprintf_s format string requires 2 parameters but 3 are given.\n", errout.str());
check("void foo() {\n"
" wchar_t str[10];\n"
" int i;\n"
" unsigned int u;\n"
" swprintf_s(str, sizeof(str) / sizeof(wchar_t), L\"%d %u\", u, i, 0);\n"
"}\n", false, false, Settings::Win32W);
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) swprintf_s format string requires 2 parameters but 3 are given.\n", errout.str());
check("void foo() {\n" check("void foo() {\n"
" TCHAR str[10];\n" " TCHAR str[10];\n"
" int i;\n" " int i;\n"
@ -2224,6 +2262,26 @@ 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) _sntprintf_s format string requires 2 parameters but 3 are given.\n", errout.str()); "[test.cpp:5]: (warning) _sntprintf_s format string requires 2 parameters but 3 are given.\n", errout.str());
check("void foo() {\n"
" char str[10];\n"
" int i;\n"
" unsigned int u;\n"
" _snprintf_s(str, sizeof(str), _TRUNCATE, \"%d %u\", u, i, 0);\n"
"}\n", false, false, Settings::Win32A);
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) _snprintf_s format string requires 2 parameters but 3 are given.\n", errout.str());
check("void foo() {\n"
" wchar_t str[10];\n"
" int i;\n"
" unsigned int u;\n"
" _snwprintf_s(str, sizeof(str) / sizeof(wchar_t), _TRUNCATE, L\"%d %u\", u, i, 0);\n"
"}\n", false, false, Settings::Win32W);
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) _snwprintf_s format string requires 2 parameters but 3 are given.\n", errout.str());
} }
void testMicrosoftSecureScanfArgument() { void testMicrosoftSecureScanfArgument() {
@ -2231,43 +2289,91 @@ private:
" int i;\n" " int i;\n"
" unsigned int u;\n" " unsigned int u;\n"
" TCHAR str[10];\n" " TCHAR str[10];\n"
" _tscanf_s(\"%s %d %u\", str, 10, &u, &i, 0)\n" " _tscanf_s(_T(\"%s %d %u %[a-z]\"), str, 10, &u, &i, str, 10, 0)\n"
"}\n", false, false, Settings::Win32A); "}\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" 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) %u in format string (no. 3) requires 'unsigned int *' but the argument type is 'int *'.\n"
"[test.cpp:5]: (warning) _tscanf_s format string requires 4 parameters but 5 are given.\n", errout.str()); "[test.cpp:5]: (warning) _tscanf_s format string requires 6 parameters but 7 are given.\n", errout.str());
check("void foo() {\n" check("void foo() {\n"
" int i;\n" " int i;\n"
" unsigned int u;\n" " unsigned int u;\n"
" TCHAR str[10];\n" " TCHAR str[10];\n"
" _tscanf_s(\"%s %d %u\", str, 10, &u, &i, 0)\n" " _tscanf_s(_T(\"%s %d %u %[a-z]\"), str, 10, &u, &i, str, 10, 0)\n"
"}\n", false, false, Settings::Win32W); "}\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" 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) %u in format string (no. 3) requires 'unsigned int *' but the argument type is 'int *'.\n"
"[test.cpp:5]: (warning) _tscanf_s format string requires 4 parameters but 5 are given.\n", errout.str()); "[test.cpp:5]: (warning) _tscanf_s format string requires 6 parameters but 7 are given.\n", errout.str());
check("void foo() {\n"
" int i;\n"
" unsigned int u;\n"
" char str[10];\n"
" scanf_s(\"%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) scanf_s format string requires 6 parameters but 7 are given.\n", errout.str());
check("void foo() {\n"
" int i;\n"
" unsigned int u;\n"
" wchar_t str[10];\n"
" wscanf_s(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) wscanf_s format string requires 6 parameters but 7 are given.\n", errout.str());
check("void foo() {\n" check("void foo() {\n"
" TCHAR txt[100];\n" " TCHAR txt[100];\n"
" int i;\n" " int i;\n"
" unsigned int u;\n" " unsigned int u;\n"
" TCHAR str[10];\n" " TCHAR str[10];\n"
" _stscanf_s(txt, \"%s %d %u\", str, 10, &u, &i, 0)\n" " _stscanf_s(txt, _T(\"%s %d %u %[a-z]\"), str, 10, &u, &i, str, 10, 0)\n"
"}\n", false, false, Settings::Win32A); "}\n", false, false, Settings::Win32A);
ASSERT_EQUALS("[test.cpp:6]: (warning) %d in format string (no. 2) requires 'int *' but the argument type is 'unsigned int *'.\n" ASSERT_EQUALS("[test.cpp:6]: (warning) %d in format string (no. 2) requires 'int *' but the argument type is 'unsigned 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) %u in format string (no. 3) requires 'unsigned int *' but the argument type is 'int *'.\n"
"[test.cpp:6]: (warning) _stscanf_s format string requires 4 parameters but 5 are given.\n", errout.str()); "[test.cpp:6]: (warning) _stscanf_s format string requires 6 parameters but 7 are given.\n", errout.str());
check("void foo() {\n" check("void foo() {\n"
" TCHAR txt[100];\n" " TCHAR txt[100];\n"
" int i;\n" " int i;\n"
" unsigned int u;\n" " unsigned int u;\n"
" TCHAR str[10];\n" " TCHAR str[10];\n"
" _stscanf_s(txt, \"%s %d %u\", str, 10, &u, &i, 0)\n" " _stscanf_s(txt, _T(\"%s %d %u %[a-z]\"), str, 10, &u, &i, str, 10, 0)\n"
"}\n", false, false, Settings::Win32W); "}\n", false, false, Settings::Win32W);
ASSERT_EQUALS("[test.cpp:6]: (warning) %d in format string (no. 2) requires 'int *' but the argument type is 'unsigned int *'.\n" ASSERT_EQUALS("[test.cpp:6]: (warning) %d in format string (no. 2) requires 'int *' but the argument type is 'unsigned 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) %u in format string (no. 3) requires 'unsigned int *' but the argument type is 'int *'.\n"
"[test.cpp:6]: (warning) _stscanf_s format string requires 4 parameters but 5 are given.\n", errout.str()); "[test.cpp:6]: (warning) _stscanf_s format string requires 6 parameters but 7 are given.\n", errout.str());
check("void foo() {\n"
" char txt[100];\n"
" int i;\n"
" unsigned int u;\n"
" char str[10];\n"
" sscanf_s(txt, \"%s %d %u %[a-z]\", str, 10, &u, &i, str, 10, 0)\n"
"}\n", false, false, Settings::Win32A);
ASSERT_EQUALS("[test.cpp:6]: (warning) %d in format string (no. 2) requires 'int *' but the argument type is 'unsigned 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) sscanf_s format string requires 6 parameters but 7 are given.\n", errout.str());
check("void foo() {\n"
" wchar_t txt[100];\n"
" int i;\n"
" unsigned int u;\n"
" wchar_t str[10];\n"
" swscanf_s(txt, L\"%s %d %u %[a-z]\", str, 10, &u, &i, str, 10, 0)\n"
"}\n", false, false, Settings::Win32W);
ASSERT_EQUALS("[test.cpp:6]: (warning) %d in format string (no. 2) requires 'int *' but the argument type is 'unsigned 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());
check("void foo() {\n"
" WCHAR msStr1[5] = {0};\n"
" wscanf_s(L\"%4[^-]\", msStr1, _countof(msStr1));\n"
"}\n", false, false, Settings::Win32W);
ASSERT_EQUALS("", errout.str());
} }
void testlibrarycfg() { void testlibrarycfg() {