我有以下C代码:
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int value = 5;
char buffer_one[8], buffer_two[8];
strcpy(buffer_one, "one"); /* Put "one" into buffer_one. */
strcpy(buffer_two, "two"); /* Put "two" into buffer_two. */
return 0;
}
根据我对堆栈的了解,buffer_one数组应该从比buffer_two数组更高的地址开始,因为堆栈增加到更低的地址,buffer_two位于堆栈的顶部。但是,当我使用gcc编译代码并使用GDB逐步执行代码时,它告诉我反之亦然:
eman@eman:~/Documents/CFiles/bufferOverflow/source$ gcc -g -o example overflow_example.c
eman@eman:~/Documents/CFiles/bufferOverflow/source$ gdb -q example
Reading symbols from example...done.
(gdb) list
1 #include <stdio.h>
2 #include <string.h>
3 int main() {
4 char buffer_one[8];
5 char buffer_two[8];
6
7 strcpy(buffer_one, "one"); /* Put "one" into buffer_one. */
8 strcpy(buffer_two, "two"); /* Put "two" into buffer_two. */
9
10 return 0;
(gdb) break 9
Breakpoint 1 at 0x400571: file overflow_example.c, line 9.
(gdb) run
Starting program: /home/eman/Documents/CFiles/bufferOverflow/source/example
Breakpoint 1, main () at overflow_example.c:10
10 return 0;
(gdb) print &buffer_one
$1 = (char (*)[8]) 0x7fffffffdd50
(gdb) print &buffer_two
$2 = (char (*)[8]) 0x7fffffffdd60
(gdb)
eman@eman:~/Documents/CFiles/bufferOverflow/source$ gcc -g -o example overflow_example.c
eman@eman:~/Documents/CFiles/bufferOverflow/source$ gdb -q example
Reading symbols from example...done.
(gdb) list
1 #include <stdio.h>
2 #include <string.h>
3 int main() {
4 char buffer_one[8];
5 char buffer_two[8];
6
7 strcpy(buffer_one, "one"); /* Put "one" into buffer_one. */
8 strcpy(buffer_two, "two"); /* Put "two" into buffer_two. */
9
10 return 0;
(gdb) break 9
Breakpoint 1 at 0x400571: file overflow_example.c, line 9.
(gdb) run
Starting program: /home/eman/Documents/CFiles/bufferOverflow/source/example
Breakpoint 1, main () at overflow_example.c:10
10 return 0;
(gdb) print &buffer_one
$1 = (char (*)[8]) 0x7fffffffdd50
(gdb) print &buffer_two
$2 = (char (*)[8]) 0x7fffffffdd60
(gdb)
< / p>
这里发生了什么?
额外的问题:为什么数组在用8个字节初始化时会占用10个字节?
答案 0 :(得分:4)
有几件事:
编译器不需要按声明的顺序(或任何其他特定顺序)布置变量。 struct
实例的成员按照声明的顺序排列,尽管每个成员之间可能有填充字节(参见2)。
平台可能要求对象在特定地址上对齐(例如,可被8或16整除的地址)。因此,对象之间可能存在未使用的字节。如果buffer_one
和buffer_two
的地址相差16,那并不意味着编译器为buffer_one
留出了16个字节,这意味着它之间有8个字节的填充。 buffer_one
的结束和buffer_two
的开头,并且尝试读/写这些字节的行为是未定义的。实际上,这意味着您的代码可以容忍buffer_one
中的小缓冲区溢出而没有任何不良影响,但您并不想依赖它。
您不能依赖对象之间的排序才有意义。你当然不能依赖它在整个实现中可重复。
虽然您很难找到不使用C实现的C实现,但语言定义并不要求使用运行时堆栈,也不要求堆栈向上(向增加地址)或向下(向减少地址)增长。这完全是一个实施细节。