diff options
| author | Tim Peters <tim.peters@gmail.com> | 2006-10-09 20:24:45 +0000 |
|---|---|---|
| committer | Tim Peters <tim.peters@gmail.com> | 2006-10-09 20:24:45 +0000 |
| commit | 2b37ea40871ec45cb1fb6d98a2696bcaf4cf6583 (patch) | |
| tree | c613bfebac501d6a94b922da81cba5070be00ab1 | |
| parent | b8f82e6febddbd534e0f08ab480367561daa0717 (diff) | |
| download | cpython-git-2b37ea40871ec45cb1fb6d98a2696bcaf4cf6583.tar.gz | |
Backport of the pieces of trunk rev 46589 relevant to
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 ;-)
| -rw-r--r-- | Lib/test/output/test_operations | 1 | ||||
| -rw-r--r-- | Lib/test/test_operations.py | 27 | ||||
| -rw-r--r-- | Misc/NEWS | 9 | ||||
| -rw-r--r-- | Objects/dictobject.c | 32 |
4 files changed, 63 insertions, 6 deletions
diff --git a/Lib/test/output/test_operations b/Lib/test/output/test_operations index 32eff3f21a..1803a4beb0 100644 --- a/Lib/test/output/test_operations +++ b/Lib/test/output/test_operations @@ -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. diff --git a/Lib/test/test_operations.py b/Lib/test/test_operations.py index b599c9da9e..fb1ab8eaea 100644 --- a/Lib/test/test_operations.py +++ b/Lib/test/test_operations.py @@ -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.' @@ -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, diff --git a/Objects/dictobject.c b/Objects/dictobject.c index 18d8d5c1af..b466abdcf0 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -418,6 +418,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 actually be smaller than the old one. @@ -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; |
