iLBC: Handle a case of bad input data

We detect an unreasonable state (caused by a bad encoded stream)
before it can lead to problems, and handle it by resetting the
decoder.

NOPRESUBMIT=true
BUG=chromium:617124

Review-Url: https://codereview.webrtc.org/2255203002
Cr-Commit-Position: refs/heads/master@{#13888}
diff --git a/webrtc/modules/audio_coding/BUILD.gn b/webrtc/modules/audio_coding/BUILD.gn
index ce8ab6f..9d426e9 100644
--- a/webrtc/modules/audio_coding/BUILD.gn
+++ b/webrtc/modules/audio_coding/BUILD.gn
@@ -446,6 +446,7 @@
   deps = [
     ":audio_decoder_interface",
     ":audio_encoder_interface",
+    "../../base:rtc_base_approved",
     "../../common_audio",
   ]
 }
diff --git a/webrtc/modules/audio_coding/codecs/ilbc/cb_construct.c b/webrtc/modules/audio_coding/codecs/ilbc/cb_construct.c
index cacf3ac..4c72a6e 100644
--- a/webrtc/modules/audio_coding/codecs/ilbc/cb_construct.c
+++ b/webrtc/modules/audio_coding/codecs/ilbc/cb_construct.c
@@ -16,6 +16,8 @@
 
 ******************************************************************/
 
+#include "cb_construct.h"
+
 #include "defines.h"
 #include "gain_dequant.h"
 #include "get_cd_vec.h"
@@ -24,7 +26,7 @@
  *  Construct decoded vector from codebook and gains.
  *---------------------------------------------------------------*/
 
