From 6c06cdd24d4621c03de27bf2ad61cb673d0e984c Mon Sep 17 00:00:00 2001 From: Robert Reif Date: Fri, 4 Oct 2013 17:30:55 +0200 Subject: [PATCH] CheckIO fixes. Ticket: #5051 --- lib/checkio.cpp | 105 ++++++++++++++++++++++++++++-------------- lib/symboldatabase.h | 8 ++++ lib/tokenize.cpp | 4 +- test/testio.cpp | 19 ++++++++ test/testtokenize.cpp | 4 +- 5 files changed, 101 insertions(+), 39 deletions(-) diff --git a/lib/checkio.cpp b/lib/checkio.cpp index 8ffcfa081..caee0efbe 100644 --- a/lib/checkio.cpp +++ b/lib/checkio.cpp @@ -403,6 +403,44 @@ void CheckIO::invalidScanfError(const Token *tok, bool portability) // printf("%u%s", 1); // Too few 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() { const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase(); @@ -416,6 +454,7 @@ void CheckIO::checkWrongPrintfScanfArguments() if (!tok->isName()) continue; const Token* argListTok = 0; // Points to first va_list argument + const Token* formatStringTok = 0; // Points to format string token std::string formatString; if (Token::Match(tok->next(), "( %any%")) { @@ -423,7 +462,7 @@ void CheckIO::checkWrongPrintfScanfArguments() int argnr = 1; while (arg) { if (Token::Match(arg, "%str% [,)]") && _settings->library.isargformatstr(tok->str(),argnr)) { - formatString = arg->str(); + formatStringTok = arg; if (arg->strAt(1) == ",") argListTok = arg->tokAt(2); else @@ -436,61 +475,57 @@ void CheckIO::checkWrongPrintfScanfArguments() } } - if (!formatString.empty()) { + if (formatStringTok) { /* formatstring found in library */ } else if (Token::Match(tok, "printf|scanf|wprintf|wscanf ( %str%") || (windows && (Token::Match(tok, "printf_s|wprintf_s|scanf_s|wscanf_s ( %str%") || (Token::Match(tok, "Format|AppendFormat ( %str%") && Token::Match(tok->tokAt(-2), "%var% .") && tok->tokAt(-2)->variable() && tok->tokAt(-2)->variable()->typeStartToken()->str() == "CString")))) { - - formatString = tok->strAt(2); - if (tok->strAt(3) == ",") { - argListTok = tok->tokAt(4); - } else if (tok->strAt(3) == ")") { - argListTok = 0; - } else { + // Find first parameter and format string + if (!findFormat(0, tok->tokAt(2), &formatStringTok, &argListTok)) continue; - } } else if (Token::Match(tok, "sprintf|fprintf|sscanf|fscanf|swscanf|fwprintf|fwscanf ( %any%") || (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%"))) { - const Token* formatStringTok = tok->tokAt(2)->nextArgument(); // Find second parameter (format string) - if (Token::Match(formatStringTok, "%str% [,)]")) { - argListTok = formatStringTok->nextArgument(); // Find third parameter (first argument of va_args) - formatString = formatStringTok->str(); - } else { + // Find second parameter and format string + if (!findFormat(1, tok->tokAt(2), &formatStringTok, &argListTok)) continue; - } } else if (Token::Match(tok, "snprintf|fnprintf (") || - (Token::simpleMatch(tok, "swprintf (") && !Token::Match(tok->tokAt(2)->nextArgument(), "%str%")) || - (windows && Token::Match(tok, "sprintf_s|swprintf_s ("))) { - const Token* formatStringTok = tok->tokAt(2); - for (int i = 0; i < 2 && formatStringTok; i++) { - 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 { + (windows && Token::Match(tok, "_snprintf|_snwprintf (")) || + (Token::simpleMatch(tok, "swprintf (") && !Token::Match(tok->tokAt(2)->nextArgument(), "%str%"))) { + // Find third parameter and format string + if (!findFormat(2, tok->tokAt(2), &formatStringTok, &argListTok)) continue; + } else if (windows && Token::Match(tok, "sprintf_s|swprintf_s (")) { + // template 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 (")) { - const Token* formatStringTok = tok->tokAt(2); - for (int i = 0; i < 3 && formatStringTok; i++) { - formatStringTok = formatStringTok->nextArgument(); // Find forth parameter (format string) + // template int _snprintf_s(char (&buffer)[size], size_t count, const char *format, ...); + if (findFormat(2, tok->tokAt(2), &formatStringTok, &argListTok)) { + if (!formatStringTok) + continue; } - if (Token::Match(formatStringTok, "%str% [,)]")) { - argListTok = formatStringTok->nextArgument(); // Find fourth parameter (first argument of va_args) - formatString = formatStringTok->str(); - } else { - continue; + // int _snprintf_s(char *buffer, size_t sizeOfBuffer, size_t count, const char *format, ...); + else if (findFormat(3, tok->tokAt(2), &formatStringTok, &argListTok)) { + if (!formatStringTok) + continue; } - } else { continue; } + if (formatStringTok) + formatString = formatStringTok->str(); + // 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 scan = Token::Match(tok, "sscanf|fscanf|scanf|swscanf|fwscanf|wscanf") || scanf_s; diff --git a/lib/symboldatabase.h b/lib/symboldatabase.h index e009a6a5e..f4b9f1fc0 100644 --- a/lib/symboldatabase.h +++ b/lib/symboldatabase.h @@ -414,6 +414,14 @@ public: 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: // only symbol database can change the type friend class SymbolDatabase; diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index aebd7030b..2803346fd 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -9669,7 +9669,7 @@ void Tokenizer::simplifyMicrosoftStringFunctions() tok->str("sprintf"); tok->originalName("_stprintf"); } else if (Token::simpleMatch(tok, "_sntprintf (")) { - tok->str("snprintf"); + tok->str("_snprintf"); tok->originalName("_sntprintf"); } else if (Token::simpleMatch(tok, "_ftscanf (")) { tok->str("fscanf"); @@ -9751,7 +9751,7 @@ void Tokenizer::simplifyMicrosoftStringFunctions() tok->str("swprintf"); tok->originalName("_stprintf"); } else if (Token::simpleMatch(tok, "_sntprintf (")) { - tok->str("snwprintf"); + tok->str("_snwprintf"); tok->originalName("_sntprintf"); } else if (Token::simpleMatch(tok, "_ftscanf (")) { tok->str("fwscanf"); diff --git a/test/testio.cpp b/test/testio.cpp index 56b2837b8..116d3d28e 100644 --- a/test/testio.cpp +++ b/test/testio.cpp @@ -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" "[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()); + + 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() { diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp index ac4518f32..1eb059a45 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -8054,7 +8054,7 @@ private: "char * d ; d = strdup ( str ) ; " "printf ( \"Hello world!\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 ) ; " "sscanf ( dst , \"%s\" , dst ) ; " "} " @@ -8101,7 +8101,7 @@ private: "wchar_t * d ; d = wcsdup ( str ) ; " "wprintf ( L\"Hello world!\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 ) ; " "swscanf ( dst , L\"%s\" , dst ) ; " "}";