仅当重要指针被覆盖时,缓冲区溢出才会引起段错误吗?

CIs*_*ies 2 c pointers buffer-overflow segmentation-fault

假设我有一个程序声明了一个char buffer[size]和另一个变量,并用于gets(buffer);将数据写入buffer。如果gets提供的输入时间过长,则它将从缓冲区溢出,进入下一个变量(假设该变量位于之后的下一个地址中buffer):

void f(){
    char str[12] = "hello_world";
    char buffer[1];

    gets(buffer); // provided with a random char and then "hello_kitty"

    printf("str = %s\n", str); // no crash. Just prints "hello_kitty" as expected
}
Run Code Online (Sandbox Code Playgroud)

当使用“合法输入”运行它(意思是-不溢出第二个缓冲区)时,这没问题。即使我稍微溢出了缓冲区也可以,但是输入太多之后,程序崩溃了。

据我了解,这(意味着-不溢出第二个缓冲区)应该不会导致任何崩溃。可能导致崩溃的原因是破坏了保存指令指针的内存,因此它现在指向无效的地址(这是页面错误吗?)。

它是否正确?不影响堆栈/框架/指令指针的错误写入是否会导致崩溃?

Dav*_*zer 5

简洁地回答您的问题,否。继续阅读,以获得更长的答案。

缓冲区溢出导致分段错误的最典型方式是,溢出的缓冲区驻留在堆栈上,并且溢出会覆盖返回指针。当函数返回时将返回指针弹出到指令指针中时,通常会发生分段错误,因为处理器试图读取您无权访问的内存。

最后一句话很重要。返回指针的覆盖只是发生分段错误的一种方式。实际上,任何缓冲区溢出都会覆盖后来用于访问内存的内存地址,这可能会导致分段错误,或者,如果尝试写入内存,则会导致访问冲突。

例如,假设您在堆上分配了一个结构。该结构采用以下形式:

 struct sample_struct {
   char bytes[20];
   struct sample_struct *next;
 };
Run Code Online (Sandbox Code Playgroud)

如果在bytes没有正确验证边界的情况下将数据复制到成员,则内存中的下一项将是next指针。如果此指针被覆盖,然后尝试从中读取指针,则很可能会发生分段错误,假设那里的值表示您无法控制的内存地址。如果您碰巧以您的内存空间中的地址结尾,则结果将是试图将位于其中的字节解释为struct sample_struct,可能会导致其他问题。


请注意,不要假设在上面的示例结构中覆盖指针仅需要21到24个字节。除非您指示编译器打包该结构,否则该结构的内存分配可能会包含用于对齐目的的其他字节。