0

の使用中に発生するプログラムのスタック破損バグであると思われるものに対処していますQNetworkAccessManager。完全なソース コードはこちらから入手できます。

ログ出力から判断すると、バグは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に接続されているスロットによって処理されます。170 ~ 174 行を次に示します。_naMgrfinished

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 は正しいようです。

メモリ破損が関係していると思われる理由の 1 つは、入力カレンダーのリストとインターネット接続の状態が同じままであるにもかかわらず、バグが一貫してポップアップしないことです。(少なくとも 2 つのカレンダーでバグを引き起こすことができます。) さらに、障害点について詳しく調べようとすると、この GCC 出力が表示されました。のメモリ チェッカーから出力valgrindを収集して追加情報を収集したはずですが、現時点では近くに Linux がインストールされていません。

このバグは、Qt のネットワーク ライブラリを誤って使用したことに関連している可能性がありますか? 問題の原因について他に何か理論はありますか? スタック破損の可能性に対処するのはこれが初めてであり、空き時間にこのソロの趣味プロジェクトを行っているため、これらの問題に対処する方法を教えてくれる人がいません。

4

2 に答える 2

0

終了したスロットで、応答を処理しているときに、グローバル フラグ (bool) を「処理中」に設定します。

そうすれば、別の応答を受け取った場合、それをキューに入れるか、無視することができます。この問題はおそらく、QNetworkAccessManager がスレッドをフォークして舞台裏のどこかで処理を実行し、コードがアクセス違反を実行するという事実によるものです。

必要に応じて、私はあなたのプロジェクトに飛び乗って詳しく見ていきます:)

〜ダン

送受信用の私のクラス:

.h ファイル

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 に答える
0

一度に 2 つの要求を送信していますか?

スレッドと QNetworkAccessManager に問題があり、そのためのラッパーを作成する必要がありました。

OK、あなたのコードの一部を読みました。QNetworkAccessManager の QT doco をチェックしてください。終了したシグナルとは別に、失敗時に発せられる他のシグナルがいくつかあります。これらをキャッチすることは常に良い習慣です。

応答の処理が完了する前に別の get 要求を送信している可能性はありますか?これは、断続的な理由を説明します。

私は探し続けますが、私が助けることができるかどうかを確認します.

〜ダン

于 2012-08-17T09:16:15.830 に答える