diff options
author | Johannes Schickel | 2014-08-24 00:36:32 +0200 |
---|---|---|
committer | Johannes Schickel | 2014-08-24 00:57:39 +0200 |
commit | c5dfe1d917ac867204aa216565b246f2815fc726 (patch) | |
tree | 4093ea70ed9e9ee7f77601d16ef3d989b12a8fad /engines/kyra | |
parent | 3612f88025c30dd04ddc1929812e9bc165f0e7ea (diff) | |
download | scummvm-rg350-c5dfe1d917ac867204aa216565b246f2815fc726.tar.gz scummvm-rg350-c5dfe1d917ac867204aa216565b246f2815fc726.tar.bz2 scummvm-rg350-c5dfe1d917ac867204aa216565b246f2815fc726.zip |
KYRA: Add safety checks for getProgram/getInstrument return values.
This fixes a crash in Hand of Fate when scaring off the rat by using the
swampsnake potion on Zanthia. This crash is timing sensitive since the game is
stopping the offending sound resource at this point. If it still gets to the
instruction setting up an invalid instrument, it will crash ScummVM with in
invalid read.
Diffstat (limited to 'engines/kyra')
-rw-r--r-- | engines/kyra/sound_adlib.cpp | 58 |
1 files changed, 52 insertions, 6 deletions
diff --git a/engines/kyra/sound_adlib.cpp b/engines/kyra/sound_adlib.cpp index 92b50bce4b..bc2931a5ae 100644 --- a/engines/kyra/sound_adlib.cpp +++ b/engines/kyra/sound_adlib.cpp @@ -1372,9 +1372,18 @@ int AdLibDriver::update_setupProgram(uint8 *&dataptr, Channel &channel, uint8 va return 0; uint8 *ptr = getProgram(value); - //TODO: Check in LoL CD AdLib driver - if (!ptr) + + // In case we encounter an invalid program we simply ignore it and do + // nothing instead. The original did not care about invalid programs and + // simply tried to play them anyway... But to avoid crashes due we ingore + // them. + // This, for example, happens in the Lands of Lore intro when Scotia gets + // the ring in the intro. + if (!ptr) { + debugC(3, kDebugLevelSound, "AdLibDriver::update_setupProgram: Invalid program %d specified", value); return 0; + } + uint8 chan = *ptr++; uint8 priority = *ptr++; @@ -1506,6 +1515,14 @@ int AdLibDriver::update_stopOtherChannel(uint8 *&dataptr, Channel &channel, uint int AdLibDriver::update_waitForEndOfProgram(uint8 *&dataptr, Channel &channel, uint8 value) { uint8 *ptr = getProgram(value); + + // Safety check in case an invalid program is specified. This would make + // getProgram return a nullptr and thus cause invalid memory reads. + if (!ptr) { + debugC(3, kDebugLevelSound, "AdLibDriver::update_waitForEndOfProgram: Invalid program %d specified", value); + return 0; + } + uint8 chan = *ptr; if (!_channels[chan].dataptr) @@ -1516,7 +1533,20 @@ int AdLibDriver::update_waitForEndOfProgram(uint8 *&dataptr, Channel &channel, u } int AdLibDriver::update_setupInstrument(uint8 *&dataptr, Channel &channel, uint8 value) { - setupInstrument(_curRegOffset, getInstrument(value), channel); + uint8 *instrument = getInstrument(value); + + // We add a safety check to avoid setting up invalid instruments. This is + // not done in the original. However, to avoid crashes due to invalid + // memory reads we simply ignore the request. + // This happens, for example, in Hand of Fate when using the swampsnake + // potion on Zanthia to scare off the rat in the cave in the first chapter + // of the game. + if (!instrument) { + debugC(3, kDebugLevelSound, "AdLibDriver::update_setupInstrument: Invalid instrument %d specified", value); + return 0; + } + + setupInstrument(_curRegOffset, instrument, channel); return 0; } @@ -1785,20 +1815,36 @@ int AdLibDriver::update_setupRhythmSection(uint8 *&dataptr, Channel &channel, ui _curChannel = 6; _curRegOffset = _regOffset[6]; - setupInstrument(_curRegOffset, getInstrument(value), channel); + uint8 *instrument; + instrument = getInstrument(value); + if (instrument) { + setupInstrument(_curRegOffset, instrument, channel); + } else { + debugC(3, kDebugLevelSound, "AdLibDriver::update_setupRhythmSection: Invalid instrument %d for channel 6 specified", value); + } _unkValue6 = channel.opLevel2; _curChannel = 7; _curRegOffset = _regOffset[7]; - setupInstrument(_curRegOffset, getInstrument(*dataptr++), channel); + instrument = getInstrument(*dataptr++); + if (instrument) { + setupInstrument(_curRegOffset, instrument, channel); + } else { + debugC(3, kDebugLevelSound, "AdLibDriver::update_setupRhythmSection: Invalid instrument %d for channel 7 specified", value); + } _unkValue7 = channel.opLevel1; _unkValue8 = channel.opLevel2; _curChannel = 8; _curRegOffset = _regOffset[8]; - setupInstrument(_curRegOffset, getInstrument(*dataptr++), channel); + instrument = getInstrument(*dataptr++); + if (instrument) { + setupInstrument(_curRegOffset, instrument, channel); + } else { + debugC(3, kDebugLevelSound, "AdLibDriver::update_setupRhythmSection: Invalid instrument %d for channel 8 specified", value); + } _unkValue9 = channel.opLevel1; _unkValue10 = channel.opLevel2; |