Commit 336735d8de0bc5f9ef8018ae11d322cb6e59fa4a

Alexei Podtelezhnikov 2014-09-03T22:55:26

[base] Tighten the overflow check in `FT_DivFix'. This fixes a 13-year old bug. The original overflow check should have been updated when rounding was introduced into this function (c2cd00443b). * src/base/ftcalc.c (FT_DivFix) [!FT_LONG64]: Updated. * include/freetype.h (FT_DivFix): Updated documentation.

diff --git a/ChangeLog b/ChangeLog
index dc8d79b..77b2bc7 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,16 @@
 2014-09-03  Alexei Podtelezhnikov  <apodtele@gmail.com>
 
+	[base] Tighten the overflow check in `FT_DivFix'.
+
+	This fixes a 13-year old bug. The original overflow check should have
+	been updated when rounding was introduced into this function
+	(c2cd00443b).
+
+	* src/base/ftcalc.c (FT_DivFix) [!FT_LONG64]: Updated.
+	* include/freetype.h (FT_DivFix): Updated documentation.
+
+2014-09-03  Alexei Podtelezhnikov  <apodtele@gmail.com>
+
 	[base] Tighten the overflow check in `FT_MulFix'.
 
 	* src/base/ftcalc.c (FT_MulFix) [!FT_LONG64]: Updated.
diff --git a/include/freetype.h b/include/freetype.h
index 1ce138c..6a31502 100644
--- a/include/freetype.h
+++ b/include/freetype.h
@@ -3807,18 +3807,12 @@ FT_BEGIN_HEADER
   /*    used to divide a given value by a 16.16 fixed-point factor.        */
   /*                                                                       */
   /* <Input>                                                               */
-  /*    a :: The first multiplier.                                         */
-  /*    b :: The second multiplier.  Use a 16.16 factor here whenever      */
-  /*         possible (see note below).                                    */
+  /*    a :: The numerator.                                                */
+  /*    b :: The denominator.  Use a 16.16 factor here.                    */
   /*                                                                       */
   /* <Return>                                                              */
   /*    The result of `(a*0x10000)/b'.                                     */
   /*                                                                       */
-  /* <Note>                                                                */
-  /*    The optimization for FT_DivFix() is simple: If (a~<<~16) fits in   */
-  /*    32~bits, then the division is computed directly.  Otherwise, we    */
-  /*    use a specialized version of @FT_MulDiv.                           */
-  /*                                                                       */
   FT_EXPORT( FT_Long )
   FT_DivFix( FT_Long  a,
              FT_Long  b );
diff --git a/src/base/ftcalc.c b/src/base/ftcalc.c
index 671eec8..723712e 100644
--- a/src/base/ftcalc.c
+++ b/src/base/ftcalc.c
@@ -397,6 +397,13 @@
   /*  covers the practical range of use. The actual test below is a bit  */
   /*  tighter to avoid the border case overflows.                        */
   /*                                                                     */
+  /*  In the case of FT_DivFix, the direct overflow check                */
+  /*                                                                     */
+  /*    a << 16 <= X - c/2                                               */
+  /*                                                                     */
+  /*  is scaled down by 2^16 and we use                                  */
+  /*                                                                     */
+  /*    a <= 65535 - (c >> 17)    .                                      */
 
   /* documentation is in freetype.h */
 
@@ -593,7 +600,7 @@
       /* check for division by 0 */
       q = 0x7FFFFFFFL;
     }
-    else if ( ( a >> 16 ) == 0 )
+    else if ( a <= 65535L - ( b >> 17 ) )
     {
       /* compute result directly */
       q = (FT_Long)( ( ( (FT_ULong)a << 16 ) + ( b >> 1 ) ) / b );