Fixed #4920 (Microsoft ATL/MFC CString::Format argument checking)
This commit is contained in:
parent
497b3c38e2
commit
789aef7fde
|
@ -1310,6 +1310,26 @@
|
||||||
<function name="KeBugCheckEx">
|
<function name="KeBugCheckEx">
|
||||||
<noreturn>true</noreturn>
|
<noreturn>true</noreturn>
|
||||||
</function>
|
</function>
|
||||||
|
<!-- void CString::Format(LPCTSTR lpszFormat, ... ); -->
|
||||||
|
<function name="CString::Format">
|
||||||
|
<noreturn>false</noreturn>
|
||||||
|
<leak-ignore/>
|
||||||
|
<formatstr/>
|
||||||
|
<arg nr="1">
|
||||||
|
<formatstr/>
|
||||||
|
<not-uninit/>
|
||||||
|
</arg>
|
||||||
|
</function>
|
||||||
|
<!-- void CString::AppendFormat(LPCTSTR lpszFormat, ... ); -->
|
||||||
|
<function name="CString::AppendFormat">
|
||||||
|
<noreturn>false</noreturn>
|
||||||
|
<leak-ignore/>
|
||||||
|
<formatstr/>
|
||||||
|
<arg nr="1">
|
||||||
|
<formatstr/>
|
||||||
|
<not-uninit/>
|
||||||
|
</arg>
|
||||||
|
</function>
|
||||||
<function name="printf_s">
|
<function name="printf_s">
|
||||||
<noreturn>false</noreturn>
|
<noreturn>false</noreturn>
|
||||||
<leak-ignore/>
|
<leak-ignore/>
|
||||||
|
|
|
@ -505,29 +505,16 @@ void CheckIO::checkWrongPrintfScanfArguments()
|
||||||
bool scanf_s = false;
|
bool scanf_s = false;
|
||||||
int formatStringArgNo = -1;
|
int formatStringArgNo = -1;
|
||||||
|
|
||||||
if (tok->strAt(1) == "(" && _settings->library.formatstr_function(tok->str())) {
|
if (tok->strAt(1) == "(" && _settings->library.formatstr_function(tok)) {
|
||||||
const std::map<int, Library::ArgumentChecks>& argumentChecks = _settings->library.argumentChecks.at(tok->str());
|
formatStringArgNo = _settings->library.formatstr_argno(tok);
|
||||||
for (std::map<int, Library::ArgumentChecks>::const_iterator i = argumentChecks.cbegin(); i != argumentChecks.cend(); ++i) {
|
scan = _settings->library.formatstr_scan(tok);
|
||||||
if (i->second.formatstr) {
|
scanf_s = _settings->library.formatstr_secure(tok);
|
||||||
formatStringArgNo = i->first - 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
scan = _settings->library.formatstr_scan(tok->str());
|
|
||||||
scanf_s = _settings->library.formatstr_secure(tok->str());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (formatStringArgNo >= 0) {
|
if (formatStringArgNo >= 0) {
|
||||||
// formatstring found in library. Find format string and first argument belonging to format string.
|
// formatstring found in library. Find format string and first argument belonging to format string.
|
||||||
if (!findFormat(static_cast<unsigned int>(formatStringArgNo), tok->tokAt(2), &formatStringTok, &argListTok))
|
if (!findFormat(static_cast<unsigned int>(formatStringArgNo), tok->tokAt(2), &formatStringTok, &argListTok))
|
||||||
continue;
|
continue;
|
||||||
} else if (isWindows && Token::Match(tok, "Format|AppendFormat (") &&
|
|
||||||
Token::Match(tok->tokAt(-2), "%var% .") && tok->tokAt(-2)->variable() &&
|
|
||||||
tok->tokAt(-2)->variable()->typeStartToken()->str() == "CString") {
|
|
||||||
// Find second parameter and format string
|
|
||||||
if (!findFormat(0, tok->tokAt(2), &formatStringTok, &argListTok))
|
|
||||||
continue;
|
|
||||||
} else if (Token::simpleMatch(tok, "swprintf (") && Token::Match(tok->tokAt(2)->nextArgument(), "%str%")) {
|
} else if (Token::simpleMatch(tok, "swprintf (") && Token::Match(tok->tokAt(2)->nextArgument(), "%str%")) {
|
||||||
// Find third parameter and format string
|
// Find third parameter and format string
|
||||||
if (!findFormat(1, tok->tokAt(2), &formatStringTok, &argListTok))
|
if (!findFormat(1, tok->tokAt(2), &formatStringTok, &argListTok))
|
||||||
|
|
|
@ -934,6 +934,33 @@ const Library::WarnInfo* Library::getWarnInfo(const Token* ftok) const
|
||||||
return &i->second;
|
return &i->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Library::formatstr_function(const Token* ftok) const
|
||||||
|
{
|
||||||
|
return (!isNotLibraryFunction(ftok) &&
|
||||||
|
_formatstr.find(functionName(ftok)) != _formatstr.cend());
|
||||||
|
}
|
||||||
|
|
||||||
|
int Library::formatstr_argno(const Token* ftok) const
|
||||||
|
{
|
||||||
|
const std::map<int, Library::ArgumentChecks>& argumentChecksFunc = argumentChecks.at(functionName(ftok));
|
||||||
|
for (std::map<int, Library::ArgumentChecks>::const_iterator i = argumentChecksFunc.cbegin(); i != argumentChecksFunc.cend(); ++i) {
|
||||||
|
if (i->second.formatstr) {
|
||||||
|
return i->first - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Library::formatstr_scan(const Token* ftok) const
|
||||||
|
{
|
||||||
|
return _formatstr.at(functionName(ftok)).first;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Library::formatstr_secure(const Token* ftok) const
|
||||||
|
{
|
||||||
|
return _formatstr.at(functionName(ftok)).second;
|
||||||
|
}
|
||||||
|
|
||||||
bool Library::isUseRetVal(const Token* ftok) const
|
bool Library::isUseRetVal(const Token* ftok) const
|
||||||
{
|
{
|
||||||
return (!isNotLibraryFunction(ftok) &&
|
return (!isNotLibraryFunction(ftok) &&
|
||||||
|
|
|
@ -137,17 +137,13 @@ public:
|
||||||
return ((func->groupId > 0) && ((func->groupId & 1) == 1));
|
return ((func->groupId > 0) && ((func->groupId & 1) == 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool formatstr_function(const std::string& funcname) const {
|
bool formatstr_function(const Token* ftok) const;
|
||||||
return _formatstr.find(funcname) != _formatstr.cend();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool formatstr_scan(const std::string& funcname) const {
|
int formatstr_argno(const Token* ftok) const;
|
||||||
return _formatstr.at(funcname).first;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool formatstr_secure(const std::string& funcname) const {
|
bool formatstr_scan(const Token* ftok) const;
|
||||||
return _formatstr.at(funcname).second;
|
|
||||||
}
|
bool formatstr_secure(const Token* ftok) const;
|
||||||
|
|
||||||
std::set<std::string> use;
|
std::set<std::string> use;
|
||||||
std::set<std::string> leakignore;
|
std::set<std::string> leakignore;
|
||||||
|
|
|
@ -2474,9 +2474,11 @@ private:
|
||||||
" CString string;\n"
|
" CString string;\n"
|
||||||
" string.Format(\"%I32d\", u32);\n"
|
" string.Format(\"%I32d\", u32);\n"
|
||||||
" string.AppendFormat(\"%I32d\", u32);\n"
|
" string.AppendFormat(\"%I32d\", u32);\n"
|
||||||
|
" CString::Format(\"%I32d\", u32);\n"
|
||||||
"}", false, false, Settings::Win32A);
|
"}", false, false, Settings::Win32A);
|
||||||
ASSERT_EQUALS("[test.cpp:4]: (warning) %I32d in format string (no. 1) requires '__int32' but the argument type is 'unsigned __int32 {aka unsigned int}'.\n"
|
ASSERT_EQUALS("[test.cpp:4]: (warning) %I32d in format string (no. 1) requires '__int32' but the argument type is 'unsigned __int32 {aka unsigned int}'.\n"
|
||||||
"[test.cpp:5]: (warning) %I32d in format string (no. 1) requires '__int32' but the argument type is 'unsigned __int32 {aka unsigned int}'.\n", errout.str());
|
"[test.cpp:5]: (warning) %I32d in format string (no. 1) requires '__int32' but the argument type is 'unsigned __int32 {aka unsigned int}'.\n"
|
||||||
|
"[test.cpp:6]: (warning) %I32d in format string (no. 1) requires '__int32' but the argument type is 'unsigned __int32 {aka unsigned int}'.\n", errout.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void testMicrosoftSecurePrintfArgument() {
|
void testMicrosoftSecurePrintfArgument() {
|
||||||
|
|
Loading…
Reference in New Issue