python-tdbus icon indicating copy to clipboard operation
python-tdbus copied to clipboard

Segfault when sending large messages

Open flo-at opened this issue 1 year ago • 0 comments

I guess this module is unmaintained but I found a bug that leads to a segfault when large messages are sent. Neither the coredump backtrace, pdb nor faulthandler helped me to track it down to it's source. It's basically the same for strings ("s") and byte arrays ("ay") and probably other types, too. It also happens with both libev and libuv as gevent backends.

Minimal program to reproduce the problem:

from gevent import monkey
monkey.patch_all()

import contextlib
import gevent
import gevent.hub
import tdbus


DATA_LEN = 5000000
# DATA_LEN = 50000 # doesn't happen with this size

OBJECT_PATH = "/com/example/TDBus"
METHOD = "Hello"
INTERFACE = "com.example.Hello"
DESTINATION = "com.example.Hello"

# dbus-test-tool echo --name=com.example.Hello

def do_call(conn):
    data = ("x"*DATA_LEN).encode()
    result = conn.call_method(
                 OBJECT_PATH,
                 METHOD,
                 INTERFACE,
                 destination=DESTINATION,
                 timeout=2,
                 format="ay",
                 args=[data])
    print(repr(result))
    return result

def main_simple():
    conn = tdbus.SimpleDBusConnection(tdbus.DBUS_BUS_SESSION)
    do_call(conn)

def main_gevent():
    conn = tdbus.GEventDBusConnection(tdbus.DBUS_BUS_SESSION)
    gevent.spawn(do_call, conn)
    with contextlib.suppress(KeyboardInterrupt):
        gevent.hub.get_hub().switch()

if __name__ == "__main__":
    #main_simple() # doesn't happen with SimpleDBusConnection
    main_gevent() # does happen here!

This is from the coredump:

Program terminated with signal SIGSEGV, Segmentation fault.
#0  Py_INCREF (op=0x0) at /usr/include/python3.11/object.h:502
502	    op->ob_refcnt++;

Backtrace:

