An interpreted, interactive, object-oriented programming language
CentOS Sources
2017-08-01 71084d584ff953f5463757ec6536406320560b4d
commit | author | age
6e8c2f 1 diff -up Python-2.7.3/Lib/test/test_gc.py.gc-assertions Python-2.7.3/Lib/test/test_gc.py
CB 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
6 -from test.test_support import verbose, run_unittest
7 +from test.test_support import verbose, run_unittest, import_module
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()
72 diff -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          }