How to prevent burning conditions when working with Qt Network classes

We have an OS X C ++ application using Qt 5.5, which provides a simple HTTP server interface. It essentially resembles the Fortune Server example provided by Qt ( http://doc.qt.io/qt-5/qtnetwork-fortuneserver-example.html ), but what we see is that sometimes the application crashes when shutting down with the following stack trace (crash in thread 6):

Thread 0:: Dispatch queue: com.apple.main-thread 0 libsystem_kernel.dylib 0x00007fff8deb4fca __open + 10 Thread 1:: Dispatch queue: com.apple.libdispatch-manager 0 libsystem_kernel.dylib 0x00007fff8deb6232 kevent64 + 10 1 libdispatch.dylib 0x00007fff90f0426e _dispatch_mgr_thread + 52 Thread 2: 0 libsystem_kernel.dylib 0x00007fff8deb594a __workq_kernreturn + 10 1 libsystem_pthread.dylib 0x00007fff887833dd start_wqthread + 13 Thread 3: 0 libsystem_kernel.dylib 0x00007fff8deb594a __workq_kernreturn + 10 1 libsystem_pthread.dylib 0x00007fff887833dd start_wqthread + 13 Thread 4: 0 libsystem_kernel.dylib 0x00007fff8deb594a __workq_kernreturn + 10 1 libsystem_pthread.dylib 0x00007fff887833dd start_wqthread + 13 Thread 5:: Dispatch queue: com.apple.NSXPCConnection.m-user.com.apple.airportd 0 libsystem_platform.dylib 0x00007fff8923378d _os_lock_handoff_lock + 23 1 libobjc.A.dylib 0x00007fff83258906 objc_object::sidetable_clearDeallocating() + 64 2 libobjc.A.dylib 0x00007fff8323e651 objc_destructInstance + 145 3 libobjc.A.dylib 0x00007fff8323e595 object_dispose + 22 4 com.apple.CoreFoundation 0x00007fff84eea448 -[__NSArrayM dealloc] + 376 5 libobjc.A.dylib 0x00007fff8325889c objc_object::sidetable_release(bool) + 236 6 com.apple.Foundation 0x00007fff85747909 -[_NSXPCInterfaceMethodInfo dealloc] + 63 7 libobjc.A.dylib 0x00007fff8325889c objc_object::sidetable_release(bool) + 236 8 com.apple.CoreFoundation 0x00007fff84ed5db0 CFRelease + 304 9 com.apple.CoreFoundation 0x00007fff84ee5b92 __CFBasicHashDrain + 498 10 com.apple.CoreFoundation 0x00007fff84ed5e8e CFRelease + 526 11 com.apple.Foundation 0x00007fff8578dd7a -[NSXPCInterface dealloc] + 28 12 libobjc.A.dylib 0x00007fff8325889c objc_object::sidetable_release(bool) + 236 13 com.apple.Foundation 0x00007fff8578df0c -[NSXPCConnection dealloc] + 281 14 libobjc.A.dylib 0x00007fff8325889c objc_object::sidetable_release(bool) + 236 15 libsystem_blocks.dylib 0x00007fff8d3166e5 _Block_release + 196 16 libdispatch.dylib 0x00007fff90effe73 _dispatch_client_callout + 8 17 libdispatch.dylib 0x00007fff90f035cd _dispatch_queue_drain + 1100 18 libdispatch.dylib 0x00007fff90f03030 _dispatch_queue_invoke + 202 19 libdispatch.dylib 0x00007fff90f02bef _dispatch_root_queue_drain + 463 20 libdispatch.dylib 0x00007fff90f02a1c _dispatch_worker_thread3 + 91 21 libsystem_pthread.dylib 0x00007fff88785a9d _pthread_wqthread + 729 22 libsystem_pthread.dylib 0x00007fff887833dd start_wqthread + 13 Thread 6 Crashed:: Qt bearer thread 0 org.qt-project.QtNetwork 0x0000000100a541cb QNetworkConfigurationManagerPrivate::~QNetworkConfigurationManagerPrivate() + 107 1 org.qt-project.QtNetwork 0x0000000100a5431e QNetworkConfigurationManagerPrivate::~QNetworkConfigurationManagerPrivate() + 14 2 org.qt-project.QtCore 0x0000000100d72427 QObject::event(QEvent*) + 823 3 org.qt-project.QtCore 0x0000000100d49588 QCoreApplication::notify(QObject*, QEvent*) + 104 4 org.qt-project.QtCore 0x0000000100d4a212 QCoreApplicationPrivate::sendPostedEvents(QObject*, int, QThreadData*) + 1058 5 org.qt-project.QtCore 0x0000000100d997db QEventDispatcherUNIX::processEvents(QFlags<QEventLoop::ProcessEventsFlag>) + 59 6 org.qt-project.QtCore 0x0000000100d46c1c QEventLoop::exec(QFlags<QEventLoop::ProcessEventsFlag>) + 412 7 org.qt-project.QtCore 0x0000000100b9c07e QThread::exec() + 110 8 org.qt-project.QtCore 0x0000000100b9fc02 QThreadPrivate::start(void*) + 338 9 libsystem_pthread.dylib 0x00007fff8878605a _pthread_body + 131 10 libsystem_pthread.dylib 0x00007fff88785fd7 _pthread_start + 176 11 libsystem_pthread.dylib 0x00007fff887833ed thread_start + 13 

As you can see, stream 0 is completed - we are outside the main one. I am sure that there is a cleaning code that I can’t name when we manage our resources, but I don’t know what it can be.

Without putting our entire source here, the main chain of calls was as follows:

 class RestServer : public QObject { RestServer::RestServer() { _tcpServer = new QTcpServer(this); } void RestServer::listen(quint16 port) { if (!_tcpServer->listen(QHostAddress::LocalHost, port)) { LOG_ERROR("RestServer", "Failed to start server at: " << port); throw std::exception(); } _portNum = _tcpServer->serverPort(); LOG_INFO("RestServer", "Server is listening at: " << _portNum); connect(_tcpServer, SIGNAL(newConnection()), this, SLOT(connectSocket())); } 

Then in our test code we basically do:

 void RestAPIServer_test::responseCallback(QNetworkReply *reply) { auto response = reply->readAll(); _uri = response; reply->close(); QCoreApplication::exit(); } TEST_F(RestAPIServer_test, urlWithPercents) { RestServer restServer(); restServer.listen(0); quint16 port = restServer.serverPort(); // "widget/foo bar.txt" QUrl serviceUrl(QString("http://localhost:%1/path/?path=widget%2Ffoo%20bar.txt").arg(port)); QNetworkAccessManager networkManager(this); connect(&networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(responseCallback(QNetworkReply*))); QNetworkRequest request(serviceUrl); request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded"); networkManager.get(request); QCoreApplication::exec(); ASSERT_EQ(QString("path=widget/foo bar.txt"), _uri); } 
+5
source share
2 answers

The problem seems to be related to some network-related threads created by Qt that still execute a bit after calling the QCoreApplication :: quit () function, probably because quit () was called from a callback function registered with QTcpSocket . The solution was to put a 1 second sleep after a call to exit:

 void RestAPIServer_test::responseCallback(QNetworkReply *reply) { auto response = reply->readAll(); _uri = response; reply->close(); QCoreApplication::exit(); // This prevents a shutdown race condition where Qt service // threads continue to run after the call to exit(). std::this_thread::sleep_for(std::chrono::milliseconds(1000)); } 
0
source

Unable to instantiate QObject on stack with parent. Look at the line

 QNetworkAccessManager networkManager(this); 

The object will be destroyed twice, which is impossible, so you see a crash. Change this line as follows (of course, you also need to update the use of the networkManager variable):

 QNetworkAccessManager* networkManager=new QNetworkAccessManager(this); 
0
source

Source: https://habr.com/ru/post/1245268/


All Articles