Fixes several overflows in the CELT fixed-point
authorJean-Marc Valin <jmvalin@jmvalin.ca>
Thu, 12 Apr 2012 15:07:21 +0000 (11:07 -0400)
committerJean-Marc Valin <jmvalin@jmvalin.ca>
Thu, 12 Apr 2012 15:09:09 +0000 (11:09 -0400)
These were all mostly benign and would at worst result in (rare)
suboptimal encoder decisions rather than signal corruption.

celt/bands.c
celt/celt.c
celt/fixed_debug.h
celt/mathops.c
celt/quant_bands.c

index 4b52eb5..1d47a92 100644 (file)
@@ -249,7 +249,7 @@ void anti_collapse(const CELTMode *m, celt_norm *X_, unsigned char *collapse_mas
             prev2 = MAX16(prev2,prev2logE[m->nbEBands+i]);
          }
          Ediff = EXTEND32(logE[c*m->nbEBands+i])-EXTEND32(MIN16(prev1,prev2));
-         Ediff = MAX16(0, Ediff);
+         Ediff = MAX32(0, Ediff);
 
 #ifdef FIXED_POINT
          if (Ediff < 16384)
index 44732a2..6af86eb 100644 (file)
@@ -607,7 +607,7 @@ static int tf_analysis(const CELTMode *m, int len, int C, int isTransient,
       /* Just add the right channel if we're in stereo */
       if (C==2)
          for (j=0;j<N;j++)
-            tmp[j] = ADD16(tmp[j],X[N0+j+(m->eBands[i]<<LM)]);
+            tmp[j] = ADD16(SHR16(tmp[j], 1),SHR16(X[N0+j+(m->eBands[i]<<LM)], 1));
       L1 = l1_metric(tmp, N, isTransient ? LM : 0, N>>LM);
       best_L1 = L1;
       /*printf ("%f ", L1);*/
index 0a1adf4..4a34b5a 100644 (file)
@@ -154,17 +154,18 @@ static inline int SHR32(long long a, int shift)
    celt_mips+=2;
    return res;
 }
-static inline int SHL32(long long a, int shift)
+#define SHL32(a, shift) SHL32_(a, shift, __FILE__, __LINE__)
+static inline int SHL32_(long long a, int shift, char *file, int line)
 {
    long long  res;
    if (!VERIFY_INT(a) || !VERIFY_SHORT(shift))
    {
-      fprintf (stderr, "SHL32: inputs are not int: %d %d\n", (int)a, shift);
+      fprintf (stderr, "SHL32: inputs are not int: %lld %d in %s: line %d\n", a, shift, file, line);
    }
    res = a<<shift;
    if (!VERIFY_INT(res))
    {
-      fprintf (stderr, "SHL32: output is not int: %d\n", (int)res);
+      fprintf (stderr, "SHL32: output is not int: %lld<<%d = %lld in %s: line %d\n", a, shift, res, file, line);
    }
    celt_mips+=2;
    return res;
index e9cdd0d..6780428 100644 (file)
@@ -75,9 +75,15 @@ opus_val32 frac_div32(opus_val32 a, opus_val32 b)
    b = VSHR32(b,shift);
    /* 16-bit reciprocal */
    rcp = ROUND16(celt_rcp(ROUND16(b,16)),3);
-   result = SHL32(MULT16_32_Q15(rcp, a),2);
-   rem = a-MULT32_32_Q31(result, b);
-   result += SHL32(MULT16_32_Q15(rcp, rem),2);
+   result = MULT16_32_Q15(rcp, a);
+   rem = PSHR32(a,2)-MULT32_32_Q31(result, b);
+   result = ADD32(result, SHL32(MULT16_32_Q15(rcp, rem),2));
+   if (result >= 536870912)       /*  2^29 */
+      return 2147483647;          /*  2^31 - 1 */
+   else if (result <= -536870912) /* -2^29 */
+      return -2147483647;         /* -2^31 */
+   else
+      return SHL32(result, 2);
    return result;
 }
 
index 04a819e..e55c645 100644 (file)
@@ -146,11 +146,11 @@ static opus_val32 loss_distortion(const opus_val16 *eBands, opus_val16 *oldEBand
    c=0; do {
       for (i=start;i<end;i++)
       {
-         opus_val16 d = SHR16(SUB16(eBands[i+c*len], oldEBands[i+c*len]),2);
+         opus_val16 d = SUB16(SHR16(eBands[i+c*len], 3), SHR16(oldEBands[i+c*len], 3));
          dist = MAC16_16(dist, d,d);
       }
    } while (++c<C);
-   return MIN32(200,SHR32(dist,2*DB_SHIFT-4));
+   return MIN32(200,SHR32(dist,2*DB_SHIFT-6));
 }
 
 static int quant_coarse_energy_impl(const CELTMode *m, int start, int end,