在Visual 2012控制台应用程序中执行以下程序时:
#include <stdio.h>
int main() {
int integer1, integer2, sum;
char str[5];
scanf("%s",str); /* Try to enter 10 chars */
printf("%s\n",str);
printf( "Enter first integer\n" );
scanf( "%d", &integer1 );
printf( "Enter second integer\n" );
scanf( "%d", &integer2 );
sum = integer1 + integer2;
printf( "Sum = %d\n", sum );
return 0;
}它抛出一个异常"StackOverFlow“,这是显而易见的,因为以下语句:
scanf("%s",str); /* Try to enter 10 chars */我的问题是:为什么程序继续执行(通过打印str字符串,要求输入两个整数,加和并打印结果),即使异常早该发生?
发布于 2013-10-01 10:42:25
堆栈向下扩展,从高地址到低地址。作为CPU寄存器,堆栈指针跟踪堆栈的顶部--实际上是在最低地址,因为堆栈朝着较低的地址增长。编译器查看您的函数(在本例中为main),并查看它需要多少自动存储,即局部变量的存储。它生成代码,根据函数所需的本地存储量来减少堆栈指针。当函数被调用时,调用方推送堆栈返回地址(递减堆栈指针),然后分支到被调用的函数,从而减少堆栈指针(创建堆栈帧),为局部变量腾出空间。
如果程序溢出局部变量(就像您的程序那样),则可能会破坏返回地址。由于堆栈向下扩展到较低的地址,在堆栈帧之外写入(向更高的地址写入)将覆盖较旧的堆栈帧(调用方和调用方的调用者等)。
虽然main()是程序中调用的第一个函数,但已经有一个活动堆栈框架,对应于main()的调用方,即运行时环境。
除非函数main()尝试返回,否则不会注意到破坏堆栈的任何副作用(比如覆盖返回地址)。接下来会发生什么,谁都猜不到。如果返回地址被指向堆栈上某个位置的值覆盖,CPU将分支到那里,这是恶意代码利用缓冲区溢出和堆栈上分配的缓冲区进行攻击的典型漏洞。
这些链接有助于理解基于堆栈的缓冲区溢出:
http://www.tenouk.com/Bufferoverflowc/Bufferoverflow3.html 攻打
最近的微处理器提供了防止执行数据的安全特性,一旦程序试图返回指向数据的损坏地址(如堆栈),CPU就会引发异常。
位

发布于 2013-10-01 10:21:20
因为C不检查所有东西(有什么吗?)您的长字符串已在堆栈上涂鸦,当函数返回时,会注意到堆栈损坏。
值得注意的是,应该始终使用安全版本的 scanf类型函数。
发布于 2013-10-01 10:22:04
在C中,代码不能抛出异常。而且,scanf()不检查堆栈。
可能发生的情况是,Visual为您的程序创建环境,包括设置堆栈。当它这样做的时候,它用一个模式填充堆栈。
当main()返回时,将检查模式。只有在那个时候,C运行时才会注意到您破坏了堆栈。
结论:不要使用不安全版本的scanf()和sprintf()。运行时可能会捕捉到错误,但是它会执行得太晚,甚至当您收到错误消息时,这也无法帮助您了解错误发生的时间。
https://stackoverflow.com/questions/19113654
复制相似问题