Fixed crash on loading state files; try/catch was missing for the first

bit of data loaded from the file.

Changed Serializer class to unique_ptr, eliminating d'tor.


git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@3130 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
This commit is contained in:
stephena 2015-01-01 03:23:06 +00:00
parent abd4c9efa8
commit 0afe070d9c
4 changed files with 48 additions and 52 deletions

View File

@ -22,6 +22,9 @@
* Fixed major bug with joysticks, where mapping was being lost on reset, * Fixed major bug with joysticks, where mapping was being lost on reset,
the app would crash when plugging/unplugging certain sticks, etc. the app would crash when plugging/unplugging certain sticks, etc.
* Fixed major (but rare) crash that could occur when state files were
zero'ed or corrupted.
* Added dialog which shows the internal joystick database (all the * Added dialog which shows the internal joystick database (all the
joysticks that Stella knows about) and the ability to remove joysticks that Stella knows about) and the ability to remove
(currently unplugged) joysticks from this database. (currently unplugged) joysticks from this database.

View File

@ -33,15 +33,13 @@ Serializer::Serializer(const string& filename, bool readonly)
FilesystemNode node(filename); FilesystemNode node(filename);
if(node.isFile() && node.isReadable()) if(node.isFile() && node.isReadable())
{ {
fstream* str = new fstream(filename.c_str(), ios::in | ios::binary); unique_ptr<fstream> str = make_ptr<fstream>(filename.c_str(), ios::in | ios::binary);
if(str && str->is_open()) if(str && str->is_open())
{ {
myStream = str; myStream = std::move(str);
myStream->exceptions( ios_base::failbit | ios_base::badbit | ios_base::eofbit ); myStream->exceptions( ios_base::failbit | ios_base::badbit | ios_base::eofbit );
reset(); reset();
} }
else
delete str;
} }
} }
else else
@ -56,15 +54,13 @@ Serializer::Serializer(const string& filename, bool readonly)
fstream temp(filename.c_str(), ios::out | ios::app); fstream temp(filename.c_str(), ios::out | ios::app);
temp.close(); temp.close();
fstream* str = new fstream(filename.c_str(), ios::in | ios::out | ios::binary); unique_ptr<fstream> str = make_ptr<fstream>(filename.c_str(), ios::in | ios::out | ios::binary);
if(str && str->is_open()) if(str && str->is_open())
{ {
myStream = str; myStream = std::move(str);
myStream->exceptions( ios_base::failbit | ios_base::badbit | ios_base::eofbit ); myStream->exceptions( ios_base::failbit | ios_base::badbit | ios_base::eofbit );
reset(); reset();
} }
else
delete str;
} }
} }
@ -73,7 +69,7 @@ Serializer::Serializer()
: myStream(nullptr), : myStream(nullptr),
myUseFilestream(false) myUseFilestream(false)
{ {
myStream = new stringstream(ios::in | ios::out | ios::binary); myStream = make_ptr<stringstream>(ios::in | ios::out | ios::binary);
// For some reason, Windows and possibly OSX needs to store something in // For some reason, Windows and possibly OSX needs to store something in
// the stream before it is used for the first time // the stream before it is used for the first time
@ -85,19 +81,6 @@ Serializer::Serializer()
} }
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Serializer::~Serializer()
{
if(myStream != nullptr)
{
if(myUseFilestream)
((fstream*)myStream)->close();
delete myStream;
myStream = nullptr;
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool Serializer::valid() const bool Serializer::valid() const
{ {

View File

@ -56,11 +56,6 @@ class Serializer
Serializer(const string& filename, bool readonly = false); Serializer(const string& filename, bool readonly = false);
Serializer(); Serializer();
/**
Destructor
*/
~Serializer();
public: public:
/** /**
Answers whether the serializer is currently initialized for reading Answers whether the serializer is currently initialized for reading
@ -193,7 +188,7 @@ class Serializer
private: private:
// The stream to send the serialized data to. // The stream to send the serialized data to.
iostream* myStream; unique_ptr<iostream> myStream;
bool myUseFilestream; bool myUseFilestream;
enum { enum {

View File

@ -184,20 +184,19 @@ void StateManager::loadState(int slot)
// First test if we have a valid header // First test if we have a valid header
// If so, do a complete state load using the Console // If so, do a complete state load using the Console
buf.str(""); buf.str("");
if(in.getString() != STATE_HEADER) try
buf << "Incompatible state " << slot << " file";
else
{ {
if(in.getString() == myOSystem.console().cartridge().name()) if(in.getString() != STATE_HEADER)
{ buf << "Incompatible state " << slot << " file";
if(myOSystem.console().load(in)) else if(in.getString() != myOSystem.console().cartridge().name())
buf << "State " << slot << " loaded";
else
buf << "Invalid data in state " << slot << " file";
}
else
buf << "State " << slot << " file doesn't match current ROM"; buf << "State " << slot << " file doesn't match current ROM";
} }
catch(...) { /* fall through to logic below */ }
if(myOSystem.console().load(in))
buf << "State " << slot << " loaded";
else
buf << "Invalid data in state " << slot << " file";
myOSystem.frameBuffer().showMessage(buf.str()); myOSystem.frameBuffer().showMessage(buf.str());
} }
@ -225,12 +224,21 @@ void StateManager::saveState(int slot)
return; return;
} }
// Add header so that if the state format changes in the future, try
// we'll know right away, without having to parse the rest of the file {
out.putString(STATE_HEADER); // Add header so that if the state format changes in the future,
// we'll know right away, without having to parse the rest of the file
out.putString(STATE_HEADER);
// Sanity check; prepend the cart type/name // Sanity check; prepend the cart type/name
out.putString(myOSystem.console().cartridge().name()); out.putString(myOSystem.console().cartridge().name());
}
catch(...)
{
buf << "Error saving state " << slot;
myOSystem.frameBuffer().showMessage(buf.str());
return;
}
// Do a complete state save using the Console // Do a complete state save using the Console
buf.str(""); buf.str("");
@ -264,18 +272,25 @@ void StateManager::changeState()
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool StateManager::loadState(Serializer& in) bool StateManager::loadState(Serializer& in)
{ {
if(myOSystem.hasConsole()) try
{ {
// Make sure the file can be opened for reading if(myOSystem.hasConsole())
if(in.valid())
{ {
// First test if we have a valid header and cart type // Make sure the file can be opened for reading
// If so, do a complete state load using the Console if(in.valid())
return in.getString() == STATE_HEADER && {
in.getString() == myOSystem.console().cartridge().name() && // First test if we have a valid header and cart type
myOSystem.console().load(in); // If so, do a complete state load using the Console
return in.getString() == STATE_HEADER &&
in.getString() == myOSystem.console().cartridge().name() &&
myOSystem.console().load(in);
}
} }
} }
catch(...)
{
cerr << "ERROR: StateManager::loadState(Serializer&)" << endl;
}
return false; return false;
} }