Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Android dns resolve crash



  • Hi, I had a problem, When android phone network is shutdown, my app crash and get the follow result

    1 dlfree 0xb6dcbf4c
    2 free 0xb6db2258
    3 __res_ndestroy 0xb6dba4da
    4 __res_vinit 0xb6dba578
    5 QHostInfoAgent::fromName(QString const&) 0xa2aadd7e
    6 QHostInfoRunnable::run() 0xa2aa5516
    7 QThreadPoolThread::run() 0xa2e6e05e
    8 QThreadPrivate::start(void *) 0xa2e6c400
    9 __pthread_start(void *) 0xb6db659c
    10 __start_thread 0xb6db44c4
    11 ??

    This is my source code.

    #include <QGuiApplication>
    #include <QQmlApplicationEngine>
    #include "QAbstractEventDispatcher"
    #include "QThread"
    #include "QTimer"
    #include "QNetworkAccessManager"
    #include "QNetworkReply"
    #include "QNetworkReply"

    int main(int argc, char *argv[])
    {
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);

    QGuiApplication app(argc, argv);
    
    QQmlApplicationEngine engine;
    const QUrl url(QStringLiteral("qrc:/main.qml"));
    QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
                     &app, [url](QObject *obj, const QUrl &objUrl) {
        if (!obj && url == objUrl)
            QCoreApplication::exit(-1);
    }, Qt::QueuedConnection);
    engine.load(url);
    
    for (int i = 0; i < 10; i++) {
        QThread *thr = new QThread();
        thr->start();
    
        while (!QAbstractEventDispatcher::instance(thr)) {
            thr->wait(1);
        }
    
        QMetaObject::invokeMethod(QAbstractEventDispatcher::instance(thr), [=](){
            QTimer *t = new QTimer();
            t->setSingleShot(true);
            t->start(1);
    
            QNetworkAccessManager *mgr = new QNetworkAccessManager();
            QObject::connect(t, &QTimer::timeout, [=](){
                QNetworkRequest request;
                request.setUrl(QString("http://xyz%1.cn").arg(i));
    
                QNetworkReply *reply = mgr->get(request);
                QObject::connect(reply, &QNetworkReply::finished, [=](){
                    reply->deleteLater();
                    t->start();
                });
            });
        });
    }
    
    return app.exec();
    

    }

    Thanks for any helps.



  • It seem that crash occur only multiple thread call QNetworkAccessManager.get() and the url is difference.


  • Qt Champions 2019

    @wantfat said in Android dns resolve crash:

    QNetworkReply *reply = mgr->get(request);

    Did you check that reply is a valid pointer?



  • @jsulm Yes, I tried it just now, but the same thing happened. I changed the code to

    QMetaObject::invokeMethod(QAbstractEventDispatcher::instance(thr), ={
    QTimer *t = new QTimer();
    t->setSingleShot(true);
    t->start(1);

            QObject::connect(t, &QTimer::timeout, [=](){
                QHostInfo::lookupHost(QString("xyz%1.cn").arg(i), [=](const QHostInfo &info){
                    qDebug() << info.errorString();
                    QMetaObject::invokeMethod(t, "start");
                });
            });
        });
    

    It also crash in the same place.


  • Qt Champions 2019

    @wantfat said in Android dns resolve crash:

    I tried it just now, but the same thing happened

    How? Please show the code.

    "It also crash in the same place." - which place exactly?



  • @jsulm This is the code, I check reply valid
    #include <QGuiApplication>
    #include <QQmlApplicationEngine>
    #include "QAbstractEventDispatcher"
    #include "QThread"
    #include "QTimer"
    #include "QNetworkAccessManager"
    #include "QNetworkReply"
    #include "QNetworkReply"
    #include "QHostInfo"

    int main(int argc, char *argv[])
    {
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);

    QGuiApplication app(argc, argv);
    
    QQmlApplicationEngine engine;
    const QUrl url(QStringLiteral("qrc:/main.qml"));
    QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
                     &app, [url](QObject *obj, const QUrl &objUrl) {
        if (!obj && url == objUrl)
            QCoreApplication::exit(-1);
    }, Qt::QueuedConnection);
    engine.load(url);
    
    for (int i = 0; i < 10; i++) {
        QThread *thr = new QThread();
        thr->start();
    
        while (!QAbstractEventDispatcher::instance(thr)) {
            thr->wait(1);
        }
    
        QMetaObject::invokeMethod(QAbstractEventDispatcher::instance(thr), [=](){
            QTimer *t = new QTimer();
            t->setSingleShot(true);
            t->start(1);
    
            QNetworkAccessManager *mgr = new QNetworkAccessManager();
            QObject::connect(t, &QTimer::timeout, [=](){
                QNetworkRequest request;
                request.setUrl(QString("http://xyz%1.cn").arg(i));
    
                QNetworkReply *reply = mgr->get(request);
                if (reply == nullptr) {
                    qDebug() << "reply is null";
                    return;
                }
    
                QObject::connect(reply, &QNetworkReply::finished, [=](){
                    reply->deleteLater();
                    t->start();
                });
            });
        });
    }
    
    return app.exec();
    

    }

    When it crash, The stack is as follows

    1 dlfree 0xb6dcbf4c
    2 free 0xb6db2258
    3 __res_ndestroy 0xb6dba4da
    4 __res_vinit 0xb6dba578
    5 QHostInfoAgent::fromName(QString const&) 0xa2aadd7e
    6 QHostInfoRunnable::run() 0xa2aa5516
    7 QThreadPoolThread::run() 0xa2e6e05e
    8 QThreadPrivate::start(void *) 0xa2e6c400
    9 __pthread_start(void *) 0xb6db659c
    10 __start_thread 0xb6db44c4
    11 ??


  • Lifetime Qt Champion

    Hi,

    Why are you creating 10 threads making get requests almost as fast as possible all the time your application is running ?

    On a side note, you are leaking QNetworkAccessManager and QTimer objects.



  • @sgaist If I had two threads, It would still crash, just for a long time. the request is serial execution .
    thank you.



  • I run on another phone (Android 9, armv7) , The code work well. The mobile phone that had abnormalities is Android 5.1 armv7. I am not sure whether it depend on mobile phone .


  • Moderators

    @wantfat you do realize that

    QThread *thr = new QThread();
        thr->start();
    
        while (!QAbstractEventDispatcher::instance(thr)) {
            thr->wait(1);
        }
    

    is doing nothing but delay forcefully delay the loop by 1 millisecond?
    Also you don't need a QNetworkAccessManager instance for each get request. QNetworkAccessManager can handle 5 get requests in parallel, IIRC, and the rest is automatically queued



  • @j-hilk After call QThread::start the eventDispatcher of thread is null, so must take a sleep wait for eventDispatcher be create, QNetworkAccessManager only one instance for per thread .


  • Moderators

    @wantfat said in Android dns resolve crash:

    , QNetworkAccessManager only one instance for per thread

    no, from your code, you create 10 QNetworkAccessManager instances and all live inside the main(Gui) thread



  • @j-hilk QMetaObject::invokeMethod(QAbstractEventDispatcher::instance(thr), ={

    });
    This code make sure lambda run on thr.


  • Moderators

    @wantfat have you checked that ? by combining invokeMethod with a lambada the object reference pointer becomes a context pointer. I see no reason, why it should be called from the Thread instance, or I personally don't know, never tried threading in this unusual way.



  • @j-hilk Yes, I have checked it, this is detail info, https://stackoverflow.com/a/21653558



  • The test code work well on Qt 5.12.3, The problematic version is Qt 5.12.4 . I compared two versions of the relevant code
    0_1564538533924_QQ图片20190731100118.png
    0_1564538549953_QQ图片20190731100124.png

    If method __res_init resolve fail dlsym be call, and it return a valid pointer, But it is not a thread safe function. Maybe so.



  • I solved this problem by export thread safe __res_init

    #if (QT_VERSION == QT_VERSION_CHECK(5,12,4))

    #include "resolv.h"
    #include "QMutex"

    static QMutex mut;

    int __res_init(void) {
    QMutexLocker lck(&mut);
    return res_init();
    }

    #endif

    Thanks every one.


Log in to reply