diff --git a/Changes.txt b/Changes.txt index c32bfdc2e..88e6c41b3 100644 --- a/Changes.txt +++ b/Changes.txt @@ -22,6 +22,9 @@ * Fixed major bug with joysticks, where mapping was being lost on reset, 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 joysticks that Stella knows about) and the ability to remove (currently unplugged) joysticks from this database. diff --git a/src/emucore/Serializer.cxx b/src/emucore/Serializer.cxx index fca626e29..2d1453733 100644 --- a/src/emucore/Serializer.cxx +++ b/src/emucore/Serializer.cxx @@ -33,15 +33,13 @@ Serializer::Serializer(const string& filename, bool readonly) FilesystemNode node(filename); if(node.isFile() && node.isReadable()) { - fstream* str = new fstream(filename.c_str(), ios::in | ios::binary); + unique_ptr str = make_ptr(filename.c_str(), ios::in | ios::binary); if(str && str->is_open()) { - myStream = str; + myStream = std::move(str); myStream->exceptions( ios_base::failbit | ios_base::badbit | ios_base::eofbit ); reset(); } - else - delete str; } } else @@ -56,15 +54,13 @@ Serializer::Serializer(const string& filename, bool readonly) fstream temp(filename.c_str(), ios::out | ios::app); temp.close(); - fstream* str = new fstream(filename.c_str(), ios::in | ios::out | ios::binary); + unique_ptr str = make_ptr(filename.c_str(), ios::in | ios::out | ios::binary); if(str && str->is_open()) { - myStream = str; + myStream = std::move(str); myStream->exceptions( ios_base::failbit | ios_base::badbit | ios_base::eofbit ); reset(); } - else - delete str; } } @@ -73,7 +69,7 @@ Serializer::Serializer() : myStream(nullptr), myUseFilestream(false) { - myStream = new stringstream(ios::in | ios::out | ios::binary); + myStream = make_ptr(ios::in | ios::out | ios::binary); // For some reason, Windows and possibly OSX needs to store something in // 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 { diff --git a/src/emucore/Serializer.hxx b/src/emucore/Serializer.hxx index ba4293f65..e62af3017 100644 --- a/src/emucore/Serializer.hxx +++ b/src/emucore/Serializer.hxx @@ -56,11 +56,6 @@ class Serializer Serializer(const string& filename, bool readonly = false); Serializer(); - /** - Destructor - */ - ~Serializer(); - public: /** Answers whether the serializer is currently initialized for reading @@ -193,7 +188,7 @@ class Serializer private: // The stream to send the serialized data to. - iostream* myStream; + unique_ptr myStream; bool myUseFilestream; enum { diff --git a/src/emucore/StateManager.cxx b/src/emucore/StateManager.cxx index ca061fc2c..cbc174a46 100644 --- a/src/emucore/StateManager.cxx +++ b/src/emucore/StateManager.cxx @@ -184,20 +184,19 @@ void StateManager::loadState(int slot) // First test if we have a valid header // If so, do a complete state load using the Console buf.str(""); - if(in.getString() != STATE_HEADER) - buf << "Incompatible state " << slot << " file"; - else + try { - if(in.getString() == myOSystem.console().cartridge().name()) - { - if(myOSystem.console().load(in)) - buf << "State " << slot << " loaded"; - else - buf << "Invalid data in state " << slot << " file"; - } - else + if(in.getString() != STATE_HEADER) + buf << "Incompatible state " << slot << " file"; + else if(in.getString() != myOSystem.console().cartridge().name()) 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()); } @@ -225,12 +224,21 @@ void StateManager::saveState(int slot) return; } - // 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); + try + { + // 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 - out.putString(myOSystem.console().cartridge().name()); + // Sanity check; prepend the cart type/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 buf.str(""); @@ -264,18 +272,25 @@ void StateManager::changeState() // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool StateManager::loadState(Serializer& in) { - if(myOSystem.hasConsole()) + try { - // Make sure the file can be opened for reading - if(in.valid()) + if(myOSystem.hasConsole()) { - // First test if we have a valid header and cart type - // 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); + // Make sure the file can be opened for reading + if(in.valid()) + { + // First test if we have a valid header and cart type + // 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; }