[Python-checkins] cpython (merge default -> default): Merge

brett.cannon python-checkins at python.org
Fri Apr 20 23:19:22 CEST 2012


http://hg.python.org/cpython/rev/f5a5b2f5c7ef
changeset:   76443:f5a5b2f5c7ef
parent:      76442:b863d7dd113c
parent:      76441:c7b0f711dc15
user:        Brett Cannon <brett at python.org>
date:        Fri Apr 20 17:19:14 2012 -0400
summary:
  Merge

files:
  Lib/test/test_long.py |  14 ++++++
  Misc/NEWS             |   6 ++
  Objects/longobject.c  |  65 ++++++++++++++++--------------
  3 files changed, 54 insertions(+), 31 deletions(-)


diff --git a/Lib/test/test_long.py b/Lib/test/test_long.py
--- a/Lib/test/test_long.py
+++ b/Lib/test/test_long.py
@@ -1228,6 +1228,20 @@
         self.assertRaises(TypeError, myint.from_bytes, 0, 'big')
         self.assertRaises(TypeError, int.from_bytes, 0, 'big', True)
 
+    def test_access_to_nonexistent_digit_0(self):
+        # http://bugs.python.org/issue14630: A bug in _PyLong_Copy meant that
+        # ob_digit[0] was being incorrectly accessed for instances of a
+        # subclass of int, with value 0.
+        class Integer(int):
+            def __new__(cls, value=0):
+                self = int.__new__(cls, value)
+                self.foo = 'foo'
+                return self
+
+        integers = [Integer(0) for i in range(1000)]
+        for n in map(int, integers):
+            self.assertEqual(n, 0)
+
 
 def test_main():
     support.run_unittest(LongTest)
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -10,6 +10,12 @@
 Core and Builtins
 -----------------
 
+- Issue #14630: Fix a memory access bug for instances of a subclass of int
+  with value 0.
+
+- Issue #14339: Speed improvements to bin, oct and hex functions.  Patch by
+  Serhiy Storchaka.
+
 - Issue #14098: New functions PyErr_GetExcInfo and PyErr_SetExcInfo.
   Patch by Stefan Behnel.
 
diff --git a/Objects/longobject.c b/Objects/longobject.c
--- a/Objects/longobject.c
+++ b/Objects/longobject.c
@@ -156,9 +156,7 @@
     if (i < 0)
         i = -(i);
     if (i < 2) {
-        sdigit ival = src->ob_digit[0];
-        if (Py_SIZE(src) < 0)
-            ival = -ival;
+        sdigit ival = MEDIUM_VALUE(src);
         CHECK_SMALL_INT(ival);
     }
     result = _PyLong_New(i);
@@ -1672,11 +1670,10 @@
 {
     register PyLongObject *a = (PyLongObject *)aa;
     PyObject *v;
-    Py_ssize_t i, sz;
+    Py_ssize_t sz;
     Py_ssize_t size_a;
-    char *p;
-    char sign = '\0';
-    char *buffer;
+    Py_UCS1 *p;
+    int negative;
     int bits;
 
     assert(base == 2 || base == 8 || base == 10 || base == 16);
@@ -1688,6 +1685,7 @@
         return NULL;
     }
     size_a = ABS(Py_SIZE(a));
+    negative = Py_SIZE(a) < 0;
 
     /* Compute a rough upper bound for the length of the string */
     switch (base) {
@@ -1704,33 +1702,40 @@
         assert(0); /* shouldn't ever get here */
         bits = 0; /* to silence gcc warning */
     }
-    /* compute length of output string: allow 2 characters for prefix and
-       1 for possible '-' sign. */
-    if (size_a > (PY_SSIZE_T_MAX - 3) / PyLong_SHIFT / sizeof(Py_UCS4)) {
-        PyErr_SetString(PyExc_OverflowError,
-                        "int is too large to format");
+
+    /* Compute exact length 'sz' of output string. */
+    if (size_a == 0) {
+        sz = 3;
+    }
+    else {
+        Py_ssize_t size_a_in_bits;
+        /* Ensure overflow doesn't occur during computation of sz. */
+        if (size_a > (PY_SSIZE_T_MAX - 3) / PyLong_SHIFT) {
+            PyErr_SetString(PyExc_OverflowError,
+                            "int is too large to format");
+            return NULL;
+        }
+        size_a_in_bits = (size_a - 1) * PyLong_SHIFT +
+                         bits_in_digit(a->ob_digit[size_a - 1]);
+        /* Allow 2 characters for prefix and 1 for a '-' sign. */
+        sz = 2 + negative + (size_a_in_bits + (bits - 1)) / bits;
+    }
+
+    v = PyUnicode_New(sz, 'x');
+    if (v == NULL) {
         return NULL;
     }
-    /* now size_a * PyLong_SHIFT + 3 <= PY_SSIZE_T_MAX, so the RHS below
-       is safe from overflow */
-    sz = 3 + (size_a * PyLong_SHIFT + (bits - 1)) / bits;
-    assert(sz >= 0);
-    buffer = PyMem_Malloc(sz);
-    if (buffer == NULL) {
-        PyErr_NoMemory();
-        return NULL;
-    }
-    p = &buffer[sz];
-    if (Py_SIZE(a) < 0)
-        sign = '-';
-
-    if (Py_SIZE(a) == 0) {
+    assert(PyUnicode_KIND(v) == PyUnicode_1BYTE_KIND);
+
+    p = PyUnicode_1BYTE_DATA(v) + sz;
+    if (size_a == 0) {
         *--p = '0';
     }
     else {
         /* JRH: special case for power-of-2 bases */
         twodigits accum = 0;
         int accumbits = 0;              /* # of bits in accum */
+        Py_ssize_t i;
         for (i = 0; i < size_a; ++i) {
             accum |= (twodigits)a->ob_digit[i] << accumbits;
             accumbits += PyLong_SHIFT;
@@ -1739,7 +1744,6 @@
                 char cdigit;
                 cdigit = (char)(accum & (base - 1));
                 cdigit += (cdigit < 10) ? '0' : 'a'-10;
-                assert(p > buffer);
                 *--p = cdigit;
                 accumbits -= bits;
                 accum >>= bits;
@@ -1754,10 +1758,9 @@
     else /* (base == 2) */
         *--p = 'b';
     *--p = '0';
-    if (sign)
-        *--p = sign;
-    v = PyUnicode_DecodeASCII(p, &buffer[sz] - p, NULL);
-    PyMem_Free(buffer);
+    if (negative)
+        *--p = '-';
+    assert(p == PyUnicode_1BYTE_DATA(v));
     return v;
 }
 

-- 
Repository URL: http://hg.python.org/cpython


More information about the Python-checkins mailing list