简单来说,仅仅因为在“buf”之后的源代码行上声明了“x”,并不意味着编译器会将它们放在堆栈上相邻的位置。在所示代码中,“x”根本没有被使用,所以它可能根本没有被放置
在任何地方。即使你使用了“x”(必须是一种防止它被存储到寄存器中的方式),很有可能编译器会精确地将其排序
在“buf”之下,这样就
不会被溢出“buf”的代码覆盖。
你可以通过
struct
结构强制该程序覆盖“x”,例如:
#include <stdio.h>
int main()
{
struct {
char buf[5];
char x[2];
} S = { { 0 }, { 'u' } };
printf("Please enter your name: ");
gets(S.buf);
printf("Hello %s!\n", S.buf);
printf("S.x[0] = %02x\n", S.x[0]);
return 0;
}
因为一个struct
的字段在内存中的顺序总是按照它们在源代码中出现的顺序进行布局。1原则上,在S.buf
和S.x
之间可能有填充,但char
必须具有1的对齐要求,因此ABI可能不要求这样。
但即使你这样做,它也不会打印出“Hello stacku!”,因为gets
总是写入一个终止的NUL。看:
$ ./a.out
Please enter your name: stac
Hello stac!
S.x[0] = 75
$ ./a.out
Please enter your name: stack
Hello stack!
S.x[0] = 00
$ ./a.out
Please enter your name: stacks
Hello stacks!
S.x[0] = 73
看看它总是打印你输入的东西,但是x [0]
会被覆盖,首先是用NUL覆盖,然后用“s”覆盖?
(你已经读过Smashing the Stack for Fun and Profit了吗? 你应该读一下。)
1 pedants的脚注:如果涉及位字段,则在内存中的字段顺序部分地变成实现定义的。但这对于此问题并不重要。
buf
是指向某个内存地址的指针,而在这种情况下该地址可能会被零值内存所跟随。 - fredrikgets
函数:https://dev59.com/nXI-5IYBdhLWcg3wwLS3 - Bob__buf
不是指针。 - Gerhardh