CheckIO: Fixed false positives when using _snprintf_s and _snwprintf_s. Ticket: #5057
This commit is contained in:
parent
f0cbeb5233
commit
cc6745fef6
|
@ -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)
|
||||||
|
|
|
@ -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");
|
||||||
|
|
122
test/testio.cpp
122
test/testio.cpp
|
@ -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() {
|
||||||
|
|
Loading…
Reference in New Issue