-void WebRtcIlbcfix_CbConstruct(
+bool WebRtcIlbcfix_CbConstruct(
     int16_t *decvector,  /* (o) Decoded vector */
     int16_t *index,   /* (i) Codebook indices */
     int16_t *gain_index,  /* (i) Gain quantization indices */
@@ -50,9 +52,12 @@
   /* codebook vector construction and construction of total vector */
 
   /* Stack based */
-  WebRtcIlbcfix_GetCbVec(cbvec0, mem, (size_t)index[0], lMem, veclen);
-  WebRtcIlbcfix_GetCbVec(cbvec1, mem, (size_t)index[1], lMem, veclen);
-  WebRtcIlbcfix_GetCbVec(cbvec2, mem, (size_t)index[2], lMem, veclen);
+  if (!WebRtcIlbcfix_GetCbVec(cbvec0, mem, (size_t)index[0], lMem, veclen))
+    return false;  // Failure.
+  if (!WebRtcIlbcfix_GetCbVec(cbvec1, mem, (size_t)index[1], lMem, veclen))
+    return false;  // Failure.
+  if (!WebRtcIlbcfix_GetCbVec(cbvec2, mem, (size_t)index[2], lMem, veclen))
+    return false;  // Failure.
 
   gainPtr = &gain[0];
   for (j=0;j<veclen;j++) {
@@ -63,5 +68,5 @@
     decvector[j] = (int16_t)((a32 + 8192) >> 14);
   }
 
-  return;
+  return true;  // Success.
 }
diff --git a/webrtc/modules/audio_coding/codecs/ilbc/cb_construct.h b/webrtc/modules/audio_coding/codecs/ilbc/cb_construct.h
index b676ef9..45db85e 100644
--- a/webrtc/modules/audio_coding/codecs/ilbc/cb_construct.h
+++ b/webrtc/modules/audio_coding/codecs/ilbc/cb_construct.h
@@ -19,20 +19,21 @@
 #ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ILBC_MAIN_SOURCE_CB_CONSTRUCT_H_
 #define WEBRTC_MODULES_AUDIO_CODING_CODECS_ILBC_MAIN_SOURCE_CB_CONSTRUCT_H_
 
+#include <stdbool.h>
 #include "defines.h"
 
 /*----------------------------------------------------------------*
  *  Construct decoded vector from codebook and gains.
  *---------------------------------------------------------------*/
 
-void WebRtcIlbcfix_CbConstruct(
-    int16_t *decvector,  /* (o) Decoded vector */
-    int16_t *index,   /* (i) Codebook indices */
-    int16_t *gain_index,  /* (i) Gain quantization indices */
-    int16_t *mem,   /* (i) Buffer for codevector construction */
-    size_t lMem,   /* (i) Length of buffer */
-    size_t veclen   /* (i) Length of vector */
-                               );
-
+// Returns true on success, false on failure.
+bool WebRtcIlbcfix_CbConstruct(
+    int16_t* decvector,  /* (o) Decoded vector */
+    int16_t* index,      /* (i) Codebook indices */
+    int16_t* gain_index, /* (i) Gain quantization indices */
+    int16_t* mem,        /* (i) Buffer for codevector construction */
+    size_t lMem,         /* (i) Length of buffer */
+    size_t veclen        /* (i) Length of vector */
+    ) WARN_UNUSED_RESULT;
 
 #endif
diff --git a/webrtc/modules/audio_coding/codecs/ilbc/decode.c b/webrtc/modules/audio_coding/codecs/ilbc/decode.c
index 4c8497a..a6e045d 100644
--- a/webrtc/modules/audio_coding/codecs/ilbc/decode.c
+++ b/webrtc/modules/audio_coding/codecs/ilbc/decode.c
@@ -28,6 +28,7 @@
 #include "decode_residual.h"
 #include "unpack_bits.h"
 #include "hp_output.h"
+#include "init_decode.h"
 #ifndef WEBRTC_ARCH_BIG_ENDIAN
 #include "swap_bytes.h"
 #endif
@@ -36,7 +37,7 @@
  *  main decoder function
  *---------------------------------------------------------------*/
 
-void WebRtcIlbcfix_DecodeImpl(
+int WebRtcIlbcfix_DecodeImpl(
     int16_t *decblock,    /* (o) decoded signal block */
     const uint16_t *bytes, /* (i) encoded signal bits */
     IlbcDecoder *iLBCdec_inst, /* (i/o) the decoder state
@@ -44,6 +45,9 @@
     int16_t mode      /* (i) 0: bad packet, PLC,
                                                                    1: normal */
                            ) {
+  const int old_mode = iLBCdec_inst->mode;
+  const int old_use_enhancer = iLBCdec_inst->use_enhancer;
+
   size_t i;
   int16_t order_plus_one;
 
@@ -100,7 +104,9 @@
                                           lsfdeq, LPC_FILTERORDER, iLBCdec_inst);
 
       /* Decode the residual using the cb and gain indexes */
-      WebRtcIlbcfix_DecodeResidual(iLBCdec_inst, iLBCbits_inst, decresidual, syntdenum);
+      if (!WebRtcIlbcfix_DecodeResidual(iLBCdec_inst, iLBCbits_inst,
+                                        decresidual, syntdenum))
+        goto error;
 
       /* preparing the plc for a future loss! */
       WebRtcIlbcfix_DoThePlc(
@@ -241,4 +247,11 @@
   if (mode==0) { /* PLC was used */
     iLBCdec_inst->prev_enh_pl=1;
   }
+
+  return 0;  // Success.
+
+error:
+  // The decoder got sick from eating that data. Reset it and return.
+  WebRtcIlbcfix_InitDecode(iLBCdec_inst, old_mode, old_use_enhancer);
+  return -1;  // Error
 }
diff --git a/webrtc/modules/audio_coding/codecs/ilbc/decode.h b/webrtc/modules/audio_coding/codecs/ilbc/decode.h
index 0c4c2ef..f45fedd 100644
--- a/webrtc/modules/audio_coding/codecs/ilbc/decode.h
+++ b/webrtc/modules/audio_coding/codecs/ilbc/decode.h
@@ -25,13 +25,14 @@
  *  main decoder function
  *---------------------------------------------------------------*/
 
-void WebRtcIlbcfix_DecodeImpl(
-    int16_t *decblock,    /* (o) decoded signal block */
-    const uint16_t *bytes, /* (i) encoded signal bits */
-    IlbcDecoder *iLBCdec_inst, /* (i/o) the decoder state
+// Returns 0 on success, -1 on error.
+int WebRtcIlbcfix_DecodeImpl(
+    int16_t* decblock,         /* (o) decoded signal block */
+    const uint16_t* bytes,     /* (i) encoded signal bits */
+    IlbcDecoder* iLBCdec_inst, /* (i/o) the decoder state
                                            structure */
-    int16_t mode      /* (i) 0: bad packet, PLC,
-                                                                   1: normal */
-                           );
+    int16_t mode               /* (i) 0: bad packet, PLC,
+                                      1: normal */
+    ) WARN_UNUSED_RESULT;
 
 #endif
diff --git a/webrtc/modules/audio_coding/codecs/ilbc/decode_residual.c b/webrtc/modules/audio_coding/codecs/ilbc/decode_residual.c
index b8a067e..dd5c353 100644
--- a/webrtc/modules/audio_coding/codecs/ilbc/decode_residual.c
+++ b/webrtc/modules/audio_coding/codecs/ilbc/decode_residual.c
@@ -16,6 +16,8 @@
 
 ******************************************************************/
 
+#include "decode_residual.h"
+
 #include <string.h>
 
 #include "defines.h"
@@ -32,7 +34,7 @@
  *  frame residual decoder function (subrutine to iLBC_decode)
  *---------------------------------------------------------------*/
 
-void WebRtcIlbcfix_DecodeResidual(
+bool WebRtcIlbcfix_DecodeResidual(
     IlbcDecoder *iLBCdec_inst,
     /* (i/o) the decoder state structure */
     iLBC_bits *iLBC_encbits, /* (i/o) Encoded bits, which are used
@@ -72,11 +74,11 @@
 
     /* construct decoded vector */
 
-    WebRtcIlbcfix_CbConstruct(
-        &decresidual[start_pos+iLBCdec_inst->state_short_len],
-        iLBC_encbits->cb_index, iLBC_encbits->gain_index,
-        mem+CB_MEML-ST_MEM_L_TBL,
-        ST_MEM_L_TBL, diff);
+    if (!WebRtcIlbcfix_CbConstruct(
+            &decresidual[start_pos + iLBCdec_inst->state_short_len],
+            iLBC_encbits->cb_index, iLBC_encbits->gain_index,
+            mem + CB_MEML - ST_MEM_L_TBL, ST_MEM_L_TBL, diff))
+      return false;  // Error.
 
   }
   else {/* put adaptive part in the beginning */
@@ -90,12 +92,11 @@
 
     /* construct decoded vector */
 
-    WebRtcIlbcfix_CbConstruct(
-        reverseDecresidual,
-        iLBC_encbits->cb_index, iLBC_encbits->gain_index,
-        mem+CB_MEML-ST_MEM_L_TBL,
-        ST_MEM_L_TBL, diff
-                              );
+    if (!WebRtcIlbcfix_CbConstruct(reverseDecresidual, iLBC_encbits->cb_index,
+                                   iLBC_encbits->gain_index,
+                                   mem + CB_MEML - ST_MEM_L_TBL, ST_MEM_L_TBL,
+                                   diff))
+      return false;  // Error.
 
     /* get decoded residual from reversed vector */
 
@@ -122,12 +123,12 @@
     for (subframe=0; subframe<Nfor; subframe++) {
 
       /* construct decoded vector */
-      WebRtcIlbcfix_CbConstruct(
-          &decresidual[(iLBC_encbits->startIdx+1+subframe)*SUBL],
-          iLBC_encbits->cb_index+subcount*CB_NSTAGES,
-          iLBC_encbits->gain_index+subcount*CB_NSTAGES,
-          mem, MEM_LF_TBL, SUBL
-                                );
+      if (!WebRtcIlbcfix_CbConstruct(
+              &decresidual[(iLBC_encbits->startIdx + 1 + subframe) * SUBL],
+              iLBC_encbits->cb_index + subcount * CB_NSTAGES,
+              iLBC_encbits->gain_index + subcount * CB_NSTAGES, mem, MEM_LF_TBL,
+              SUBL))
+        return false;  // Error;
 
       /* update memory */
       memmove(mem, mem + SUBL, (CB_MEML - SUBL) * sizeof(*mem));
@@ -160,12 +161,12 @@
     for (subframe=0; subframe<Nback; subframe++) {
 
       /* construct decoded vector */
-      WebRtcIlbcfix_CbConstruct(
-          &reverseDecresidual[subframe*SUBL],
-          iLBC_encbits->cb_index+subcount*CB_NSTAGES,
-          iLBC_encbits->gain_index+subcount*CB_NSTAGES,
-          mem, MEM_LF_TBL, SUBL
-                                );
+      if (!WebRtcIlbcfix_CbConstruct(
+              &reverseDecresidual[subframe * SUBL],
+              iLBC_encbits->cb_index + subcount * CB_NSTAGES,
+              iLBC_encbits->gain_index + subcount * CB_NSTAGES, mem, MEM_LF_TBL,
+              SUBL))
+        return false;  // Error.
 
       /* update memory */
       memmove(mem, mem + SUBL, (CB_MEML - SUBL) * sizeof(*mem));
@@ -179,4 +180,6 @@
     WebRtcSpl_MemCpyReversedOrder(decresidual+SUBL*Nback-1,
                                   reverseDecresidual, SUBL*Nback);
   }
+
+  return true;  // Success.
 }
diff --git a/webrtc/modules/audio_coding/codecs/ilbc/decode_residual.h b/webrtc/modules/audio_coding/codecs/ilbc/decode_residual.h
index 67f05a5..38f896e 100644
--- a/webrtc/modules/audio_coding/codecs/ilbc/decode_residual.h
+++ b/webrtc/modules/audio_coding/codecs/ilbc/decode_residual.h
@@ -19,20 +19,22 @@
 #ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ILBC_MAIN_SOURCE_DECODE_RESIDUAL_H_
 #define WEBRTC_MODULES_AUDIO_CODING_CODECS_ILBC_MAIN_SOURCE_DECODE_RESIDUAL_H_
 
+#include <stdbool.h>
 #include "defines.h"
 
 /*----------------------------------------------------------------*
  *  frame residual decoder function (subrutine to iLBC_decode)
  *---------------------------------------------------------------*/
 
-void WebRtcIlbcfix_DecodeResidual(
-    IlbcDecoder *iLBCdec_inst,
-    /* (i/o) the decoder state structure */
-    iLBC_bits *iLBC_encbits, /* (i/o) Encoded bits, which are used
-                                   for the decoding  */
-    int16_t *decresidual,  /* (o) decoded residual frame */
-    int16_t *syntdenum   /* (i) the decoded synthesis filter
-                                                   coefficients */
-                                  );
+// Returns true on success, false on failure. In case of failure, the decoder
+// state may be corrupted and needs resetting.
+bool WebRtcIlbcfix_DecodeResidual(
+    IlbcDecoder* iLBCdec_inst, /* (i/o) the decoder state structure */
+    iLBC_bits* iLBC_encbits,   /* (i/o) Encoded bits, which are used
+                                        for the decoding  */
+    int16_t* decresidual,      /* (o) decoded residual frame */
+    int16_t* syntdenum         /* (i) the decoded synthesis filter
+                                                         coefficients */
+    ) WARN_UNUSED_RESULT;
 
 #endif
diff --git a/webrtc/modules/audio_coding/codecs/ilbc/encode.c b/webrtc/modules/audio_coding/codecs/ilbc/encode.c
index 812ec8d..8206687 100644
--- a/webrtc/modules/audio_coding/codecs/ilbc/encode.c
+++ b/webrtc/modules/audio_coding/codecs/ilbc/encode.c
@@ -29,6 +29,7 @@
 #include "index_conv_enc.h"
 #include "pack_bits.h"
 #include "hp_input.h"
+#include "webrtc/base/checks.h"
 
 #ifdef SPLIT_10MS
 #include "unpack_bits.h"
@@ -206,11 +207,10 @@
 
       /* construct decoded vector */
 
-      WebRtcIlbcfix_CbConstruct(&decresidual[start_pos+iLBCenc_inst->state_short_len],
-                                iLBCbits_inst->cb_index, iLBCbits_inst->gain_index,
-                                mem+CB_MEML-ST_MEM_L_TBL, ST_MEM_L_TBL,
-                                diff
-                                );
+      RTC_CHECK(WebRtcIlbcfix_CbConstruct(
+          &decresidual[start_pos + iLBCenc_inst->state_short_len],
+          iLBCbits_inst->cb_index, iLBCbits_inst->gain_index,
+          mem + CB_MEML - ST_MEM_L_TBL, ST_MEM_L_TBL, diff));
 
     }
     else { /* put adaptive part in the beginning */
@@ -233,12 +233,10 @@
                              0);
 
       /* construct decoded vector */
-
-      WebRtcIlbcfix_CbConstruct(reverseDecresidual,
-                                iLBCbits_inst->cb_index, iLBCbits_inst->gain_index,
-                                mem+CB_MEML-ST_MEM_L_TBL, ST_MEM_L_TBL,
-                                diff
-                                );
+      RTC_CHECK(WebRtcIlbcfix_CbConstruct(
+            reverseDecresidual, iLBCbits_inst->cb_index,
+            iLBCbits_inst->gain_index, mem + CB_MEML - ST_MEM_L_TBL,
+            ST_MEM_L_TBL, diff));
 
       /* get decoded residual from reversed vector */
 
@@ -344,13 +342,11 @@
                              subcount);
 
       /* construct decoded vector */
-
-      WebRtcIlbcfix_CbConstruct(&decresidual[(iLBCbits_inst->startIdx+1+subframe)*SUBL],
-                                iLBCbits_inst->cb_index+subcount*CB_NSTAGES,
-                                iLBCbits_inst->gain_index+subcount*CB_NSTAGES,
-                                mem, MEM_LF_TBL,
-                                SUBL
-                                );
+      RTC_CHECK(WebRtcIlbcfix_CbConstruct(
+            &decresidual[(iLBCbits_inst->startIdx + 1 + subframe) * SUBL],
+            iLBCbits_inst->cb_index + subcount * CB_NSTAGES,
+            iLBCbits_inst->gain_index + subcount * CB_NSTAGES, mem, MEM_LF_TBL,
+            SUBL));
 
       /* update memory */
 
@@ -450,12 +446,11 @@
                              subcount);
 
       /* construct decoded vector */
