我在我为我的网站进行负载测试而编写的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
我不知道为什么这个电话会导致段错误。有什么想法吗?
我知道你的意思是只提供一小部分相关代码,但在这里我提供了整个事情,因为我觉得这里需要上下文。 (事实上,它是从许多线程运行的。)
答案 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