]> granicus.if.org Git - python/commitdiff
k_mul(): White-box testing turned up that (ah+al)*(bh+bl) can, in rare
authorTim Peters <tim.peters@gmail.com>
Mon, 12 Aug 2002 19:30:26 +0000 (19:30 +0000)
committerTim Peters <tim.peters@gmail.com>
Mon, 12 Aug 2002 19:30:26 +0000 (19:30 +0000)
cases, overflow the allocated result object by 1 bit.  In such cases,
it would have been brought back into range if we subtracted al*bl and
ah*bh from it first, but I don't want to do that because it hurts cache
behavior.  Instead we just ignore the excess bit when it appears -- in
effect, this is forcing unsigned mod BASE**(asize + bsize) arithmetic
in a case where that doesn't happen all by itself.

Objects/longobject.c

index 0801e6498183c7c63355cbda05517710282e4573..0f4910edd691746c353d3d58e1e010e4640bb8a0 100644 (file)
@@ -1663,7 +1663,7 @@ k_mul(PyLongObject *a, PyLongObject *b)
         */
 
        /* 1. Allocate result space. */
-       ret = _PyLong_New(asize + bsize);
+       ret = _PyLong_New(asize + bsize + 1);
        if (ret == NULL) goto fail;
 #ifdef Py_DEBUG
        /* Fill with trash, to catch reference to uninitialized digits. */
@@ -1727,7 +1727,15 @@ k_mul(PyLongObject *a, PyLongObject *b)
        Py_DECREF(t2);
        if (t3 == NULL) goto fail;
 
-       /* Add t3. */
+       /* Add t3.  Caution:  t3 can spill one bit beyond the allocated
+        * result space; it's t3-al*bl-ah*bh that always fits.  We have
+        * to arrange to ignore the hight bit.
+        */
+       if (t3->ob_size > i) {
+               assert(t3->ob_size == i+1);     /* just one digit over */
+               assert(t3->ob_digit[t3->ob_size - 1] == 1); /* & just one bit */
+               --t3->ob_size;  /* ignore the overflow bit */
+       }
        (void)v_iadd(ret->ob_digit + shift, i, t3->ob_digit, t3->ob_size);
        Py_DECREF(t3);
 
@@ -1761,7 +1769,7 @@ long_mul(PyLongObject *v, PyLongObject *w)
                return Py_NotImplemented;
        }
 
-#if 0
+#if 1
        if (Py_GETENV("KARAT") != NULL)
                z = k_mul(a, b);
        else