-
-      WebRtcIlbcfix_CbConstruct(&reverseDecresidual[subframe*SUBL],
-                                iLBCbits_inst->cb_index+subcount*CB_NSTAGES,
-                                iLBCbits_inst->gain_index+subcount*CB_NSTAGES,
-                                mem, MEM_LF_TBL, SUBL
-                                );
+      RTC_CHECK(WebRtcIlbcfix_CbConstruct(
+            &reverseDecresidual[subframe * SUBL],
+            iLBCbits_inst->cb_index + subcount * CB_NSTAGES,
+            iLBCbits_inst->gain_index + subcount * CB_NSTAGES, mem, MEM_LF_TBL,
+            SUBL));
 
       /* update memory */
       memmove(mem, mem + SUBL, (CB_MEML - SUBL) * sizeof(*mem));
diff --git a/webrtc/modules/audio_coding/codecs/ilbc/get_cd_vec.c b/webrtc/modules/audio_coding/codecs/ilbc/get_cd_vec.c
index d7c2e75..272b49a 100644
--- a/webrtc/modules/audio_coding/codecs/ilbc/get_cd_vec.c
+++ b/webrtc/modules/audio_coding/codecs/ilbc/get_cd_vec.c
@@ -16,6 +16,8 @@
 
 ******************************************************************/
 
