You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

多线程调用gethostbyname时memcpy触发Segmentation Fault问题排查

多线程域名解析程序memcpy段错误排查

我有一个Linux程序,需要从包含数百万域名的文本文件中获取每个域名的IP,并将其存入struct sockaddr_in结构体。为了提升效率,采用多线程实现,但程序运行4-5分钟后,会在memcpy代码处触发Segmentation Fault(段错误)。

线程主例程代码

#include <netdb.h>
#include <arpa/inet.h>

void* startcheckingdomains(){
    while(1){
        char* domain = "www.google.com";
        struct hostent* hp = gethostbyname(domain);
        struct sockaddr_in sockaddr;

        if(hp == NULL){
            herror("hp");
        }else{
            memcpy(&sockaddr.sin_addr, hp->h_addr, hp->h_length);
        }
    }
}

GDB错误输出

线程 535 "main" 收到信号 SIGSEGV,段错误。
[切换到线程 0x7ffe8f606700 (LWP 27402)]
__memmove_avx_unaligned_erms ()

问题根源

核心问题是**gethostbyname并非线程安全函数**:它返回的struct hostent结构体是内部静态分配的内存空间,多线程并发调用时,这个静态内存会被不同线程互相覆盖。当某个线程刚拿到hp指针,还没完成memcpy操作时,其他线程调用gethostbyname就会修改hp指向的内容,导致访问hp->h_addr或hp->h_length时出现非法内存引用,运行一段时间后触发段错误。

解决方法

1. 使用线程安全的域名解析函数

推荐使用符合POSIX标准的线程安全函数,比如:

  • gethostbyname_r:gethostbyname的可重入版本,需要自行提供内存缓冲区存储结果。
  • getaddrinfo:更现代的API,支持IPv6,天然线程安全,是官方推荐的替代方案。

2. 用getaddrinfo改写的示例代码

#include <netdb.h>
#include <arpa/inet.h>
#include <string.h>

void* startcheckingdomains(){
    while(1){
        const char* domain = "www.google.com";
        struct addrinfo hints, *res, *p;
        struct sockaddr_in sockaddr;
        int rv;

        memset(&hints, 0, sizeof(hints));
        hints.ai_family = AF_INET; // 指定IPv4
        hints.ai_socktype = SOCK_STREAM;

        if((rv = getaddrinfo(domain, NULL, &hints, &res)) != 0){
            fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
            continue;
        }

        // 遍历结果取第一个IPv4地址
        for(p = res; p != NULL; p = p->ai_next){
            if(p->ai_family == AF_INET){
                memcpy(&sockaddr, p->ai_addr, p->ai_addrlen);
                break;
            }
        }

        freeaddrinfo(res); // 必须释放getaddrinfo分配的内存
    }
}

3. 额外注意事项

  • 控制线程并发数:过多线程同时发起DNS请求可能导致本地DNS缓存过载或被远端DNS服务器限制,反而降低效率。
  • 域名队列的线程同步:如果是从文件读取域名分发给线程,要使用互斥锁或条件变量保证队列访问的线程安全,避免数据竞争。

内容的提问来源于stack exchange,提问作者user19628924

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 23:30:18