为何此C函数中出现“fread: EFAULT, bad address”错误?
为啥你的generator函数读大文件会报"fread: Bad address"?
咱们先揪出问题的核心:你的fread调用参数写错了,直接引发了缓冲区溢出,进而触发了内存访问错误。
先看这段出问题的代码:
limit = fread(buffer, sizeof (unsigned int), sizeof buffer, stdin);
搞懂fread的参数逻辑是关键
fread的官方原型是这样的:
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
每个参数的作用得理清楚:
ptr:用来存数据的缓冲区指针size:单个数据元素的字节大小(比如你的unsigned int的大小)nmemb:要读取的元素个数(不是总字节数!)- 返回值:实际成功读取的元素个数
你的错误就出在第三个参数:你传了sizeof buffer,这是整个缓冲区的总字节数,但fread期望这里是缓冲区能装下的unsigned int元素个数。
举个实际场景的例子(假设unsigned int占4字节):
- 你的
buffer定义是unsigned int[8192 / sizeof(unsigned int)],也就是2048个元素,总字节数8192 - 但你告诉
fread要读取8192个unsigned int元素,这需要32768字节的空间——你的缓冲区根本装不下这么多!
缓冲区溢出为啥会导致"Bad address"?
当fread往buffer里写超出它容量的数据时,会直接覆盖缓冲区后面的内存区域。而你的pos和limit都是静态变量,它们的内存位置刚好和buffer紧挨着(静态变量通常存在同一个内存段里)。
这种溢出会带来两个致命问题:
- 直接破坏
pos和limit的正常数值,导致后续访问buffer数组时出现越界 - 严重时会覆盖其他关键内存数据,触发系统的非法内存访问检测,也就是你看到的"Bad address"错误
怎么修复?
把fread的第三个参数改成缓冲区能容纳的元素个数就行——其实你定义buffer的时候已经算过这个值了,直接复用:
// 用缓冲区总字节数除以单个元素大小,得到元素个数 limit = fread(buffer, sizeof(unsigned int), sizeof(buffer)/sizeof(unsigned int), stdin);
或者更通用的写法(不管数组元素类型是什么都能用):
limit = fread(buffer, sizeof(buffer[0]), sizeof(buffer)/sizeof(buffer[0]), stdin);
为啥大文件才触发错误?
小文件可能只需要1-2次读取操作,溢出的内存还没破坏到关键变量,所以暂时没报错;但你的95MiB大文件需要多次填充缓冲区,很快就会把pos、limit甚至其他内存数据搞乱,直接触发内存访问错误。
内容的提问来源于stack exchange,提问作者user9654148
相关产品推荐
相关产品推荐

