Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions lib/checkio.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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_) {}
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the error message says something about the C11 standard. Nothing about windows.

Copy link
Copy Markdown
Author

@damorinCan damorinCan Apr 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will add a comment about this reference to this Microsoft page:

https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/ftell-ftelli64?view=msvc-170

An update for the error message with this, would it be OK ?

According to Microsoft, the value returned by ftell may not reflect the physical byte offset for streams opened in text mode, because text mode causes carriage return-line feed translation. See also 7.21.9.4 in C11 standard.".

I will remove the reference to _wfopen(), it's not part of the C++ standard.

ftellFileError(tok);
break;
case Filepointer::Operation::UNKNOWN_OP:
f.mode = OpenMode::UNKNOWN_OM;
Expand Down Expand Up @@ -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,
Expand Down
1 change: 1 addition & 0 deletions lib/checkio.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
16 changes: 16 additions & 0 deletions test/testio.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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));
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

test what happens on unix platform . test what happens when C99 is used - that works as expected right?

Copy link
Copy Markdown
Author

@damorinCan damorinCan Apr 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Selecting Win32A is too limiting, it should apply to all platforms for portability.

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"
Expand Down
Loading