Menu

Segmentation fault after emiting a signal

Help
2017-05-31
2017-05-31
  • David Brooks

    David Brooks - 2017-05-31

    Hi Florian,

    First run the following:

    from PythonQt import QtCore
    
    class C(QtCore.QObject):
        received = QtCore.Signal(object)
        def __init__(self):
            super(C, self).__init__(None)
        def process(self, msg):
            self.received.emit(msg)
    
    class D(QtCore.QObject):
        def __init__(self, sender):
            super(D, self).__init__(None)
            sender.received.connect(self.process)
        def process(self, msg):
            print(msg)
    
    c = C()
    d = D(c)
    m = {'h': {'t': 's'}, 'c': {'e': 'i'}}
    

    Now pass the dictionary m through the Signal/Slot mechanism -- its value is correctly printed by the connected slot.

    >>> c.process(m)
    {'c': {'e': 'i'}, 'h': {'t': 's'}}
    

    However a segmentation fault is raised when m is next referenced:

    >>> m
    
    Program received signal SIGSEGV, Segmentation fault.
    0x00007ffff70daebb in dict_repr (mp=0x7fffc7956a48) at /home/dave/OpenCOR/build/ext/Build/Python-3.5.2/Objects/dictobject.c:1647
    1647            Py_INCREF(key);
    

    My theory is that the dictionary object is being freed somewhere along the way; doing the following in PythonQtSignal.cpp appears to fix things.

    static PyObject *PythonQtSignalFunction_emit(PythonQtSignalFunctionObject* func, PyObject *args)
    {
      PythonQtSignalFunctionObject* f = (PythonQtSignalFunctionObject*)func;
      Py_INCREF(args);  // <------------ Ensure args are not freed
      return PythonQtMemberFunction_Call(f->m_ml, f->m_self, args, NULL);
    }
    

    Python output:

    >>> c.process(m)
    {'c': {'e': 'i'}, 'h': {'t': 's'}}
    >>> m
    {'c': {'e': 'i'}, 'h': {'t': 's'}}
    >>> c.process(m)
    {'c': {'e': 'i'}, 'h': {'t': 's'}}
    >>> m
    {'c': {'e': 'i'}, 'h': {'t': 's'}}
    >>> c.process(m)
    {'c': {'e': 'i'}, 'h': {'t': 's'}}
    >>> m
    {'c': {'e': 'i'}, 'h': {'t': 's'}}
    >>> c.process(m)
    {'c': {'e': 'i'}, 'h': {'t': 's'}}
    >>> m
    {'c': {'e': 'i'}, 'h': {'t': 's'}}
    >>> c.process(m)
    {'c': {'e': 'i'}, 'h': {'t': 's'}}
    >>> m
    {'c': {'e': 'i'}, 'h': {'t': 's'}}
    

    The following though will crash:

    static PyObject *PythonQtSignalFunction_emit(PythonQtSignalFunctionObject* func, PyObject *args)
    {
      PythonQtSignalFunctionObject* f = (PythonQtSignalFunctionObject*)func;
      Py_INCREF(args);
      PyObject* result = PythonQtMemberFunction_Call(f->m_ml, f->m_self, args, NULL);
      Py_DECREF(args);
      return result;
    }
    

    Thanks,
    Dave

     
  • Florian Link

    Florian Link - 2017-05-31

    It works if I change

    received = QtCore.Signal(object)
    

    to

    received = QtCore.Signal("QVariant")
    

    so I think you found a bug in the reference counting when PyObject is usedin signal/slot connections.
    I have to think about this, it requires some extra ref/decref at the right places.

     
  • Florian Link

    Florian Link - 2017-05-31

    I fixed this on svn trunk. It was indeed a missing ref-count on the PyObject, but in the signal receiver call (I never had a signal with a PyObject before).

     
  • David Brooks

    David Brooks - 2017-06-01

    It turns out that the reference has to be counted before the PyObject is passed to the slot, not when the object is received. (A local variable, passed to emit() may well be deleted by the time the slot method is called...).

    The code added to PythonQtSignalTarget::call() needs to be removed, and instead, line 114 of PythonQtSlot.cpp replaced with:

        PyObject *arg = PyTuple_GET_ITEM(args, i - 1 - instanceDecoOffset);
        if (arg && (param.pointerCount == 1) && (param.name == "PyObject")) {
          // We need to ref-count the PyObject that is being passed to the slot
          Py_INCREF(arg);
        }
        argList[i] = PythonQtConv::ConvertPythonToQt(param, arg, strict, classInfo);
    

    As in aside, have you given serious consideration to using GitHub for PythonQt? IMHO, using GitHub would greatly simplify working on the code base!

     

Log in to post a comment.

Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.