+#include "get_cd_vec.h"
+
 #include "defines.h"
 #include "constants.h"
 #include "create_augmented_vec.h"
@@ -24,7 +26,7 @@
  *  Construct codebook vector for given index.
  *---------------------------------------------------------------*/
 
-void WebRtcIlbcfix_GetCbVec(
+bool WebRtcIlbcfix_GetCbVec(
     int16_t *cbvec,   /* (o) Constructed codebook vector */
     int16_t *mem,   /* (i) Codebook buffer */
     size_t index,   /* (i) Codebook index */
@@ -93,6 +95,17 @@
     /* interpolated vectors */
 
     else {
+      if (cbveclen < SUBL) {
+        // We're going to fill in cbveclen + 5 elements of tempbuff2 in
+        // WebRtcSpl_FilterMAFastQ12, less than the SUBL + 5 elements we'll be
+        // using in WebRtcIlbcfix_CreateAugmentedVec. This error is caused by
+        // bad values in |index| (which come from the encoded stream). Tell the
+        // caller that things went south, and that the decoder state is now
+        // corrupt (because it's half-way through an update that we can't
+        // complete).
+        return false;
+      }
+
       /* Stuff zeros outside memory buffer  */
       memIndTest = lMem-cbveclen-CB_FILTERLEN;
       WebRtcSpl_MemSetW16(mem+lMem, 0, CB_HALFFILTERLEN);
@@ -108,4 +121,6 @@
       WebRtcIlbcfix_CreateAugmentedVec(lag, tempbuff2+SUBL+5, cbvec);
     }
   }
+
+  return true;  // Success.
 }
