CheckIO fixes. Ticket: #5051
This commit is contained in:
parent
a8cf8f0984
commit
6c06cdd24d
105
lib/checkio.cpp
105
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 <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 (")) {
|
||||
const Token* formatStringTok = tok->tokAt(2);
|
||||
for (int i = 0; i < 3 && formatStringTok; i++) {
|
||||
formatStringTok = formatStringTok->nextArgument(); // Find forth parameter (format string)
|
||||
// template <size_t size> 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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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 ) ; "
|
||||
"}";
|
||||
|
|
Loading…
Reference in New Issue