| From beacc44eb8cdf6d58717ec1a5103c5141f1b37f9 Mon Sep 17 00:00:00 2001 |
| From: Antonio Larrosa <larrosa@kde.org> |
| Date: Mon, 6 Mar 2017 13:43:53 +0100 |
| Subject: [PATCH] Check for multiplication overflow in MSADPCM decodeSample |
| |
| Check for multiplication overflow (using __builtin_mul_overflow |
| if available) in MSADPCM.cpp decodeSample and return an empty |
| decoded block if an error occurs. |
| |
| This fixes the 00193-audiofile-signintoverflow-MSADPCM case of #41 |
| |
| Signed-off-by: Peter Korsgaard <peter@korsgaard.com> |
| --- |
| libaudiofile/modules/BlockCodec.cpp | 5 ++-- |
| libaudiofile/modules/MSADPCM.cpp | 47 +++++++++++++++++++++++++++++++++---- |
| 2 files changed, 46 insertions(+), 6 deletions(-) |
| |
| diff --git a/libaudiofile/modules/BlockCodec.cpp b/libaudiofile/modules/BlockCodec.cpp |
| index 45925e8..4731be1 100644 |
| --- a/libaudiofile/modules/BlockCodec.cpp |
| +++ b/libaudiofile/modules/BlockCodec.cpp |
| @@ -52,8 +52,9 @@ void BlockCodec::runPull() |
| // Decompress into m_outChunk. |
| for (int i=0; i<blocksRead; i++) |
| { |
| - decodeBlock(static_cast<const uint8_t *>(m_inChunk->buffer) + i * m_bytesPerPacket, |
| - static_cast<int16_t *>(m_outChunk->buffer) + i * m_framesPerPacket * m_track->f.channelCount); |
| + if (decodeBlock(static_cast<const uint8_t *>(m_inChunk->buffer) + i * m_bytesPerPacket, |
| + static_cast<int16_t *>(m_outChunk->buffer) + i * m_framesPerPacket * m_track->f.channelCount)==0) |
| + break; |
| |
| framesRead += m_framesPerPacket; |
| } |
| diff --git a/libaudiofile/modules/MSADPCM.cpp b/libaudiofile/modules/MSADPCM.cpp |
| index 8ea3c85..ef9c38c 100644 |
| --- a/libaudiofile/modules/MSADPCM.cpp |
| +++ b/libaudiofile/modules/MSADPCM.cpp |
| @@ -101,24 +101,60 @@ static const int16_t adaptationTable[] = |
| 768, 614, 512, 409, 307, 230, 230, 230 |
| }; |
| |
| +int firstBitSet(int x) |
| +{ |
| + int position=0; |
| + while (x!=0) |
| + { |
| + x>>=1; |
| + ++position; |
| + } |
| + return position; |
| +} |
| + |
| +#ifndef __has_builtin |
| +#define __has_builtin(x) 0 |
| +#endif |
| + |
| +int multiplyCheckOverflow(int a, int b, int *result) |
| +{ |
| +#if (defined __GNUC__ && __GNUC__ >= 5) || ( __clang__ && __has_builtin(__builtin_mul_overflow)) |
| + return __builtin_mul_overflow(a, b, result); |
| +#else |
| + if (firstBitSet(a)+firstBitSet(b)>31) // int is signed, so we can't use 32 bits |
| + return true; |
| + *result = a * b; |
| + return false; |
| +#endif |
| +} |
| + |
| + |
| // Compute a linear PCM value from the given differential coded value. |
| static int16_t decodeSample(ms_adpcm_state &state, |
| - uint8_t code, const int16_t *coefficient) |
| + uint8_t code, const int16_t *coefficient, bool *ok=NULL) |
| { |
| int linearSample = (state.sample1 * coefficient[0] + |
| state.sample2 * coefficient[1]) >> 8; |
| + int delta; |
| |
| linearSample += ((code & 0x08) ? (code - 0x10) : code) * state.delta; |
| |
| linearSample = clamp(linearSample, MIN_INT16, MAX_INT16); |
| |
| - int delta = (state.delta * adaptationTable[code]) >> 8; |
| + if (multiplyCheckOverflow(state.delta, adaptationTable[code], &delta)) |
| + { |
| + if (ok) *ok=false; |
| + _af_error(AF_BAD_COMPRESSION, "Error decoding sample"); |
| + return 0; |
| + } |
| + delta >>= 8; |
| if (delta < 16) |
| delta = 16; |
| |
| state.delta = delta; |
| state.sample2 = state.sample1; |
| state.sample1 = linearSample; |
| + if (ok) *ok=true; |
| |
| return static_cast<int16_t>(linearSample); |
| } |
| @@ -212,13 +248,16 @@ int MSADPCM::decodeBlock(const uint8_t *encoded, int16_t *decoded) |
| { |
| uint8_t code; |
| int16_t newSample; |
| + bool ok; |
| |
| code = *encoded >> 4; |
| - newSample = decodeSample(*state[0], code, coefficient[0]); |
| + newSample = decodeSample(*state[0], code, coefficient[0], &ok); |
| + if (!ok) return 0; |
| *decoded++ = newSample; |
| |
| code = *encoded & 0x0f; |
| - newSample = decodeSample(*state[1], code, coefficient[1]); |
| + newSample = decodeSample(*state[1], code, coefficient[1], &ok); |
| + if (!ok) return 0; |
| *decoded++ = newSample; |
| |
| encoded++; |
| -- |
| 2.11.0 |
| |