New submission from asterite:
I faced a crash during iterpreter shutdown (Py_Finalize), in final garbage
collection phase.
The reason, as far as I could understand, was the following:
In Python 3, when an unclosed socket is destroyed, it issues a ResourceWarning,
which contains a string representation of socket object (obtained by __repr__).
If socket class object and unclosed socket object (instance) are in a reference
cycle, GC may collect socket class object before it collects an instance when
dealing with that cycle. Then, when instance is collected, sock_dealloc() will
be called, which will call PyErr_WarnFormat with %R format specifier, which
triggers a call to __repr__:
static void
sock_dealloc(PySocketSockObject *s)
{
if (s->sock_fd != INVALID_SOCKET) {
// ...
if (PyErr_WarnFormat(PyExc_ResourceWarning, 1,
"unclosed %R", s))
//...
}
At this moment, socket class object was already deallocated, so was __repr__,
resides in it. Particularly, in my tests, when __repr__ attempted to access a
global variable (getattr), it tried to take it's name from co_names tuple in
it's code object. This tuple was deallocated, and co_names pointed to tuple
free list. Trying to use a tuple from free list as a dict key resulted in a
crash (more detailed stack trace will be provided in attachment):
# gdb python3.5 test.py
GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.04) 7.11.1
...
Starting program: /usr/local/bin/python3.5 test.py
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
test
Program received signal SIGSEGV, Segmentation fault.
0x0048998c in PyObject_Hash (v=0x0) at Objects/object.c:761
761 PyTypeObject *tp = Py_TYPE(v);
(gdb) bt
#0 0x0048998c in PyObject_Hash (v=0x0) at Objects/object.c:761
#1 0x00498d96 in tuplehash (v=0x77f39948) at
Objects/tupleobject.c:351
#2 0x004899b2 in PyObject_Hash (v=0x77f39948) at
Objects/object.c:763
... tuplehash and PyObject_Hash here also ...
#34 0x004899b2 in PyObject_Hash (v=0x76801708) at
Objects/object.c:763
#35 0x00498d96 in tuplehash (v=0x76812ca8) at
Objects/tupleobject.c:351
#36 0x004899b2 in PyObject_Hash (v=0x76812ca8) at
Objects/object.c:763
#37 0x0047a056 in PyDict_GetItemWithError (op=0x77e83608,
key=0x76812ca8) at Objects/dictobject.c:1143
#38 0x0047a1e8 in _PyDict_LoadGlobal (globals=0x77e83608,
builtins=0x76ea8a88, key=0x76812ca8) at Objects/dictobject.c:1192
#39 0x00509117 in PyEval_EvalFrameEx (f=0xa196d8, throwflag=0) at
Python/ceval.c:2408
#40 0x00511d0b in _PyEval_EvalCodeWithName (_co=0x77e85270,
globals=0x77e83608, locals=0x0, args=0x77f07c68, argcount=1, kws=0x0,
kwcount=0, defs=0x0, defcount=0, kwdefs=0x0, closure=0x0, name=0x0,
qualname=0x0) at Python/ceval.c:4071
#41 0x00511e00 in PyEval_EvalCodeEx (_co=0x77e85270,
globals=0x77e83608, locals=0x0, args=0x77f07c68, argcount=1, kws=0x0,
kwcount=0, defs=0x0, defcount=0, kwdefs=0x0, closure=0x0) at Python/ceval.c:4092
#42 0x005db41c in function_call (func=0x7683ec80,
arg=0x77f07c50, kw=0x0) at Objects/funcobject.c:627
#43 0x0043ae8f in PyObject_Call (func=0x7683ec80,
arg=0x77f07c50, kw=0x0) at Objects/abstract.c:2166
#44 0x005cb13c in method_call (func=0x7683ec80, arg=0x77f07c50,
kw=0x0) at Objects/classobject.c:330
#45 0x0043ae8f in PyObject_Call (func=0x77eaca48,
arg=0x77fa8048, kw=0x0) at Objects/abstract.c:2166
#46 0x005138a9 in PyEval_CallObjectWithKeywords (func=0x77eaca48,
arg=0x77fa8048, kw=0x0) at Python/ceval.c:4633
#47 0x004abf3e in slot_tp_repr (self=0x7684e8d0) at
Objects/typeobject.c:5992
#48 0x00488ef9 in PyObject_Repr (v=0x7684e8d0) at
Objects/object.c:482
#49 0x004c03fb in unicode_fromformat_arg (writer=0x7fffdeb0,
f=0x76ed9850 "R", vargs=0x7fffdef0) at Objects/unicodeobject.c:2645
#50 0x004c0754 in PyUnicode_FromFormatV (format=0x76ed9846
"unclosed %R", vargs=0x7fffdf60) at Objects/unicodeobject.c:2710
#51 0x004f90e7 in PyErr_WarnFormat (category=0x8a1a20
<_PyExc_ResourceWarning>, stack_level=1, format=0x76ed9846 "unclosed %R")
at Python/_warnings.c:895
#52 0x76ed438a in sock_dealloc (s=0x7684e8d0) at
/root/test/test35/cpython/Modules/socketmodule.c:4177
#53 0x0049d02c in subtype_dealloc (self=0x7684e8d0) at
Objects/typeobject.c:1209
#54 0x004781c5 in free_keys_object (keys=0xa3fd90) at
Objects/dictobject.c:351
#55 0x0047a908 in PyDict_Clear (op=0x77f55448) at
Objects/dictobject.c:1388
#56 0x0047df02 in dict_tp_clear (op=0x77f55448) at
Objects/dictobject.c:2595
#57 0x00567