Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 23cf6be

Browse files
committed
Coredumpers from Michael Hudson, mutating dicts while printing or
converting to string. Critical bugfix candidate -- if you take this seriously <wink>.
1 parent 89e90d6 commit 23cf6be

2 files changed

Lines changed: 84 additions & 8 deletions

File tree

Lib/test/test_mutants.py

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
from test_support import verbose
1+
from test_support import verbose, TESTFN
22
import random
3+
import os
34

45
# From SF bug #422121: Insecurities in dict comparison.
56

@@ -151,3 +152,66 @@ def test(n):
151152

152153
# See last comment block for clues about good values for n.
153154
test(100)
155+
156+
##########################################################################
157+
# Another segfault bug, distilled by Micheal Hundson from a c.l.py post.
158+
159+
class Child:
160+
def __init__(self, parent):
161+
self.__dict__['parent'] = parent
162+
def __getattr__(self, attr):
163+
self.parent.a = 1
164+
self.parent.b = 1
165+
self.parent.c = 1
166+
self.parent.d = 1
167+
self.parent.e = 1
168+
self.parent.f = 1
169+
self.parent.g = 1
170+
self.parent.h = 1
171+
self.parent.i = 1
172+
return getattr(self.parent, attr)
173+
174+
class Parent:
175+
def __init__(self):
176+
self.a = Child(self)
177+
178+
# Hard to say what this will print! May vary from time to time. But
179+
# we're specifically trying to test the tp_print slot here, and this is
180+
# the clearest way to do it. We print the result to a temp file so that
181+
# the expected-output file doesn't need to change.
182+
183+
f = open(TESTFN, "w")
184+
print >> f, Parent().__dict__
185+
f.close()
186+
os.unlink(TESTFN)
187+
188+
##########################################################################
189+
# And another core-dumper from Michael Hudson.
190+
191+
dict = {}
192+
193+
# Force dict to malloc its table.
194+
for i in range(1, 10):
195+
dict[i] = i
196+
197+
f = open(TESTFN, "w")
198+
199+
class Machiavelli:
200+
def __repr__(self):
201+
dict.clear()
202+
203+
# Michael sez: "doesn't crash without this. don't know why."
204+
# Tim sez: "luck of the draw; crashes with or without for me."
205+
print >> f
206+
207+
return `"machiavelli"`
208+
209+
def __hash__(self):
210+
return 0
211+
212+
dict[Machiavelli()] = Machiavelli()
213+
214+
print >> f, str(dict)
215+
f.close()
216+
os.unlink(TESTFN)
217+
del f, dict

Objects/dictobject.c

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -740,7 +740,6 @@ dict_print(register dictobject *mp, register FILE *fp, register int flags)
740740
{
741741
register int i;
742742
register int any;
743-
register dictentry *ep;
744743

745744
i = Py_ReprEnter((PyObject*)mp);
746745
if (i != 0) {
@@ -752,19 +751,27 @@ dict_print(register dictobject *mp, register FILE *fp, register int flags)
752751

753752
fprintf(fp, "{");
754753
any = 0;
755-
for (i = 0, ep = mp->ma_table; i < mp->ma_size; i++, ep++) {
756-
if (ep->me_value != NULL) {
754+
for (i = 0; i < mp->ma_size; i++) {
755+
dictentry *ep = mp->ma_table + i;
756+
PyObject *pvalue = ep->me_value;
757+
if (pvalue != NULL) {
758+
/* Prevent PyObject_Repr from deleting value during
759+
key format */
760+
Py_INCREF(pvalue);
757761
if (any++ > 0)
758762
fprintf(fp, ", ");
759763
if (PyObject_Print((PyObject *)ep->me_key, fp, 0)!=0) {
764+
Py_DECREF(pvalue);
760765
Py_ReprLeave((PyObject*)mp);
761766
return -1;
762767
}
763768
fprintf(fp, ": ");
764769
if (PyObject_Print(ep->me_value, fp, 0) != 0) {
770+
Py_DECREF(pvalue);
765771
Py_ReprLeave((PyObject*)mp);
766772
return -1;
767773
}
774+
Py_DECREF(pvalue);
768775
}
769776
}
770777
fprintf(fp, "}");
@@ -779,7 +786,6 @@ dict_repr(dictobject *mp)
779786
PyObject *sepa, *colon;
780787
register int i;
781788
register int any;
782-
register dictentry *ep;
783789

784790
i = Py_ReprEnter((PyObject*)mp);
785791
if (i != 0) {
@@ -792,13 +798,19 @@ dict_repr(dictobject *mp)
792798
sepa = PyString_FromString(", ");
793799
colon = PyString_FromString(": ");
794800
any = 0;
795-
for (i = 0, ep = mp->ma_table; i < mp->ma_size && v; i++, ep++) {
796-
if (ep->me_value != NULL) {
801+
for (i = 0; i < mp->ma_size && v; i++) {
802+
dictentry *ep = mp->ma_table + i;
803+
PyObject *pvalue = ep->me_value;
804+
if (pvalue != NULL) {
805+
/* Prevent PyObject_Repr from deleting value during
806+
key format */
807+
Py_INCREF(pvalue);
797808
if (any++)
798809
PyString_Concat(&v, sepa);
799810
PyString_ConcatAndDel(&v, PyObject_Repr(ep->me_key));
800811
PyString_Concat(&v, colon);
801-
PyString_ConcatAndDel(&v, PyObject_Repr(ep->me_value));
812+
PyString_ConcatAndDel(&v, PyObject_Repr(pvalue));
813+
Py_DECREF(pvalue);
802814
}
803815
}
804816
PyString_ConcatAndDel(&v, PyString_FromString("}"));

0 commit comments

Comments
 (0)