为什么libcurl segfaulting对curl_easy_perform()的调用?

时间:2014-07-14 21:29:26

标签: c segmentation-fault libcurl

我在我为我的网站进行负载测试而编写的HTTP flooder中使用libCURL时遇到了段错误。

以下是相关代码:https://gist.github.com/AppleDash/a26e0ce0b138cd9eacd2(此处粘贴有点大。)

这里是指向它的行的链接:https://gist.github.com/AppleDash/a26e0ce0b138cd9eacd2#file-httpflood-improved-c-L57

这是段错误的回溯:

#0  0x00007ffff760d65b in fwrite () from /usr/lib/libc.so.6
#1  0x00007ffff79656d8 in ?? () from /usr/lib/libcurl.so.4
#2  0x00007ffff797a76b in ?? () from /usr/lib/libcurl.so.4
#3  0x00007ffff7984349 in ?? () from /usr/lib/libcurl.so.4
#4  0x00007ffff7984b11 in curl_multi_perform () from /usr/lib/libcurl.so.4
#5  0x00007ffff797b977 in curl_easy_perform () from /usr/lib/libcurl.so.4
#6  0x0000000000400f42 in flood (structPointer=0x7fffffffe060) at httpflood.c:57
#7  0x00007ffff7bc5124 in start_thread () from /usr/lib/libpthread.so.0
#8  0x00007ffff768b4bd in clone () from /usr/lib/libc.so.6

我不知道为什么这个电话会导致段错误。有什么想法吗?

我知道你的意思是只提供一小部分相关代码,但在这里我提供了整个事情,因为我觉得这里需要上下文。 (事实上​​,它是从许多线程运行的。)

1 个答案:

答案 0 :(得分:5)

这是你的问题:

for (i = 0; i < threadnum; i++) {
    struct flood_data ddosData;
    memset(&ddosData, 0, sizeof(struct flood_data));
    ddosData.url = url;
    ddosData.proxy = getProxy();
    pthread_create(&threads[i], NULL, flood, (void *)&ddosData);
}

您在堆栈上分配单个struct flood_data实例,并将其同时传递给所有新线程。每次遍历循环时,都会覆盖同一个实例,同时从早期迭代中生成的线程可能会尝试从中读取。主要的未定义行为。

执行此操作的正确方法是为每个线程动态分配单独的实例:

for (i = 0; i < threadnum; i++) {
    struct flood_data *ddosData = calloc(1, sizeof(*ddosData));
    ddosData->url = url;
    ddosData->proxy = getProxy();
    pthread_create(&threads[i], NULL, flood, ddosData);
}

...

void *flood(void *structPointer) {
    struct flood_data *data = structPointer;
    char *bootable = data->url;
    char *proxy = data->proxy;
    free(data);
    ...
}

正如评论中指出的那样,您还需要检查系统调用是否失败。您应该验证所有对fopen()的调用是否成功,因为您很可能会达到流程中打开的最大文件描述符数。而不是将文件打开到/dev/null,为什么不用CURLOPT_WRITEFUNCTION选项设置无操作写入函数?

static size_t noop_write_callback(char *ptr, size_t size, size_t nmemb, void *userdata)
{
    // Do nothing
    return size * nmemb;
}

...

curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &noop_write_callback);
// No need to call fopen("/dev/null") or set CURLOPT_WRITEDATA now