diff --git a/webrtc/modules/audio_coding/codecs/ilbc/get_cd_vec.h b/webrtc/modules/audio_coding/codecs/ilbc/get_cd_vec.h
index 07f67a2..b770e76 100644
--- a/webrtc/modules/audio_coding/codecs/ilbc/get_cd_vec.h
+++ b/webrtc/modules/audio_coding/codecs/ilbc/get_cd_vec.h
@@ -19,12 +19,18 @@
 #ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ILBC_MAIN_SOURCE_GET_CD_VEC_H_
 #define WEBRTC_MODULES_AUDIO_CODING_CODECS_ILBC_MAIN_SOURCE_GET_CD_VEC_H_
 
-void WebRtcIlbcfix_GetCbVec(
-    int16_t *cbvec,   /* (o) Constructed codebook vector */
-    int16_t *mem,   /* (i) Codebook buffer */
+#include <stdbool.h>
+
+#include "defines.h"
+
+// Returns true on success, false on failure. In case of failure, the decoder
+// state may be corrupted and needs resetting.
+bool WebRtcIlbcfix_GetCbVec(
+    int16_t* cbvec, /* (o) Constructed codebook vector */
+    int16_t* mem,   /* (i) Codebook buffer */
     size_t index,   /* (i) Codebook index */
-    size_t lMem,   /* (i) Length of codebook buffer */
-    size_t cbveclen   /* (i) Codebook vector length */
-                            );
+    size_t lMem,    /* (i) Length of codebook buffer */
+    size_t cbveclen /* (i) Codebook vector length */
+    ) WARN_UNUSED_RESULT;
 
 #endif
