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

App*_*ash 0 c libcurl segmentation-fault

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

以下是相关代码:https://gist.github.com/AppleDash/a26e0ce0b138cd9eacd2(这里要粘贴一点点.)

这是一个链接到它是segfaulting的行: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
Run Code Online (Sandbox Code Playgroud)

我不明白为什么这个电话会导致段错误.有任何想法吗?

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

Ada*_*eld 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);
}
Run Code Online (Sandbox Code Playgroud)

您在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);
    ...
}
Run Code Online (Sandbox Code Playgroud)

正如评论中指出的那样,您还需要检查系统调用是否失败.您应该验证所有调用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
Run Code Online (Sandbox Code Playgroud)