]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
Backport of the pieces of trunk rev 46589 relevant to
authorTim Peters <tim.peters@gmail.com>
Mon, 9 Oct 2006 20:24:45 +0000 (20:24 +0000)
committerTim Peters <tim.peters@gmail.com>
Mon, 9 Oct 2006 20:24:45 +0000 (20:24 +0000)
fixing an unlikely crash bug in dict resizing, SF
bug 1456209.

The rest of rev 46589 changes whether Python suppresses
exceptions during some dict-related comparisons.  While I
think that's a good idea, it does change visible behavior at
times, and there was already some complaining about that on
the trunk.  Not a good idea for backporting.  The part of
46589 checked in here can at worst stop segfaults, and I doubt
anyone will gripe about that ;-)

Lib/test/output/test_operations
Lib/test/test_operations.py
Misc/NEWS
Objects/dictobject.c

index 32eff3f21a8acf68e6b6cc273214b284641e0303..1803a4beb0ec1ff8fd8e1770feb1446d444c2a5a 100644 (file)
@@ -4,3 +4,4 @@ XXX Mostly not yet implemented
 3.1 Dictionary lookups succeed even if __cmp__() raises an exception
 raising error
 No exception passed through.
+resize bugs not triggered.
index b599c9da9e3fb135d1167c9fb1d8a8f0ff614cbf..fb1ab8eaea834d849b82f020f57bc439db0ece1c 100644 (file)
@@ -7,9 +7,6 @@ print 'XXX Mostly not yet implemented'
 
 print '3.1 Dictionary lookups succeed even if __cmp__() raises an exception'
 
-# SourceForge bug #112558:
-# http://sourceforge.net/bugs/?func=detailbug&bug_id=112558&group_id=5470
-
 class BadDictKey:
     already_printed_raising_error = 0
 
@@ -50,3 +47,27 @@ for i in range(5):
     del d[i]
 for i in range(5, 9):  # i==8 was the problem
     d[i] = i
+
+
+# Another dict resizing bug (SF bug #1456209).
+# This caused Segmentation faults or Illegal instructions.
+
+class X(object):
+    def __hash__(self):
+        return 5
+    def __eq__(self, other):
+        if resizing:
+            d.clear()
+        return False
+d = {}
+resizing = False
+d[X()] = 1
+d[X()] = 2
+d[X()] = 3
+d[X()] = 4
+d[X()] = 5
+# now trigger a resize
+resizing = True
+d[9] = 6
+
+print 'resize bugs not triggered.'
index 220bbb64c5bfa23ec9efe85968cb9ffce2419f57..a2e71ad705a47db04b268af27e84cfc86633c668 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -12,6 +12,11 @@ What's New in Python 2.4.4c1?
 Core and builtins
 -----------------
 
+- Bug #1456209: In some obscure cases it was possible for a class with a
+  custom ``__eq__()`` method to confuse dict internals when class instances
+  were used as a dict's keys and the ``__eq__()`` method mutated the dict.
+  No, you don't have any code that did this ;-)
+
 - A number of places, including integer negation and absolute value,
   were fixed to not rely on undefined behaviour of the C compiler
   anymore.
@@ -73,7 +78,7 @@ Core and builtins
 Extension Modules
 -----------------
 
-- Fix buffer handling in posix.confstr. 
+- Fix buffer handling in posix.confstr.
 
 - Bug #1572832: fix a bug in ISO-2022 codecs which may cause segfault
   when encoding non-BMP unicode characters.
@@ -142,7 +147,7 @@ Extension Modules
 Library
 -------
 
-- Bug #1545341: The 'classifier' keyword argument to the Distutils setup() 
+- Bug #1545341: The 'classifier' keyword argument to the Distutils setup()
   function now accepts tuples as well as lists.
 
 - Bug #1560617: in pyclbr, return full module name not only for classes,
index 18d8d5c1afa14f41df6e2ca3adf52338ef4ea176..b466abdcf08f0a68582ea560a88969e19a2820bb 100644 (file)
@@ -417,6 +417,35 @@ insertdict(register dictobject *mp, PyObject *key, long hash, PyObject *value)
        }
 }
 
+/*
+Internal routine used by dictresize() to insert an item which is
+known to be absent from the dict.  This routine also assumes that
+the dict contains no deleted entries.  Besides the performance benefit,
+using insertdict() in dictresize() is dangerous (SF bug #1456209).
+*/
+static void
+insertdict_clean(register dictobject *mp, PyObject *key, long hash,
+                PyObject *value)
+{
+       register unsigned int i;
+       register unsigned int perturb;
+       register unsigned int mask = mp->ma_mask;
+       dictentry *ep0 = mp->ma_table;
+       register dictentry *ep;
+
+       i = hash & mask;
+       ep = &ep0[i];
+       for (perturb = hash; ep->me_key != NULL; perturb >>= PERTURB_SHIFT) {
+               i = (i << 2) + i + perturb + 1;
+               ep = &ep0[i & mask];
+       }
+       mp->ma_fill++;
+       ep->me_key = key;
+       ep->me_hash = hash;
+       ep->me_value = value;
+       mp->ma_used++;
+}
+
 /*
 Restructure the table by allocating a new table and reinserting all
 items again.  When entries have been deleted, the new table may
@@ -489,7 +518,8 @@ dictresize(dictobject *mp, int minused)
        for (ep = oldtable; i > 0; ep++) {
                if (ep->me_value != NULL) {     /* active entry */
                        --i;
-                       insertdict(mp, ep->me_key, ep->me_hash, ep->me_value);
+                       insertdict_clean(mp, ep->me_key, ep->me_hash,
+                                        ep->me_value);
                }
                else if (ep->me_key != NULL) {  /* dummy entry */
                        --i;