From 14d63abe65b473ee9b09417a0d2064ba8d6da18c Mon Sep 17 00:00:00 2001 From: Robert M Date: Sat, 21 Mar 2026 12:39:48 -0400 Subject: [PATCH] ftell() have a different behavior in Windows 11 than before. https://stackoverflow.com/questions/79762122/ftell-no-more-returning-the-correct-offset-on-a-text-file-with-windows-11-ente --- lib/checkio.cpp | 20 ++++++++++++++++++++ lib/checkio.h | 1 + test/testio.cpp | 16 ++++++++++++++++ 3 files changed, 37 insertions(+) diff --git a/lib/checkio.cpp b/lib/checkio.cpp index ee1b4e36c73..dbc698087e9 100644 --- a/lib/checkio.cpp +++ b/lib/checkio.cpp @@ -53,6 +53,7 @@ namespace { // CVE ID used: static const CWE CWE119(119U); // Improper Restriction of Operations within the Bounds of a Memory Buffer static const CWE CWE398(398U); // Indicator of Poor Code Quality +static const CWE CWE474(474U); // Use of Function with Inconsistent Implementations static const CWE CWE664(664U); // Improper Control of a Resource Through its Lifetime static const CWE CWE685(685U); // Function Call With Incorrect Number of Arguments static const CWE CWE686(686U); // Function Call With Incorrect Argument Type @@ -116,6 +117,8 @@ namespace { nonneg int op_indent{}; enum class AppendMode : std::uint8_t { UNKNOWN_AM, APPEND, APPEND_EX }; AppendMode append_mode = AppendMode::UNKNOWN_AM; + enum class ReadMode : std::uint8_t { READ_TEXT, READ_BIN }; + ReadMode read_mode = ReadMode::READ_BIN; std::string filename; explicit Filepointer(OpenMode mode_ = OpenMode::UNKNOWN_OM) : mode(mode_) {} @@ -188,6 +191,7 @@ void CheckIO::checkFileUsage() } } else if (Token::Match(tok, "%name% (") && tok->previous() && (!tok->previous()->isName() || Token::Match(tok->previous(), "return|throw"))) { std::string mode; + bool isftell = false; const Token* fileTok = nullptr; const Token* fileNameTok = nullptr; Filepointer::Operation operation = Filepointer::Operation::NONE; @@ -249,6 +253,9 @@ void CheckIO::checkFileUsage() fileTok = tok->tokAt(2); if ((tok->str() == "ungetc" || tok->str() == "ungetwc") && fileTok) fileTok = fileTok->nextArgument(); + else if (tok->str() == "ftell") { + isftell = true; + } operation = Filepointer::Operation::UNIMPORTANT; } else if (!Token::Match(tok, "if|for|while|catch|switch") && !mSettings->library.isFunctionConst(tok->str(), true)) { const Token* const end2 = tok->linkAt(1); @@ -304,10 +311,15 @@ void CheckIO::checkFileUsage() f.append_mode = Filepointer::AppendMode::APPEND_EX; else f.append_mode = Filepointer::AppendMode::APPEND; + } + else if (mode.find('r') != std::string::npos && + mode.find('t') != std::string::npos) { + f.read_mode = Filepointer::ReadMode::READ_TEXT; } else f.append_mode = Filepointer::AppendMode::UNKNOWN_AM; f.mode_indent = indent; break; + case Filepointer::Operation::POSITIONING: if (f.mode == OpenMode::CLOSED) useClosedFileError(tok); @@ -340,6 +352,8 @@ void CheckIO::checkFileUsage() case Filepointer::Operation::UNIMPORTANT: if (f.mode == OpenMode::CLOSED) useClosedFileError(tok); + if (isftell && windows && f.read_mode == Filepointer::ReadMode::READ_TEXT && printPortability) + ftellFileError(tok); break; case Filepointer::Operation::UNKNOWN_OP: f.mode = OpenMode::UNKNOWN_OM; @@ -398,6 +412,12 @@ void CheckIO::seekOnAppendedFileError(const Token *tok) "seekOnAppendedFile", "Repositioning operation performed on a file opened in append mode has no effect.", CWE398, Certainty::normal); } +void CheckIO::ftellFileError(const Token *tok) +{ + reportError(tok, Severity::portability, + "ftellTextModeFile", "For a text stream, its file position indicator contains unspecified information. See Section 7.21.9.4p2 of the C11 standard", CWE474, Certainty::normal); +} + void CheckIO::incompatibleFileOpenError(const Token *tok, const std::string &filename) { reportError(tok, Severity::warning, diff --git a/lib/checkio.h b/lib/checkio.h index e37a942770b..273aa6d7949 100644 --- a/lib/checkio.h +++ b/lib/checkio.h @@ -106,6 +106,7 @@ class CPPCHECKLIB CheckIO : public Check { void writeReadOnlyFileError(const Token *tok); void useClosedFileError(const Token *tok); void seekOnAppendedFileError(const Token *tok); + void ftellFileError(const Token *tok); void incompatibleFileOpenError(const Token *tok, const std::string &filename); void invalidScanfError(const Token *tok); void wrongPrintfScanfArgumentsError(const Token* tok, diff --git a/test/testio.cpp b/test/testio.cpp index b402f5c0aa1..411477c417c 100644 --- a/test/testio.cpp +++ b/test/testio.cpp @@ -44,6 +44,7 @@ class TestIO : public TestFixture { TEST_CASE(fileIOwithoutPositioning); TEST_CASE(seekOnAppendedFile); TEST_CASE(fflushOnInputStream); + TEST_CASE(ftellCompatibility); TEST_CASE(incompatibleFileOpen); TEST_CASE(testScanf1); // Scanf without field limiters @@ -704,6 +705,21 @@ class TestIO : public TestFixture { ASSERT_EQUALS("", errout_str()); // #6566 } + void ftellCompatibility() { + + check("void foo() {\n" + " FILE *f = fopen(\"\", \"rt\");\n" + " if (f)\n" + " {\n" + " fseek(f, 0, SEEK_END);\n" + " (void)ftell(f);\n" + " fclose(f);\n" + " }\n" + "}\n", dinit(CheckOptions, $.platform = Platform::Type::Win32A, $.portability = true)); + ASSERT_EQUALS("[test.cpp:6:16]: (portability) For a text stream, its file position indicator contains unspecified information. See Section 7.21.9.4p2 of the C11 standard [ftellTextModeFile]\n", errout_str()); + } + + void fflushOnInputStream() { check("void foo()\n" "{\n"