check overflow & clamp
authorMichiharu Ariza <ariza@adobe.com>
Wed, 5 Dec 2018 06:24:38 +0000 (22:24 -0800)
committerMichiharu Ariza <ariza@adobe.com>
Wed, 5 Dec 2018 06:24:38 +0000 (22:24 -0800)
src/hb-cff-interp-dict-common.hh

index 2822af4..62c87e9 100644 (file)
@@ -105,16 +105,17 @@ struct DictOpSet : OpSet<Number>
 
   static inline double parse_bcd (SubByteStr& substr)
   {
-    double v = 0.0;
-
     bool    neg = false;
     double  int_part = 0;
     long    frac_part = 0;
     unsigned int  frac_count = 0;
     bool    exp_neg = false;
     unsigned int  exp_part = 0;
+    bool    exp_overflow = false;
     enum Part { INT_PART=0, FRAC_PART, EXP_PART } part = INT_PART;
     enum Nibble { DECIMAL=10, EXP_POS, EXP_NEG, RESERVED, NEG, END };
+    const unsigned long MAX_FRACT = 0xFFFFFFFFFFFFFlu; /* 1^52-1 */
+    const unsigned int MAX_EXP = 0x7FFu; /* 1^11-1 */
 
     double  value = 0.0;
     unsigned char byte = 0;
@@ -139,12 +140,21 @@ struct DictOpSet : OpSet<Number>
       {
        case RESERVED:
          substr.set_error ();
-         return v;
+         return value;
 
        case END:
          value = (double)(neg? -int_part: int_part);
          if (frac_count > 0)
            value += (frac_part / pow (10.0, (double)frac_count));
+         if (unlikely (exp_overflow))
+         {
+           if (value == 0.0)
+             return value;
+           if (exp_neg)
+             return neg? -DBL_MIN: DBL_MIN;
+           else
+             return neg? -DBL_MAX: DBL_MAX;
+         }
          if (exp_part != 0)
          {
            if (exp_neg)
@@ -167,7 +177,7 @@ struct DictOpSet : OpSet<Number>
          if (part != INT_PART)
          {
            substr.set_error ();
-           return v;
+           return value;
          }
          part = FRAC_PART;
          break;
@@ -180,7 +190,7 @@ struct DictOpSet : OpSet<Number>
          if (part == EXP_PART)
          {
            substr.set_error ();
-           return v;
+           return value;
          }
          part = EXP_PART;
          break;
@@ -193,18 +203,26 @@ struct DictOpSet : OpSet<Number>
              break;
 
            case FRAC_PART:
-             frac_part = (frac_part * 10) + d;
-             frac_count++;
+             if (likely ((fract_count <= MAX_FRACT / 10)))
+             {
+               frac_part = (frac_part * 10) + d;
+               frac_count++;
+             }
              break;
 
            case EXP_PART:
-             exp_part = (exp_part * 10) + d;
+             if (likely (exp_part * 10) + d <= MAX_EXP)
+             {
+               exp_part = (exp_part * 10) + d;
+             }
+             else
+               exp_overflow = true;
              break;
          }
       }
     }
 
-    return v;
+    return value;
   }
 
   static inline bool is_hint_op (OpCode op)