mirror of
https://github.com/scummvm/scummvm.git
synced 2026-06-20 05:45:29 +00:00
SCI: Prevent script lockers from overflowing
Script::_locker is supposed to track the number of classes and objects that use a script in order to determine when it can be safely unloaded. But for system script 999, _locker rapidly increases throughout the game and eventually overflows. This causes script 999 to unload and crash. Other scripts may also be affected. We have been provided QFG1 SCI0 saves where this occurred over the course of hours within only three days. Logging shows this value skyrocketing in many games even when they are just polling input or animating the screen. Alarmingly, this suggests that many SCI games become unplayable in ScummVM after an achievable amount of game time. This may be a large and complex problem within the script locker system. For now, we can mitigate this by making Script::_locker unsigned, which its callers expected it to be, and by logging overflow attempts and lowering the locker. This fixes existing save games, even if they have already overflowed the signed maximum.
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user