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