Skip to content

Commit

Permalink
Check for multiplication overflow in MSADPCM decodeSample
Browse files Browse the repository at this point in the history
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 mpruett#41
  • Loading branch information
antlarr committed Mar 6, 2017
1 parent c48e4c6 commit beacc44
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 6 deletions.
5 changes: 3 additions & 2 deletions libaudiofile/modules/BlockCodec.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
47 changes: 43 additions & 4 deletions libaudiofile/modules/MSADPCM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down Expand Up @@ -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++;
Expand Down

0 comments on commit beacc44

Please sign in to comment.