Skip to content

Greening existing locks doesn't always work right #864

@tipabu

Description

@tipabu

Following abbe7a5 (though I feel bad -- the problem seems most likely to be in code I wrote in an earlier version of #754), monkey-patching sometimes leaves lock references as empty dicts (??)

Given a simple repro script like

import unittest.mock
import eventlet
import sys

print(f'{sys.version.split()[0]=}, {eventlet.__version__=}')
print(f'{unittest.mock.NonCallableMock._lock=}')
eventlet.monkey_patch(thread=True)
print(f'{unittest.mock.NonCallableMock._lock=}')

(Note that unittest.mock.NonCallableMock._lock only exists for python>=3.10.9,!=3.11.0; see python/cpython#98624 for some background.)

I get output like

sys.version.split()[0]='3.10.12', eventlet.__version__='0.34.2'
unittest.mock.NonCallableMock._lock=<unlocked _thread.RLock object owner=0 count=0 at 0x7fac882f5b00>
unittest.mock.NonCallableMock._lock={}
Segmentation fault (core dumped)

The segfault seems like a give-away that something is amiss; trying again with -X dev and gdb attached, it either continues to segfault during garbage collection:

sys.version.split()[0]='3.10.12', eventlet.__version__='0.34.2'
unittest.mock.NonCallableMock._lock=<unlocked _thread.RLock object owner=0 count=0 at 0x7ffff6c416d0>
unittest.mock.NonCallableMock._lock={}

Program received signal SIGSEGV, Segmentation fault.
0x000055555567d7eb in gc_list_remove (node=0x7ffff6c416c0) at ../Modules/gcmodule.c:273
273     ../Modules/gcmodule.c: No such file or directory.
(gdb) #0  0x000055555567d7eb in gc_list_remove (node=0x7ffff6c416c0) at ../Modules/gcmodule.c:273
#1  PyObject_GC_Del (op=0x7ffff6c416d0) at ../Modules/gcmodule.c:2369
#2  0x0000555555736bb8 in _PyDict_ClearFreeList (interp=0x555555b3e260) at ../Objects/dictobject.c:269
#3  0x000055555567e328 in clear_freelists (interp=0x555555b3e260) at ../Modules/gcmodule.c:1045
#4  gc_collect_main (tstate=0x555555b5a130, generation=2, n_collected=0x7fffffffe148, n_uncollectable=0x7fffffffe140, nofail=0) at ../Modules/gcmodule.c:1326
#5  0x0000555555785470 in gc_collect_with_callback (tstate=0x555555b5a130, generation=2) at ../Modules/gcmodule.c:1413
#6  0x00005555557b6aae in PyGC_Collect () at ../Modules/gcmodule.c:2099
#7  0x00005555557b44c0 in Py_FinalizeEx () at ../Python/pylifecycle.c:1781
#8  0x00005555557a5913 in Py_RunMain () at ../Modules/main.c:668
#9  0x000055555577c02d in Py_BytesMain (argc=<optimized out>, argv=<optimized out>) at ../Modules/main.c:720
(More stack frames follow...)

Or bombs our trying to get the repr for the last print:

sys.version.split()[0]='3.10.12', eventlet.__version__='0.34.2'
unittest.mock.NonCallableMock._lock=<unlocked _thread.RLock object owner=0 count=0 at 0x7ffff6c416d0>

Program received signal SIGSEGV, Segmentation fault.
type_getattro (type=<optimized out>, name=<optimized out>) at ../Objects/typeobject.c:3936
3936    ../Objects/typeobject.c: No such file or directory.
(gdb) #0  type_getattro (type=<optimized out>, name=<optimized out>) at ../Objects/typeobject.c:3936
#1  0x00005555556aae5a in PyObject_GetAttr (v=<type at remote 0x555555d8b950>, name='_lock') at ../Objects/object.c:932
#2  0x000055555569c971 in _PyEval_EvalFrameDefault (tstate=<optimized out>, f=<optimized out>, throwflag=<optimized out>) at ../Python/ceval.c:3592
#3  0x00005555556939c6 in _PyEval_EvalFrame (throwflag=0, f=Frame 0x555555bbe060, for file /home/tburke/repro.py, line 8, in <module> (), tstate=0x555555b5a130)
    at ../Include/internal/pycore_ceval.h:46
#4  _PyEval_Vector (tstate=0x555555b5a130, con=<optimized out>, locals=<optimized out>, args=<optimized out>, argcount=<optimized out>, kwnames=<optimized out>) at ../Python/ceval.c:5067
#5  0x0000555555789256 in PyEval_EvalCode (co=<code at remote 0x7ffff7798ee0>, 
    globals={'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <SourceFileLoader(name='__main__', path='/home/tburke/repro.py') at remote 0x7ffff777e710>, '__spec__': None, '__annotations__': {}, '__builtins__': <module at remote 0x7ffff7914290>, '__file__': '/home/tburke/repro.py', '__cached__': None, 'unittest': <module at remote 0x7ffff765f710>, 'eventlet': <module at remote 0x7ffff765f3b0>, 'sys': <module at remote 0x7ffff78f35f0>}, locals=<optimized out>) at ../Python/ceval.c:1134
#6  0x00005555557b4108 in run_eval_code_obj (tstate=0x555555b5a130, co=0x7ffff7798ee0, 
    globals={'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <SourceFileLoader(name='__main__', path='/home/tburke/repro.py') at remote 0x7ffff777e710>, '__spec__': None, '__annotations__': {}, '__builtins__': <module at remote 0x7ffff7914290>, '__file__': '/home/tburke/repro.py', '__cached__': None, 'unittest': <module at remote 0x7ffff765f710>, 'eventlet': <module at remote 0x7ffff765f3b0>, 'sys': <module at remote 0x7ffff78f35f0>}, 
    locals={'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <SourceFileLoader(name='__main__', path='/home/tburke/repro.py') at remote 0x7ffff777e710>, '__spec__': None, '__annotations__': {}, '__builtins__': <module at remote 0x7ffff7914290>, '__file__': '/home/tburke/repro.py', '__cached__': None, 'unittest': <module at remote 0x7ffff765f710>, 'eventlet': <module at remote 0x7ffff765f3b0>, 'sys': <module at remote 0x7ffff78f35f0>}) at ../Python/pythonrun.c:1291
#7  0x00005555557ad9cb in run_mod (mod=<optimized out>, filename=<optimized out>, 
    globals={'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <SourceFileLoader(name='__main__', path='/home/tburke/repro.py') at remote 0x7ffff777e710>, '__spec__': None, '__annotations__': {}, '__builtins__': <module at remote 0x7ffff7914290>, '__file__': '/home/tburke/repro.py', '__cached__': None, 'unittest': <module at remote 0x7ffff765f710>, 'eventlet': <module at remote 0x7ffff765f3b0>, 'sys': <module at remote 0x7ffff78f35f0>}, 
    locals={'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <SourceFileLoader(name='__main__', path='/home/tburke/repro.py') at remote 0x7ffff777e710>, '__spec__': None, '__annotations__': {}, '__builtins__': <module at remote 0x7ffff7914290>, '__file__': '/home/tburke/repro.py', '__cached__': None, 'unittest': <module at remote 0x7ffff765f710>, 'eventlet': <module at remote 0x7ffff765f3b0>, 'sys': <module at remote 0x7ffff78f35f0>}, flags=<optimized out>, arena=<optimized out>) at ../Python/pythonrun.c:1312
#8  0x00005555557b3e55 in pyrun_file (fp=fp@entry=0x555555b69280, filename=filename@entry='/home/tburke/repro.py', start=start@entry=257, 
    globals=globals@entry={'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <SourceFileLoader(name='__main__', path='/home/tburke/repro.py') at remote 0x7ffff777e710>, '__spec__': None, '__annotations__': {}, '__builtins__': <module at remote 0x7ffff7914290>, '__file__': '/home/tburke/repro.py', '__cached__': None, 'unittest': <module at remote 0x7ffff765f710>, 'eventlet': <module at remote 0x7ffff765f3b0>, 'sys': <module at remote 0x7ffff78f35f0>}, 
    locals=locals@entry={'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <SourceFileLoader(name='__main__', path='/home/tburke/repro.py') at remote 0x7ffff777e710>, '__spec__': None, '__annotations__': {}, '__builtins__': <module at remote 0x7ffff7914290>, '__file__': '/home/tburke/repro.py', '__cached__': None, 'unittest': <module at remote 0x7ffff765f710>, 'eventlet': <module at remote 0x7ffff765f3b0>, 'sys': <module at remote 0x7ffff78f35f0>}, closeit=closeit@entry=1, flags=0x7fffffffe218)
    at ../Python/pythonrun.c:1208
#9  0x00005555557b3338 in _PyRun_SimpleFileObject (fp=0x555555b69280, filename='/home/tburke/repro.py', closeit=1, flags=0x7fffffffe218) at ../Python/pythonrun.c:456
(More stack frames follow...)

FWIW, I see similar trouble with python 3.12.1.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions