我正在尝试将 libcurl 包装为辅助 QObject 类。不幸的是,我遇到了一个神秘的段错误,当完全相同的代码放在类之外时不会发生这种错误。
示例代码:
无类工作代码
//main.cpp
size_t writeCallback(char* ptr, size_t size, size_t nmemb, void* up)
{
size_t data_size = size * nmemb;
QByteArray *data = static_cast<QByteArray*>(up);
data->append(ptr, data_size);
return data_size;
}
int main(int argc, char *argv[]) {
QCoreApplication a(argc, argv);
QByteArray buffer;
CURL *curl;
CURLcode res;
curl = curl_easy_init();
if (curl) {
curl_easy_setopt(curl, CURLOPT_URL, "http://cnn.com");
/* example.com is redirected, so we tell libcurl to follow redirection */
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &writeCallback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &buffer);
/* Perform the request, res will get the return code */
res = curl_easy_perform(curl);
/* Check for errors */
if (res != CURLE_OK)
fprintf(stderr, "curl_easy_perform() failed: %s\n",
curl_easy_strerror(res));
/* always cleanup */
curl_easy_cleanup(curl);
}
qDebug() << buffer;
return a.exec();
}
段错误的 QObject 包装器
//Http.h
class Http : public QObject
{
Q_OBJECT
public:
Http();
void download();
signals:
void finished(const QByteArray &buffer);
private:
size_t writeCallback(char* ptr, size_t size, size_t nmemb, void* up);
};
//Http.cpp
Http::Http()
{
}
void Http::download()
{
QByteArray buffer;
CURL *curl;
CURLcode res;
curl = curl_easy_init();
if (curl) {
curl_easy_setopt(curl, CURLOPT_URL, "http://cnn.com");
/* example.com is redirected, so we tell libcurl to follow redirection */
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &Http::writeCallback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &buffer);
/* Perform the request, res will get the return code */
res = curl_easy_perform(curl);
/* Check for errors */
if (res != CURLE_OK)
fprintf(stderr, "curl_easy_perform() failed: %s\n",
curl_easy_strerror(res));
/* always cleanup */
curl_easy_cleanup(curl);
}
qDebug() << buffer;
emit finished(buffer);
}
size_t Http::writeCallback(char* ptr, size_t size, size_t nmemb, void* up)
{
size_t data_size = size * nmemb;
QByteArray *data = static_cast<QByteArray*>(up);
data->append(ptr, data_size); //<--SEGFAULTS
return data_size;
}
//main.cpp
int main(int argc, char *argv[]) {
QCoreApplication a(argc, argv);
Http http;
http.download();
return a.exec();
}
出现段错误的行Http::writeCallback(char* ptr, size_t size, size_t nmemb, void* up)
valgrind 输出
==11246== Invalid read of size 1
==11246== at 0x4C2D7A2: strlen (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==11246== by 0x511EA14: QByteArray::append(char const*, int) (in /usr/lib/x86_64-linux-gnu/libQt5Core.so.5.0.1)
==11246== by 0x401B77: Http::writeCallback(char*, unsigned long, unsigned long, void*) (http.cpp:45)
==11246== by 0x4E48717: ??? (in /usr/lib/x86_64-linux-gnu/libcurl.so.4.3.0)
==11246== by 0x4E64A1B: ??? (in /usr/lib/x86_64-linux-gnu/libcurl.so.4.3.0)
==11246== by 0x4E5F8B1: ??? (in /usr/lib/x86_64-linux-gnu/libcurl.so.4.3.0)
==11246== by 0x4E68739: ??? (in /usr/lib/x86_64-linux-gnu/libcurl.so.4.3.0)
==11246== by 0x4E693D4: curl_multi_perform (in /usr/lib/x86_64-linux-gnu/libcurl.so.4.3.0)
==11246== by 0x4E60FDC: curl_easy_perform (in /usr/lib/x86_64-linux-gnu/libcurl.so.4.3.0)
==11246== by 0x401A45: Http::download() (http.cpp:26)
==11246== by 0x401838: main (main.cpp:57)
==11246== Address 0x1 is not stack'd, malloc'd or (recently) free'd
==11246==
==11246==
==11246== Process terminating with default action of signal 11 (SIGSEGV)
==11246== Access not within mapped region at address 0x1
==11246== at 0x4C2D7A2: strlen (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==11246== by 0x511EA14: QByteArray::append(char const*, int) (in /usr/lib/x86_64-linux-gnu/libQt5Core.so.5.0.1)
==11246== by 0x401B77: Http::writeCallback(char*, unsigned long, unsigned long, void*) (http.cpp:45)
==11246== by 0x4E48717: ??? (in /usr/lib/x86_64-linux-gnu/libcurl.so.4.3.0)
==11246== by 0x4E64A1B: ??? (in /usr/lib/x86_64-linux-gnu/libcurl.so.4.3.0)
==11246== by 0x4E5F8B1: ??? (in /usr/lib/x86_64-linux-gnu/libcurl.so.4.3.0)
==11246== by 0x4E68739: ??? (in /usr/lib/x86_64-linux-gnu/libcurl.so.4.3.0)
==11246== by 0x4E693D4: curl_multi_perform (in /usr/lib/x86_64-linux-gnu/libcurl.so.4.3.0)
==11246== by 0x4E60FDC: curl_easy_perform (in /usr/lib/x86_64-linux-gnu/libcurl.so.4.3.0)
==11246== by 0x401A45: Http::download() (http.cpp:26)
我完全迷失了为什么代码失败了。
PS。我知道这个示例代码被阻塞了,我知道有 QNetworkAccessManager。我计划稍后将其移至 QThread。我使用 libcurl 的原因是我需要访问的 Web 服务与 QNAM 发送的默认标头不兼容。