diff --git a/webrtc/modules/audio_coding/codecs/ilbc/ilbc.c b/webrtc/modules/audio_coding/codecs/ilbc/ilbc.c
index 6cd9a72..6587e4f 100644
--- a/webrtc/modules/audio_coding/codecs/ilbc/ilbc.c
+++ b/webrtc/modules/audio_coding/codecs/ilbc/ilbc.c
@@ -22,6 +22,7 @@
 #include "encode.h"
 #include "init_decode.h"
 #include "decode.h"
+#include "webrtc/base/checks.h"
 #include <stdlib.h>
 
 int16_t WebRtcIlbcfix_EncoderAssign(IlbcEncoderInstance** iLBC_encinst,
@@ -180,11 +181,12 @@
   }
 
   while ((i*((IlbcDecoder*)iLBCdec_inst)->no_of_bytes)<len) {
-    WebRtcIlbcfix_DecodeImpl(
-        &decoded[i * ((IlbcDecoder*)iLBCdec_inst)->blockl],
-        (const uint16_t*)&encoded
-            [2 * i * ((IlbcDecoder*)iLBCdec_inst)->no_of_words],
-        (IlbcDecoder*)iLBCdec_inst, 1);
+    if (WebRtcIlbcfix_DecodeImpl(
+            &decoded[i * ((IlbcDecoder*)iLBCdec_inst)->blockl],
+            (const uint16_t*)&encoded
+                [2 * i * ((IlbcDecoder*)iLBCdec_inst)->no_of_words],
+            (IlbcDecoder*)iLBCdec_inst, 1) == -1)
+      return -1;
     i++;
   }
   /* iLBC does not support VAD/CNG yet */
