[pypy-svn] r37808 - in pypy/dist/pypy/objspace/std: . test

cfbolz at codespeak.net cfbolz at codespeak.net
Fri Feb 2 15:22:32 CET 2007


Author: cfbolz
Date: Fri Feb  2 15:22:31 2007
New Revision: 37808

Modified:
   pypy/dist/pypy/objspace/std/listobject.py
   pypy/dist/pypy/objspace/std/test/test_listobject.py
Log:
make list.remove safe against list elements with an __eq__ that mutate the
list. Before, you could get an interp-level exception :-(.


Modified: pypy/dist/pypy/objspace/std/listobject.py
==============================================================================
--- pypy/dist/pypy/objspace/std/listobject.py	(original)
+++ pypy/dist/pypy/objspace/std/listobject.py	Fri Feb  2 15:22:31 2007
@@ -376,11 +376,13 @@
 def list_remove__List_ANY(space, w_list, w_any):
     # needs to be safe against eq_w() mutating the w_list behind our back
     items = w_list.wrappeditems
-    length = len(items)
-    for i in range(length):
+    i = 0
+    while i < len(items):
         if space.eq_w(items[i], w_any):
-            del items[i]
+            if i < len(items): # if this is wrong the list was changed
+                del items[i]
             return space.w_None
+        i += 1
     raise OperationError(space.w_ValueError,
                          space.wrap("list.remove(x): x not in list"))
 

Modified: pypy/dist/pypy/objspace/std/test/test_listobject.py
==============================================================================
--- pypy/dist/pypy/objspace/std/test/test_listobject.py	(original)
+++ pypy/dist/pypy/objspace/std/test/test_listobject.py	Fri Feb  2 15:22:31 2007
@@ -1,4 +1,3 @@
-#from __future__ import nested_scopes
 import autopath, random
 from pypy.objspace.std.listobject import W_ListObject
 from pypy.interpreter.error import OperationError
@@ -553,3 +552,28 @@
     def test_reversed(self):
         assert list(list('hello').__reversed__()) == ['o', 'l', 'l', 'e', 'h']
         assert list(reversed(list('hello'))) == ['o', 'l', 'l', 'e', 'h']
+
+    def test_mutate_while_remove(self):
+        class Mean(object):
+            def __init__(self, i):
+                self.i = i
+            def __eq__(self, other):
+                if self.i == 9:
+                    del l[i - 1]
+                    return True
+                else:
+                    return False
+        l = [Mean(i) for i in range(10)]
+        # does not crash
+        l.remove(None)
+        class Mean2(object):
+            def __init__(self, i):
+                self.i = i
+            def __eq__(self, other):
+                l.append(self.i)
+                return False
+        l = [Mean2(i) for i in range(10)]
+        # does not crash
+        l.remove(5)
+        print l
+        assert l[10:] == [0, 1, 2, 3, 4, 6, 7, 8, 9]


More information about the pypy-svn mailing list