为什么缓冲区溢出会在访问整数时导致分段错误?

在从函数A()调用函数B()期间,B()分配一个100-char数组并多次填充,包括一次使用101个字符的字符串,一次使用110个字符的字符串。 这是一个明显的错误。

之后,函数A()尝试访问完全不相关的int变量i,并发生分段错误。

我理解为什么会发生缓冲区溢出,但为什么在访问此整数时会出现分段错误? 为什么我不简单地得到垃圾数据?

A()调用B() ,B的前导码指令保存A的帧指针 – 堆栈中A保持局部变量的位置,然后用B自己的帧指针替换它。 它看起来像这样:

堆栈框架

当B超出其局部变量时,它会混淆将重新加载到帧指针中的值。 这是垃圾作为帧指针值,因此所有A的局部变量都被删除。 更糟糕的是,未来对局部变量的写入会混淆属于其他人的内存。

缓冲区溢出可能会破坏堆栈上先前保存的帧指针版本。 当函数返回时,此损坏版本将加载到帧指针寄存器中,从而导致您描述的行为。

维基百科的页面包含图形和定义。

你描述中最可能的解释是B中的溢出会破坏堆栈上保存的帧指针。因此,在B返回后,A在其帧指针中有垃圾,并在尝试访问局部变量时崩溃。

如果你通过指针访问我,那么问题是指针是垃圾。

重要的是要记住你为nul终止字符分配了足够的内存和一个(Astute读者会指出这个nul,主要是因为有一个原因 – 一个’l’是'\0' [感谢软件猴子为了指出错误!],带有两个’l’的null是指向什么都没有的指针。

这是一个如何发生seg故障的例子

 int main(int argc,char ** argv){
     int * x = NULL;
     * x = 5;
     //热潮
 }

由于x是一个指针并设置为null,我们尝试取消引用指针并为其赋值。 保证生成分段错误的方法。

有一个老技巧可以实际捕获seg错误并获得堆栈跟踪,在unix环境中更常见,通过设置信号处理程序来捕获SIGSEGV,并在信号处理程序中调用这样的进程:

 char buf [250];
 buf [0] ='\ 0';
 sprintf(buf,“gdb -a%d | where> mysegfault.txt”,getpid());
系统(BUF);

这会将当前正在执行的C程序附加到调试器并将其自身附加到调试器上, where部分显示导致seg错误的违规行的堆栈跟踪,并将输出重定向到当前目录中的文件。

注意:这是实现定义的,取决于安装,在AIX下,gnu调试器存在,因此这将起作用,您的里程可能会有所不同。

希望这会有所帮助,最好的问候,汤姆。