CheckIO fixes. Ticket: #5051

This commit is contained in:
Robert Reif 2013-10-04 17:30:55 +02:00 committed by Daniel Marjamäki
parent a8cf8f0984
commit 6c06cdd24d
5 changed files with 101 additions and 39 deletions

View File

@ -403,6 +403,44 @@ void CheckIO::invalidScanfError(const Token *tok, bool portability)
// printf("%u%s", 1); // Too few arguments // printf("%u%s", 1); // Too few arguments
// printf("", 1); // Too much arguments // printf("", 1); // Too much arguments
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
static bool findFormat(unsigned int arg, const Token *firstArg,
const Token **formatStringTok, const Token **formatArgTok)
{
const Token* argTok = firstArg;
for (unsigned int i = 0; i < arg && argTok; ++i)
argTok = argTok->nextArgument();
if (Token::Match(argTok, "%str% [,)]")) {
*formatArgTok = argTok->nextArgument();
*formatStringTok = argTok;
return true;
} else if (Token::Match(argTok, "%var% [,)]") &&
(argTok->variable() &&
Token::Match(argTok->variable()->typeStartToken(), "char|wchar_t") &&
(argTok->variable()->isPointer() ||
(argTok->variable()->dimensions().size() == 1 &&
argTok->variable()->dimensionKnown(0) &&
argTok->variable()->dimension(0) != 0)))) {
*formatArgTok = argTok->nextArgument();
*formatStringTok = 0;
if (argTok->variable()) {
const Token *varTok = argTok->variable()->nameToken();
if (Token::Match(varTok, "%var% ; %var% = %str% ;") &&
varTok->str() == varTok->strAt(2) &&
Token::Match(varTok->tokAt(-4), "const char|wchar_t * const")) {
*formatStringTok = varTok->tokAt(4);
} else if (Token::Match(varTok, "%var% [ %num% ] = %str% ;") &&
Token::Match(varTok->tokAt(-2), "const char|wchar_t")) {
*formatStringTok = varTok->tokAt(5);
}
}
return true;
}
return false;
}
void CheckIO::checkWrongPrintfScanfArguments() void CheckIO::checkWrongPrintfScanfArguments()
{ {
const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase(); const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase();
@ -416,6 +454,7 @@ void CheckIO::checkWrongPrintfScanfArguments()
if (!tok->isName()) continue; if (!tok->isName()) continue;
const Token* argListTok = 0; // Points to first va_list argument const Token* argListTok = 0; // Points to first va_list argument
const Token* formatStringTok = 0; // Points to format string token
std::string formatString; std::string formatString;
if (Token::Match(tok->next(), "( %any%")) { if (Token::Match(tok->next(), "( %any%")) {
@ -423,7 +462,7 @@ void CheckIO::checkWrongPrintfScanfArguments()
int argnr = 1; int argnr = 1;
while (arg) { while (arg) {
if (Token::Match(arg, "%str% [,)]") && _settings->library.isargformatstr(tok->str(),argnr)) { if (Token::Match(arg, "%str% [,)]") && _settings->library.isargformatstr(tok->str(),argnr)) {
formatString = arg->str(); formatStringTok = arg;
if (arg->strAt(1) == ",") if (arg->strAt(1) == ",")
argListTok = arg->tokAt(2); argListTok = arg->tokAt(2);
else else
@ -436,61 +475,57 @@ void CheckIO::checkWrongPrintfScanfArguments()
} }
} }
if (!formatString.empty()) { if (formatStringTok) {
/* formatstring found in library */ /* formatstring found in library */
} else if (Token::Match(tok, "printf|scanf|wprintf|wscanf ( %str%") || } else if (Token::Match(tok, "printf|scanf|wprintf|wscanf ( %str%") ||
(windows && (Token::Match(tok, "printf_s|wprintf_s|scanf_s|wscanf_s ( %str%") || (windows && (Token::Match(tok, "printf_s|wprintf_s|scanf_s|wscanf_s ( %str%") ||
(Token::Match(tok, "Format|AppendFormat ( %str%") && (Token::Match(tok, "Format|AppendFormat ( %str%") &&
Token::Match(tok->tokAt(-2), "%var% .") && tok->tokAt(-2)->variable() && Token::Match(tok->tokAt(-2), "%var% .") && tok->tokAt(-2)->variable() &&
tok->tokAt(-2)->variable()->typeStartToken()->str() == "CString")))) { tok->tokAt(-2)->variable()->typeStartToken()->str() == "CString")))) {
// Find first parameter and format string
formatString = tok->strAt(2); if (!findFormat(0, tok->tokAt(2), &formatStringTok, &argListTok))
if (tok->strAt(3) == ",") {
argListTok = tok->tokAt(4);
} else if (tok->strAt(3) == ")") {
argListTok = 0;
} else {
continue; continue;
}
} else if (Token::Match(tok, "sprintf|fprintf|sscanf|fscanf|swscanf|fwprintf|fwscanf ( %any%") || } else if (Token::Match(tok, "sprintf|fprintf|sscanf|fscanf|swscanf|fwprintf|fwscanf ( %any%") ||
(Token::simpleMatch(tok, "swprintf (") && Token::Match(tok->tokAt(2)->nextArgument(), "%str%")) || (Token::simpleMatch(tok, "swprintf (") && Token::Match(tok->tokAt(2)->nextArgument(), "%str%")) ||
(windows && Token::Match(tok, "sscanf_s|swscanf_s|fscanf_s|fwscanf_s|fprintf_s|fwprintf_s ( %any%"))) { (windows && Token::Match(tok, "sscanf_s|swscanf_s|fscanf_s|fwscanf_s|fprintf_s|fwprintf_s ( %any%"))) {
const Token* formatStringTok = tok->tokAt(2)->nextArgument(); // Find second parameter (format string) // Find second parameter and format string
if (Token::Match(formatStringTok, "%str% [,)]")) { if (!findFormat(1, tok->tokAt(2), &formatStringTok, &argListTok))
argListTok = formatStringTok->nextArgument(); // Find third parameter (first argument of va_args)
formatString = formatStringTok->str();
} else {
continue; continue;
}
} else if (Token::Match(tok, "snprintf|fnprintf (") || } else if (Token::Match(tok, "snprintf|fnprintf (") ||
(Token::simpleMatch(tok, "swprintf (") && !Token::Match(tok->tokAt(2)->nextArgument(), "%str%")) || (windows && Token::Match(tok, "_snprintf|_snwprintf (")) ||
(windows && Token::Match(tok, "sprintf_s|swprintf_s ("))) { (Token::simpleMatch(tok, "swprintf (") && !Token::Match(tok->tokAt(2)->nextArgument(), "%str%"))) {
const Token* formatStringTok = tok->tokAt(2); // Find third parameter and format string
for (int i = 0; i < 2 && formatStringTok; i++) { if (!findFormat(2, tok->tokAt(2), &formatStringTok, &argListTok))
formatStringTok = formatStringTok->nextArgument(); // Find third parameter (format string)
}
if (Token::Match(formatStringTok, "%str% [,)]")) {
argListTok = formatStringTok->nextArgument(); // Find fourth parameter (first argument of va_args)
formatString = formatStringTok->str();
} else {
continue; continue;
} else if (windows && Token::Match(tok, "sprintf_s|swprintf_s (")) {
// template <size_t size> int sprintf_s(char (&buffer)[size], const char *format, ...);
if (findFormat(1, tok->tokAt(2), &formatStringTok, &argListTok)) {
if (!formatStringTok)
continue;
}
// int sprintf_s(char *buffer, size_t sizeOfBuffer, const char *format, ...);
else if (findFormat(2, tok->tokAt(2), &formatStringTok, &argListTok)) {
if (!formatStringTok)
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); // template <size_t size> int _snprintf_s(char (&buffer)[size], size_t count, const char *format, ...);
for (int i = 0; i < 3 && formatStringTok; i++) { if (findFormat(2, tok->tokAt(2), &formatStringTok, &argListTok)) {
formatStringTok = formatStringTok->nextArgument(); // Find forth parameter (format string) if (!formatStringTok)
continue;
} }
if (Token::Match(formatStringTok, "%str% [,)]")) { // int _snprintf_s(char *buffer, size_t sizeOfBuffer, size_t count, const char *format, ...);
argListTok = formatStringTok->nextArgument(); // Find fourth parameter (first argument of va_args) else if (findFormat(3, tok->tokAt(2), &formatStringTok, &argListTok)) {
formatString = formatStringTok->str(); if (!formatStringTok)
} else { continue;
continue;
} }
} else { } else {
continue; continue;
} }
if (formatStringTok)
formatString = formatStringTok->str();
// Count format string parameters.. // Count format string parameters..
bool scanf_s = windows ? Token::Match(tok, "scanf_s|wscanf_s|sscanf_s|swscanf_s|fscanf_s|fwscanf_s") : false; bool scanf_s = windows ? Token::Match(tok, "scanf_s|wscanf_s|sscanf_s|swscanf_s|fscanf_s|fwscanf_s") : false;
bool scan = Token::Match(tok, "sscanf|fscanf|scanf|swscanf|fwscanf|wscanf") || scanf_s; bool scan = Token::Match(tok, "sscanf|fscanf|scanf|swscanf|fwscanf|wscanf") || scanf_s;

View File

@ -414,6 +414,14 @@ public:
return _dimensions[index_].num; return _dimensions[index_].num;
} }
/**
* Get array dimension known.
* @return length of dimension known
*/
bool dimensionKnown(std::size_t index_) const {
return _dimensions[index_].known;
}
private: private:
// only symbol database can change the type // only symbol database can change the type
friend class SymbolDatabase; friend class SymbolDatabase;

View File

@ -9669,7 +9669,7 @@ void Tokenizer::simplifyMicrosoftStringFunctions()
tok->str("sprintf"); tok->str("sprintf");
tok->originalName("_stprintf"); tok->originalName("_stprintf");
} else if (Token::simpleMatch(tok, "_sntprintf (")) { } else if (Token::simpleMatch(tok, "_sntprintf (")) {
tok->str("snprintf"); tok->str("_snprintf");
tok->originalName("_sntprintf"); tok->originalName("_sntprintf");
} else if (Token::simpleMatch(tok, "_ftscanf (")) { } else if (Token::simpleMatch(tok, "_ftscanf (")) {
tok->str("fscanf"); tok->str("fscanf");
@ -9751,7 +9751,7 @@ void Tokenizer::simplifyMicrosoftStringFunctions()
tok->str("swprintf"); tok->str("swprintf");
tok->originalName("_stprintf"); tok->originalName("_stprintf");
} else if (Token::simpleMatch(tok, "_sntprintf (")) { } else if (Token::simpleMatch(tok, "_sntprintf (")) {
tok->str("snwprintf"); tok->str("_snwprintf");
tok->originalName("_sntprintf"); tok->originalName("_sntprintf");
} else if (Token::simpleMatch(tok, "_ftscanf (")) { } else if (Token::simpleMatch(tok, "_ftscanf (")) {
tok->str("fwscanf"); tok->str("fwscanf");

View File

@ -2403,6 +2403,25 @@ private:
ASSERT_EQUALS("[test.cpp:4]: (warning) %d in format string (no. 1) requires 'int' but the argument type is 'unsigned int'.\n" 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) %u in format string (no. 2) requires 'unsigned int' but the argument type is 'int'.\n"
"[test.cpp:4]: (warning) fwprintf_s format string requires 2 parameters but 3 are given.\n", errout.str()); "[test.cpp:4]: (warning) fwprintf_s format string requires 2 parameters but 3 are given.\n", errout.str());
check("void foo() {\n"
" char lineBuffer [600];\n"
" const char * const format = \"%15s%17s%17s%17s%17s\n\";\n"
" sprintf_s(lineBuffer, format, \"type\", \"sum\", \"avg\", \"min\", \"max\");\n"
"}\n", false, false, Settings::Win32A);
ASSERT_EQUALS("", errout.str());
check("void foo() {\n"
" const char * const format1 = \"%15s%17s%17s%17s%17s\n\";\n"
" const char format2[] = \"%15s%17s%17s%17s%17s\n\";\n"
" const char * const format3 = format1;\n"
" sprintf_s(lineBuffer, format1, \"type\", \"sum\", \"avg\", \"min\", \"max\", 0);\n"
" sprintf_s(lineBuffer, format2, \"type\", \"sum\", \"avg\", \"min\", \"max\", 0);\n"
" sprintf_s(lineBuffer, format3, \"type\", \"sum\", \"avg\", \"min\", \"max\", 0);\n"
"}\n", false, false, Settings::Win32A);
ASSERT_EQUALS("[test.cpp:5]: (warning) sprintf_s format string requires 5 parameters but 6 are given.\n"
"[test.cpp:6]: (warning) sprintf_s format string requires 5 parameters but 6 are given.\n", errout.str());
} }
void testMicrosoftSecureScanfArgument() { void testMicrosoftSecureScanfArgument() {

View File

@ -8054,7 +8054,7 @@ private:
"char * d ; d = strdup ( str ) ; " "char * d ; d = strdup ( str ) ; "
"printf ( \"Hello world!\n\" ) ; " "printf ( \"Hello world!\n\" ) ; "
"sprintf ( dst , \"Hello!\n\" ) ; " "sprintf ( dst , \"Hello!\n\" ) ; "
"snprintf ( dst , sizeof ( dst ) / sizeof ( char ) , \"Hello world!\n\" ) ; " "_snprintf ( dst , sizeof ( dst ) / sizeof ( char ) , \"Hello world!\n\" ) ; "
"scanf ( \"%s\" , dst ) ; " "scanf ( \"%s\" , dst ) ; "
"sscanf ( dst , \"%s\" , dst ) ; " "sscanf ( dst , \"%s\" , dst ) ; "
"} " "} "
@ -8101,7 +8101,7 @@ private:
"wchar_t * d ; d = wcsdup ( str ) ; " "wchar_t * d ; d = wcsdup ( str ) ; "
"wprintf ( L\"Hello world!\n\" ) ; " "wprintf ( L\"Hello world!\n\" ) ; "
"swprintf ( dst , L\"Hello!\n\" ) ; " "swprintf ( dst , L\"Hello!\n\" ) ; "
"snwprintf ( dst , sizeof ( dst ) / sizeof ( wchar_t ) , L\"Hello world!\n\" ) ; " "_snwprintf ( dst , sizeof ( dst ) / sizeof ( wchar_t ) , L\"Hello world!\n\" ) ; "
"wscanf ( L\"%s\" , dst ) ; " "wscanf ( L\"%s\" , dst ) ; "
"swscanf ( dst , L\"%s\" , dst ) ; " "swscanf ( dst , L\"%s\" , dst ) ; "
"}"; "}";