使用readv读取文件时为iovec数组赋值基地址出现段错误排查
问题根因分析
- 缓冲区分配不足:你定义的
buffers是指向长度为1001的char数组的指针,仅通过malloc分配了2个该类型数组的空间,循环却要访问buffers[0]到buffers[999],属于严重的堆内存越界访问,这是触发段错误的核心原因。 strlen使用错误:malloc申请的内存默认未初始化,存储的都是随机垃圾值,strlen(buffers[i])会尝试在垃圾内存中查找\0结束符,大概率触发内存越界。另外iov_len的作用是告知readv当前缓冲区可接收的最大字节数,不需要通过strlen计算,直接设置为缓冲区可用长度即可。- 指针取值逻辑错误:
buffers[i]本身就指向第i个1001字节数组的首地址,不需要额外加&取地址,多余的取地址操作不会改变地址值,但会导致类型逻辑错误,进一步加剧越界风险。 - 输出逻辑存在隐患:
readv读取到的内容是原始二进制字节,不会自动追加\0结束符,直接用printf("%s")输出会导致字符串读取越界。 - 缺少错误检查:你没有判断
open、malloc的返回值,若文件打开失败、内存申请失败也会触发异常。
修正后的完整代码
#include <stdio.h> #include <stdlib.h> #include <fcntl.h> #include <sys/types.h> #include <sys/uio.h> #include <string.h> #include <sys/stat.h> #define IP_FORMAT "*.*.*.*/*,*,*,*,*,*,*,*" #define BUF_COUNT 1000 // 缓冲区数量 #define BUF_SIZE 1001 // 单个缓冲区大小 int main() { // 申请BUF_COUNT个大小为BUF_SIZE的缓冲区 char (*buffers)[BUF_SIZE] = malloc(sizeof(char[BUF_COUNT][BUF_SIZE])); if (buffers == NULL) { perror("malloc failed"); return 1; } struct iovec iov[BUF_COUNT]; int fd = open("./geoip2-ipv4_csv.csv", O_RDONLY); if (fd == -1) { perror("open file failed"); free(buffers); return 1; } // 初始化iovec结构体 for (int i = 0; i < BUF_COUNT; i++) { iov[i].iov_base = buffers[i]; iov[i].iov_len = BUF_SIZE - 1; // 留1字节存结束符 } int valread = readv(fd, iov, BUF_COUNT); if (valread == -1) { perror("readv failed"); close(fd); free(buffers); return 1; } // 输出读取到的内容 for(int i = 0; i < BUF_COUNT; i++) { buffers[i][BUF_SIZE - 1] = '\0'; // 手动添加字符串结束符 printf("%d: %s", i, buffers[i]); } // 资源释放 close(fd); free(buffers); return 0; }
补充注意点
- 如果不需要1000个这么多的缓冲区,可以根据实际需求调整
BUF_COUNT宏的取值,避免不必要的内存浪费。 readv会按顺序填充iovec数组里的缓冲区,返回值是读取到的总字节数,你可以根据返回值按需处理读取到的内容,不需要强制遍历所有缓冲区。
内容的提问来源于stack exchange,提问作者user786
相关产品推荐
相关产品推荐

