我对如何在堆栈上排序局部变量感到很困惑。据我所知,(在Intel x86上)局部变量在代码中存储时从较高地址到较低地址存储。很明显,这段代码:
int i = 0;
char buffer[4];
strcpy(buffer, "aaaaaaaaaaaaaaa");
printf("%d", i);
,产生这样的东西:
1633771873
被覆盖的缓冲区覆盖了i
变量。
但是,如果我交换前两行:
char buffer[4];
int i = 0;
strcpy(buffer, "aaaaaaaaaaaaaaa");
printf("%d", i);
,输出完全相同。
怎么可能? i
的地址低于buffer
的地址,因此缓冲区的溢出应覆盖其他数据,但不会覆盖i
。或者我错过了什么?
感谢您的帮助!
答案 0 :(得分:2)
没有关于局部变量顺序的规则,因此编译器通常可以按照自己喜欢的方式自由分配它们。但另一方面,编译器将使用许多策略来减少您自愿尝试的可能性。
其中一个安全性增强是分配一个总是远离其他标量变量的缓冲区,因为一个数组可以超出边界并且更倾向于膨胀相邻变量。另一个技巧是在数组之后添加一些陷阱空空间,以便为边界问题创建一种隔离。
无论如何,您可以使用调试器查看程序集以确认变量定位。
答案 1 :(得分:0)
如果要查看编译器如何分配局部变量,请尝试使用gcc -S
进行编译,这将输出汇编代码。在汇编代码中,您可以看到编译器如何选择对变量进行排序。
编译器选择如何对局部变量进行排序时要记住的一件事是每个char只需要对齐1(这意味着它可以从内存的任何字节开始),另一方面int必须对齐4(这意味着它只能从一个可被4整除的字节开始),因此根据对齐方式,编译器有自己的逻辑,如何避免使用空字节数据,这意味着它通常是组以某种顺序组合相似类型的变量。所以即使你这样定义它们:
int a;
char c;
int b;
char d;
编译器很可能将内存和字符组合在内存中,因此从顶部的低内存到底部的高内存的内存可能类似于:
low memory
| | | char d | char c|
| int b |
| int a |
high memory
每个块的||表示一个字节,整行表示4个字节。