Updated-2
I have interesting combination of warnings & errors.
Firstly, when debugging, i get warnings:
can't find linker symbol for virtual table for `QFile' value
found `WebCore::JSDocument::JSDocument(JSC::Structure*, WebCore::JSDOMGlobalObject*, WTF::PassRefPtr<WebCore::Document>)' instead
RTTI symbol not found for class 'WebCore::JSHTMLDocument'
RTTI symbol not found for class 'WebCore::JSHTMLDocument'
RTTI symbol not found for class 'WebCore::JSHTMLDocument'
secondly, i have runtime error:
QIODevice::open: File access not specified
and momently
*** glibc detected *** <path>: double free or corruption (out): 0x081f9d00 ***
Here’s the minimal code that causes that errors (i’ve minimized it):
Files
In result folder created folder “resources” and in it file “vk.cookie” (everything without quotes).
Bug.pro
QT += core gui webkit network xml
TARGET = Bug
TEMPLATE = app
SOURCES += main.cpp \
api_vk.cpp \
printer.cpp
HEADERS += \
api_vk.h \
printer.h
main.cpp
#include <QtGui/QApplication>
#include "api_vk.h"
#include "printer.h"
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
API_VK *apivk = new API_VK;
apivk->authorise();
Printer *printer = new Printer;
QObject::connect(apivk, SIGNAL(authorisationSucceed()), printer, SLOT(printOK()));
QObject::connect(apivk, SIGNAL(authorisationFailed(QString,QString)), printer, SLOT(printFail()));
return a.exec(); }
api_vk.h
#ifndef API_VK_H
#define API_VK_H
#include <QObject>
#include <QTimer>
#include <QUrl>
#include <QtNetwork/QNetworkCookieJar>
class QWebView;
class QString;
class QNetworkReply;
class QXmlInputSource;
class QTimer;
class QNetworkCookie;
class API_VK : public QObject
{
Q_OBJECT
public:
explicit API_VK(QObject *parent = 0);
signals:
void authorisationFailed(QString error, QString error_description);
void authorisationSucceed();
public slots:
void authorise();
protected:
void readCookies();
void writeCookies();
protected slots:
void newAuthoriseRequest();
void processUrl(QUrl url);
private:
static const QString app_id;
static QString access_token;
static qint32 expires_in;
QWebView *messagesPage;
QList<QNetworkCookie> cookies;
QNetworkCookieJar jar;
static bool authorised;
};
#endif
api_vk.cpp
#include "api_vk.h"
#include <QtGui>
#include <QWebView>
#include <QtNetwork/QNetworkRequest>
#include <QtNetwork/QNetworkAccessManager>
#include <QtNetwork/QNetworkReply>
#include <QtNetwork/QNetworkCookie>
#include <QtNetwork/QNetworkCookieJar>
#include <QString>
#include <QStringList>
#include <QFile>
#include <QTextStream>
#include <QTimer>
#include <QUrl>
#include <QtXml>
#include <QVariant>
#include <QDateTime>
#include <QDebug>
bool API_VK::authorised = false;
const QString API_VK::app_id = "2783286";
QString API_VK::access_token = "";
int API_VK::expires_in = 0;
// defining class methods
API_VK::API_VK(QObject *parent) :
QObject(parent)
{
}
void API_VK::authorise() {
newAuthoriseRequest(); // 1. going here
}
void API_VK::newAuthoriseRequest() {
// gets new access_token
// 2. going here
messagesPage = new QWebView;
readCookies();
jar.setCookiesFromUrl(cookies, QUrl("http://vk.com"));
messagesPage->page()->networkAccessManager()->setCookieJar(&jar);
QUrl url("http://oauth.vk.com/authorize");
url.addQueryItem("client_id", app_id);
url.addQueryItem("scope", "messages");
url.addQueryItem("redirect_uri","http://api.vk.com/blank.html");
url.addQueryItem("display","page");
url.addQueryItem("response_type","token");
messagesPage->load(QNetworkRequest(url));
connect(messagesPage, SIGNAL(urlChanged(QUrl)), this, SLOT(processUrl(QUrl)));
messagesPage->show();
}
void API_VK::processUrl(QUrl url) { // 3. going here
/* firstly we're here when oath.vk.com redirects us to api.vk.com/login...
* in this case we're exiting at 4.
* secondly, user logs in, and api.vk.com/login redirects us back to oath.vk.com,
* where we get access_token, etc
* and when debugging, we start receiving warnings about "can't find linker symbol" secondly, not firstly
*/
// if (!url.hasQueryItem("access_token"))
// return;
/* I commented previous part because most of you doesn't have VK accounts so you can't go
* to the next part of code */
access_token = url.queryItemValue("access_token");
expires_in = url.queryItemValue("expires_in").toInt();
emit authorisationSucceed();
authorised = true;
cookies = messagesPage->page()->networkAccessManager()->cookieJar()->cookiesForUrl(QUrl("http://vk.com"));
messagesPage->deleteLater();
writeCookies();
}
void API_VK::readCookies() {
QFile file("./resouces/vk.cookie");
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
return;
}
QTextStream in(&file);
QByteArray name, value;
while (!in.atEnd()) {
in >> name >> value;
cookies.append(QNetworkCookie(name, value));
}
}
void API_VK::writeCookies() {
QFile file("./resouces/vk.cookie"); // note: this file exists
if (!file.open(QIODevice::Truncate | QIODevice::Text)) { // 5. at this line i receive runtime errors
return;
}
QTextStream out(&file);
for (QList<QNetworkCookie>::const_iterator i = cookies.begin(); i != cookies.end(); ++i) {
out << (*i).name() << ' ' << (*i).value() << '\n';
}
}
printer.h
#ifndef PRINTER_H
#define PRINTER_H
#include <QObject>
#include <QDebug>
struct Printer: public QObject {
Q_OBJECT
public slots:
void printOK() { qDebug() << "OK"; }
void printFail() { qDebug() << "Fail"; }
};
#endif // PRINTER_H
printer.cpp
#include "printer.h"
Here’s the full output with memory dump: http://pastebin.com/btVNe4nd
At 5 QtCreator says that app received signal from OS (signal: SIGABRT) and decompiles
Disassembler (__kernel_vsyscall)
0x132414 <+0x0000> int $0x80
0x132416 <+0x0002> ret
And valgrind says:
Analysis of memory <path>
QMetaObject::connectSlotsByName: No matching signal for on_cancelButton_clicked()
"sni-qt/23102" WARN 20:28:53.697 void StatusNotifierItemFactory::connectToSnw() Invalid interface to SNW_SERVICE
** Analysis finished **
** Unknown error **
And one more thing. When I added qDebug() output after each line of code in writeCookies() and launched the program in Run (not debug) mode, it have printed all this output. So, the problem is in some Qt class destructor. (code with qDebug output)
So, why I receive that errors?
Your problem is in the line
The documentation for
setCookieJar()states:That means that when the QNetworkAccessManager gets destroyed, it will execute the following code:
Note that when this happens:
The stack-allocated
jaryou passed tosetCookieJaris long gone. The network manager was likely corrupting things by accessing a destroyed cookie jar — it got destroyed as soon asnewAuthoriseRequest()had exited. Remember that network manager can run some of its functionality in a separate thread.A deletion is attempted on an object that was not allocated directly on the heap via
new.Simply change the declaration to
and allocate a new cookie jar whenever you create a new
QWebView.The use of QPointer will protect you from trying to use a dangling pointer to a cookie jar that got deleted by QWebView’s network access manager. If, by mistake, you try to use it, the pointer will be already reset to zero, and you’ll get an instant segfault at the line where you try to dereference the pointer. That’s easy to debug.
Your major mistake was stopping to further minimize your self-contained example. If you kept at it, you’d have found the problem in the next 10-15 minutes tops.
This is a minimal example that reproduces your problem:
Homework: read up on QPointer, QScopedPointer, QSharedPointer and QWeakPointer. They are very useful, and in most cases you’ll find that use of naked pointers as class members in your code is a bug waiting to happen, with exception of child QObjects (such as QWidgets) whose lifetime matches the lifetime of their parent (i.e. they die only when the parent dies).