]> git.ipfire.org Git - people/ms/ipfire-3.x.git/blame - python/patches/00170-gc-assertions.patch
gcc: Update to 6.4.0
[people/ms/ipfire-3.x.git] / python / patches / 00170-gc-assertions.patch
CommitLineData
48d9a6a0
MT
1diff -up Python-2.7.3/Lib/test/test_gc.py.gc-assertions Python-2.7.3/Lib/test/test_gc.py
2--- Python-2.7.3/Lib/test/test_gc.py.gc-assertions 2013-02-20 16:28:20.890536607 -0500
3+++ Python-2.7.3/Lib/test/test_gc.py 2013-02-20 16:39:52.720489297 -0500
4@@ -1,6 +1,7 @@
5 import unittest
4034c523
SS
6-from test.test_support import verbose, run_unittest, start_threads
7+from test.test_support import verbose, run_unittest, start_threads, import_module
48d9a6a0
MT
8 import sys
9+import sysconfig
10 import time
11 import gc
12 import weakref
13@@ -32,6 +33,8 @@ class GC_Detector(object):
14 self.wr = weakref.ref(C1055820(666), it_happened)
15
16
17+BUILT_WITH_NDEBUG = ('-DNDEBUG' in sysconfig.get_config_vars()['PY_CFLAGS'])
18+
19 ### Tests
20 ###############################################################################
21
22@@ -476,6 +479,49 @@ class GCTests(unittest.TestCase):
23 # would be damaged, with an empty __dict__.
24 self.assertEqual(x, None)
25
26+ @unittest.skipIf(BUILT_WITH_NDEBUG,
27+ 'built with -NDEBUG')
28+ def test_refcount_errors(self):
29+ # Verify the "handling" of objects with broken refcounts
30+
31+ import_module("ctypes") #skip if not supported
32+
33+ import subprocess
34+ code = '''if 1:
35+ a = []
36+ b = [a]
37+
38+ # Simulate the refcount of "a" being too low (compared to the
39+ # references held on it by live data), but keeping it above zero
40+ # (to avoid deallocating it):
41+ import ctypes
42+ ctypes.pythonapi.Py_DecRef(ctypes.py_object(a))
43+
44+ # The garbage collector should now have a fatal error when it reaches
45+ # the broken object:
46+ import gc
47+ gc.collect()
48+ '''
49+ p = subprocess.Popen([sys.executable, "-c", code],
50+ stdout=subprocess.PIPE,
51+ stderr=subprocess.PIPE)
52+ stdout, stderr = p.communicate()
53+ p.stdout.close()
54+ p.stderr.close()
55+ # Verify that stderr has a useful error message:
56+ self.assertRegexpMatches(stderr,
57+ b'Modules/gcmodule.c:[0-9]+: visit_decref: Assertion "gc->gc.gc_refs != 0" failed.')
58+ self.assertRegexpMatches(stderr,
59+ b'refcount was too small')
60+ self.assertRegexpMatches(stderr,
61+ b'object : \[\]')
62+ self.assertRegexpMatches(stderr,
63+ b'type : list')
64+ self.assertRegexpMatches(stderr,
65+ b'refcount: 1')
66+ self.assertRegexpMatches(stderr,
67+ b'address : 0x[0-9a-f]+')
68+
69 class GCTogglingTests(unittest.TestCase):
70 def setUp(self):
71 gc.enable()
72diff -up Python-2.7.3/Modules/gcmodule.c.gc-assertions Python-2.7.3/Modules/gcmodule.c
73--- Python-2.7.3/Modules/gcmodule.c.gc-assertions 2012-04-09 19:07:34.000000000 -0400
74+++ Python-2.7.3/Modules/gcmodule.c 2013-02-20 16:28:21.029536600 -0500
75@@ -21,6 +21,73 @@
76 #include "Python.h"
77 #include "frameobject.h" /* for PyFrame_ClearFreeList */
78
79+/*
80+ Define a pair of assertion macros.
81+
82+ These work like the regular C assert(), in that they will abort the
83+ process with a message on stderr if the given condition fails to hold,
84+ but compile away to nothing if NDEBUG is defined.
85+
86+ However, before aborting, Python will also try to call _PyObject_Dump() on
87+ the given object. This may be of use when investigating bugs in which a
88+ particular object is corrupt (e.g. buggy a tp_visit method in an extension
89+ module breaking the garbage collector), to help locate the broken objects.
90+
91+ The WITH_MSG variant allows you to supply an additional message that Python
92+ will attempt to print to stderr, after the object dump.
93+*/
94+#ifdef NDEBUG
95+/* No debugging: compile away the assertions: */
96+#define PyObject_ASSERT_WITH_MSG(obj, expr, msg) ((void)0)
97+#else
98+/* With debugging: generate checks: */
99+#define PyObject_ASSERT_WITH_MSG(obj, expr, msg) \
100+ ((expr) \
101+ ? (void)(0) \
102+ : _PyObject_AssertFailed((obj), \
103+ (msg), \
104+ (__STRING(expr)), \
105+ (__FILE__), \
106+ (__LINE__), \
107+ (__PRETTY_FUNCTION__)))
108+#endif
109+
110+#define PyObject_ASSERT(obj, expr) \
111+ PyObject_ASSERT_WITH_MSG(obj, expr, NULL)
112+
113+static void _PyObject_AssertFailed(PyObject *, const char *,
114+ const char *, const char *, int,
115+ const char *);
116+
117+static void
118+_PyObject_AssertFailed(PyObject *obj, const char *msg, const char *expr,
119+ const char *file, int line, const char *function)
120+{
121+ fprintf(stderr,
122+ "%s:%d: %s: Assertion \"%s\" failed.\n",
123+ file, line, function, expr);
124+ if (msg) {
125+ fprintf(stderr, "%s\n", msg);
126+ }
127+
128+ fflush(stderr);
129+
130+ if (obj) {
131+ /* This might succeed or fail, but we're about to abort, so at least
132+ try to provide any extra info we can: */
133+ _PyObject_Dump(obj);
134+ }
135+ else {
136+ fprintf(stderr, "NULL object\n");
137+ }
138+
139+ fflush(stdout);
140+ fflush(stderr);
141+
142+ /* Terminate the process: */
143+ abort();
144+}
145+
146 /* Get an object's GC head */
147 #define AS_GC(o) ((PyGC_Head *)(o)-1)
148
149@@ -288,7 +355,8 @@ update_refs(PyGC_Head *containers)
150 {
151 PyGC_Head *gc = containers->gc.gc_next;
152 for (; gc != containers; gc = gc->gc.gc_next) {
153- assert(gc->gc.gc_refs == GC_REACHABLE);
154+ PyObject_ASSERT(FROM_GC(gc),
155+ gc->gc.gc_refs == GC_REACHABLE);
156 gc->gc.gc_refs = Py_REFCNT(FROM_GC(gc));
157 /* Python's cyclic gc should never see an incoming refcount
158 * of 0: if something decref'ed to 0, it should have been
159@@ -308,7 +376,8 @@ update_refs(PyGC_Head *containers)
160 * so serious that maybe this should be a release-build
161 * check instead of an assert?
162 */
163- assert(gc->gc.gc_refs != 0);
164+ PyObject_ASSERT(FROM_GC(gc),
165+ gc->gc.gc_refs != 0);
166 }
167 }
168
169@@ -323,7 +392,9 @@ visit_decref(PyObject *op, void *data)
170 * generation being collected, which can be recognized
171 * because only they have positive gc_refs.
172 */
173- assert(gc->gc.gc_refs != 0); /* else refcount was too small */
174+ PyObject_ASSERT_WITH_MSG(FROM_GC(gc),
175+ gc->gc.gc_refs != 0,
176+ "refcount was too small");
177 if (gc->gc.gc_refs > 0)
178 gc->gc.gc_refs--;
179 }
180@@ -383,9 +454,10 @@ visit_reachable(PyObject *op, PyGC_Head
181 * If gc_refs == GC_UNTRACKED, it must be ignored.
182 */
183 else {
184- assert(gc_refs > 0
185- || gc_refs == GC_REACHABLE
186- || gc_refs == GC_UNTRACKED);
187+ PyObject_ASSERT(FROM_GC(gc),
188+ gc_refs > 0
189+ || gc_refs == GC_REACHABLE
190+ || gc_refs == GC_UNTRACKED);
191 }
192 }
193 return 0;
194@@ -427,7 +499,7 @@ move_unreachable(PyGC_Head *young, PyGC_
195 */
196 PyObject *op = FROM_GC(gc);
197 traverseproc traverse = Py_TYPE(op)->tp_traverse;
198- assert(gc->gc.gc_refs > 0);
199+ PyObject_ASSERT(op, gc->gc.gc_refs > 0);
200 gc->gc.gc_refs = GC_REACHABLE;
201 (void) traverse(op,
202 (visitproc)visit_reachable,
203@@ -494,7 +566,8 @@ move_finalizers(PyGC_Head *unreachable,
204 for (gc = unreachable->gc.gc_next; gc != unreachable; gc = next) {
205 PyObject *op = FROM_GC(gc);
206
207- assert(IS_TENTATIVELY_UNREACHABLE(op));
208+ PyObject_ASSERT(op, IS_TENTATIVELY_UNREACHABLE(op));
209+
210 next = gc->gc.gc_next;
211
212 if (has_finalizer(op)) {
213@@ -570,7 +643,7 @@ handle_weakrefs(PyGC_Head *unreachable,
214 PyWeakReference **wrlist;
215
216 op = FROM_GC(gc);
217- assert(IS_TENTATIVELY_UNREACHABLE(op));
218+ PyObject_ASSERT(op, IS_TENTATIVELY_UNREACHABLE(op));
219 next = gc->gc.gc_next;
220
221 if (! PyType_SUPPORTS_WEAKREFS(Py_TYPE(op)))
222@@ -591,9 +664,9 @@ handle_weakrefs(PyGC_Head *unreachable,
223 * the callback pointer intact. Obscure: it also
224 * changes *wrlist.
225 */
226- assert(wr->wr_object == op);
227+ PyObject_ASSERT(wr->wr_object, wr->wr_object == op);
228 _PyWeakref_ClearRef(wr);
229- assert(wr->wr_object == Py_None);
230+ PyObject_ASSERT(wr->wr_object, wr->wr_object == Py_None);
231 if (wr->wr_callback == NULL)
232 continue; /* no callback */
233
234@@ -627,7 +700,7 @@ handle_weakrefs(PyGC_Head *unreachable,
235 */
236 if (IS_TENTATIVELY_UNREACHABLE(wr))
237 continue;
238- assert(IS_REACHABLE(wr));
239+ PyObject_ASSERT(op, IS_REACHABLE(wr));
240
241 /* Create a new reference so that wr can't go away
242 * before we can process it again.
243@@ -636,7 +709,8 @@ handle_weakrefs(PyGC_Head *unreachable,
244
245 /* Move wr to wrcb_to_call, for the next pass. */
246 wrasgc = AS_GC(wr);
247- assert(wrasgc != next); /* wrasgc is reachable, but
248+ PyObject_ASSERT(op, wrasgc != next);
249+ /* wrasgc is reachable, but
250 next isn't, so they can't
251 be the same */
252 gc_list_move(wrasgc, &wrcb_to_call);
253@@ -652,11 +726,11 @@ handle_weakrefs(PyGC_Head *unreachable,
254
255 gc = wrcb_to_call.gc.gc_next;
256 op = FROM_GC(gc);
257- assert(IS_REACHABLE(op));
258- assert(PyWeakref_Check(op));
259+ PyObject_ASSERT(op, IS_REACHABLE(op));
260+ PyObject_ASSERT(op, PyWeakref_Check(op));
261 wr = (PyWeakReference *)op;
262 callback = wr->wr_callback;
263- assert(callback != NULL);
264+ PyObject_ASSERT(op, callback != NULL);
265
266 /* copy-paste of weakrefobject.c's handle_callback() */
267 temp = PyObject_CallFunctionObjArgs(callback, wr, NULL);
268@@ -759,7 +833,7 @@ delete_garbage(PyGC_Head *collectable, P
269 PyGC_Head *gc = collectable->gc.gc_next;
270 PyObject *op = FROM_GC(gc);
271
272- assert(IS_TENTATIVELY_UNREACHABLE(op));
273+ PyObject_ASSERT(op, IS_TENTATIVELY_UNREACHABLE(op));
274 if (debug & DEBUG_SAVEALL) {
275 PyList_Append(garbage, op);
276 }