[New-bugs-announce] [issue30484] Garbage Collector can cause Segfault whilst iterating dictionary items

Jim Wright report at bugs.python.org
Fri May 26 08:48:10 EDT 2017


New submission from Jim Wright:

We discovered this issue whilst using h5py (HDF5 python library) under python 3.5.2 on Ubuntu 16.04.2 x86_64.  The construct used is very dubious, and I will separately be raising an issue with the h5py team.  However I thought you might like to know there is a possible way to cause a segmentation violation using pure python.

There appears to be a new implementation of dictionaries in 3.6 vs 3.5, so I compiled up 3.6.1 and it also segfaults, but not so obviously related to the dictionary iteration (both stack traces are included below).

Regards, Jim.

--------

$ cat segfault.py 
#!/usr/bin/python3

class CyclicObject:
    def __init__(self, key, register):
        self.key = key
        self.self = self
        self.register = register
        self.register[self.key] = None

    def __del__(self):
        del self.register[self.key]

while True:
    register = { }
    objs = set([CyclicObject(i, register) for i in range(10000)])

    while len(objs) > 0:
        objs.remove(next(iter(objs)))

        try:
            list(register.items())
        except RuntimeError as err:
            print(err)

--------

$ python3 --version
Python 3.5.2

$ gdb --args python3 segfault.py
GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.04) 7.11.1

(gdb) r
Starting program: /usr/bin/python3 segfault.py
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
dictionary changed size during iteration
dictionary changed size during iteration
dictionary changed size during iteration

Program received signal SIGSEGV, Segmentation fault.
dictiter_iternextitem.lto_priv () at ../Objects/dictobject.c:3158
3158	../Objects/dictobject.c: No such file or directory.

(gdb) bt
#0  dictiter_iternextitem.lto_priv () at ../Objects/dictobject.c:3158
#1  0x000000000059f024 in listextend.lto_priv () at ../Objects/listobject.c:855
#2  0x000000000058fd1c in list_init.lto_priv () at ../Objects/listobject.c:2314
#3  0x000000000055d17c in type_call.lto_priv () at ../Objects/typeobject.c:905
#4  0x00000000005b7167 in PyObject_Call () at ../Objects/abstract.c:2165
#5  0x0000000000528d06 in do_call (nk=<optimised out>, na=<optimised out>, pp_stack=0x7fffffffd9b0, func=<optimised out>) at ../Python/ceval.c:4936
#6  call_function (oparg=<optimised out>, pp_stack=0x7fffffffd9b0) at ../Python/ceval.c:4732
#7  PyEval_EvalFrameEx () at ../Python/ceval.c:3236
#8  0x000000000052d2e3 in _PyEval_EvalCodeWithName () at ../Python/ceval.c:4018
#9  0x000000000052dfdf in PyEval_EvalCodeEx () at ../Python/ceval.c:4039
#10 PyEval_EvalCode (co=<optimised out>, globals=<optimised out>, locals=<optimised out>) at ../Python/ceval.c:777
#11 0x00000000005fd2c2 in run_mod () at ../Python/pythonrun.c:976
#12 0x00000000005ff76a in PyRun_FileExFlags () at ../Python/pythonrun.c:929
#13 0x00000000005ff95c in PyRun_SimpleFileExFlags () at ../Python/pythonrun.c:396
#14 0x000000000063e7d6 in run_file (p_cf=0x7fffffffdc20, filename=0xa73280 L"segfault.py", fp=0xad19a0) at ../Modules/main.c:318
#15 Py_Main () at ../Modules/main.c:768
#16 0x00000000004cfe41 in main () at ../Programs/python.c:65
#17 0x00007ffff7811830 in __libc_start_main (main=0x4cfd60 <main>, argc=2, argv=0x7fffffffde38, init=<optimised out>, fini=<optimised out>, rtld_fini=<optimised out>, 
    stack_end=0x7fffffffde28) at ../csu/libc-start.c:291
#18 0x00000000005d5f29 in _start ()

--------

$ ./python --version
Python 3.6.1

$ gdb --args ./python ./segfault.py 
GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.04) 7.11.1

(gdb) r
Starting program: ./python ./segfault.py
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
dictionary changed size during iteration
dictionary changed size during iteration
dictionary changed size during iteration
dictionary changed size during iteration
dictionary changed size during iteration

