Issue #26194: Fix undefined behavior for deque.insert() when len(d) == maxlen
authorRaymond Hettinger <python@rcn.com>
Wed, 27 Jan 2016 05:44:16 +0000 (21:44 -0800)
committerRaymond Hettinger <python@rcn.com>
Wed, 27 Jan 2016 05:44:16 +0000 (21:44 -0800)
Doc/library/collections.rst
Lib/test/test_deque.py
Misc/NEWS
Modules/_collectionsmodule.c

index 00d2916415cc06a5612b3064cc9ad2485816f11a..e89da350230b82571442b1fd7604f981ba727cc9 100644 (file)
@@ -477,6 +477,9 @@ or subtracting from an empty counter.
 
         Insert *x* into the deque at position *i*.
 
+        If the insertion causes a bounded deque to grow beyond *maxlen*, the
+        rightmost element is then removed to restore the size limit.
+
         .. versionadded:: 3.5
 
 
index 87187161ab30d84bbc2febf7cfa31bec431bd339..d2a463351bd4978990fcb009a72b03124b6d609e 100644 (file)
@@ -304,6 +304,20 @@ class TestBasic(unittest.TestCase):
             s.insert(i, 'Z')
             self.assertEqual(list(d), s)
 
+    def test_index_bug_26194(self):
+        data = 'ABC'
+        for i in range(len(data) + 1):
+            d = deque(data, len(data))
+            d.insert(i, None)
+            s = list(data)
+            s.insert(i, None)
+            s.pop()
+            self.assertEqual(list(d), s)
+            if i < len(data):
+                self.assertIsNone(d[i])
+            else:
+                self.assertTrue(None not in d)
+
     def test_imul(self):
         for n in (-10, -1, 0, 1, 2, 10, 1000):
             d = deque()
index 75df5325271f04fdcbe3b5036b32725f49ca4158..5e461f9205ca252d74f5d2c8624e24cbfc167ebc 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -17,6 +17,10 @@ Core and Builtins
   Python 3.5.1 to hide the exact implementation of atomic C types, to avoid
   compiler issues.
 
+- Issue #26194:  Deque.insert() gave odd results for bounded deques that had
+  reached their maximum size.  Now, the insert will happen normally and then
+  any overflowing element will be truncated from the right side.
+
 - Issue #25843: When compiling code, don't merge constants if they are equal
   but have a different types. For example, ``f1, f2 = lambda: 1, lambda: 1.0``
   is now correctly compiled to two different functions: ``f1()`` returns ``1``
index 1a334285c1662a95072e2c91a0d870a007aadb57..b9c4f3b9263cc6326fe3994d8b4e067775310213 100644 (file)
@@ -973,10 +973,17 @@ deque_insert(dequeobject *deque, PyObject *args)
     Py_ssize_t index;
     Py_ssize_t n = Py_SIZE(deque);
     PyObject *value;
+    PyObject *oldvalue;
     PyObject *rv;
 
     if (!PyArg_ParseTuple(args, "nO:insert", &index, &value))
         return NULL;
+    if (deque->maxlen == Py_SIZE(deque)) {
+        if (index >= deque->maxlen || Py_SIZE(deque) == 0)
+            Py_RETURN_NONE;
+        oldvalue = deque_pop(deque, NULL);
+        Py_DECREF(oldvalue);
+    }
     if (index >= n)
         return deque_append(deque, value);
     if (index <= -n || index == 0)