@@ -208,11 +210,12 @@
   }
 
   while ((i*((IlbcDecoder*)iLBCdec_inst)->no_of_bytes)<len) {
-    WebRtcIlbcfix_DecodeImpl(
+    if (!WebRtcIlbcfix_DecodeImpl(
         &decoded[i * ((IlbcDecoder*)iLBCdec_inst)->blockl],
         (const uint16_t*)&encoded
             [2 * i * ((IlbcDecoder*)iLBCdec_inst)->no_of_words],
-        (IlbcDecoder*)iLBCdec_inst, 1);
+        (IlbcDecoder*)iLBCdec_inst, 1))
+      return -1;
     i++;
   }
   /* iLBC does not support VAD/CNG yet */
@@ -236,11 +239,12 @@
   }
 
   while ((i*((IlbcDecoder*)iLBCdec_inst)->no_of_bytes)<len) {
-    WebRtcIlbcfix_DecodeImpl(
+    if (!WebRtcIlbcfix_DecodeImpl(
         &decoded[i * ((IlbcDecoder*)iLBCdec_inst)->blockl],
         (const uint16_t*)&encoded
             [2 * i * ((IlbcDecoder*)iLBCdec_inst)->no_of_words],
-        (IlbcDecoder*)iLBCdec_inst, 1);
+        (IlbcDecoder*)iLBCdec_inst, 1))
+      return -1;
     i++;
   }
   /* iLBC does not support VAD/CNG yet */
@@ -255,10 +259,11 @@
   uint16_t dummy;
 
   for (i=0;i<noOfLostFrames;i++) {
-    /* call decoder */
-    WebRtcIlbcfix_DecodeImpl(
+    // PLC decoding shouldn't fail, because there is no external input data
+    // that can be bad.
+    RTC_CHECK(WebRtcIlbcfix_DecodeImpl(
         &decoded[i * ((IlbcDecoder*)iLBCdec_inst)->blockl], &dummy,
-        (IlbcDecoder*)iLBCdec_inst, 0);
+        (IlbcDecoder*)iLBCdec_inst, 0));
   }
   return (noOfLostFrames*((IlbcDecoder*)iLBCdec_inst)->blockl);
 }
