0

我正在处理我怀疑是在使用QNetworkAccessManager. 完整的源代码可在此处获得。

从日志输出来看,我猜这个 bug 是在calendar.cpp第 44 行的异步请求之后触发的。我没有确凿的证据。我只注意到第 45 行的消息大部分时间是最后一条日志消息。

这是第 39-46 行:

void Calendar::update()
{
    // Start calendar download asynchronously. After retrieving the
    // file, parseNetworkResponse will take over.
    Logger::instance()->add(CLASSNAME, "Fetching update for 0x" + QString::number((unsigned)this, 16) + "...");
    _naMgr.get(QNetworkRequest(_url));
    Logger::instance()->add(CLASSNAME, "Update request for 0x" + QString::number((unsigned)this, 16) + " was filed.");
}

这个 HTTP GET 请求由Calendar::parseNetworkResponse连接到_naMgr'finished信号的插槽处理。这是第 170-174 行:

void Calendar::parseNetworkResponse(QNetworkReply* reply) {
    // TODO: we suspect that sometimes a SIGSEGV occurs within the bounds
    // of this function. We'll remove the excessive log calls when we've
    // successfully tracked down the problem.
    Logger::instance()->add(CLASSNAME, "Got update response for 0x" + QString::number((unsigned)this, 16) + ".");

即使第 45 行的日志消息不是崩溃后出现在日志中的最后一条消息,日志中总是有一个更新请求,而第 174 行的日志消息从未跟进过。这让我相信HTTP GET 请求可能会破坏这里的东西。提交 GET 请求的 URL 似乎是正确的。

我认为涉及内存损坏的原因之一是即使输入日历列表和我的互联网连接状态保持不变,该错误也不会始终弹出。(我可以用至少 2 个日历触发错误。)此外,当我试图了解有关故障点的更多信息时,我看到了这个 GCC 输出。我会从valgrind的内存检查器收集输出以收集其他信息,但目前我附近没有可用的 Linux 安装。

Can this bug be related to incorrect use of Qt's network libraries from my side? Have you got any other theories as to what might be causing the issue? This is my first time dealing with possible stack corruption and since I'm doing this solo hobby project in my spare time I don't have anyone to train me in dealing with these issues.

4

2 回答 2

0

Are you sending off two requests at once?

I had an issue with threading and QNetworkAccessManager, i had to write a wrapper for it.

Ok, I read some of your code, check out the QT doco for QNetworkAccessManager, aside from the finished signal, there are a couple of other signals that get emitted on failure - its always good practice to catch these.

Is there any chance that you are sending another get request before you finish processing the response, this would explain why it is intermittent.

I will keep looking though and see if I can help.

~ Dan

于 2012-08-17T09:16:15.830 回答
0

In your finished slot, when you are processing the response set a global flag (bool) to "processing"

That way, if you get another response, you can either queue it up, or you can ignore it. The problem is probably more due to the fact that QNetworkAccessManager forks a thread to do its processing somewhere behind the scenes, which causes your code to perform access violations.

If you want I will jump on your project and have a closer look :)

~ Dan

My class for sending and receiving:

.h file

class sendRec : public QObject
{
    Q_OBJECT
public:
    sendRec(QObject *parent = 0);
    sendRec(QUrl);
    QString lastError;
    QUrl thisURL;
    //QNetworkAccessManager manager;
    //FUNCTIONS
    void doGet();
    void doPost(QByteArray*);
    void doPut(QString, QString);
    void doConnects(QNetworkReply *reply, QNetworkAccessManager *manager);

signals:
    void sendResponse(bool, QString*);
public slots:

    /** NETWORK_ACCESS_MANAGER_SLOT **/
    //SUCCESS SLOTS FOR BOTH
    void requestReturned(QNetworkReply * reply );
    //FAILURE SLOTS
    void proxyAuthFail(const QNetworkProxy & proxy, QAuthenticator * authenticator);
    void sslErrorFail(QNetworkReply * reply, const QList<QSslError> & errors);
    /** QNETWORK_REPLY_SLOTS **/
    //FAILURE SLOTS
    void reqError ( QNetworkReply::NetworkError code );
    void sslError ( const QList<QSslError> & errors );

};

.cpp:

#include "sendrec.h"

sendRec::sendRec(QObject *parent) :
    QObject(parent)
{
}


sendRec::sendRec(QUrl url) {
    thisURL = url;
}

void sendRec::doGet() {
    QNetworkRequest request(thisURL);
    QNetworkAccessManager *manager = new QNetworkAccessManager(this);
    QNetworkReply *reply = manager->get(request);
    doConnects(reply, manager);
}

void sendRec::doPost(QByteArray *message) {
    QNetworkRequest request(thisURL);
    QNetworkAccessManager *manager = new QNetworkAccessManager(this);
    QNetworkReply *reply = manager->post(request, *message);
    doConnects(reply, manager);
}

void sendRec::doConnects(QNetworkReply *reply, QNetworkAccessManager* manager){
    //Reply Connects
    QObject::connect(reply, SIGNAL(error(QNetworkReply::NetworkError)),
                     this, SLOT(reqError(QNetworkReply::NetworkError)));
    QObject::connect(reply, SIGNAL(sslErrors(QList<QSslError>)),
                     this, SLOT(sslError(QList<QSslError>)));
    //manager connects
    QObject::connect(manager, SIGNAL(finished(QNetworkReply*)),
               this, SLOT(requestReturned(QNetworkReply*)));
    QObject::connect(manager, SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)),
            this, SLOT(sslErrorFail(QNetworkReply*,QList<QSslError>)));
    QObject::connect(manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
               this, SLOT(proxyAuthFail(QNetworkProxy,QAuthenticator*)));


}


void sendRec::requestReturned(QNetworkReply * rep ){
    qDebug() << "Request Returned";
    QVariant status = rep->attribute(QNetworkRequest::HttpStatusCodeAttribute);
    if(status != 200 || status == NULL) {
        QString *lastError = new QString("ERROR: " + status.toString()
                                         + " " + rep->readAll());
        emit sendResponse(false, lastError);
    } else {
        QString *retString = new QString(rep->readAll());
        *retString = retString->trimmed();
        emit sendResponse(true, retString);
    }
    rep->manager()->deleteResource(rep->request());
    rep->manager()->deleteLater();
    rep->deleteLater();
    sender()->deleteLater();


}
于 2012-08-18T06:55:12.607 回答