[New-bugs-announce] [issue41909] Segfault on __getattr__ infinite recursion on certain attribute accesses

Ran Benita report at bugs.python.org
Fri Oct 2 06:49:51 EDT 2020


New submission from Ran Benita <ran at unusedvar.com>:

The following program crashes with a segfault:

class Segfault:
    def __getattr__(self, name):
        self.unknown_attribute

instance = Segfault()
issubclass(instance, int)  # int doesn't matter

Tested with Python 3.7, 3.8, 3.9rc2, and master in debug mode (commit 497126f7ea955ee005e78f2cdd61f175d4fcdbb2).

The program is odd, but this affects pytest (see https://github.com/pytest-dev/pytest/issues/2330).
The class is buggy user code, pytest does the issubclass check.
In pytest there are other code paths which trigger it besides issubclass, but that's the one I am able to quickly reproduce standalone.

Here is the backtrace with python master:

ran at ran:~/src/cpython$ gdb --args ./python segfault.py
Reading symbols from ./python...
(gdb) r
Starting program: /home/ran/src/cpython/python segfault.py

Program received signal SIGSEGV, Segmentation fault.
0x00005555556bc55e in PyGILState_Check () at Python/pystate.c:1353
1353	    if (!PyThread_tss_is_created(&gilstate->autoTSSkey)) {


(gdb) bt 29
#0  0x00005555556bc55e in PyGILState_Check () at Python/pystate.c:1353
#1  0x00005555555fc117 in _PyMem_DebugCheckGIL (func=0x55555581b330 <__func__.10> "_PyMem_DebugMalloc") at Objects/obmalloc.c:2329
#2  _PyMem_DebugMalloc (ctx=0x55555593b140 <_PyMem_Debug+96>, nbytes=185) at Objects/obmalloc.c:2329
#3  0x00005555555fcee8 in PyObject_Malloc (size=<optimized out>) at Objects/obmalloc.c:685
#4  0x000055555562d6f3 in PyUnicode_New (size=136, maxchar=<optimized out>) at Objects/unicodeobject.c:1455
#5  0x00005555556556e7 in _PyUnicodeWriter_PrepareInternal (writer=writer at entry=0x7fffff7ff0c0, length=length at entry=1, maxchar=<optimized out>, maxchar at entry=127)
    at Objects/unicodeobject.c:14004
#6  0x0000555555658439 in _PyUnicodeWriter_WriteASCIIString (writer=writer at entry=0x7fffff7ff0c0, ascii=ascii at entry=0x5555558196c8 "'%.50s' object has no attribute '%U'", 
    len=1) at Objects/unicodeobject.c:14174
#7  0x000055555565a18d in PyUnicode_FromFormatV (format=format at entry=0x5555558196c8 "'%.50s' object has no attribute '%U'", vargs=vargs at entry=0x7fffff7ff170)
    at Objects/unicodeobject.c:3114
#8  0x000055555569646b in _PyErr_FormatV (tstate=0x5555559aa300, exception=<type at remote 0x555555932040>, 
    format=format at entry=0x5555558196c8 "'%.50s' object has no attribute '%U'", vargs=vargs at entry=0x7fffff7ff170) at Python/errors.c:1029
#9  0x0000555555696ff3 in PyErr_Format (exception=<optimized out>, format=format at entry=0x5555558196c8 "'%.50s' object has no attribute '%U'") at Python/errors.c:1071
#10 0x00005555555fa4a5 in _PyObject_GenericGetAttrWithDict (obj=obj at entry=<Segfault at remote 0x7ffff772dd70>, name=name at entry='unknown_attribute', dict=<optimized out>, 
    dict at entry=0x0, suppress=suppress at entry=0) at Objects/object.c:1268
#11 0x00005555555fa96f in PyObject_GenericGetAttr (obj=obj at entry=<Segfault at remote 0x7ffff772dd70>, name=name at entry='unknown_attribute') at Objects/object.c:1281
#12 0x000055555561c3f8 in slot_tp_getattr_hook (self=<Segfault at remote 0x7ffff772dd70>, name='unknown_attribute') at Objects/typeobject.c:6805
#13 0x00005555555f68c2 in PyObject_GetAttr (v=v at entry=<Segfault at remote 0x7ffff772dd70>, name=<optimized out>) at Objects/object.c:891
#14 0x000055555567c254 in _PyEval_EvalFrameDefault (tstate=0x5555559aa300, 
    f=Frame 0x7ffff71cc3b0, for file /home/ran/src/cpython/segfault.py, line 3, in __getattr__ (self=<Segfault at remote 0x7ffff772dd70>, name='unknown_attribute'), 
    throwflag=<optimized out>) at Python/ceval.c:3036
