I'm able to reproduce the bug on my Fedora using:
vstinner@apu$ gdb -args ENV/bin/python -m coverage run --pylib -m test --fail-env-changed -uall,-cpu test_urllib -F
(gdb) run
python: Objects/typeobject.c:3086: _PyType_Lookup: Assertion `!PyErr_Occurred()' failed.
Program received signal SIGABRT, Aborted.
0x00007ffff7093f2b in raise () from /lib64/libc.so.6
(gdb) py-bt
Traceback (most recent call first):
<built-in method close of HTTPResponse object at remote 0x7fffe581ff50>
File "/home/vstinner/prog/python/master/Lib/http/client.py", line 405, in close
super().close() # set "closed" flag
File "/home/vstinner/prog/python/master/Lib/traceback.py", line 216, in clear_frames
tb.tb_frame.clear()
File "/home/vstinner/prog/python/master/Lib/unittest/case.py", line 205, in __exit__
traceback.clear_frames(tb)
File "/home/vstinner/prog/python/master/Lib/unittest/case.py", line 178, in handle
callable_obj(*args, **kwargs)
File "/home/vstinner/prog/python/master/Lib/unittest/case.py", line 743, in assertRaises
return context.handle('assertRaises', args, kwargs)
File "/home/vstinner/prog/python/master/Lib/test/test_urllib.py", line 382, in test_redirect_limit_independent
"http://something")
(...)
(gdb) where
#0 0x00007ffff7093f2b in raise () from /lib64/libc.so.6
#1 0x00007ffff707e561 in abort () from /lib64/libc.so.6
#2 0x00007ffff707e431 in __assert_fail_base.cold.0 () from /lib64/libc.so.6
#3 0x00007ffff708c692 in __assert_fail () from /lib64/libc.so.6
#4 0x00000000004aa2ea in _PyType_Lookup (type=0xdc1b30, name='__IOBase_closed') at Objects/typeobject.c:3086
#5 0x00000000004883ff in _PyObject_GenericSetAttrWithDict (
obj=<HTTPResponse(fp=<FakeSocket(io_refs=0) at remote 0x7fffe4e2f1d0>, debuglevel=0, _method='GET', headers=<HTTPMessage(policy=<Compat32 at remote 0x7fffe553efb0>, _headers=[('Location', 'file://guidocomputer.athome.com:/python/license'), ('Connection', 'close')], _unixfrom=None, _payload='', _charset=None, preamble=None, epilogue=None, defects=[], _default_type='text/plain') at remote 0x7fffe542f4d0>, msg=<...>, version=11, status=302, reason='Found', chunked=False, chunk_left='UNKNOWN', length=None, will_close=True, code=302, _finalizing=True) at remote 0x7fffe581ff50>, name='__IOBase_closed', value=True, dict=0x0) at Objects/object.c:1292
#6 0x000000000048871a in PyObject_GenericSetAttr (
obj=<HTTPResponse(fp=<FakeSocket(io_refs=0) at remote 0x7fffe4e2f1d0>, debuglevel=0, _method='GET', headers=<HTTPMessage(policy=<Compat32 at remote 0x7fffe553efb0>, _headers=[('Location', 'file://guidocomputer.athome.com:/python/license'), ('Connection', 'close')], _unixfrom=None, _payload='', _charset=None, preamble=None, epilogue=None, defects=[], _default_type='text/plain') at remote 0x7fffe542f4d0>, msg=<...>, version=11, status=302, reason='Found', chunked=False, chunk_left='UNKNOWN', length=None, will_close=True, code=302, _finalizing=True) at remote 0x7fffe581ff50>, name='__IOBase_closed', value=True) at Objects/object.c:1340
#7 0x00000000004873a0 in PyObject_SetAttr (
v=<HTTPResponse(fp=<FakeSocket(io_refs=0) at remote 0x7fffe4e2f1d0>, debuglevel=0, _method='GET', headers=<HTTPMessage(policy=<Compat32 at remote 0x7fffe553efb0>, _headers=[('Location', 'file://guidocomputer.athome.com:/python/license'), ('Connection', 'close')], _unixfrom=None, _payload='', _charset=None, preamble=None, epilogue=None, defects=[], _default_type='text/plain') at remote 0x7fffe542f4d0>, msg=<...>, version=11, status=302, reason='Found', chunked=False, chunk_left='UNKNOWN', length=None, will_close=True, code=302, _finalizing=True) at remote 0x7fffe581ff50>, name='__IOBase_closed', value=True) at Objects/object.c:977
#8 0x0000000000486f03 in _PyObject_SetAttrId (
v=<HTTPResponse(fp=<FakeSocket(io_refs=0) at remote 0x7fffe4e2f1d0>, debuglevel=0, _method='GET', headers=<HTTPMessage(policy=<Compat32 at remote 0x7fffe553efb0>, _headers=[('Location', 'file://guidocomputer.athome.com:/python/license'), ('Connection', 'close')], _unixfrom=None, _payload='', _charset=None, preamble=None, epilogue=None, defects=[], _default_type='text/plain') at remote 0x7fffe542f4d0>, msg=<...>, version=11, status=302, reason='Found', chunked=False, chunk_left='UNKNOWN', length=None, will_close=True, code=302, _finalizing=True) at remote 0x7fffe581ff50>, name=0x9d4330 <PyId___IOBase_closed>, w=True) at Objects/object.c:857
#9 0x0000000000625d9c in _io__IOBase_close_impl (
self=<HTTPResponse(fp=<FakeSocket(io_refs=0) at remote 0x7fffe4e2f1d0>, debuglevel=0, _method='GET', headers=<HTTPMessage(policy=<Compat32 at remote 0x7fffe553efb0>, _headers=[('Location', 'file://guidocomputer.athome.com:/python/license'), ('Connection', 'close')], _unixfrom=None, _payload='', _charset=None, preamble=None, epilogue=None, defects=[], _default_type='text/plain') at remote 0x7fffe542f4d0>, msg=<...>, version=11, status=302, reason='Found', chunked=False, chunk_left='UNKNOWN', length=None, will_close=True, code=302, _finalizing=---T---Type ---Type <return>---Type <ret---Type <ret---Type ---Type ---Type <return>---Type <ret---Type <return> to ---Type <return>---Type ---T---Type <return>---Type ---T---Type <return> to continue, or q <return> to quit---
) at remote 0x7fffe581ff50>) at ./Modules/_io/iobase.c:239
#10 0x0000000000627e12 in _io__IOBase_close (
self=<HTTPResponse(fp=<FakeSocket(io_refs=0) at remote 0x7fffe4e2f1d0>, debuglevel=0, _method='GET', headers=<HTTPMessage(policy=<Compat32 at remote 0x7fffe553efb0>, _headers=[('Location', 'file://guidocomputer.athome.com:/python/license'), ('Connection', 'close')], _unixfrom=None, _payload='', _charset=None, preamble=None, epilogue=None, defects=[], _default_type='text/plain') at remote 0x7fffe542f4d0>, msg=<...>, version=11, status=302, reason='Found', chunked=False, chunk_left='UNKNOWN', length=None, will_close=True, code=302, _finalizing=True) at remote 0x7fffe581ff50>, _unused_ignored=0x0) at ./Modules/_io/clinic/iobase.c.h:60
#11 0x0000000000438cb3 in _PyMethodDef_RawFastCallKeywords (method=0x9d4d40 <iobase_methods+128>,
self=<HTTPResponse(fp=<FakeSocket(io_refs=0) at remote 0x7fffe4e2f1d0>, debuglevel=0, _method='GET', headers=<HTTPMessage(policy=<Compat32 at remote 0x7fffe553efb0>, _headers=[('Location', 'file://guidocomputer.athome.com:/python/license'), ('Connection', 'close')], _unixfrom=None, _payload='', _charset=None, preamble=None, epilogue=None, defects=[], _default_type='text/plain') at remote 0x7fffe542f4d0>, msg=<...>, version=11, status=302, reason='Found', chunked=False, chunk_left='UNKNOWN', length=None, will_close=True, code=302, _finalizing=True) at remote 0x7fffe581ff50>, args=0x7fffe4e793e8, nargs=0, kwnames=0x0) at Objects/call.c:629
#12 0x000000000043910d in _PyCFunction_FastCallKeywords (func=<built-in method close of HTTPResponse object at remote 0x7fffe581ff50>, args=0x7fffe4e793e8, nargs=0, kwnames=0x0)
at Objects/call.c:730
#13 0x00000000005500e9 in call_function (pp_stack=0x7ffffffb7da0, oparg=0, kwnames=0x0) at Python/ceval.c:4565
#14 0x0000000000548e1d in _PyEval_EvalFrameDefault (
f=Frame 0x7fffe4e79250, for file /home/vstinner/prog/python/master/Lib/http/client.py, line 405, in close (self=<HTTPResponse(fp=<FakeSocket(io_refs=0) at remote 0x7fffe4e2f1d0>, debuglevel=0, _method='GET', headers=<HTTPMessage(policy=<Compat32 at remote 0x7fffe553efb0>, _headers=[('Location', 'file://guidocomputer.athome.com:/python/license'), ('Connection', 'close')], _unixfrom=None, _payload='', _charset=None, preamble=None, epilogue=None, defects=[], _default_type='text/plain') at remote 0x7fffe542f4d0>, msg=<...>, version=11, status=302, reason='Found', chunked=False, chunk_left='UNKNOWN', length=None, will_close=True, code=302, _finalizing=True) at remote 0x7fffe581ff50>), throwflag=0)
at Python/ceval.c:3159
(...)
The bug is in _io__IOBase_close_impl(). I modified the code:
assert(!PyErr_Occurred());
res = PyObject_CallMethodObjArgs(self, _PyIO_str_flush, NULL);
assert(!PyErr_Occurred()); /* <---- THIS ASSERTION FAILS */
if (_PyObject_SetAttrId(self, &PyId___IOBase_closed, Py_True) < 0) {
Py_XDECREF(res);
return NULL;
}
The problem is that _PyObject_SetAttrId() is called while the flush() method raised an exception.
We need something like PyErr_Fetch/PyErr_Store to set the attribute. |