假设您的应用程序中的某处有以下调用堆栈:
- 主要例程
- Function1 的局部变量
- Function2 的局部变量
在这种情况下,main 调用 function1,而 function1 调用 function2。
现在假设function2调用function3,并且function3的返回值返回到堆栈上:
- 主要例程
- Function1 的局部变量
- Function2的局部变量
- Function3的局部变量,包括返回值
Function3 将返回值存入堆栈,然后返回。返回意味着,再次减少堆栈指针,所以堆栈变成这样:
- 主要例程
- Function1 的局部变量
- Function2 的局部变量
你看,function3 的栈帧已经不在这里了。
好吧,实际上我撒了一点谎。堆栈框架仍然存在:
- 主要例程
- Function1 的局部变量
- Function2 的局部变量
- Function3的局部变量,包括返回值
因此,访问堆栈来获取返回值似乎是安全的。
但是,如果在 function3 返回之后、但在 function2 从堆栈获取返回值之前发生中断,我们会得到以下结果:
- 主要例程
- Function1 的局部变量
- Function2的局部变量
- 中断函数的局部变量
而现在栈帧真的被覆盖了,我们迫切需要的返回值已经消失了。
这就是为什么在堆栈上返回返回值不安全的原因。
该问题与这段简单的 C 代码中显示的问题类似:
char *buf = (char *)malloc(100*sizeof(char *));
strcpy (buf, "Hello World");
free (buf);
printf ("Buffer is %s\n",buf);
大多数时候,用于 buf 的内存仍将包含“Hello World”内容,但如果有人能够在调用 free 之后、调用 printf 之前分配内存,则可能会出现严重错误。一个这样的例子是在多线程应用程序中(我们已经在内部遇到了这个问题),如下所示:
THREAD 1: THREAD 2:
--------- ---------
char *buf = (char *)malloc(100);
strcpy (buf, "Hello World");
free (buf);
char *mybuf = (char *)malloc(100);
strcpy (mybuf, "This is my string");
printf ("Buffer is %s\n",buf);
线程 1 的 printf 现在可以打印“Hello World”,也可以打印“This is my string”。任何事情都可能发生。