I'm currently struggling with a weird segfault I'm getting when using QSerialPort and emitting a signal, with Windows XP SP3, Python 3.3.3 and PyQt5 5.1.1.
I really wonder if this happens in pure Qt with C++ as well, but my C++ is horrible and I don't have a running toolchain set up.
Minimal example code (sorry, couldn't manage to simplify more):
#!/usr/bin/python
import sys
from PyQt5.QtWidgets import QWidget, QApplication, QPushButton
from PyQt5.QtCore import QObject, pyqtSlot, QIODevice, pyqtSignal
from PyQt5.QtSerialPort import QSerialPort
PORT = 'COM59'
class DVIFlasher(QObject):
ser = None
flash_done = pyqtSignal(int, int)
def __init__(self):
super(DVIFlasher, self).__init__()
self.ser = QSerialPort(PORT)
self.ser.readyRead.connect(self.read)
def flash(self):
print(self.ser.open(QIODevice.ReadWrite))
self.ser.setBaudRate(115200)
def read(self):
print("Got data")
self.ser.close()
self.flash_done.emit(0, 0)
class Widget(QWidget):
def __init__(self):
super(Widget, self).__init__()
self.btn = QPushButton("Start", self)
self.flasher = DVIFlasher()
self.btn.clicked.connect(self.flasher.flash)
self.resize(self.btn.sizeHint())
if __name__ == '__main__':
app = QApplication(sys.argv)
win = Widget()
win.show()
sys.exit(app.exec_())
When I run this and receive a byte via the serial port, I get an "Access violation" (aka segfault) in qt5serialport.dll. Sometimes it happens when clicking "Start" the first time, sometimes after the second time.
Some things I observed so far:
The signal needs to have a bool/int as first parameter, and some other parameter -- otherwise it doesn't seem to trigger.
When I emit the signal before the port has been closed (
self.ser.close()
), it doesn't seem to trigger.On Linux (Archlinux, Python 3.3.2, PyQt 5.1.1) I can't reproduce this, but after starting a second time, I always get
QSocketNotifier: Invalid socket specified
.
What gives? Am I doing something wrong? Or is this a bug in [Py]Qt somewhere?
You are facing this bug. This is a relative old issue and known. If we are lucky, it can be fixed for 5.2.1. Your workaround about not calling
ser.close()
in thereadyRead
signal handler looks reasonable.Hope, this helps.