diff --git a/webrtc/modules/audio_coding/codecs/ilbc/ilbc.gypi b/webrtc/modules/audio_coding/codecs/ilbc/ilbc.gypi
index ffb0574..27dfd88 100644
--- a/webrtc/modules/audio_coding/codecs/ilbc/ilbc.gypi
+++ b/webrtc/modules/audio_coding/codecs/ilbc/ilbc.gypi
@@ -12,6 +12,7 @@
       'target_name': 'ilbc',
       'type': 'static_library',
       'dependencies': [
+        '<(webrtc_root)/base/base.gyp:rtc_base_approved',
         '<(webrtc_root)/common_audio/common_audio.gyp:common_audio',
         'audio_encoder_interface',
       ],
@@ -172,6 +173,11 @@
             'ilbc',
           ],
           'sources': [
+            # The empty .cc file is a hack to get GYP to use the C++
+            # linker even though all sources here are .c files; this
+            # is necessary because we transitively depend on
+            # rtc_base_approved, which calls the C++ standard library.
+            'test/empty.cc',
             'test/iLBC_test.c',
           ],
         }, # ilbc_test
diff --git a/webrtc/modules/audio_coding/codecs/ilbc/ilbc_unittest.cc b/webrtc/modules/audio_coding/codecs/ilbc/ilbc_unittest.cc
new file mode 100644
index 0000000..c23cbc4
--- /dev/null
+++ b/webrtc/modules/audio_coding/codecs/ilbc/ilbc_unittest.cc
@@ -0,0 +1,57 @@
+/*
+ *  Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "webrtc/modules/audio_coding/codecs/ilbc/audio_decoder_ilbc.h"
+#include "webrtc/modules/audio_coding/codecs/ilbc/audio_encoder_ilbc.h"
+
+namespace webrtc {
+
+TEST(IlbcTest, BadPacket) {
+  // Get a good packet.
+  AudioEncoderIlbc::Config config;
+  config.frame_size_ms = 20;  // We need 20 ms rather than the default 30 ms;
+                              // otherwise, all possible values of cb_index[2]
+                              // are valid.
+  AudioEncoderIlbc encoder(config);
+  std::vector<int16_t> samples(encoder.SampleRateHz() / 100, 4711);
+  rtc::Buffer packet;
+  int num_10ms_chunks = 0;
+  while (packet.size() == 0) {
+    encoder.Encode(0, samples, &packet);
+    num_10ms_chunks += 1;
+  }
+
+  // Break the packet by setting all bits of the unsigned 7-bit number
+  // cb_index[2] to 1, giving it a value of 127. For a 20 ms packet, this is
+  // too large.
+  EXPECT_EQ(38u, packet.size());
+  rtc::Buffer bad_packet(packet.data(), packet.size());
+  bad_packet[29] |= 0x3f;  // Bits 1-6.
+  bad_packet[30] |= 0x80;  // Bit 0.
+
+  // Decode the bad packet. We expect the decoder to respond by returning -1.
+  AudioDecoderIlbc decoder;
+  std::vector<int16_t> decoded_samples(num_10ms_chunks * samples.size());
+  AudioDecoder::SpeechType speech_type;
+  EXPECT_EQ(-1, decoder.Decode(bad_packet.data(), bad_packet.size(),
+                               encoder.SampleRateHz(),
+                               sizeof(int16_t) * decoded_samples.size(),
+                               decoded_samples.data(), &speech_type));
+
+  // Decode the good packet. This should work, because the failed decoding
+  // should not have left the decoder in a broken state.
+  EXPECT_EQ(static_cast<int>(decoded_samples.size()),
+            decoder.Decode(packet.data(), packet.size(), encoder.SampleRateHz(),
+                           sizeof(int16_t) * decoded_samples.size(),
+                           decoded_samples.data(), &speech_type));
+}
+
+}  // namespace webrtc
diff --git a/webrtc/modules/audio_coding/codecs/ilbc/test/empty.cc b/webrtc/modules/audio_coding/codecs/ilbc/test/empty.cc
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/webrtc/modules/audio_coding/codecs/ilbc/test/empty.cc