Modify autoconf tests for intrinsics to stop clang from optimizing them away.
[opus.git] / src / opus_multistream_decoder.c
index 495fb07..b95eaa6 100644 (file)
@@ -75,7 +75,7 @@ int opus_multistream_decoder_init(
    char *ptr;
 
    if ((channels>255) || (channels<1) || (coupled_streams>streams) ||
-       (coupled_streams+streams>255) || (streams<1) || (coupled_streams<0))
+       (streams<1) || (coupled_streams<0) || (streams>255-coupled_streams))
       return OPUS_BAD_ARG;
 
    st->layout.nb_channels = channels;
@@ -119,7 +119,7 @@ OpusMSDecoder *opus_multistream_decoder_create(
    int ret;
    OpusMSDecoder *st;
    if ((channels>255) || (channels<1) || (coupled_streams>streams) ||
-       (coupled_streams+streams>255) || (streams<1) || (coupled_streams<0))
+       (streams<1) || (coupled_streams<0) || (streams>255-coupled_streams))
    {
       if (error)
          *error = OPUS_BAD_ARG;
@@ -152,6 +152,35 @@ typedef void (*opus_copy_channel_out_func)(
   int frame_size
 );
 
+static int opus_multistream_packet_validate(const unsigned char *data,
+      opus_int32 len, int nb_streams, opus_int32 Fs)
+{
+   int s;
+   int count;
+   unsigned char toc;
+   opus_int16 size[48];
+   int samples=0;
+   opus_int32 packet_offset;
+
+   for (s=0;s<nb_streams;s++)
+   {
+      int tmp_samples;
+      if (len<=0)
+         return OPUS_INVALID_PACKET;
+      count = opus_packet_parse_impl(data, len, s!=nb_streams-1, &toc, NULL,
+                                     size, NULL, &packet_offset);
+      if (count<0)
+         return count;
+      tmp_samples = opus_packet_get_nb_samples(data, packet_offset, Fs);
+      if (s!=0 && samples != tmp_samples)
+         return OPUS_INVALID_PACKET;
+      samples = tmp_samples;
+      data += packet_offset;
+      len -= packet_offset;
+   }
+   return samples;
+}
+
 static int opus_multistream_decode_native(
       OpusMSDecoder *st,
       const unsigned char *data,
@@ -183,9 +212,28 @@ static int opus_multistream_decode_native(
    if (len==0)
       do_plc = 1;
    if (len < 0)
+   {
+      RESTORE_STACK;
       return OPUS_BAD_ARG;
+   }
    if (!do_plc && len < 2*st->layout.nb_streams-1)
+   {
+      RESTORE_STACK;
       return OPUS_INVALID_PACKET;
+   }
+   if (!do_plc)
+   {
+      int ret = opus_multistream_packet_validate(data, len, st->layout.nb_streams, Fs);
+      if (ret < 0)
+      {
+         RESTORE_STACK;
+         return ret;
+      } else if (ret > frame_size)
+      {
+         RESTORE_STACK;
+         return OPUS_BUFFER_TOO_SMALL;
+      }
+   }
    for (s=0;s<st->layout.nb_streams;s++)
    {
       OpusDecoder *dec;
@@ -197,22 +245,12 @@ static int opus_multistream_decode_native(
       if (!do_plc && len<=0)
       {
          RESTORE_STACK;
-         return OPUS_INVALID_PACKET;
+         return OPUS_INTERNAL_ERROR;
       }
       packet_offset = 0;
       ret = opus_decode_native(dec, data, len, buf, frame_size, decode_fec, s!=st->layout.nb_streams-1, &packet_offset, soft_clip);
       data += packet_offset;
       len -= packet_offset;
-      if (ret > frame_size)
-      {
-         RESTORE_STACK;
-         return OPUS_BUFFER_TOO_SMALL;
-      }
-      if (s>0 && ret != frame_size)
-      {
-         RESTORE_STACK;
-         return OPUS_INVALID_PACKET;
-      }
       if (ret <= 0)
       {
          RESTORE_STACK;
@@ -400,6 +438,10 @@ int opus_multistream_decoder_ctl(OpusMSDecoder *st, int request, ...)
           int s;
           opus_uint32 *value = va_arg(ap, opus_uint32*);
           opus_uint32 tmp;
+          if (!value)
+          {
+             goto bad_arg;
+          }
           *value = 0;
           for (s=0;s<st->layout.nb_streams;s++)
           {
@@ -442,6 +484,10 @@ int opus_multistream_decoder_ctl(OpusMSDecoder *st, int request, ...)
           if (stream_id<0 || stream_id >= st->layout.nb_streams)
              ret = OPUS_BAD_ARG;
           value = va_arg(ap, OpusDecoder**);
+          if (!value)
+          {
+             goto bad_arg;
+          }
           for (s=0;s<stream_id;s++)
           {
              if (s < st->layout.nb_coupled_streams)
@@ -479,6 +525,9 @@ int opus_multistream_decoder_ctl(OpusMSDecoder *st, int request, ...)
 
    va_end(ap);
    return ret;
+bad_arg:
+   va_end(ap);
+   return OPUS_BAD_ARG;
 }