在从函数A()调用函数B()期间,B()分配一个100-char数组并多次填充,包括一次使用101个字符的字符串,一次使用110个字符的字符串。这是一个明显的错误。
稍后,函数A()尝试访问完全不相关的int变量i,并发生分段错误。
我理解为什么会发生缓冲区溢出,但为什么在访问此整数时会出现分段错误?为什么我不简单地获取垃圾数据?
答案 0 :(得分:14)
缓冲区溢出可能会破坏堆栈上先前保存的帧指针版本。 当函数返回时,这个损坏的版本被加载到帧指针寄存器中,从而导致你描述的行为。
Wikipedia's page包含数字和定义。
答案 1 :(得分:5)
当A()
调用B()
时,B的前导码指令保存A的帧指针 - 堆栈中A保持局部变量的位置,然后用B自己的帧指针替换它。它看起来像这样:
当B超出其局部变量时,它会混淆将重新加载到帧指针中的值。这是垃圾作为帧指针值,因此所有A的局部变量都被删除。更糟糕的是,未来对局部变量的写入会混淆属于其他人的记忆。
答案 2 :(得分:3)
你描述中最可能的解释是B中的溢出会破坏堆栈上保存的帧指针。因此,在B返回后,A在其帧指针中有垃圾,并在尝试访问局部变量时崩溃。
答案 3 :(得分:0)
如果你通过指针访问我,那么问题是指针是垃圾。
答案 4 :(得分:0)
重要的是要记住你为nul终止字符分配了足够的内存和一个(Astute读者会指出这个nul,主要是因为有一个原因 - 一个'l'是'\0'
[感谢Software Monkey指出错误!],带有两个'l'的null是一个指向什么都没有的指针。
这是一个如何发生seg故障的例子
int main(int argc, char **argv){ int *x = NULL; *x = 5; // boom }
由于x是一个指针并设置为null,我们尝试取消引用指针并为其赋值。保证生成分段错误的方法。
有一个老技巧可以实际捕获seg错误并获得堆栈跟踪,在unix环境中更常见,通过设置信号处理程序来捕获SIGSEGV,并在信号处理程序中调用类似的进程这样:
char buf[250]; buf[0] = '\0'; sprintf(buf, "gdb -a %d | where > mysegfault.txt", getpid()); system(buf);
这会附加当前正在执行的C程序并向调试器发送并附加到它上面,where
部分显示导致seg错误并将输出重定向到a的违规行的堆栈跟踪文件在当前目录中。
注意:这是实现定义的,取决于安装,在AIX下,gnu调试器存在,因此这将起作用,您的里程可能会有所不同。
希望这有帮助, 最好的祝福, 汤姆。