Commit 93572190822160f0671b32000ea6a01d9a0ffd07

Werner Lemberg 2017-05-28T07:20:09

Fix negation of INT_MIN and LONG_MIN (#46149). * src/base/ftcalc.c (FT_MOVE_SIGN): Add argument to pass unsigned value, to be used as the result. (FT_MulDiv, FT_MulDiv_No_Round, FT_DivFix, FT_MulFix, FT_Vector_NormLen): Updated.

diff --git a/ChangeLog b/ChangeLog
index f4f64d1..feb14f7 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2017-05-28  Werner Lemberg  <wl@gnu.org>
+
+	Fix negation of INT_MIN and LONG_MIN (#46149).
+
+	* src/base/ftcalc.c (FT_MOVE_SIGN): Add argument to pass unsigned
+	value, to be used as the result.
+	(FT_MulDiv, FT_MulDiv_No_Round, FT_DivFix, FT_MulFix,
+	FT_Vector_NormLen): Updated.
+
 2017-05-27  Werner Lemberg  <wl@gnu.org>
 
 	[truetype] Fix handling of design coordinates (#51127).
diff --git a/src/base/ftcalc.c b/src/base/ftcalc.c
index f052550..b4b66e4 100644
--- a/src/base/ftcalc.c
+++ b/src/base/ftcalc.c
@@ -68,14 +68,15 @@
 #define FT_COMPONENT  trace_calc
 
 
-  /* transfer sign leaving a positive number */
-#define FT_MOVE_SIGN( x, s ) \
-  FT_BEGIN_STMNT             \
-    if ( x < 0 )             \
-    {                        \
-      x = -x;                \
-      s = -s;                \
-    }                        \
+  /* transfer sign, leaving a positive number;                        */
+  /* we need an unsigned value to safely negate INT_MIN (or LONG_MIN) */
+#define FT_MOVE_SIGN( x, x_unsigned, s ) \
+  FT_BEGIN_STMNT                         \
+    if ( x < 0 )                         \
+    {                                    \
+      x_unsigned = -x_unsigned;          \
+      s          = -s;                   \
+    }                                    \
   FT_END_STMNT
 
   /* The following three functions are available regardless of whether */
@@ -179,14 +180,14 @@
     FT_Long    d_;
 
 
-    FT_MOVE_SIGN( a_, s );
-    FT_MOVE_SIGN( b_, s );
-    FT_MOVE_SIGN( c_, s );
-
     a = (FT_UInt64)a_;
     b = (FT_UInt64)b_;
     c = (FT_UInt64)c_;
 
+    FT_MOVE_SIGN( a_, a, s );
+    FT_MOVE_SIGN( b_, b, s );
+    FT_MOVE_SIGN( c_, c, s );
+
     d = c > 0 ? ( a * b + ( c >> 1 ) ) / c
               : 0x7FFFFFFFUL;
 
@@ -208,14 +209,14 @@
     FT_Long    d_;
 
 
-    FT_MOVE_SIGN( a_, s );
-    FT_MOVE_SIGN( b_, s );
-    FT_MOVE_SIGN( c_, s );
-
     a = (FT_UInt64)a_;
     b = (FT_UInt64)b_;
     c = (FT_UInt64)c_;
 
+    FT_MOVE_SIGN( a_, a, s );
+    FT_MOVE_SIGN( b_, b, s );
+    FT_MOVE_SIGN( c_, c, s );
+
     d = c > 0 ? a * b / c
               : 0x7FFFFFFFUL;
 
@@ -257,12 +258,12 @@
     FT_Long    q_;
 
 
-    FT_MOVE_SIGN( a_, s );
-    FT_MOVE_SIGN( b_, s );
-
     a = (FT_UInt64)a_;
     b = (FT_UInt64)b_;
 
+    FT_MOVE_SIGN( a_, a, s );
+    FT_MOVE_SIGN( b_, a, s );
+
     q = b > 0 ? ( ( a << 16 ) + ( b >> 1 ) ) / b
               : 0x7FFFFFFFUL;
 
@@ -422,14 +423,14 @@
 
     /* XXX: this function does not allow 64-bit arguments */
 
-    FT_MOVE_SIGN( a_, s );
-    FT_MOVE_SIGN( b_, s );
-    FT_MOVE_SIGN( c_, s );
-
     a = (FT_UInt32)a_;
     b = (FT_UInt32)b_;
     c = (FT_UInt32)c_;
 
+    FT_MOVE_SIGN( a_, a, s );
+    FT_MOVE_SIGN( b_, b, s );
+    FT_MOVE_SIGN( c_, c, s );
+
     if ( c == 0 )
       a = 0x7FFFFFFFUL;
 
@@ -470,14 +471,14 @@
 
     /* XXX: this function does not allow 64-bit arguments */
 
-    FT_MOVE_SIGN( a_, s );
-    FT_MOVE_SIGN( b_, s );
-    FT_MOVE_SIGN( c_, s );
-
     a = (FT_UInt32)a_;
     b = (FT_UInt32)b_;
     c = (FT_UInt32)c_;
 
+    FT_MOVE_SIGN( a_, a, s );
+    FT_MOVE_SIGN( b_, b, s );
+    FT_MOVE_SIGN( c_, c, s );
+
     if ( c == 0 )
       a = 0x7FFFFFFFUL;
 
@@ -575,12 +576,12 @@
 
     /* XXX: this function does not allow 64-bit arguments */
 
-    FT_MOVE_SIGN( a_, s );
-    FT_MOVE_SIGN( b_, s );
-
     a = (FT_UInt32)a_;
     b = (FT_UInt32)b_;
 
+    FT_MOVE_SIGN( a_, a, s );
+    FT_MOVE_SIGN( b_, b, s );
+
     if ( a + ( b >> 8 ) <= 8190UL )
       a = ( a * b + 0x8000UL ) >> 16;
     else
@@ -614,12 +615,12 @@
 
     /* XXX: this function does not allow 64-bit arguments */
 
-    FT_MOVE_SIGN( a_, s );
-    FT_MOVE_SIGN( b_, s );
-
     a = (FT_UInt32)a_;
     b = (FT_UInt32)b_;
 
+    FT_MOVE_SIGN( a_, a, s );
+    FT_MOVE_SIGN( b_, b, s );
+
     if ( b == 0 )
     {
       /* check for division by 0 */
@@ -770,12 +771,12 @@
     FT_Int     sx = 1, sy = 1, shift;
 
 
-    FT_MOVE_SIGN( x_, sx );
-    FT_MOVE_SIGN( y_, sy );
-
     x = (FT_UInt32)x_;
     y = (FT_UInt32)y_;
 
+    FT_MOVE_SIGN( x_, x, sx );
+    FT_MOVE_SIGN( y_, y, sy );
+
     /* trivial cases */
     if ( x == 0 )
     {