Don't crash in wxFFile::Eof() and Error() if file is closed

Assert and return false instead, this is more developer-friendly.

Add unit tests to check that these functions really work as expected when
called on a closed file.

Closes #17828.
This commit is contained in:
jprotopopov 2017-04-01 18:38:14 +02:00 committed by Vadim Zeitlin
parent a05b1f39f5
commit 9b1afaa7a6
5 changed files with 79 additions and 11 deletions

View File

@ -84,6 +84,7 @@ All:
wxEvtHandler and/or wxTrackable in C++11 code (Raul Tambre, mmarsan).
- Update bundled expat to 2.2.0 (Catalin Raceanu).
- Add wxCMD_LINE_HIDDEN wxCmdLineParser flag (Lauri Nurmi).
- Don't crash in wxFFile::Eof() or Error() on closed file (jprotopopov).
All (GUI):

View File

@ -76,13 +76,13 @@ public:
wxFileOffset Length() const;
// simple accessors: note that Eof() and Error() may only be called if
// IsOpened()!
// IsOpened(). Otherwise they assert and return false.
// is file opened?
bool IsOpened() const { return m_fp != NULL; }
// is end of file reached?
bool Eof() const { return feof(m_fp) != 0; }
bool Eof() const;
// has an error occurred?
bool Error() const { return ferror(m_fp) != 0; }
bool Error() const;
// get the file name
const wxString& GetName() const { return m_name; }
// type such as disk or pipe

View File

@ -89,10 +89,7 @@ public:
Note that the behaviour of the file descriptor based class wxFile is different as
wxFile::Eof() will return @true here as soon as the last byte of the file has been read.
Also note that this method may only be called for opened files and may crash if
the file is not opened.
@todo THIS METHOD MAY CRASH? DOESN'T SOUND GOOD
Also note that this method may only be called for opened files. Otherwise it asserts and returns false.
@see IsOpened()
*/
@ -102,10 +99,7 @@ public:
Returns @true if an error has occurred on this file, similar to the standard
@c ferror() function.
Please note that this method may only be called for opened files and may crash
if the file is not opened.
@todo THIS METHOD MAY CRASH? DOESN'T SOUND GOOD
Please note that this method may only be called for opened files. Otherwise it asserts and returns false.
@see IsOpened()
*/

View File

@ -281,4 +281,18 @@ wxFileOffset wxFFile::Length() const
return wxInvalidOffset;
}
bool wxFFile::Eof() const
{
wxCHECK_MSG( IsOpened(), false,
wxT("wxFFile::Eof(): file is closed!") );
return feof(m_fp) != 0;
}
bool wxFFile::Error() const
{
wxCHECK_MSG( IsOpened(), false,
wxT("wxFFile::Error(): file is closed!") );
return ferror(m_fp) != 0;
}
#endif // wxUSE_FFILE

View File

@ -48,6 +48,8 @@ private:
CPPUNIT_TEST( RenameFile );
CPPUNIT_TEST( ConcatenateFiles );
CPPUNIT_TEST( GetCwd );
CPPUNIT_TEST( FileEof );
CPPUNIT_TEST( FileError );
CPPUNIT_TEST_SUITE_END();
void GetTempFolder();
@ -60,6 +62,8 @@ private:
void RenameFile();
void ConcatenateFiles();
void GetCwd();
void FileEof();
void FileError();
// Helper methods
void DoCreateFile(const wxString& filePath);
@ -423,6 +427,61 @@ void FileFunctionsTestCase::GetCwd()
CPPUNIT_ASSERT( !cwd.IsEmpty() );
}
void FileFunctionsTestCase::FileEof()
{
const wxString filename(wxT("horse.bmp"));
const wxString msg = wxString::Format(wxT("File: %s"), filename.c_str());
const char *pUnitMsg = (const char*) msg.mb_str(wxConvUTF8);
wxFFile file(filename, wxT("r"));
// wxFFile::Eof must be false at start
CPPUNIT_ASSERT_MESSAGE( pUnitMsg, !file.Eof() );
CPPUNIT_ASSERT_MESSAGE( pUnitMsg, file.SeekEnd() );
// wxFFile::Eof returns true only after attempt to read last byte
char array[1];
CPPUNIT_ASSERT_MESSAGE( pUnitMsg, file.Read(array, 1) == 0 );
CPPUNIT_ASSERT_MESSAGE( pUnitMsg, file.Eof() );
CPPUNIT_ASSERT_MESSAGE( pUnitMsg, file.Close() );
// wxFFile::Eof after close should not cause crash but fail instead
bool failed = true;
try
{
file.Eof();
failed = false;
}
catch (...)
{
}
CPPUNIT_ASSERT_MESSAGE( pUnitMsg, failed );
}
void FileFunctionsTestCase::FileError()
{
const wxString filename(wxT("horse.bmp"));
const wxString msg = wxString::Format(wxT("File: %s"), filename.c_str());
const char *pUnitMsg = (const char*) msg.mb_str(wxConvUTF8);
wxFFile file(filename, wxT("r"));
// wxFFile::Error must be false at start assuming file "horse.bmp" exists.
CPPUNIT_ASSERT_MESSAGE( pUnitMsg, !file.Error() );
// Attempt to write to file opened in readonly mode should cause error
CPPUNIT_ASSERT_MESSAGE( pUnitMsg, !file.Write(filename) );
CPPUNIT_ASSERT_MESSAGE( pUnitMsg, file.Error() );
CPPUNIT_ASSERT_MESSAGE( pUnitMsg, file.Close() );
// wxFFile::Error after close should not cause crash but fail instead
bool failed = true;
try
{
file.Error();
failed = false;
}
catch (...)
{
}
CPPUNIT_ASSERT_MESSAGE( pUnitMsg, failed );
}
/*
TODO: other file functions to test: