diff --git a/engines/sci/engine/savegame.cpp b/engines/sci/engine/savegame.cpp index a27b699dd1a..e67e4764a2d 100644 --- a/engines/sci/engine/savegame.cpp +++ b/engines/sci/engine/savegame.cpp @@ -568,7 +568,7 @@ void Script::saveLoadWithSerializer(Common::Serializer &s) { s.skip(4, VER(14), VER(19)); // OBSOLETE: Used to be _numExports s.skip(4, VER(14), VER(19)); // OBSOLETE: Used to be _numSynonyms - s.syncAsSint32LE(_lockers); + s.syncAsUint32LE(_lockers); // Sync _objects. This is a hashmap, and we use the following on disk format: // First we store the number of items in the hashmap, then we store each diff --git a/engines/sci/engine/script.cpp b/engines/sci/engine/script.cpp index a1ba52184d8..cbc91293530 100644 --- a/engines/sci/engine/script.cpp +++ b/engines/sci/engine/script.cpp @@ -841,6 +841,21 @@ void Script::relocateSci3(const SegmentId segmentId) { void Script::incrementLockers() { assert(!_markedAsDeleted); + if (_lockers == 0xffffffff) { + // FIXME + // The locker on system scripts, most notably script 999, increases throughout + // the game and can eventually overflow, causing script 999 to be unloaded + // and crash. We have been provided QFG1 SCI0 save games where this occurred + // within hours of play over the course of three days. Debugging shows that + // this value increases rapidly, for example: on every `class Event` opcode + // during input polling, or when our kAnimate code calls `doit` on objects. + // Until this is fixed properly, log these overflow attempts and lower the + // counter so that the warnings continue without flooding the log. + // At the point where a resource usage counter reaches the billions, its value + // no longer has meaning, so the important thing for now is that it not crash. + warning("script %d locker maximum reached, resetting", _nr); + _lockers = 0x80000000; + } _lockers++; } @@ -849,11 +864,11 @@ void Script::decrementLockers() { _lockers--; } -int Script::getLockers() const { +uint Script::getLockers() const { return _lockers; } -void Script::setLockers(int lockers) { +void Script::setLockers(uint lockers) { assert(lockers == 0 || !_markedAsDeleted); _lockers = lockers; } diff --git a/engines/sci/engine/script.h b/engines/sci/engine/script.h index 4f9e086daf1..13c441d071c 100644 --- a/engines/sci/engine/script.h +++ b/engines/sci/engine/script.h @@ -75,7 +75,7 @@ private: SciSpan _script; /**< Script size includes alignment byte */ SciSpan _heap; /**< Start of heap if SCI1.1, NULL otherwise */ - int _lockers; /**< Number of classes and objects that require this script */ + uint _lockers; /**< Number of classes and objects that require this script */ SciSpan _exports; /**< Exports block or 0 if not present */ uint16 _numExports; /**< Number of export entries */ @@ -197,10 +197,10 @@ public: * Retrieves the number of locks held on this script. * @return the number of locks held on the previously identified script */ - int getLockers() const; + uint getLockers() const; /** Sets the number of locks held on this script. */ - void setLockers(int lockers); + void setLockers(uint lockers); /** * Retrieves the offset of the export table in the script