#0  Py_INCREF (op=0x0) at /usr/include/python3.11/object.h:502
#1  __pyx_pf_6gevent_5libev_8corecext_7watcher_4stop (__pyx_v_self=0x7c7e4551a8c0) at src/gevent/libev/corecext.c:15339
#2  __pyx_pw_6gevent_5libev_8corecext_7watcher_5stop (__pyx_v_self=0x7c7e4551a8c0, unused=0x0) at src/gevent/libev/corecext.c:15321
#3  0x00007c7e469ad973 in ?? () from /usr/lib/libpython3.11.so.1.0
#4  0x00007c7e469ad100 in ?? () from /usr/lib/libpython3.11.so.1.0
#5  0x00007c7e45fc2cb4 in gevent_stop (watcher=0x7c7e4551a8c0, loop=0x7c7e45202b20) at src/gevent/libev/callbacks.c:67
#6  0x00007c7e45fc3b68 in gevent_callback (revents=2, c_watcher=0x7c7e4551a900, watcher=0x7c7e4551a8c0, args=0x7c7e4553c3c0, callback=0x7c7e45265200, loop=0x7c7e45202b20) at src/gevent/libev/callbacks.c:131
#7  gevent_callback_io (_loop=<optimized out>, c_watcher=0x7c7e4551a900, revents=2) at src/gevent/libev/callbacks.c:214
#8  0x00007c7e45fbaa23 in ev_invoke_pending (loop=0x7c7e45ffeb40 <default_loop_struct>) at /opt/flo_nobackup/gevent/deps/libev/ev.c:3770
#9  0x00007c7e45fc0c23 in ev_run (loop=0x7c7e45ffeb40 <default_loop_struct>, flags=0) at /opt/flo_nobackup/gevent/deps/libev/ev.c:4190
#10 0x00007c7e45fcd7cb in __pyx_pf_6gevent_5libev_8corecext_4loop_14run (__pyx_v_once=<optimized out>, __pyx_v_nowait=<optimized out>, __pyx_v_self=0x7c7e45202b20) at src/gevent/libev/corecext.c:10211
#11 __pyx_pw_6gevent_5libev_8corecext_4loop_15run (__pyx_v_self=0x7c7e45202b20, __pyx_args=<optimized out>, __pyx_nargs=<optimized out>, __pyx_kwds=<optimized out>) at src/gevent/libev/corecext.c:10161
#12 0x00007c7e46974237 in PyObject_Vectorcall () from /usr/lib/libpython3.11.so.1.0
#13 0x00007c7e469665d3 in _PyEval_EvalFrameDefault () from /usr/lib/libpython3.11.so.1.0
#14 0x00007c7e469ad613 in ?? () from /usr/lib/libpython3.11.so.1.0
#15 0x00007c7e469ad100 in ?? () from /usr/lib/libpython3.11.so.1.0
#16 0x00007c7e465249a3 in greenlet::UserGreenlet::inner_bootstrap (this=this@entry=0x7c7e45537570, origin_greenlet=<optimized out>, run=run@entry=0x7c7e45264f80) at src/greenlet/TUserGreenlet.cpp:464
#17 0x00007c7e46525c8f in greenlet::UserGreenlet::g_initialstub (this=0x7c7e45537570, mark=0x7fff1fbf2ee8) at src/greenlet/TUserGreenlet.cpp:311
#18 0x00007c7e4652446f in greenlet::UserGreenlet::g_switch (this=0x7c7e45537570) at src/greenlet/TUserGreenlet.cpp:179
#19 0x00007c7e4651f331 in green_switch (self=0x7c7e45887a10, args=0x7c7e46cf3338 <_PyRuntime+58904>, kwargs=0x0) at src/greenlet/greenlet.cpp:530
#20 0x00007c7e45e94222 in __pyx_f_6gevent_29_gevent_c_greenlet_primitives__greenlet_switch (__pyx_v_self=0x7c7e45887a10) at src/gevent/_greenlet_primitives.c:2649
#21 __pyx_f_6gevent_29_gevent_c_greenlet_primitives_25SwitchOutGreenletWithLoop_switch (__pyx_v_self=0x7c7e45887a10, __pyx_skip_dispatch=__pyx_skip_dispatch@entry=1) at src/gevent/_greenlet_primitives.c:3180
#22 0x00007c7e45e94d02 in __pyx_pf_6gevent_29_gevent_c_greenlet_primitives_25SwitchOutGreenletWithLoop_switch (__pyx_v_self=<optimized out>) at src/gevent/_greenlet_primitives.c:3235
#23 __pyx_pw_6gevent_29_gevent_c_greenlet_primitives_25SwitchOutGreenletWithLoop_1switch (__pyx_v_self=<optimized out>, unused=<optimized out>) at src/gevent/_greenlet_primitives.c:3219
#24 0x00007c7e46974237 in PyObject_Vectorcall () from /usr/lib/libpython3.11.so.1.0
#25 0x00007c7e469665d3 in _PyEval_EvalFrameDefault () from /usr/lib/libpython3.11.so.1.0
#26 0x00007c7e46a1fae4 in ?? () from /usr/lib/libpython3.11.so.1.0
#27 0x00007c7e46a1f4cc in PyEval_EvalCode () from /usr/lib/libpython3.11.so.1.0
#28 0x00007c7e46a3cd03 in ?? () from /usr/lib/libpython3.11.so.1.0
#29 0x00007c7e46a38e0a in ?? () from /usr/lib/libpython3.11.so.1.0
#30 0x00007c7e46a4f383 in ?? () from /usr/lib/libpython3.11.so.1.0
#31 0x00007c7e46a4ecf5 in _PyRun_SimpleFileObject () from /usr/lib/libpython3.11.so.1.0
#32 0x00007c7e46a4d5f8 in _PyRun_AnyFileObject () from /usr/lib/libpython3.11.so.1.0
#33 0x00007c7e46a48098 in Py_RunMain () from /usr/lib/libpython3.11.so.1.0
#34 0x00007c7e46a131eb in Py_BytesMain () from /usr/lib/libpython3.11.so.1.0
#35 0x00007c7e46643cd0 in __libc_start_call_main (main=main@entry=0x5bc5076e0120, argc=argc@entry=2, argv=argv@entry=0x7fff1fbf36a8) at ../sysdeps/nptl/libc_start_call_main.h:58
#36 0x00007c7e46643d8a in __libc_start_main_impl (main=0x5bc5076e0120, argc=2, argv=0x7fff1fbf36a8, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7fff1fbf3698) at ../csu/libc-start.c:360
#37 0x00005bc5076e0045 in _start ()

From the perspective of the python code, it's

class GEventDBusConnection(DBusConnection):

    Loop = GEventLoop
    Local = local.local

    def call_method(self, *args, **kwargs):
        """Call a method."""
        callback = kwargs.get('callback')
        if callback is not None:
            super(GEventDBusConnection, self).call_method(*args, **kwargs)
            return
        waiter = Waiter()
        def _gevent_callback(message):
            waiter.switch(message)
        kwargs['callback'] = _gevent_callback
        super(GEventDBusConnection, self).call_method(*args, **kwargs)
        reply = waiter.get() # <--- here
        self._handle_errors(reply)
        return reply

flo-at avatar May 13 '24 11:05 flo-at