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">
|
||||
<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/>
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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) &&
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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() {
|
||||
|
|
Loading…
Reference in New Issue