Skip to content

Commit a2c4ac8

Browse files
fixup! fixup! fixup! fixup! fixup! Fix #1473: warn when fclose() is used as a while loop condition
1 parent 28f2247 commit a2c4ac8

3 files changed

Lines changed: 18 additions & 14 deletions

File tree

lib/checkio.cpp

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -248,20 +248,13 @@ void CheckIO::checkFileUsage()
248248

249249
// #1473 Check if fclose is in a while loop condition
250250
if (fileTok && fileTok->isVariable()) {
251-
const Token* tmp = tok->astParent();
252-
const Token* loopTok = nullptr;
253-
while (tmp) {
254-
if (Token::simpleMatch(tmp->previous(), "while (")) {
255-
loopTok = tmp->previous();
256-
break;
257-
}
258-
tmp = tmp->astParent();
259-
}
260-
if (loopTok) {
251+
const Token* loopTok = tok->astTop()->previous();
252+
253+
if (loopTok && loopTok->str() == "while") {
261254
const Token* bodyEnd = nullptr;
262255
const Token* bodyStart = nullptr;
263256

264-
if (Token::simpleMatch(loopTok->previous(), "}") && Token::simpleMatch(loopTok->linkAt(-1)->previous(), "do")) { // Handle do-while loops
257+
if (Token::simpleMatch(loopTok->previous(), "}") && loopTok->previous()->scope()->type == ScopeType::eDo) { // Handle do-while loops
265258
bodyEnd = loopTok->previous();
266259
bodyStart = bodyEnd->link();
267260
} else {
@@ -271,7 +264,7 @@ void CheckIO::checkFileUsage()
271264

272265
// Do not trigger a warning if the loop always exits or if the file is opened again in the loop.
273266
if (!isReturnScope(bodyEnd, mSettings->library) && Token::findmatch(bodyStart, "%var% =", bodyEnd, fileTok->varId()) == nullptr)
274-
useClosedFileError(tok);
267+
fcloseInLoopConditionError(tok, fileTok->str());
275268
}
276269
}
277270
} else if (whitelist.find(tok->str()) != whitelist.end()) {
@@ -421,6 +414,15 @@ void CheckIO::useClosedFileError(const Token *tok)
421414
"useClosedFile", "Used file that is not opened.", CWE910, Certainty::normal);
422415
}
423416

417+
void CheckIO::fcloseInLoopConditionError(const Token *tok, const std::string &varname)
418+
{
419+
reportError(tok, Severity::warning,
420+
"fcloseInLoopCondition",
421+
"fclose() should not be used as a loop condition.\n"
422+
"fclose() closes '" + varname + "' each time it is evaluated. On success the loop body might never execute, on failure fclose() might be called again on the already-closed file handle.",
423+
CWE910, Certainty::normal);
424+
}
425+
424426
void CheckIO::seekOnAppendedFileError(const Token *tok)
425427
{
426428
reportError(tok, Severity::warning,
@@ -2071,6 +2073,7 @@ void CheckIO::getErrorMessages(ErrorLogger *errorLogger, const Settings *setting
20712073
c.readWriteOnlyFileError(nullptr);
20722074
c.writeReadOnlyFileError(nullptr);
20732075
c.useClosedFileError(nullptr);
2076+
c.fcloseInLoopConditionError(nullptr, "fp");
20742077
c.seekOnAppendedFileError(nullptr);
20752078
c.incompatibleFileOpenError(nullptr, "tmp");
20762079
c.invalidScanfError(nullptr);

lib/checkio.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ class CPPCHECKLIB CheckIO : public Check {
105105
void readWriteOnlyFileError(const Token *tok);
106106
void writeReadOnlyFileError(const Token *tok);
107107
void useClosedFileError(const Token *tok);
108+
void fcloseInLoopConditionError(const Token *tok, const std::string &varname);
108109
void seekOnAppendedFileError(const Token *tok);
109110
void incompatibleFileOpenError(const Token *tok, const std::string &filename);
110111
void invalidScanfError(const Token *tok);

test/testio.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -544,7 +544,7 @@ class TestIO : public TestFixture {
544544
" FILE *a = fopen(\"aa\", \"r\");\n"
545545
" while (fclose(a)) {}\n"
546546
"}");
547-
ASSERT_EQUALS("[test.cpp:3:12]: (error) Used file that is not opened. [useClosedFile]\n", errout_str());
547+
ASSERT_EQUALS("[test.cpp:3:12]: (warning) fclose() should not be used as a loop condition. [fcloseInLoopCondition]\n", errout_str());
548548

549549
check("void foo() {\n"
550550
" FILE *a = fopen(\"aa\", \"r\");\n"
@@ -566,7 +566,7 @@ class TestIO : public TestFixture {
566566
" FILE *a = fopen(\"aa\", \"r\");\n"
567567
" do {} while (fclose(a));\n"
568568
"}");
569-
ASSERT_EQUALS("[test.cpp:3:18]: (error) Used file that is not opened. [useClosedFile]\n", errout_str());
569+
ASSERT_EQUALS("[test.cpp:3:18]: (warning) fclose() should not be used as a loop condition. [fcloseInLoopCondition]\n", errout_str());
570570

571571
// #6823
572572
check("void foo() {\n"

0 commit comments

Comments
 (0)