diff --git a/lib/checkio.cpp b/lib/checkio.cpp index 0e1d0395146..009bcad6df3 100644 --- a/lib/checkio.cpp +++ b/lib/checkio.cpp @@ -245,6 +245,35 @@ void CheckIO::checkFileUsage() } else if (tok->str() == "fclose") { fileTok = tok->tokAt(2); operation = Filepointer::Operation::CLOSE; + + // #1473 Check if fclose is in a while loop condition + if (fileTok) { + const Token* tmp = tok->astParent(); + const Token* loopTok = nullptr; + while (tmp) { + if (Token::simpleMatch(tmp->previous(), "while (")) { + loopTok = tmp->previous(); + break; + } + tmp = tmp->astParent(); + } + if (loopTok) { + const Token* bodyEnd = nullptr; + const Token* bodyStart = nullptr; + + if (Token::simpleMatch(loopTok->previous(), "}")) { // Handle do-while loops + bodyEnd = loopTok->previous(); + bodyStart = bodyEnd->link(); + } else { + bodyStart = loopTok->linkAt(1)->next(); + bodyEnd = bodyStart->link(); + } + + // Do not trigger a warning if the loop always exits or if the file is opened again in the loop. + if (!isReturnScope(bodyEnd, mSettings->library) && Token::findmatch(bodyStart, "%var% = fopen|freopen", bodyEnd, fileTok->varId()) == nullptr) + useClosedFileError(tok); + } + } } else if (whitelist.find(tok->str()) != whitelist.end()) { fileTok = tok->tokAt(2); if ((tok->str() == "ungetc" || tok->str() == "ungetwc") && fileTok) diff --git a/test/testio.cpp b/test/testio.cpp index ec6a87a1e16..7cfc657180d 100644 --- a/test/testio.cpp +++ b/test/testio.cpp @@ -544,7 +544,29 @@ class TestIO : public TestFixture { " FILE *a = fopen(\"aa\", \"r\");\n" " while (fclose(a)) {}\n" "}"); - TODO_ASSERT_EQUALS("[test.cpp:3:5]: (error) Used file that is not opened. [useClosedFile]\n", "", errout_str()); + ASSERT_EQUALS("[test.cpp:3:12]: (error) Used file that is not opened. [useClosedFile]\n", errout_str()); + + check("void foo() {\n" + " FILE *a = fopen(\"aa\", \"r\");\n" + " while (fclose(a)) {\n" + " break;\n" + " }\n" + "}"); + ASSERT_EQUALS("", errout_str()); + + check("void foo() {\n" + " FILE *a = fopen(\"aa\", \"r\");\n" + " while (fclose(a)) {\n" + " a = fopen(\"aa\", \"r\");\n" + " }\n" + "}"); + ASSERT_EQUALS("", errout_str()); + + check("void foo() {\n" + " FILE *a = fopen(\"aa\", \"r\");\n" + " do {} while (fclose(a));\n" + "}"); + ASSERT_EQUALS("[test.cpp:3:18]: (error) Used file that is not opened. [useClosedFile]\n", errout_str()); // #6823 check("void foo() {\n"