如果缓冲区大小太小而无法通过read()系统调用保持读取数据返回,会发生什么?

时间:2013-04-07 09:36:29

标签: linux unix

考虑下面的程序,程序执行时会发生什么?

 #include <fcntl.h>
 #include <stdio.h>
 #include <string.h>
 main()
 {
    int fd;
    char buf[256];
    fd=open("/etc/passwd",O_RDONLY);
    if(read(fd,buf,1024)<0)
       printf("read fail\n");
    printf("strlen%d:\n",strlen(buf));
}

我认为读取系统调用会将1024字节从内核缓冲区复制到buf,结果应该是&#34; strlen:1024&#34;

但我在gcc 4.1中执行它,结果是:

strlen:1024
segment fault

我想知道为什么会出现段故障?

至少,如果应该有,为什么不在读取系统调用中立即抛出段错误但是在printf&#34; stelen之后:&#34;?

任何帮助将不胜感激。

1 个答案:

答案 0 :(得分:3)

看起来你愿意将1024个字节复制到堆栈分配的256字节缓冲区中。这导致undefined behavior任何事情都可能发生。

在您的特定情况下,read()愉快地写入缓冲区并覆盖部分堆栈,包括当前正在执行的函数的返回地址。在main()尝试返回到内存空间的未映射部分,然后程序段错误之前,没有太严重的事情发生。

另请注意,正如wildplasser在其评论中正确指出的那样,看起来被覆盖的堆栈部分仍然是零填充的,因此strlen()在索引处找到终止\0字符1024并且不会漫游到未映射的区域。

当然,这种行为完全不可靠,如果您稍微修改程序,甚至在同一程序的运行之间,这种行为可能会发生变化。