[MLton-commit] r6527

Matthew Fluet fluet at mlton.org
Fri Apr 4 13:43:58 PST 2008


Avoid an overflow when initializing an __mpz_struct for an IntInf result.

The _mp_alloc field of an __mpz_struct is declared as an int.  On a
64-bit architecture, the computation of the number of available limbs
from the space available in the heap occurs at 64-bits.  With
>8Gb heap and sizeof(mp_limb_t) == 4 or >16Gb heap and
sizeof(mp_limb_t) == 8, the result will overflow when being assigned
to an int.

----------------------------------------------------------------------

U   mlton/trunk/runtime/gc/int-inf.c
U   mlton/trunk/runtime/gc/int-inf.h

----------------------------------------------------------------------

Modified: mlton/trunk/runtime/gc/int-inf.c
===================================================================
--- mlton/trunk/runtime/gc/int-inf.c	2008-04-03 14:28:06 UTC (rev 6526)
+++ mlton/trunk/runtime/gc/int-inf.c	2008-04-04 21:43:57 UTC (rev 6527)
@@ -1,5 +1,5 @@
-/* Copyright (C) 1999-2005, 2007 Henry Cejtin, Matthew Fluet, Suresh
- *    Jagannathan, and Stephen Weeks.
+/* Copyright (C) 1999-2005, 2007-2008 Henry Cejtin, Matthew Fluet,
+ *    Suresh Jagannathan, and Stephen Weeks.
  * Copyright (C) 1997-2000 NEC Research Institute.
  *
  * MLton is released under a BSD-style license.
@@ -57,26 +57,29 @@
       const objptr highBitMask = (objptr)1 << (CHAR_BIT * OBJPTR_SIZE - 1);
       bool neg = (arg & highBitMask) != (objptr)0;
       if (neg) {
-        res->_mp_size = - (mp_size_t)LIMBS_PER_OBJPTR;
+        res->_mp_size = - LIMBS_PER_OBJPTR;
         arg = -((arg >> 1) | highBitMask);
       } else {
-        res->_mp_size = (mp_size_t)LIMBS_PER_OBJPTR;
+        res->_mp_size = LIMBS_PER_OBJPTR;
         arg = (arg >> 1);
       }
-      for (unsigned int i = 0; i < LIMBS_PER_OBJPTR; i++) {
+      for (int i = 0; i < LIMBS_PER_OBJPTR; i++) {
         space[i] = (mp_limb_t)arg;
         // The conditional below is to quell a gcc warning:
         //   right shift count >= width of type
         // When 1 == LIMBS_PER_OBJPTR, the for loop will not continue,
         // so the shift doesn't matter.
         arg = arg >> (1 == LIMBS_PER_OBJPTR ?
-                        0 :
-                        CHAR_BIT * sizeof(mp_limb_t));
+                      0 : CHAR_BIT * sizeof(mp_limb_t));
       }
     }
   } else {
     bp = toBignum (s, arg);
-    res->_mp_alloc = bp->length - 1;
+    /* The _mp_alloc field is declared as int.  
+     * No possibility of an overflowing assignment, as all *huge*
+     * intInfs must have come from some previous GnuMP evaluation.
+     */
+    res->_mp_alloc = (int)(bp->length - 1);
     res->_mp_d = (mp_limb_t*)(bp->obj.body.limbs);
     res->_mp_size = bp->obj.body.isneg ? - res->_mp_alloc : res->_mp_alloc;
   }
@@ -95,13 +98,19 @@
 void initIntInfRes (GC_state s, __mpz_struct *res,
                     __attribute__ ((unused)) size_t bytes) {
   GC_intInf bp;
+  size_t nlimbs;
 
   assert (bytes <= (size_t)(s->limitPlusSlop - s->frontier));
   bp = (GC_intInf)s->frontier;
   /* We have as much space for the limbs as there is to the end of the
    * heap.  Divide by (sizeof(mp_limb_t)) to get number of limbs.
    */
-  res->_mp_alloc = (s->limitPlusSlop - (pointer)bp->obj.body.limbs) / (sizeof(mp_limb_t));
+  nlimbs = ((size_t)(s->limitPlusSlop - (pointer)bp->obj.body.limbs)) / (sizeof(mp_limb_t));
+  /* The _mp_alloc field is declared as int. 
+   * Avoid an overflowing assignment, which could happen with huge
+   * heaps.
+   */
+  res->_mp_alloc = (int)(min(nlimbs,(size_t)INT_MAX));
   res->_mp_d = (mp_limb_t*)(bp->obj.body.limbs);
   res->_mp_size = 0; /* is this necessary? */
 }
@@ -116,7 +125,7 @@
  */
 objptr finiIntInfRes (GC_state s, __mpz_struct *res, size_t bytes) {
   GC_intInf bp;
-  mp_size_t size;
+  int size;
 
   assert ((res->_mp_size == 0)
           or (res->_mp_d[(res->_mp_size < 0
@@ -136,6 +145,7 @@
     size = - size;
   } else
     bp->obj.body.isneg = FALSE;
+  assert (size >= 0);
   if (size <= 1) {
     uintmax_t val, ans;
 
@@ -159,8 +169,8 @@
     }
   }
   setFrontier (s, (pointer)(&bp->obj.body.limbs[size]), bytes);
-  bp->counter = 0;
-  bp->length = size + 1; /* +1 for isneg field */
+  bp->counter = (GC_arrayCounter)0;
+  bp->length = (GC_arrayLength)(size + 1); /* +1 for isneg field */
   bp->header = GC_INTINF_HEADER;
   return pointerToObjptr ((pointer)&bp->obj, s->heap.start);
 }

Modified: mlton/trunk/runtime/gc/int-inf.h
===================================================================
--- mlton/trunk/runtime/gc/int-inf.h	2008-04-03 14:28:06 UTC (rev 6526)
+++ mlton/trunk/runtime/gc/int-inf.h	2008-04-04 21:43:57 UTC (rev 6527)
@@ -1,4 +1,4 @@
-/* Copyright (C) 1999-2007 Henry Cejtin, Matthew Fluet, Suresh
+/* Copyright (C) 1999-2008 Henry Cejtin, Matthew Fluet, Suresh
  *    Jagannathan, and Stephen Weeks.
  * Copyright (C) 1997-2000 NEC Research Institute.
  *
@@ -54,7 +54,7 @@
                     (sizeof(objptr) % sizeof(mp_limb_t) == 0));
 #define LIMBS_PER_OBJPTR ( \
         sizeof(mp_limb_t) >= sizeof(objptr) ? \
-        1 : sizeof(objptr) / sizeof(mp_limb_t))
+        1 : (int)(sizeof(objptr) / sizeof(mp_limb_t)))
 
 void initIntInf (GC_state s);
 static inline void fillIntInfArg (GC_state s, objptr arg, __mpz_struct *res, 




More information about the MLton-commit mailing list