Weird crash of QNetworkAccessManager::post()
-
- OSX 10.12.3 (16D32)
- Clang 800.0.42.1 (Qt default)
- LLDB 360.1.70 (Xcode default)
Migrated from Qt 5.7 to Qt 5.8 several days ago, my QNetworkAccessManager::post() stop working.
What more weird is that it does work if the url you set is a loopback address.
here i find a minimal way to reproduce it:#include "mainwindow.h" #include "ui_mainwindow.h" #include <QNetworkAccessManager> #include <QNetworkReply> MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); this->mNetworkReply = NULL; this->mNetworkAccessManager = new QNetworkAccessManager(); } MainWindow::~MainWindow() { delete ui; } void MainWindow::on_btn_crash_clicked() { // QUrl url = QUrl("http://127.0.0.1:5000/api"); // it's ok to post to a loopback address QUrl url = QUrl("http://192.168.1.103:5000/api"); // crash on specific ip address or domain name address QNetworkRequest networkRequest; networkRequest.setUrl(url); networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded"); if (this->mNetworkReply != NULL) delete this->mNetworkReply; this->mNetworkReply = this->mNetworkAccessManager->post(networkRequest, ""); connect(this->mNetworkReply, &QNetworkReply::readyRead, [=](){ qDebug() << "readyRead"; }); connect(this->mNetworkReply, &QNetworkReply::finished, [=](){ qDebug() << "finished"; }); }
Is there some thing wrong with my implement?
why it can't work on the new version?
Is it a bug?@MemphisWang Not related: are you coming from Python? :-)
Because you prefix everything with this->, it is not needed in C++.Another note: there is no need to allocate mNetworkAccessManager on the heap.
-
Program looks ok. When does it crash ? After you post or while constructing URL ? Also IP address u specified is pingable? IP address displayed when u run ifconfig command ?
@dheerendra
'192.168.1.103' is my local machine's IP address. (on ifconfig of course: it is in en0: )
I had a python flask server on port 5000. normally these two IP did not tell from each other.
but on this code snippet, they do. -
I'm not quite sure, but:
if (this->mNetworkReply != NULL) delete this->mNetworkReply; this->mNetworkReply = this->mNetworkAccessManager->post(networkRequest, "");
you delete your NetworkReply object here and in the next line, try to access the object via the pointer -> This usually results in a crash.
-
@MemphisWang Not related: are you coming from Python? :-)
Because you prefix everything with this->, it is not needed in C++.Another note: there is no need to allocate mNetworkAccessManager on the heap.
@jsulm
I personally like to user this->, it can help me find out if it is a local variable.
but yeah~ I use python :P wrote Qt for ui, script for data handling.and thanks for allocate advice.
-
I'm not quite sure, but:
if (this->mNetworkReply != NULL) delete this->mNetworkReply; this->mNetworkReply = this->mNetworkAccessManager->post(networkRequest, "");
you delete your NetworkReply object here and in the next line, try to access the object via the pointer -> This usually results in a crash.
@J.Hilk No, that is not the case: he deletes the object mNetworkReply (not mNetworkReply itself) is pointing to and then assigns a pointer pointing to the new object. This is perfectly valid.
delete this->mNetworkReply does not delete mNetworkReply - it deletes the object mNetworkReply is pointing to. -
I'm not quite sure, but:
if (this->mNetworkReply != NULL) delete this->mNetworkReply; this->mNetworkReply = this->mNetworkAccessManager->post(networkRequest, "");
you delete your NetworkReply object here and in the next line, try to access the object via the pointer -> This usually results in a crash.
@J.Hilk
I don't think so.
first I free the memory of a pointer, it's the value (represents some memory address) of pointer not available, pointer itself can be access.
then I assign a new memory address as the value for the pointer. now it get a new memory to point to.those code works in the old day, and still works if the url is 127.0.0.1, I just don't why others can't work.
-
@J.Hilk
I don't think so.
first I free the memory of a pointer, it's the value (represents some memory address) of pointer not available, pointer itself can be access.
then I assign a new memory address as the value for the pointer. now it get a new memory to point to.those code works in the old day, and still works if the url is 127.0.0.1, I just don't why others can't work.
@MemphisWang It works for 127.0.0.1? Then you should connect error signal to a slot and print the error you get for other destinations.
-
@MemphisWang It works for 127.0.0.1? Then you should connect error signal to a slot and print the error you get for other destinations.
@jsulm yes it works only for 127.0.0.1, and I have tried to step over this code. after
on_btn_crash_clicked()
been invoked, it didn't have the chance to send out any useful signal. it just crashed. in moc code. -
That crash stack seems to point to issue with getting proxy configuration from platform.
You could try disabling proxy for QNAM using setProxy(QNetworkProxy::NoProxy).
Most likely some bug with Mac OS integration and you should report it if not reported already. -
I don't understand, it's so weird. and my program can't even finish it's login work now.
if it's a bug, it's a huge bug, it will not be allowed to release. so I guess there must be some thing wrong with my code.
can any body repeat this problem? here is my header for your convenience: http://paste2.org/ZABXaUUJ -
Found report for that issue:
https://bugreports.qt.io/browse/QTBUG-56747 -
That crash stack seems to point to issue with getting proxy configuration from platform.
You could try disabling proxy for QNAM using setProxy(QNetworkProxy::NoProxy).
Most likely some bug with Mac OS integration and you should report it if not reported already.@tomma Thannnnnnnnnnnnnnnnnks men! you are so amazing! It works when i set my mNetworkAccessManager's proxy to NoProxy!
-
@tomma Thannnnnnnnnnnnnnnnnks men! you are so amazing! It works when i set my mNetworkAccessManager's proxy to NoProxy!
As a side note, this delete:
delete this->mNetworkReply;
is rather suspicious. In some use cases (e.g. using multiple threads) you might have events pending for that object in the event loop. Consider using
QObject::deleteLater()
instead. -
As a side note, this delete:
delete this->mNetworkReply;
is rather suspicious. In some use cases (e.g. using multiple threads) you might have events pending for that object in the event loop. Consider using
QObject::deleteLater()
instead.@kshegunov or, given the use case, use
QScopedPointer<QNetworkReply,QScopedPointerDeleteLater> mNetworkReply;
-
@kshegunov or, given the use case, use
QScopedPointer<QNetworkReply,QScopedPointerDeleteLater> mNetworkReply;
Yes indeed. It does the same thing though. ;)
-
As a side note, this delete:
delete this->mNetworkReply;
is rather suspicious. In some use cases (e.g. using multiple threads) you might have events pending for that object in the event loop. Consider using
QObject::deleteLater()
instead.@kshegunov You are right. I'll use deleteLater next time. and I have a further questions for this:
if i have a pointer to a QObjectthis->pObj
,this->pObj = new Foo(); this->pObj->doingSomeThing(); this->pObj->deleteLater();
can i continue to use this pointer immediately
this->pObj = new Foo(); this->pObj->doingSomeThing();
Is it OK?
-
@kshegunov You are right. I'll use deleteLater next time. and I have a further questions for this:
if i have a pointer to a QObjectthis->pObj
,this->pObj = new Foo(); this->pObj->doingSomeThing(); this->pObj->deleteLater();
can i continue to use this pointer immediately
this->pObj = new Foo(); this->pObj->doingSomeThing();
Is it OK?
@MemphisWang said in Weird crash of QNetworkAccessManager::post():
can i continue to use this pointer immediately
Yes, you can even use the same object immediately.
this->pObj = new Foo(); this->pObj->doingSomeThing(); this->pObj->deleteLater(); this->pObj->someOtherThing(); //< Valid until you return control to the event loop
-
@MemphisWang said in Weird crash of QNetworkAccessManager::post():
can i continue to use this pointer immediately
Yes, you can even use the same object immediately.
this->pObj = new Foo(); this->pObj->doingSomeThing(); this->pObj->deleteLater(); this->pObj->someOtherThing(); //< Valid until you return control to the event loop
@kshegunov that's nice, and convenient. I can be less careful about memory and care more about business logic.
-
@kshegunov that's nice, and convenient. I can be less careful about memory and care more about business logic.
Well, it's "invented" not to make you less careful about memory, but exactly because
delete
ing an object that's referenced in a queued event in the event loop is pretty nasty - I'd segfault.