[Python-checkins] r76971 - in python/branches/py3k: Doc/c-api/long.rst Modules/_testcapimodule.c Objects/longobject.c

mark.dickinson python-checkins at python.org
Mon Dec 21 13:37:07 CET 2009


Author: mark.dickinson
Date: Mon Dec 21 13:37:06 2009
New Revision: 76971

Log:
Keep PyLong_AsLongAndOverflow documentation and implementation in sync
between py3k and trunk;  merge new tests from trunk to py3k.
(See issue #7528.)


Modified:
   python/branches/py3k/Doc/c-api/long.rst
   python/branches/py3k/Modules/_testcapimodule.c
   python/branches/py3k/Objects/longobject.c

Modified: python/branches/py3k/Doc/c-api/long.rst
==============================================================================
--- python/branches/py3k/Doc/c-api/long.rst	(original)
+++ python/branches/py3k/Doc/c-api/long.rst	Mon Dec 21 13:37:06 2009
@@ -121,10 +121,13 @@
 
 .. 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)

Modified: python/branches/py3k/Modules/_testcapimodule.c
==============================================================================
--- python/branches/py3k/Modules/_testcapimodule.c	(original)
+++ python/branches/py3k/Modules/_testcapimodule.c	Mon Dec 21 13:37:06 2009
@@ -359,6 +359,171 @@
 #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 @@
 	{"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},

Modified: python/branches/py3k/Objects/longobject.c
==============================================================================
--- python/branches/py3k/Objects/longobject.c	(original)
+++ python/branches/py3k/Objects/longobject.c	Mon Dec 21 13:37:06 2009
@@ -346,9 +346,10 @@
 
 	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 @@
 			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 @@
 			res = LONG_MIN;
 		}
 		else {
-			*overflow = Py_SIZE(v) > 0 ? 1 : -1;
+			*overflow = sign;
 			/* res is already set to -1 */
-		}	
+		}
 	}
  exit:
 	if (do_decref) {


More information about the Python-checkins mailing list