Fixed #5079 (CheckIO::checkFileUsage doesn't support wide char and microsoft functions)

This commit is contained in:
Robert Reif 2014-03-12 19:22:44 +01:00 committed by Daniel Marjamäki
parent b1dc51ba9c
commit cb1fc06a80
3 changed files with 211 additions and 22 deletions

View File

@ -97,9 +97,10 @@ struct Filepointer {
void CheckIO::checkFileUsage() void CheckIO::checkFileUsage()
{ {
static const char* _whitelist[] = { static const char* _whitelist[] = {
"clearerr", "feof", "ferror", "fgetpos", "ftell", "setbuf", "setvbuf", "ungetc" "clearerr", "feof", "ferror", "fgetpos", "ftell", "setbuf", "setvbuf", "ungetc", "ungetwc"
}; };
static const std::set<std::string> whitelist(_whitelist, _whitelist + sizeof(_whitelist)/sizeof(*_whitelist)); static const std::set<std::string> whitelist(_whitelist, _whitelist + sizeof(_whitelist)/sizeof(*_whitelist));
const bool windows = _settings->isWindowsPlatform();
std::map<unsigned int, Filepointer> filepointers; std::map<unsigned int, Filepointer> filepointers;
@ -147,7 +148,9 @@ void CheckIO::checkFileUsage()
i->second.op_indent = 0; i->second.op_indent = 0;
i->second.lastOperation = Filepointer::UNKNOWN_OP; i->second.lastOperation = Filepointer::UNKNOWN_OP;
} }
} else if (tok->varId() && Token::Match(tok, "%var% =") && (tok->strAt(2) != "fopen" && tok->strAt(2) != "freopen" && tok->strAt(2) != "tmpfile")) { } else if (tok->varId() && Token::Match(tok, "%var% =") &&
(tok->strAt(2) != "fopen" && tok->strAt(2) != "freopen" && tok->strAt(2) != "tmpfile" &&
(windows ? (tok->str() != "_wfopen" && tok->str() != "_wfreopen") : true))) {
std::map<unsigned int, Filepointer>::iterator i = filepointers.find(tok->varId()); std::map<unsigned int, Filepointer>::iterator i = filepointers.find(tok->varId());
if (i != filepointers.end()) { if (i != filepointers.end()) {
i->second.mode = UNKNOWN; i->second.mode = UNKNOWN;
@ -158,7 +161,9 @@ void CheckIO::checkFileUsage()
const Token* fileTok = 0; const Token* fileTok = 0;
Filepointer::Operation operation = Filepointer::NONE; Filepointer::Operation operation = Filepointer::NONE;
if ((tok->str() == "fopen" || tok->str() == "freopen" || tok->str() == "tmpfile") && tok->strAt(-1) == "=") { if ((tok->str() == "fopen" || tok->str() == "freopen" || tok->str() == "tmpfile" ||
(windows && (tok->str() == "_wfopen" || tok->str() == "_wfreopen"))) &&
tok->strAt(-1) == "=") {
if (tok->str() != "tmpfile") { if (tok->str() != "tmpfile") {
const Token* modeTok = tok->tokAt(2)->nextArgument(); const Token* modeTok = tok->tokAt(2)->nextArgument();
if (modeTok && modeTok->type() == Token::eString) if (modeTok && modeTok->type() == Token::eString)
@ -167,21 +172,34 @@ void CheckIO::checkFileUsage()
mode = "wb+"; mode = "wb+";
fileTok = tok->tokAt(-2); fileTok = tok->tokAt(-2);
operation = Filepointer::OPEN; operation = Filepointer::OPEN;
} else if (tok->str() == "rewind" || tok->str() == "fseek" || tok->str() == "fsetpos" || tok->str() == "fflush") { } else if (windows && Token::Match(tok, "fopen_s|freopen_s|_wfopen_s|_wfreopen_s ( & %var%")) {
const Token* modeTok = tok->tokAt(2)->nextArgument()->nextArgument();
if (modeTok && modeTok->type() == Token::eString)
mode = modeTok->strValue();
fileTok = tok->tokAt(3);
operation = Filepointer::OPEN;
} else if ((tok->str() == "rewind" || tok->str() == "fseek" || tok->str() == "fsetpos" || tok->str() == "fflush") ||
(windows && tok->str() == "_fseeki64")) {
if (Token::simpleMatch(tok, "fflush ( stdin )")) if (Token::simpleMatch(tok, "fflush ( stdin )"))
fflushOnInputStreamError(tok, tok->strAt(2)); fflushOnInputStreamError(tok, tok->strAt(2));
else { else {
fileTok = tok->tokAt(2); fileTok = tok->tokAt(2);
operation = Filepointer::POSITIONING; operation = Filepointer::POSITIONING;
} }
} else if (tok->str() == "fgetc" || tok->str() == "fgets" || tok->str() == "fread" || tok->str() == "fscanf" || tok->str() == "getc") { } else if (tok->str() == "fgetc" || tok->str() == "fgetwc" ||
if (tok->str() == "fscanf") tok->str() == "fgets" || tok->str() == "fgetws" || tok->str() == "fread" ||
tok->str() == "fscanf" || tok->str() == "fwscanf" || tok->str() == "getc" ||
(windows && (tok->str() == "fscanf_s" || tok->str() == "fwscanf_s"))) {
if (tok->str().find("scanf") != std::string::npos)
fileTok = tok->tokAt(2); fileTok = tok->tokAt(2);
else else
fileTok = tok->linkAt(1)->previous(); fileTok = tok->linkAt(1)->previous();
operation = Filepointer::READ; operation = Filepointer::READ;
} else if (tok->str() == "fputc" || tok->str() == "fputs" || tok->str() == "fwrite" || tok->str() == "fprintf" || tok->str() == "putcc") { } else if (tok->str() == "fputc" || tok->str() == "fputwc" ||
if (tok->str() == "fprintf") tok->str() == "fputs" || tok->str() == "fputws" || tok->str() == "fwrite" ||
tok->str() == "fprintf" || tok->str() == "fwprintf" || tok->str() == "putcc" ||
(windows && (tok->str() == "fprintf_s" || tok->str() == "fwprintf_s"))) {
if (tok->str().find("printf") != std::string::npos)
fileTok = tok->tokAt(2); fileTok = tok->tokAt(2);
else else
fileTok = tok->linkAt(1)->previous(); fileTok = tok->linkAt(1)->previous();
@ -191,7 +209,7 @@ void CheckIO::checkFileUsage()
operation = Filepointer::CLOSE; operation = Filepointer::CLOSE;
} else if (whitelist.find(tok->str()) != whitelist.end()) { } else if (whitelist.find(tok->str()) != whitelist.end()) {
fileTok = tok->tokAt(2); fileTok = tok->tokAt(2);
if (tok->str() == "ungetc" && fileTok) if ((tok->str() == "ungetc" || tok->str() == "ungetwc") && fileTok)
fileTok = fileTok->nextArgument(); fileTok = fileTok->nextArgument();
operation = Filepointer::UNIMPORTANT; operation = Filepointer::UNIMPORTANT;
} else if (!Token::Match(tok, "if|for|while|catch|switch")) { } else if (!Token::Match(tok, "if|for|while|catch|switch")) {
@ -313,6 +331,7 @@ void CheckIO::invalidScanf()
if (!_settings->isEnabled("warning") && !_settings->isEnabled("portability")) if (!_settings->isEnabled("warning") && !_settings->isEnabled("portability"))
return; return;
const bool windows = _settings->isWindowsPlatform();
const SymbolDatabase * const symbolDatabase = _tokenizer->getSymbolDatabase(); const SymbolDatabase * const symbolDatabase = _tokenizer->getSymbolDatabase();
std::size_t functions = symbolDatabase->functionScopes.size(); std::size_t functions = symbolDatabase->functionScopes.size();
for (std::size_t j = 0; j < functions; ++j) { for (std::size_t j = 0; j < functions; ++j) {
@ -348,7 +367,7 @@ void CheckIO::invalidScanf()
else if (std::isalpha(formatstr[i]) || formatstr[i] == '[') { else if (std::isalpha(formatstr[i]) || formatstr[i] == '[') {
if ((formatstr[i] == 's' || formatstr[i] == '[' || formatstr[i] == 'S' || (formatstr[i] == 'l' && formatstr[i+1] == 's')) && _settings->isEnabled("warning")) // #3490 - field width limits are only necessary for string input if ((formatstr[i] == 's' || formatstr[i] == '[' || formatstr[i] == 'S' || (formatstr[i] == 'l' && formatstr[i+1] == 's')) && _settings->isEnabled("warning")) // #3490 - field width limits are only necessary for string input
invalidScanfError(tok, false); invalidScanfError(tok, false);
else if (formatstr[i] != 'n' && formatstr[i] != 'c' && _settings->platformType != Settings::Win32A && _settings->platformType != Settings::Win32W && _settings->platformType != Settings::Win64 && _settings->isEnabled("portability")) else if (formatstr[i] != 'n' && formatstr[i] != 'c' && !windows && _settings->isEnabled("portability"))
invalidScanfError(tok, true); // Warn about libc bug in versions prior to 2.13-25 invalidScanfError(tok, true); // Warn about libc bug in versions prior to 2.13-25
format = false; format = false;
} }
@ -444,8 +463,8 @@ static bool findFormat(unsigned int arg, const Token *firstArg,
void CheckIO::checkWrongPrintfScanfArguments() void CheckIO::checkWrongPrintfScanfArguments()
{ {
const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase(); const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase();
bool warning = _settings->isEnabled("warning"); const bool warning = _settings->isEnabled("warning");
bool windows = _settings->isWindowsPlatform(); const bool windows = _settings->isWindowsPlatform();
std::size_t functions = symbolDatabase->functionScopes.size(); std::size_t functions = symbolDatabase->functionScopes.size();
for (std::size_t j = 0; j < functions; ++j) { for (std::size_t j = 0; j < functions; ++j) {

View File

@ -9535,32 +9535,58 @@ void Tokenizer::simplifyMicrosoftStringFunctions()
for (Token *tok = list.front(); tok; tok = tok->next()) { for (Token *tok = list.front(); tok; tok = tok->next()) {
if (Token::simpleMatch(tok, "_topen (")) { if (Token::simpleMatch(tok, "_topen (")) {
tok->str("open"); tok->str("open");
tok->originalName("_topen");
} else if (Token::simpleMatch(tok, "_tsopen_s (")) {
tok->str("_sopen_s");
tok->originalName("_tsopen_s");
} else if (Token::simpleMatch(tok, "_tfopen (")) { } else if (Token::simpleMatch(tok, "_tfopen (")) {
tok->str("fopen"); tok->str("fopen");
tok->originalName("_tfopen");
} else if (Token::simpleMatch(tok, "_tfopen_s (")) {
tok->str("fopen_s");
tok->originalName("_tfopen_s");
} else if (Token::simpleMatch(tok, "_tfreopen (")) {
tok->str("_wfreopen");
tok->originalName("_tfreopen");
} else if (Token::simpleMatch(tok, "_tfreopen_s (")) {
tok->str("_wfreopen_s");
tok->originalName("_tfreopen_s");
} else if (Token::simpleMatch(tok, "_tcscat (")) { } else if (Token::simpleMatch(tok, "_tcscat (")) {
tok->str("strcat"); tok->str("strcat");
tok->originalName("_tcscat");
} else if (Token::simpleMatch(tok, "_tcschr (")) { } else if (Token::simpleMatch(tok, "_tcschr (")) {
tok->str("strchr"); tok->str("strchr");
tok->originalName("_tcschr");
} else if (Token::simpleMatch(tok, "_tcscmp (")) { } else if (Token::simpleMatch(tok, "_tcscmp (")) {
tok->str("strcmp"); tok->str("strcmp");
tok->originalName("_tcscmp");
} else if (Token::simpleMatch(tok, "_tcsdup (")) { } else if (Token::simpleMatch(tok, "_tcsdup (")) {
tok->str("strdup"); tok->str("strdup");
tok->originalName("_tcsdup");
} else if (Token::simpleMatch(tok, "_tcscpy (")) { } else if (Token::simpleMatch(tok, "_tcscpy (")) {
tok->str("strcpy"); tok->str("strcpy");
tok->originalName("_tcscpy");
} else if (Token::simpleMatch(tok, "_tcslen (")) { } else if (Token::simpleMatch(tok, "_tcslen (")) {
tok->str("strlen"); tok->str("strlen");
tok->originalName("_tcslen");
} else if (Token::simpleMatch(tok, "_tcsncat (")) { } else if (Token::simpleMatch(tok, "_tcsncat (")) {
tok->str("strncat"); tok->str("strncat");
tok->originalName("_tcscat");
} else if (Token::simpleMatch(tok, "_tcsncpy (")) { } else if (Token::simpleMatch(tok, "_tcsncpy (")) {
tok->str("strncpy"); tok->str("strncpy");
tok->originalName("_tcsncpy");
} else if (Token::simpleMatch(tok, "_tcsnlen (")) { } else if (Token::simpleMatch(tok, "_tcsnlen (")) {
tok->str("strnlen"); tok->str("strnlen");
tok->originalName("_tcslen");
} else if (Token::simpleMatch(tok, "_tcsrchr (")) { } else if (Token::simpleMatch(tok, "_tcsrchr (")) {
tok->str("strrchr"); tok->str("strrchr");
tok->originalName("_tcsrchr");
} else if (Token::simpleMatch(tok, "_tcsstr (")) { } else if (Token::simpleMatch(tok, "_tcsstr (")) {
tok->str("strstr"); tok->str("strstr");
tok->originalName("_tcsstr");
} else if (Token::simpleMatch(tok, "_tcstok (")) { } else if (Token::simpleMatch(tok, "_tcstok (")) {
tok->str("strtok"); tok->str("strtok");
tok->originalName("_tcstok");
} else if (Token::simpleMatch(tok, "_ftprintf (")) { } else if (Token::simpleMatch(tok, "_ftprintf (")) {
tok->str("fprintf"); tok->str("fprintf");
tok->originalName("_ftprintf"); tok->originalName("_ftprintf");
@ -9619,30 +9645,60 @@ void Tokenizer::simplifyMicrosoftStringFunctions()
} else if (_settings->platformType == Settings::Win32W || } else if (_settings->platformType == Settings::Win32W ||
_settings->platformType == Settings::Win64) { _settings->platformType == Settings::Win64) {
for (Token *tok = list.front(); tok; tok = tok->next()) { for (Token *tok = list.front(); tok; tok = tok->next()) {
if (Token::simpleMatch(tok, "_tcscat (")) { if (Token::simpleMatch(tok, "_topen (")) {
tok->str("_wopen");
tok->originalName("_topen");
} else if (Token::simpleMatch(tok, "_tsfopen_s (")) {
tok->str("_wsopen_s");
tok->originalName("_tsopen_s");
} else if (Token::simpleMatch(tok, "_tfopen (")) {
tok->str("_wfopen");
tok->originalName("_tfopen");
} else if (Token::simpleMatch(tok, "_tfopen_s (")) {
tok->str("_wfopen_s");
tok->originalName("_tfopen_s");
} else if (Token::simpleMatch(tok, "_tfreopen (")) {
tok->str("_wfreopen");
tok->originalName("_tfreopen");
} else if (Token::simpleMatch(tok, "_tfreopen_s (")) {
tok->str("_wfreopen_s");
tok->originalName("_tfreopen_s");
} else if (Token::simpleMatch(tok, "_tcscat (")) {
tok->str("wcscat"); tok->str("wcscat");
tok->originalName("_tcscat");
} else if (Token::simpleMatch(tok, "_tcschr (")) { } else if (Token::simpleMatch(tok, "_tcschr (")) {
tok->str("wcschr"); tok->str("wcschr");
tok->originalName("_tcschr");
} else if (Token::simpleMatch(tok, "_tcscmp (")) { } else if (Token::simpleMatch(tok, "_tcscmp (")) {
tok->str("wcscmp"); tok->str("wcscmp");
tok->originalName("_tcscmp");
} else if (Token::simpleMatch(tok, "_tcscpy (")) { } else if (Token::simpleMatch(tok, "_tcscpy (")) {
tok->str("wcscpy"); tok->str("wcscpy");
tok->originalName("_tcscpy");
} else if (Token::simpleMatch(tok, "_tcsdup (")) { } else if (Token::simpleMatch(tok, "_tcsdup (")) {
tok->str("wcsdup"); tok->str("wcsdup");
tok->originalName("_tcsdup");
} else if (Token::simpleMatch(tok, "_tcslen (")) { } else if (Token::simpleMatch(tok, "_tcslen (")) {
tok->str("wcslen"); tok->str("wcslen");
tok->originalName("_tcslen");
} else if (Token::simpleMatch(tok, "_tcsncat (")) { } else if (Token::simpleMatch(tok, "_tcsncat (")) {
tok->str("wcsncat"); tok->str("wcsncat");
tok->originalName("_tcsncat");
} else if (Token::simpleMatch(tok, "_tcsncpy (")) { } else if (Token::simpleMatch(tok, "_tcsncpy (")) {
tok->str("wcsncpy"); tok->str("wcsncpy");
tok->originalName("_tcsncpy");
} else if (Token::simpleMatch(tok, "_tcsnlen (")) { } else if (Token::simpleMatch(tok, "_tcsnlen (")) {
tok->str("wcsnlen"); tok->str("wcsnlen");
tok->originalName("_tcsnlen");
} else if (Token::simpleMatch(tok, "_tcsrchr (")) { } else if (Token::simpleMatch(tok, "_tcsrchr (")) {
tok->str("wcsrchr"); tok->str("wcsrchr");
tok->originalName("_tcsrchr");
} else if (Token::simpleMatch(tok, "_tcsstr (")) { } else if (Token::simpleMatch(tok, "_tcsstr (")) {
tok->str("wcsstr"); tok->str("wcsstr");
tok->originalName("_tcsstr");
} else if (Token::simpleMatch(tok, "_tcstok (")) { } else if (Token::simpleMatch(tok, "_tcstok (")) {
tok->str("wcstok"); tok->str("wcstok");
tok->originalName("_tcstok");
} else if (Token::simpleMatch(tok, "_ftprintf (")) { } else if (Token::simpleMatch(tok, "_ftprintf (")) {
tok->str("fwprintf"); tok->str("fwprintf");
tok->originalName("_ftprintf"); tok->originalName("_ftprintf");

View File

@ -139,12 +139,96 @@ private:
"}"); "}");
ASSERT_EQUALS("[test.cpp:5]: (error) Write operation on a file that was opened only for reading.\n", errout.str()); ASSERT_EQUALS("[test.cpp:5]: (error) Write operation on a file that was opened only for reading.\n", errout.str());
check("void foo(FILE*& f) {\n"
" f = _wfopen(name, L\"r\");\n"
" fread(buffer, 5, 6, f);\n"
" rewind(f);\n"
" fwrite(buffer, 5, 6, f);\n"
"}", false, false, Settings::Win32W);
ASSERT_EQUALS("[test.cpp:5]: (error) Write operation on a file that was opened only for reading.\n", errout.str());
check("void foo(FILE*& f) {\n"
" f = _tfopen(name, _T(\"r\"));\n"
" fread(buffer, 5, 6, f);\n"
" rewind(f);\n"
" fwrite(buffer, 5, 6, f);\n"
"}", false, false, Settings::Win32A);
ASSERT_EQUALS("[test.cpp:5]: (error) Write operation on a file that was opened only for reading.\n", errout.str());
check("void foo(FILE*& f) {\n"
" f = _tfopen(name, _T(\"r\"));\n"
" fread(buffer, 5, 6, f);\n"
" rewind(f);\n"
" fwrite(buffer, 5, 6, f);\n"
"}", false, false, Settings::Win32W);
ASSERT_EQUALS("[test.cpp:5]: (error) Write operation on a file that was opened only for reading.\n", errout.str());
check("void foo(FILE*& f) {\n"
" _wfopen_s(&f, name, L\"r\");\n"
" fread(buffer, 5, 6, f);\n"
" rewind(f);\n"
" fwrite(buffer, 5, 6, f);\n"
"}", false, false, Settings::Win32W);
ASSERT_EQUALS("[test.cpp:5]: (error) Write operation on a file that was opened only for reading.\n", errout.str());
check("void foo(FILE*& f) {\n"
" _tfopen_s(&f, name, _T(\"r\"));\n"
" fread(buffer, 5, 6, f);\n"
" rewind(f);\n"
" fwrite(buffer, 5, 6, f);\n"
"}", false, false, Settings::Win32A);
ASSERT_EQUALS("[test.cpp:5]: (error) Write operation on a file that was opened only for reading.\n", errout.str());
check("void foo(FILE*& f) {\n"
" _tfopen_s(&f, name, _T(\"r\"));\n"
" fread(buffer, 5, 6, f);\n"
" rewind(f);\n"
" fwrite(buffer, 5, 6, f);\n"
"}", false, false, Settings::Win32W);
ASSERT_EQUALS("[test.cpp:5]: (error) Write operation on a file that was opened only for reading.\n", errout.str());
check("void foo(FILE*& f) {\n" check("void foo(FILE*& f) {\n"
" f = fopen(name, \"r+\");\n" " f = fopen(name, \"r+\");\n"
" fwrite(buffer, 5, 6, f);\n" " fwrite(buffer, 5, 6, f);\n"
"}"); "}");
ASSERT_EQUALS("", errout.str()); ASSERT_EQUALS("", errout.str());
check("void foo(FILE*& f) {\n"
" f = _wfopen(name, L\"r+\");\n"
" fwrite(buffer, 5, 6, f);\n"
"}", false, false, Settings::Win32W);
ASSERT_EQUALS("", errout.str());
check("void foo(FILE*& f) {\n"
" f = _tfopen(name, _T(\"r+\"));\n"
" fwrite(buffer, 5, 6, f);\n"
"}", false, false, Settings::Win32A);
ASSERT_EQUALS("", errout.str());
check("void foo(FILE*& f) {\n"
" f = _tfopen(name, _T(\"r+\"));\n"
" fwrite(buffer, 5, 6, f);\n"
"}", false, false, Settings::Win32W);
ASSERT_EQUALS("", errout.str());
check("void foo(FILE*& f) {\n"
" _wfopen_s(&f, name, L\"r+\");\n"
" fwrite(buffer, 5, 6, f);\n"
"}", false, false, Settings::Win32W);
ASSERT_EQUALS("", errout.str());
check("void foo(FILE*& f) {\n"
" _tfopen_s(&f, name, _T(\"r+\"));\n"
" fwrite(buffer, 5, 6, f);\n"
"}", false, false, Settings::Win32A);
ASSERT_EQUALS("", errout.str());
check("void foo(FILE*& f) {\n"
" _tfopen_s(&f, name, _T(\"r+\"));\n"
" fwrite(buffer, 5, 6, f);\n"
"}", false, false, Settings::Win32W);
ASSERT_EQUALS("", errout.str());
// Write mode // Write mode
check("void foo(FILE*& f) {\n" check("void foo(FILE*& f) {\n"
" f = fopen(name, \"w\");\n" " f = fopen(name, \"w\");\n"
@ -192,14 +276,6 @@ private:
"}"); "}");
ASSERT_EQUALS("", errout.str()); ASSERT_EQUALS("", errout.str());
check("void foo(FILE*& f) {\n"
" f = fopen(name, \"a\");\n"
" fwrite(buffer, 5, 6, f);\n"
" clearerr(f);\n"
" fread(buffer, 5, 6, f);\n"
"}");
ASSERT_EQUALS("[test.cpp:5]: (error) Read operation on a file that was opened only for writing.\n", errout.str());
// freopen and tmpfile // freopen and tmpfile
check("void foo(FILE*& f) {\n" check("void foo(FILE*& f) {\n"
" f = freopen(name, \"r\", f);\n" " f = freopen(name, \"r\", f);\n"
@ -207,6 +283,42 @@ private:
"}"); "}");
ASSERT_EQUALS("[test.cpp:3]: (error) Write operation on a file that was opened only for reading.\n", errout.str()); ASSERT_EQUALS("[test.cpp:3]: (error) Write operation on a file that was opened only for reading.\n", errout.str());
check("void foo(FILE*& f) {\n"
" f = _wfreopen(name, L\"r\", f);\n"
" fwrite(buffer, 5, 6, f);\n"
"}", false, false, Settings::Win32W);
ASSERT_EQUALS("[test.cpp:3]: (error) Write operation on a file that was opened only for reading.\n", errout.str());
check("void foo(FILE*& f) {\n"
" f = _tfreopen(name, _T(\"r\"), f);\n"
" fwrite(buffer, 5, 6, f);\n"
"}", false, false, Settings::Win32A);
ASSERT_EQUALS("[test.cpp:3]: (error) Write operation on a file that was opened only for reading.\n", errout.str());
check("void foo(FILE*& f) {\n"
" f = _tfreopen(name, _T(\"r\"), f);\n"
" fwrite(buffer, 5, 6, f);\n"
"}", false, false, Settings::Win32W);
ASSERT_EQUALS("[test.cpp:3]: (error) Write operation on a file that was opened only for reading.\n", errout.str());
check("void foo(FILE*& f) {\n"
" f = _wfreopen_s(&f, name, L\"r\", f);\n"
" fwrite(buffer, 5, 6, f);\n"
"}", false, false, Settings::Win32W);
ASSERT_EQUALS("[test.cpp:3]: (error) Write operation on a file that was opened only for reading.\n", errout.str());
check("void foo(FILE*& f) {\n"
" f = _tfreopen_s(&f, name, _T(\"r\"), f);\n"
" fwrite(buffer, 5, 6, f);\n"
"}", false, false, Settings::Win32A);
ASSERT_EQUALS("[test.cpp:3]: (error) Write operation on a file that was opened only for reading.\n", errout.str());
check("void foo(FILE*& f) {\n"
" f = _tfreopen_s(&f, name, _T(\"r\"), f);\n"
" fwrite(buffer, 5, 6, f);\n"
"}", false, false, Settings::Win32W);
ASSERT_EQUALS("[test.cpp:3]: (error) Write operation on a file that was opened only for reading.\n", errout.str());
// Crash tests // Crash tests
check("void foo(FILE*& f) {\n" check("void foo(FILE*& f) {\n"
" f = fopen(name, mode);\n" // No assertion failure (#3830) " f = fopen(name, mode);\n" // No assertion failure (#3830)
@ -250,11 +362,13 @@ private:
" clearerr(f);\n" " clearerr(f);\n"
" fread(buffer, 5, 6, f);\n" " fread(buffer, 5, 6, f);\n"
" ungetc('a', f);\n" " ungetc('a', f);\n"
" ungetwc(L'a', f);\n"
"}"); "}");
ASSERT_EQUALS("[test.cpp:3]: (error) Used file that is not opened.\n" ASSERT_EQUALS("[test.cpp:3]: (error) Used file that is not opened.\n"
"[test.cpp:4]: (error) Used file that is not opened.\n" "[test.cpp:4]: (error) Used file that is not opened.\n"
"[test.cpp:5]: (error) Used file that is not opened.\n" "[test.cpp:5]: (error) Used file that is not opened.\n"
"[test.cpp:6]: (error) Used file that is not opened.\n", errout.str()); "[test.cpp:6]: (error) Used file that is not opened.\n"
"[test.cpp:7]: (error) Used file that is not opened.\n", errout.str());
check("void foo(FILE*& f) {\n" check("void foo(FILE*& f) {\n"
" if(!ferror(f)) {\n" " if(!ferror(f)) {\n"