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:
committed by
Vadim Zeitlin
parent
a05b1f39f5
commit
9b1afaa7a6
@@ -84,6 +84,7 @@ All:
|
|||||||
wxEvtHandler and/or wxTrackable in C++11 code (Raul Tambre, mmarsan).
|
wxEvtHandler and/or wxTrackable in C++11 code (Raul Tambre, mmarsan).
|
||||||
- Update bundled expat to 2.2.0 (Catalin Raceanu).
|
- Update bundled expat to 2.2.0 (Catalin Raceanu).
|
||||||
- Add wxCMD_LINE_HIDDEN wxCmdLineParser flag (Lauri Nurmi).
|
- Add wxCMD_LINE_HIDDEN wxCmdLineParser flag (Lauri Nurmi).
|
||||||
|
- Don't crash in wxFFile::Eof() or Error() on closed file (jprotopopov).
|
||||||
|
|
||||||
All (GUI):
|
All (GUI):
|
||||||
|
|
||||||
|
@@ -76,13 +76,13 @@ public:
|
|||||||
wxFileOffset Length() const;
|
wxFileOffset Length() const;
|
||||||
|
|
||||||
// simple accessors: note that Eof() and Error() may only be called if
|
// simple accessors: note that Eof() and Error() may only be called if
|
||||||
// IsOpened()!
|
// IsOpened(). Otherwise they assert and return false.
|
||||||
// is file opened?
|
// is file opened?
|
||||||
bool IsOpened() const { return m_fp != NULL; }
|
bool IsOpened() const { return m_fp != NULL; }
|
||||||
// is end of file reached?
|
// is end of file reached?
|
||||||
bool Eof() const { return feof(m_fp) != 0; }
|
bool Eof() const;
|
||||||
// has an error occurred?
|
// has an error occurred?
|
||||||
bool Error() const { return ferror(m_fp) != 0; }
|
bool Error() const;
|
||||||
// get the file name
|
// get the file name
|
||||||
const wxString& GetName() const { return m_name; }
|
const wxString& GetName() const { return m_name; }
|
||||||
// type such as disk or pipe
|
// type such as disk or pipe
|
||||||
|
@@ -89,10 +89,7 @@ public:
|
|||||||
Note that the behaviour of the file descriptor based class wxFile is different as
|
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.
|
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
|
Also note that this method may only be called for opened files. Otherwise it asserts and returns false.
|
||||||
the file is not opened.
|
|
||||||
|
|
||||||
@todo THIS METHOD MAY CRASH? DOESN'T SOUND GOOD
|
|
||||||
|
|
||||||
@see IsOpened()
|
@see IsOpened()
|
||||||
*/
|
*/
|
||||||
@@ -102,10 +99,7 @@ public:
|
|||||||
Returns @true if an error has occurred on this file, similar to the standard
|
Returns @true if an error has occurred on this file, similar to the standard
|
||||||
@c ferror() function.
|
@c ferror() function.
|
||||||
|
|
||||||
Please note that this method may only be called for opened files and may crash
|
Please note that this method may only be called for opened files. Otherwise it asserts and returns false.
|
||||||
if the file is not opened.
|
|
||||||
|
|
||||||
@todo THIS METHOD MAY CRASH? DOESN'T SOUND GOOD
|
|
||||||
|
|
||||||
@see IsOpened()
|
@see IsOpened()
|
||||||
*/
|
*/
|
||||||
|
@@ -281,4 +281,18 @@ wxFileOffset wxFFile::Length() const
|
|||||||
return wxInvalidOffset;
|
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
|
#endif // wxUSE_FFILE
|
||||||
|
@@ -48,6 +48,8 @@ private:
|
|||||||
CPPUNIT_TEST( RenameFile );
|
CPPUNIT_TEST( RenameFile );
|
||||||
CPPUNIT_TEST( ConcatenateFiles );
|
CPPUNIT_TEST( ConcatenateFiles );
|
||||||
CPPUNIT_TEST( GetCwd );
|
CPPUNIT_TEST( GetCwd );
|
||||||
|
CPPUNIT_TEST( FileEof );
|
||||||
|
CPPUNIT_TEST( FileError );
|
||||||
CPPUNIT_TEST_SUITE_END();
|
CPPUNIT_TEST_SUITE_END();
|
||||||
|
|
||||||
void GetTempFolder();
|
void GetTempFolder();
|
||||||
@@ -60,6 +62,8 @@ private:
|
|||||||
void RenameFile();
|
void RenameFile();
|
||||||
void ConcatenateFiles();
|
void ConcatenateFiles();
|
||||||
void GetCwd();
|
void GetCwd();
|
||||||
|
void FileEof();
|
||||||
|
void FileError();
|
||||||
|
|
||||||
// Helper methods
|
// Helper methods
|
||||||
void DoCreateFile(const wxString& filePath);
|
void DoCreateFile(const wxString& filePath);
|
||||||
@@ -423,6 +427,61 @@ void FileFunctionsTestCase::GetCwd()
|
|||||||
CPPUNIT_ASSERT( !cwd.IsEmpty() );
|
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:
|
TODO: other file functions to test:
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user