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 ;-)
3.1 Dictionary lookups succeed even if __cmp__() raises an exception
raising error
No exception passed through.
+resize bugs not triggered.
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
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.'
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.
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.
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,
}
}
+/*
+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
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;