diff options
author | Colin Snover | 2017-11-11 16:11:06 -0600 |
---|---|---|
committer | Colin Snover | 2017-11-12 23:15:05 -0600 |
commit | a6659ba9d577998139cbb9a61532f823a24bc3b9 (patch) | |
tree | cccf6501b521fc8c20d3faf05ec1edbe2c711ea2 /engines/dreamweb/object.cpp | |
parent | 0eda63bed1b2d7fe0dba1360cad880b826248eaa (diff) | |
download | scummvm-rg350-a6659ba9d577998139cbb9a61532f823a24bc3b9.tar.gz scummvm-rg350-a6659ba9d577998139cbb9a61532f823a24bc3b9.tar.bz2 scummvm-rg350-a6659ba9d577998139cbb9a61532f823a24bc3b9.zip |
DREAMWEB: Use accurate memory reclamation for Ex transfers
When the Ex memory regions are close to full, it is possible for
the game to fail to purge objects and then crash with an OOM error
even if it isn't actually out of memory. This patch calculates the
amount of free memory truly needed when allocating to Ex memory to
allow exactly the entire frame & text regions to be used, instead
previously where a hard-coded amount of free space to maintain was
used, which guaranteed that the entire memory region could not
actually be used by the game.
This change may be masking some underlying memory leak, or it may
just be that near the end of the game the game naturally comes
close to reaching the maximum memory region size. For the moment,
I am assuming the latter.
This commit also adds some assertion checks to the memory transfer
functions to make sure the regions don't quietly overflow in other
cases, since pickupConts performs transfers in a manner that
doesn't ensure enough free memory exists for them to be successful.
Fixes Trac#6820.
Diffstat (limited to 'engines/dreamweb/object.cpp')
-rw-r--r-- | engines/dreamweb/object.cpp | 16 |
1 files changed, 12 insertions, 4 deletions
diff --git a/engines/dreamweb/object.cpp b/engines/dreamweb/object.cpp index 181987d721..9191702eee 100644 --- a/engines/dreamweb/object.cpp +++ b/engines/dreamweb/object.cpp @@ -253,6 +253,7 @@ void DreamWebEngine::transferText(uint8 from, uint8 to) { char *dst = _exText._text + _vars._exTextPos; size_t len = strlen(src); + assert(_vars._exTextPos + len + 1 <= kExtextlen); memcpy(dst, src, len + 1); _vars._exTextPos += len + 1; } @@ -1010,7 +1011,7 @@ ObjectRef DreamWebEngine::findOpenPos() { } byte DreamWebEngine::transferToEx(uint8 from) { - emergencyPurge(); + emergencyPurge(from); byte pos = getExPos(); DynObject *exObject = getExAd(pos); @@ -1128,11 +1129,18 @@ void DreamWebEngine::incRyanPage() { delPointer(); } -void DreamWebEngine::emergencyPurge() { +void DreamWebEngine::emergencyPurge(uint8 from) { debug(2, "Ex memory: frames %d/%d, text %d/%d", _vars._exFramePos, kExframeslen, _vars._exTextPos, kExtextlen); - while (_vars._exFramePos + 4000 >= kExframeslen || - _vars._exTextPos + 400 >= kExtextlen) + uint16 frameBytesNeeded = 0; + for (int offset = 0; offset <= 1; ++offset) { + const Frame &freeFrame = _freeFrames._frames[3 * from + offset]; + frameBytesNeeded += freeFrame.width * freeFrame.height; + } + const uint16 textBytesNeeded = strlen(_freeDesc.getString(from)) + 1; + + while (_vars._exFramePos + frameBytesNeeded > kExframeslen || + _vars._exTextPos + textBytesNeeded > kExtextlen) { purgeAnItem(); debug(2, "Ex memory after purging: frames %d/%d, text %d/%d", _vars._exFramePos, kExframeslen, _vars._exTextPos, kExtextlen); |