]> granicus.if.org Git - python/commitdiff
Keep PyLong_AsLongAndOverflow documentation and implementation in sync
authorMark Dickinson <dickinsm@gmail.com>
Mon, 21 Dec 2009 12:37:06 +0000 (12:37 +0000)
committerMark Dickinson <dickinsm@gmail.com>
Mon, 21 Dec 2009 12:37:06 +0000 (12:37 +0000)
between py3k and trunk;  merge new tests from trunk to py3k.
(See issue #7528.)

Doc/c-api/long.rst
Modules/_testcapimodule.c
Objects/longobject.c

index 19d65b8a49800f1f1621dee9d100fcffe6f05fde..083fe8bfd838be7c5766457f6bac592d3f90c9e7 100644 (file)
@@ -121,10 +121,13 @@ All integers are implemented as "long" integer objects of arbitrary size.
 
 .. cfunction:: long PyLong_AsLongAndOverflow(PyObject *pylong, int* overflow)
 
-   Return a C :ctype:`long` representation of the contents of *pylong*.  If
-   *pylong* is greater than :const:`LONG_MAX`, return -1 and
-   set `*overflow` to 1 (for overflow) or -1 (for underflow).
-   If an exception is set because of type errors, also return -1.
+   Return a C :ctype:`long` representation of the contents of
+   *pylong*.  If *pylong* is greater than :const:`LONG_MAX` or less
+   than :const:`LONG_MIN`, set `*overflow` to ``1`` or ``-1``,
+   respectively, and return ``-1``; otherwise, set `*overflow` to
+   ``0``.  If any other exception occurs (for example a TypeError or
+   MemoryError), then ``-1`` will be returned and ``*overflow`` will
+   be ``0``.
 
 
 .. cfunction:: Py_ssize_t PyLong_AsSsize_t(PyObject *pylong)
index 70da707d4370aafdbb630ad187a66a8d4f2cee91..e549151ec9364e0fc3d8d2c3d9c6b9df613cb464 100644 (file)
@@ -359,6 +359,171 @@ test_longlong_api(PyObject* self, PyObject *args)
 #undef F_U_TO_PY
 #undef F_PY_TO_U
 
+/* Test the PyLong_AsLongAndOverflow API. General conversion to PY_LONG
+   is tested by test_long_api_inner. This test will concentrate on proper
+   handling of overflow.
+*/
+
+static PyObject *
+test_long_and_overflow(PyObject *self)
+{
+       PyObject *num, *one, *temp;
+       long value;
+       int overflow;
+
+       /* Test that overflow is set properly for a large value. */
+       /* num is a number larger than LONG_MAX even on 64-bit platforms */
+       num = PyLong_FromString("FFFFFFFFFFFFFFFFFFFFFFFF", NULL, 16);
+       if (num == NULL)
+               return NULL;
+       overflow = 1234;
+       value = PyLong_AsLongAndOverflow(num, &overflow);
+       Py_DECREF(num);
+       if (value == -1 && PyErr_Occurred())
+               return NULL;
+       if (value != -1)
+               return raiseTestError("test_long_and_overflow",
+                       "return value was not set to -1");
+       if (overflow != 1)
+               return raiseTestError("test_long_and_overflow",
+                       "overflow was not set to 1");
+
+       /* Same again, with num = LONG_MAX + 1 */
+       num = PyLong_FromLong(LONG_MAX);
+       if (num == NULL)
+               return NULL;
+       one = PyLong_FromLong(1L);
+       if (one == NULL) {
+               Py_DECREF(num);
+               return NULL;
+       }
+       temp = PyNumber_Add(num, one);
+       Py_DECREF(one);
+       Py_DECREF(num);
+       num = temp;
+       if (num == NULL)
+               return NULL;
+       overflow = 0;
+       value = PyLong_AsLongAndOverflow(num, &overflow);
+       Py_DECREF(num);
+       if (value == -1 && PyErr_Occurred())
+               return NULL;
+       if (value != -1)
+               return raiseTestError("test_long_and_overflow",
+                       "return value was not set to -1");
+       if (overflow != 1)
+               return raiseTestError("test_long_and_overflow",
+                       "overflow was not set to 1");
+
+       /* Test that overflow is set properly for a large negative value. */
+       /* num is a number smaller than LONG_MIN even on 64-bit platforms */
+       num = PyLong_FromString("-FFFFFFFFFFFFFFFFFFFFFFFF", NULL, 16);
+       if (num == NULL)
+               return NULL;
+       overflow = 1234;
+       value = PyLong_AsLongAndOverflow(num, &overflow);
+       Py_DECREF(num);
+       if (value == -1 && PyErr_Occurred())
+               return NULL;
+       if (value != -1)
+               return raiseTestError("test_long_and_overflow",
+                       "return value was not set to -1");
+       if (overflow != -1)
+               return raiseTestError("test_long_and_overflow",
+                       "overflow was not set to -1");
+
+       /* Same again, with num = LONG_MIN - 1 */
+       num = PyLong_FromLong(LONG_MIN);
+       if (num == NULL)
+               return NULL;
+       one = PyLong_FromLong(1L);
+       if (one == NULL) {
+               Py_DECREF(num);
+               return NULL;
+       }
+       temp = PyNumber_Subtract(num, one);
+       Py_DECREF(one);
+       Py_DECREF(num);
+       num = temp;
+       if (num == NULL)
+               return NULL;
+       overflow = 0;
+       value = PyLong_AsLongAndOverflow(num, &overflow);
+       Py_DECREF(num);
+       if (value == -1 && PyErr_Occurred())
+               return NULL;
+       if (value != -1)
+               return raiseTestError("test_long_and_overflow",
+                       "return value was not set to -1");
+       if (overflow != -1)
+               return raiseTestError("test_long_and_overflow",
+                       "overflow was not set to -1");
+
+       /* Test that overflow is cleared properly for small values. */
+       num = PyLong_FromString("FF", NULL, 16);
+       if (num == NULL)
+               return NULL;
+       overflow = 1234;
+       value = PyLong_AsLongAndOverflow(num, &overflow);
+       Py_DECREF(num);
+       if (value == -1 && PyErr_Occurred())
+               return NULL;
+       if (value != 0xFF)
+               return raiseTestError("test_long_and_overflow",
+                       "expected return value 0xFF");
+       if (overflow != 0)
+               return raiseTestError("test_long_and_overflow",
+                       "overflow was not cleared");
+
+       num = PyLong_FromString("-FF", NULL, 16);
+       if (num == NULL)
+               return NULL;
+       overflow = 0;
+       value = PyLong_AsLongAndOverflow(num, &overflow);
+       Py_DECREF(num);
+       if (value == -1 && PyErr_Occurred())
+               return NULL;
+       if (value != -0xFF)
+               return raiseTestError("test_long_and_overflow",
+                       "expected return value 0xFF");
+       if (overflow != 0)
+               return raiseTestError("test_long_and_overflow",
+                       "overflow was set incorrectly");
+
+       num = PyLong_FromLong(LONG_MAX);
+       if (num == NULL)
+               return NULL;
+       overflow = 1234;
+       value = PyLong_AsLongAndOverflow(num, &overflow);
+       Py_DECREF(num);
+       if (value == -1 && PyErr_Occurred())
+               return NULL;
+       if (value != LONG_MAX)
+               return raiseTestError("test_long_and_overflow",
+                       "expected return value LONG_MAX");
+       if (overflow != 0)
+               return raiseTestError("test_long_and_overflow",
+                       "overflow was not cleared");
+
+       num = PyLong_FromLong(LONG_MIN);
+       if (num == NULL)
+               return NULL;
+       overflow = 0;
+       value = PyLong_AsLongAndOverflow(num, &overflow);
+       Py_DECREF(num);
+       if (value == -1 && PyErr_Occurred())
+               return NULL;
+       if (value != LONG_MIN)
+               return raiseTestError("test_long_and_overflow",
+                       "expected return value LONG_MIN");
+       if (overflow != 0)
+               return raiseTestError("test_long_and_overflow",
+                       "overflow was not cleared");
+
+       Py_INCREF(Py_None);
+       return Py_None;
+}
+
 /* Test the L code for PyArg_ParseTuple.  This should deliver a PY_LONG_LONG
    for both long and int arguments.  The test may leak a little memory if
    it fails.
@@ -1560,6 +1725,8 @@ static PyMethodDef TestMethods[] = {
        {"test_dict_iteration", (PyCFunction)test_dict_iteration,METH_NOARGS},
        {"test_lazy_hash_inheritance",  (PyCFunction)test_lazy_hash_inheritance,METH_NOARGS},
        {"test_long_api",       (PyCFunction)test_long_api,      METH_NOARGS},
+       {"test_long_and_overflow", (PyCFunction)test_long_and_overflow,
+        METH_NOARGS},
        {"test_long_numbits",   (PyCFunction)test_long_numbits,  METH_NOARGS},
        {"test_k_code",         (PyCFunction)test_k_code,        METH_NOARGS},
        {"test_empty_argparse", (PyCFunction)test_empty_argparse,METH_NOARGS},
index b46ce4eb479eb7403dc71ac5be7a9190c6783943..8e4093c79d50f3a0161c47d5f5f101928783b9e2 100644 (file)
@@ -346,9 +346,10 @@ PyLong_AsLongAndOverflow(PyObject *vv, int *overflow)
 
        if (!PyLong_Check(vv)) {
                PyNumberMethods *nb;
-               if ((nb = vv->ob_type->tp_as_number) == NULL ||
-                   nb->nb_int == NULL) {
-                       PyErr_SetString(PyExc_TypeError, "an integer is required");
+               nb = vv->ob_type->tp_as_number;
+               if (nb == NULL || nb->nb_int == NULL) {
+                       PyErr_SetString(PyExc_TypeError,
+                                       "an integer is required");
                        return -1;
                }
                vv = (*nb->nb_int) (vv);
@@ -388,13 +389,13 @@ PyLong_AsLongAndOverflow(PyObject *vv, int *overflow)
                        prev = x;
                        x = (x << PyLong_SHIFT) | v->ob_digit[i];
                        if ((x >> PyLong_SHIFT) != prev) {
-                               *overflow = Py_SIZE(v) > 0 ? 1 : -1;
+                               *overflow = sign;
                                goto exit;
                        }
                }
-               /* Haven't lost any bits, but casting to long requires extra care
-                * (see comment above).
-                */
+               /* Haven't lost any bits, but casting to long requires extra
+                * care (see comment above).
+                */
                if (x <= (unsigned long)LONG_MAX) {
                        res = (long)x * sign;
                }
@@ -402,9 +403,9 @@ PyLong_AsLongAndOverflow(PyObject *vv, int *overflow)
                        res = LONG_MIN;
                }
                else {
-                       *overflow = Py_SIZE(v) > 0 ? 1 : -1;
+                       *overflow = sign;
                        /* res is already set to -1 */
-               }       
+               }
        }
  exit:
        if (do_decref) {