当您使用GCC编译C代码时,堆栈是否以错误的方式增长

时间:2016-06-22 12:43:32

标签: c gcc gdb

我有以下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个字节?

1 个答案:

答案 0 :(得分:4)

有几件事:

  1. 编译器不需要按声明的顺序(或任何其他特定顺序)布置变量。 struct实例的成员按照声明的顺序排列,尽管每个成员之间可能有填充字节(参见2)。

  2. 平台可能要求对象在特定地址上对齐(例如,可被8或16整除的地址)。因此,对象之间可能存在未使用的字节。如果buffer_onebuffer_two的地址相差16,那并不意味着编译器为buffer_one留出了16个字节,这意味着它之间有8个字节的填充。 buffer_one的结束和buffer_two的开头,并且尝试读/写这些字节的行为是未定义的。实际上,这意味着您的代码可以容忍buffer_one中的小缓冲区溢出而没有任何不良影响,但您并不想依赖它。

  3. 您不能依赖对象之间的排序才有意义。你当然不能依赖它在整个实现中可重复。

  4. 虽然您很难找到不使用C实现的C实现,但语言定义并不要求使用运行时堆栈,也不要求堆栈向上(向增加地址)或向下(向减少地址)增长。这完全是一个实施细节。