QProcess in event loop causes memory leak?
-
Hi,
I have an iMX6 board and I'm creating a UI to allow me to connect and disconnect from a WiFi access point. Under the hood, I'm using nmcli to manage the WiFi connections and using QProcess to make the appropriate system call. Unfortunately, in order to disconnect, I have to invoke nmcli on the command line 3 times with some time in between; this was determined empirically by trying to make repeated calls to nmcli on the command line.
When migrating this methodology to Qt, my thought process was as follows. On a button click, I will make a call from QML to an INVOKABLE that makes a system call via QProcess. Then I will kick off a Timer that runs for about 500 ms. In the onTriggered of the Timer, I will call another INVOKABLE that checks if the WiFi connection has been severed. If not, it will make another call to the INVOKABLE to disconnect and restart the timer. If it's determined that we don't have a connection anymore, we're done.
However, I'm noticing that this results in consistent crashes of the app due to munmap_chunk, or a unaligned tcache chunk detected. Can anybody point me to why I am seeing this? Note, I don't think it's repeated calls to QProcess, because I've implemented this by adding sleeps in between the calls to QProcess::execute in disablewifi, and that seems to work fine all the time. I'm not sure why incorporating a timer in QML would cause such issues.
This is the button click logic:
onSigClicked: { if (!infoData.getwifiStatus()) { wifiResultView = true textNotify.text = qsTr("WiFi already disconnected") } else { root.showSpinner() infoData.disablewifi() // For some reason disable needs to be executed three times with some pauses in between wifiDisconnectTimer.start() } }
This is the timer logic:
function handleWiFiDisconnectResult() { if (!wifiConnected) { textNotify.text = qsTr("Disconnected successfully") root.hideSpinner() wifiResultView = true } else { infoData.disablewifi() wifiDisconnectTimer.start() } } Timer { id: wifiDisconnectTimer interval: 500 running: false repeat: false onTriggered: root.handleWiFiDisconnectResult() }
And these are the C++ functions to check the WiFi status and disconnect from WiFi:
bool InfoData::getwifiStatus() { QString temp = ""; memset(buf, 0, sizeof(buf)); FILE *in = popen("nmcli connection show --active | grep wlan0", "r"); if(in == NULL) { perror("popen:"); exit(EXIT_FAILURE); } // Write the output of the command to the console. while(fgets(buf, sizeof(buf), in) != NULL) int pcloseRetVal = pclose(in); // wait for process to finish. // If grep returned anything then a connection still exists if (strlen(buf) > 0) { return true; } else { return false; } } void InfoData::disablewifi() { // "ssid" determined elsewhere (statically set for now) QString disconnectCommand = "nmcli connection down id " + ssid; QProcess::execute(disconnectCommand); }
-
I've implemented this by adding sleeps in between the calls
This will likely cause crashes.
QML and main thread communicate frequently and relay on queued signal connections. If you disrupt them with sleeps, all sorts of weird stuff can start happening (been there, done that ;) ).
Avoid using sleep/msleep etc., also avoid semi-blocking the main thread with
QProcess::execute()
. Better use non-static methods and rely onfinished()
andreadyRead()
signals.Same goes for your
getwifiStatus()
method.