Program received signal SIGSEGV, Segmentation fault.
_PyObject_Alloc (ctx=0x0, elsize=28, nelem=1, use_calloc=0) at Objects/obmalloc.c:1258
1258	            if ((pool->freeblock = *(block **)bp) != NULL) {

(gdb) bt
#0  _PyObject_Alloc (ctx=0x0, elsize=28, nelem=1, use_calloc=0) at Objects/obmalloc.c:1258
#1  _PyObject_Malloc (ctx=0x0, nbytes=28) at Objects/obmalloc.c:1437
#2  0x0000000000490732 in _PyLong_New (size=1) at Objects/longobject.c:196
#3  PyLong_FromLong (ival=<optimised out>) at Objects/longobject.c:254
#4  0x0000000000542fda in _PyEval_EvalFrameDefault (f=<optimised out>, throwflag=<optimised out>) at Python/ceval.c:3060
#5  0x000000000053d671 in PyEval_EvalFrameEx (throwflag=0, f=0x7ffff7fa1648) at Python/ceval.c:718
#6  _PyFunction_FastCall (co=<optimised out>, args=<optimised out>, nargs=1, globals=globals at entry=0x7ffff7f452d0) at Python/ceval.c:4880
#7  0x000000000053e521 in fast_function (kwnames=0x0, nargs=<optimised out>, stack=<optimised out>, func=0x7ffff7eae510) at Python/ceval.c:4915
#8  call_function (pp_stack=pp_stack at entry=0x7fffffffd920, oparg=oparg at entry=1, kwnames=kwnames at entry=0x0) at Python/ceval.c:4819
#9  0x0000000000542c17 in _PyEval_EvalFrameDefault (f=<optimised out>, throwflag=<optimised out>) at Python/ceval.c:3284
#10 0x000000000053e015 in PyEval_EvalFrameEx (throwflag=0, f=0x93a368) at Python/ceval.c:718
#11 _PyEval_EvalCodeWithName (_co=_co at entry=0x7ffff7ec26f0, globals=globals at entry=0x7ffff7f5e078, locals=locals at entry=0x7ffff7ec26f0, args=args at entry=0x0, 
    argcount=argcount at entry=0, kwnames=kwnames at entry=0x0, kwargs=0x8, kwcount=0, kwstep=2, defs=0x0, defcount=0, kwdefs=0x0, closure=0x0, name=0x0, qualname=0x0)
    at Python/ceval.c:4128
#12 0x000000000053ee43 in PyEval_EvalCodeEx (closure=0x0, kwdefs=0x0, defcount=0, defs=0x0, kwcount=0, kws=0x0, argcount=0, args=0x0, locals=locals at entry=0x7ffff7ec26f0, 
    globals=globals at entry=0x7ffff7f5e078, _co=_co at entry=0x7ffff7ec26f0) at Python/ceval.c:4149
#13 PyEval_EvalCode (co=co at entry=0x7ffff7ec26f0, globals=globals at entry=0x7ffff7f452d0, locals=locals at entry=0x7ffff7f452d0) at Python/ceval.c:695
#14 0x000000000042740f in run_mod (arena=0x7ffff7f5e078, flags=0x7fffffffdc00, locals=0x7ffff7f452d0, globals=0x7ffff7f452d0, filename=0x7ffff7e844f8, mod=0x933c28)
    at Python/pythonrun.c:980
#15 PyRun_FileExFlags (fp=0x93a350, filename_str=<optimised out>, start=<optimised out>, globals=0x7ffff7f452d0, locals=0x7ffff7f452d0, closeit=1, flags=0x7fffffffdc00)
    at Python/pythonrun.c:933
#16 0x000000000042763c in PyRun_SimpleFileExFlags (fp=0x93a350, filename=<optimised out>, closeit=1, flags=0x7fffffffdc00) at Python/pythonrun.c:396
#17 0x000000000043b975 in run_file (p_cf=0x7fffffffdc00, filename=0x8f82a0 L"./segfault.py", fp=0x93a350) at Modules/main.c:338
#18 Py_Main (argc=argc at entry=2, argv=argv at entry=0x8f7010) at Modules/main.c:809
#19 0x000000000041dc52 in main (argc=2, argv=<optimised out>) at ./Programs/python.c:69

----------
components: Interpreter Core
files: segfault.py
messages: 294548
nosy: jimwright
priority: normal
severity: normal
status: open
title: Garbage Collector can cause Segfault whilst iterating dictionary items
type: crash
versions: Python 3.5, Python 3.6
Added file: http://bugs.python.org/file46905/segfault.py

_______________________________________
Python tracker <report at bugs.python.org>
<http://bugs.python.org/issue30484>
_______________________________________


More information about the New-bugs-announce mailing list