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

执行memcpy拷贝以太网地址时触发SegFault段错误 已初始化指针仍崩溃

段错误根因与修复方案

核心触发原因

  • 未初始化局部变量导致内存分配完全失效
    get_payload_to_send函数中定义的int t1是栈上未赋值的局部变量,存储的是随机垃圾值。你直接用这个垃圾值计算内存分配大小:malloc(sizeof(t1) + 1020),会出现两种必然导致崩溃的情况:
    1. 垃圾值为负数时,转成无符号的内存分配长度会变成超大值,malloc直接返回NULL
    2. 垃圾值过小(比如0、1)时,实际分配的内存远小于构造完整数据包需要的长度
      由于代码完全没有对malloc的返回值做合法性检查,你直接把返回的空指针强转为struct ethhdr*。gdb观察到的eth->h_dest为NULL并非偶然:由于h_dest是struct ethhdr的第一个成员,当eth指针的基地址为NULL时,eth->h_dest的地址计算结果就是NULL + 0偏移,和调试现象完全吻合,直接证明malloc没有返回合法内存——对空指针做成员写入操作必然触发段错误。
  • 越界内存写操作破坏堆结构
    代码中两处IP地址拷贝存在严重的长度越界:
    memcpy(ip->saddr, inet_addr(p->ip_dest), sizeof(c) - 1);
    memcpy(ip->daddr, inet_addr(p->ip_source), sizeof(c) - 1);
    
    其中ip->saddr、ip->daddr都是只有4字节的32位地址字段,但你取了栈上20字节数组c的长度减1(也就是19字节)做拷贝长度,直接向只有4字节的字段后面越界写15字节数据,会踩坏堆内存的管理结构、相邻的TCP头、甚至其他动态内存块。堆结构被破坏后,后续任意内存操作都可能访问到非法地址,表现为随机位置的段错误。
  • 类型与字节序转换使用错误
    以太网头的h_proto字段是16位长度的网络序值,你用32位的字节序转换函数htonl(ETH_P_IP)给这个2字节的字段赋值,会额外多写2字节到相邻内存区域,也是越界来源。

针对性修复步骤

  • 删除未初始化的int t1变量,按真实数据包结构计算内存分配长度,并补充返回值检查:
    // 总长度 = 以太网头 + IP头 + TCP头 + 1000字节payload
    size_t total_len = sizeof(struct ethhdr) + sizeof(struct iphdr) + sizeof(struct tcphdr) + 1000;
    *pay = (char*)malloc(total_len);
    if (*pay == NULL) {
        perror("allocate packet buffer failed");
        return;
    }
    memset(*pay, 0, total_len);
    
  • 修正所有越界的IP地址赋值逻辑:inet_addr本身返回4字节的网络序IP值,不需要memcpy,直接赋值即可:
    ip->saddr = inet_addr(p->ip_dest);
    ip->daddr = inet_addr(p->ip_source);
    
  • 修正以太网类型字段的字节序转换:
    把原来的eth->h_proto = htonl(ETH_P_IP);改成:
    eth->h_proto = htons(ETH_P_IP);
    
  • 修正IP头总长度字段的计算与字节序转换:
    原来的ip->tot_len = sizeof(t1) + 1020;改成:
    // tot_len是IP头+负载的总长度,不含以太网头,且需要转网络序
    ip->tot_len = htons(sizeof(struct iphdr) + sizeof(struct tcphdr) + 1000);
    
  • 补充以太网MAC地址的正确拷贝逻辑,统一使用ETH_ALEN(即6字节MAC长度)做拷贝长度:
    memcpy(eth->h_dest, p->h_source, ETH_ALEN);
    memcpy(eth->h_source, p->h_dest, ETH_ALEN);
    

额外优化提示

当前代码在持锁状态下调用get_payload_to_send,而函数内部存在sleep(2)的阻塞操作,会长时间持有互斥锁导致其他线程阻塞,建议把sleep操作移出临界区。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.26 19:15:03