[issue30260] sock_dealloc() may call __repr__ when socket class is already collected by GC

2021-06-15 Thread asterite


Change by asterite :


--
stage:  -> resolved
status: pending -> closed

___
Python tracker 
<https://bugs.python.org/issue30260>
___
___
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue30260] sock_dealloc() may call __repr__ when socket class is already collected by GC

2017-05-03 Thread asterite

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

[issue30260] sock_dealloc() may call __repr__ when socket class is already collected by GC

2017-05-03 Thread asterite

Changes by asterite :


Added file: http://bugs.python.org/file46847/test.py

___
Python tracker 
<http://bugs.python.org/issue30260>
___
___
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue30260] sock_dealloc() may call __repr__ when socket class is already collected by GC

2017-05-03 Thread asterite

Changes by asterite :


Added file: http://bugs.python.org/file46848/test2.py

___
Python tracker 
<http://bugs.python.org/issue30260>
___
___
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue30260] sock_dealloc() may call __repr__ when socket class is already collected by GC

2017-05-03 Thread asterite

asterite added the comment:

I made up a small program to reproduce an issue, it consists of two files, 
test.py and test2.py, the second one is imported as a module by the first one, 
so they should be but in the same dir.

# ls
test.py  test2.py
# python3.5 test.py 
test
Segmentation fault

The files contain a rather weird combination of references to objects put in 
other objects or to modules of standard lib. This is what I got after reducing 
the code to reproduce the problem. All those references are probably needed to 
make a cycle and to postpone it's deallocation until the interpreter shutdown.

Regarding where in the real world such a code exists: it was spread by a 
combination of modules, namely tornado (https://github.com/tornadoweb/tornado), 
pyzmq (https://github.com/zeromq/pyzmq) and circus 
(https://github.com/circus-tent/circus), I found the problem when running one 
of the tests of circus:

~/circus# python3.5 -m nose -v 
circus.tests.test_reloadconfig:TestConfig.test_reload_ignorearbiterwatchers
test_reload_ignorearbiterwatchers (circus.tests.test_reloadconfig.TestConfig) 
... ok

--
Ran 1 test in 0.037s

OK
Segmentation fault

Also, sometimes that test fails like this:
# python3.5 -m nose -v 
circus.tests.test_reloadconfig:TestConfig.test_reload_ignorearbiterwatchers
test_reload_ignorearbiterwatchers (circus.tests.test_reloadconfig.TestConfig) 
... ok

--
Ran 1 test in 0.021s

OK
Fatal Python error: GC object already tracked

Current thread 0x7f20aa7b6700 (most recent call first):
Aborted

--

___
Python tracker 
<http://bugs.python.org/issue30260>
___
___
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue30260] sock_dealloc() may call __repr__ when socket class is already collected by GC

2017-05-11 Thread asterite

asterite added the comment:

Sorry if I misunderstood how the bug tracker works, but why did you delete 
version 3.4 ? Python 3.4 is also affected.

--

___
Python tracker 
<http://bugs.python.org/issue30260>
___
___
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com