#15 0x00005555555b9d1d in _PyEval_EvalFrame (throwflag=0, 
    f=Frame 0x7ffff71cc3b0, for file /home/ran/src/cpython/segfault.py, line 3, in __getattr__ (self=<Segfault at remote 0x7ffff772dd70>, name='unknown_attribute'), 
    tstate=0x5555559aa300) at ./Include/internal/pycore_ceval.h:40
#16 function_code_fastcall (tstate=0x5555559aa300, co=<optimized out>, args=0x7fffff7ff590, nargs=2, globals=<optimized out>) at Objects/call.c:329
#17 0x00005555555ba67b in _PyFunction_Vectorcall (func=<optimized out>, stack=<optimized out>, nargsf=<optimized out>, kwnames=<optimized out>) at Objects/call.c:366
#18 0x000055555576c2d4 in _PyObject_VectorcallTstate (tstate=0x5555559aa300, callable=<function at remote 0x7ffff773c4b0>, args=0x7fffff7ff580, nargsf=2, kwnames=0x0)
    at ./Include/cpython/abstract.h:114
#19 0x000055555576cb87 in method_vectorcall (method=<optimized out>, args=0x7fffff7ff588, nargsf=<optimized out>, kwnames=0x0) at Objects/classobject.c:53
#20 0x00005555556109ac in _PyObject_VectorcallTstate (kwnames=0x0, nargsf=9223372036854775809, args=0x7fffff7ff588, callable=<method at remote 0x7ffff71c8c50>, 
    tstate=0x5555559aa300) at ./Include/cpython/abstract.h:114
#21 PyObject_CallOneArg (arg='unknown_attribute', func=<method at remote 0x7ffff71c8c50>) at ./Include/cpython/abstract.h:184
#22 call_attribute (self=self at entry=<Segfault at remote 0x7ffff772dd70>, attr=<method at remote 0x7ffff71c8c50>, attr at entry=<function at remote 0x7ffff773c4b0>, 
    name=name at entry='unknown_attribute') at Objects/typeobject.c:6771
#23 0x000055555561c44a in slot_tp_getattr_hook (self=<Segfault at remote 0x7ffff772dd70>, name='unknown_attribute') at Objects/typeobject.c:6813
#24 0x00005555555f68c2 in PyObject_GetAttr (v=v at entry=<Segfault at remote 0x7ffff772dd70>, name=<optimized out>) at Objects/object.c:891
#25 0x000055555567c254 in _PyEval_EvalFrameDefault (tstate=0x5555559aa300, 
    f=Frame 0x7ffff71cc200, for file /home/ran/src/cpython/segfault.py, line 3, in __getattr__ (self=<Segfault at remote 0x7ffff772dd70>, name='unknown_attribute'), 
    throwflag=<optimized out>) at Python/ceval.c:3036
#26 0x00005555555b9d1d in _PyEval_EvalFrame (throwflag=0, 
    f=Frame 0x7ffff71cc200, for file /home/ran/src/cpython/segfault.py, line 3, in __getattr__ (self=<Segfault at remote 0x7ffff772dd70>, name='unknown_attribute'), 
    tstate=0x5555559aa300) at ./Include/internal/pycore_ceval.h:40
#27 function_code_fastcall (tstate=0x5555559aa300, co=<optimized out>, args=0x7fffff7ff8b0, nargs=2, globals=<optimized out>) at Objects/call.c:329
#28 0x00005555555ba67b in _PyFunction_Vectorcall (func=<optimized out>, stack=<optimized out>, nargsf=<optimized out>, kwnames=<optimized out>) at Objects/call.c:366
(More stack frames follow...)



(gdb) py-bt
Traceback (most recent call first):
  File "/home/ran/src/cpython/segfault.py", line 3, in __getattr__
    self.unknown_attribute
  File "/home/ran/src/cpython/segfault.py", line 3, in __getattr__
    self.unknown_attribute
  File "/home/ran/src/cpython/segfault.py", line 3, in __getattr__
    self.unknown_attribute
  File "/home/ran/src/cpython/segfault.py", line 3, in __getattr__
    self.unknown_attribute
  File "/home/ran/src/cpython/segfault.py", line 3, in __getattr__
    self.unknown_attribute
  File "/home/ran/src/cpython/segfault.py", line 3, in __getattr__
    self.unknown_attribute
  File "/home/ran/src/cpython/segfault.py", line 3, in __getattr__
    self.unknown_attribute
  File "/home/ran/src/cpython/segfault.py", line 3, in __getattr__
    self.unknown_attribute
--Type <RET> for more, q to quit, c to continue without paging--q

----------
components: Interpreter Core
messages: 377807
nosy: bluetech
priority: normal
severity: normal
status: open
title: Segfault on __getattr__ infinite recursion on certain attribute accesses

_______________________________________
Python tracker <report at bugs.python.org>
<https://bugs.python.org/issue41909>
_______________________________________


More information about the New-bugs-announce mailing list