Fixed #4920 (Microsoft ATL/MFC CString::Format argument checking)

This commit is contained in:
Daniel Marjamäki 2016-08-19 17:36:27 +02:00
parent 497b3c38e2
commit 789aef7fde
5 changed files with 59 additions and 27 deletions

View File

@ -1310,6 +1310,26 @@
<function name="KeBugCheckEx">
<noreturn>true</noreturn>
</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">
<noreturn>false</noreturn>
<leak-ignore/>

View File

@ -505,29 +505,16 @@ void CheckIO::checkWrongPrintfScanfArguments()
bool scanf_s = false;
int formatStringArgNo = -1;
if (tok->strAt(1) == "(" && _settings->library.formatstr_function(tok->str())) {
const std::map<int, Library::ArgumentChecks>& argumentChecks = _settings->library.argumentChecks.at(tok->str());
for (std::map<int, Library::ArgumentChecks>::const_iterator i = argumentChecks.cbegin(); i != argumentChecks.cend(); ++i) {
if (i->second.formatstr) {
formatStringArgNo = i->first - 1;
break;
}
}
scan = _settings->library.formatstr_scan(tok->str());
scanf_s = _settings->library.formatstr_secure(tok->str());
if (tok->strAt(1) == "(" && _settings->library.formatstr_function(tok)) {
formatStringArgNo = _settings->library.formatstr_argno(tok);
scan = _settings->library.formatstr_scan(tok);
scanf_s = _settings->library.formatstr_secure(tok);
}
if (formatStringArgNo >= 0) {
// 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))
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%")) {
// Find third parameter and format string
if (!findFormat(1, tok->tokAt(2), &formatStringTok, &argListTok))

View File

@ -934,6 +934,33 @@ const Library::WarnInfo* Library::getWarnInfo(const Token* ftok) const
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
{
return (!isNotLibraryFunction(ftok) &&

View File

@ -137,17 +137,13 @@ public:
return ((func->groupId > 0) && ((func->groupId & 1) == 1));
}
bool formatstr_function(const std::string& funcname) const {
return _formatstr.find(funcname) != _formatstr.cend();
}
bool formatstr_function(const Token* ftok) const;
bool formatstr_scan(const std::string& funcname) const {
return _formatstr.at(funcname).first;
}
int formatstr_argno(const Token* ftok) const;
bool formatstr_secure(const std::string& funcname) const {
return _formatstr.at(funcname).second;
}
bool formatstr_scan(const Token* ftok) const;
bool formatstr_secure(const Token* ftok) const;
std::set<std::string> use;
std::set<std::string> leakignore;

View File

@ -2474,9 +2474,11 @@ private:
" CString string;\n"
" string.Format(\"%I32d\", u32);\n"
" string.AppendFormat(\"%I32d\", u32);\n"
" CString::Format(\"%I32d\", u32);\n"
"}", 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"
"[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() {