diff --git a/celt/stack_alloc.h b/celt/stack_alloc.h
index a6f06d2263afcf146bf7c5d6c15f39d32f6ba60e..1c093a8cdce619487ddecc20bf33936012e371a7 100644
--- a/celt/stack_alloc.h
+++ b/celt/stack_alloc.h
@@ -146,4 +146,26 @@ extern char *global_stack_top;
 
 #endif /* VAR_ARRAYS */
 
+
+#ifdef ENABLE_VALGRIND
+
+#include <valgrind/memcheck.h>
+#define OPUS_CHECK_ARRAY(ptr, len) VALGRIND_CHECK_MEM_IS_DEFINED(ptr, len*sizeof(*ptr))
+#define OPUS_CHECK_VALUE(value) VALGRIND_CHECK_VALUE_IS_DEFINED(value)
+#define OPUS_CHECK_ARRAY_COND(ptr, len) VALGRIND_CHECK_MEM_IS_DEFINED(ptr, len*sizeof(*ptr))
+#define OPUS_CHECK_VALUE_COND(value) VALGRIND_CHECK_VALUE_IS_DEFINED(value)
+#define OPUS_PRINT_INT(value) do {fprintf(stderr, #value " = %d at %s:%d\n", value, __FILE__, __LINE__);}while(0)
+#define OPUS_FPRINTF fprintf
+
+#else
+
+static inline int _opus_false(void) {return 0;}
+#define OPUS_CHECK_ARRAY(ptr, len) _opus_false()
+#define OPUS_CHECK_VALUE(value) _opus_false()
+#define OPUS_PRINT_INT(value) do{}while(0)
+#define OPUS_FPRINTF (void)
+
+#endif
+
+
 #endif /* STACK_ALLOC_H */
diff --git a/src/opus_decoder.c b/src/opus_decoder.c
index cf838df753554ced12909f62e8ff24ddc822e805..2265cc1b44512824c8c1be4513b64255858b5009 100644
--- a/src/opus_decoder.c
+++ b/src/opus_decoder.c
@@ -543,6 +543,13 @@ static int opus_decode_frame(OpusDecoder *st, const unsigned char *data,
 
    st->prev_mode = mode;
    st->prev_redundancy = redundancy && !celt_to_silk;
+
+   if (celt_ret>=0)
+   {
+      if (OPUS_CHECK_ARRAY(pcm, audiosize*st->channels))
+         OPUS_PRINT_INT(audiosize);
+   }
+
    RESTORE_STACK;
    return celt_ret < 0 ? celt_ret : audiosize;
 
@@ -744,12 +751,14 @@ int opus_decode_native(OpusDecoder *st, const unsigned char *data,
       int pcm_count=0;
       do {
          int ret;
-         ret = opus_decode_frame(st, NULL, 0, pcm, frame_size-pcm_count, 0);
+         ret = opus_decode_frame(st, NULL, 0, pcm+pcm_count*st->channels, frame_size-pcm_count, 0);
          if (ret<0)
             return ret;
-         pcm += st->channels*ret;
          pcm_count += ret;
       } while (pcm_count < frame_size);
+      celt_assert(pcm_count == frame_size);
+      if (OPUS_CHECK_ARRAY(pcm, pcm_count*st->channels))
+         OPUS_PRINT_INT(pcm_count);
       return pcm_count;
    } else if (len<0)
       return OPUS_BAD_ARG;
@@ -782,8 +791,11 @@ int opus_decode_native(OpusDecoder *st, const unsigned char *data,
             packet_frame_size, 1);
       if (ret<0)
          return ret;
-      else
+      else {
+         if (OPUS_CHECK_ARRAY(pcm, frame_size*st->channels))
+            OPUS_PRINT_INT(frame_size);
          return frame_size;
+      }
    }
    tot_offset = 0;
    if (count < 0)
@@ -804,17 +816,19 @@ int opus_decode_native(OpusDecoder *st, const unsigned char *data,
    for (i=0;i<count;i++)
    {
       int ret;
-      ret = opus_decode_frame(st, data, size[i], pcm, frame_size-nb_samples, decode_fec);
+      ret = opus_decode_frame(st, data, size[i], pcm+nb_samples*st->channels, frame_size-nb_samples, 0);
       if (ret<0)
          return ret;
+      celt_assert(ret==packet_frame_size);
       data += size[i];
       tot_offset += size[i];
-      pcm += ret*st->channels;
       nb_samples += ret;
    }
    if (packet_offset != NULL)
       *packet_offset = tot_offset;
    st->last_packet_duration = nb_samples;
+   if (OPUS_CHECK_ARRAY(pcm, nb_samples*st->channels))
+      OPUS_PRINT_INT(nb_samples);
    return nb_samples;
 }