2015-12-01 37 views
1

我跑在Mac此代码,也可以在Linux:这个字符串怎么没有溢出缓冲区?

#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"); 
    strcpy(buffer_two, "two"); 

    printf("[BEFORE] buffer_two is at %p and contains \'%s\'\n", buffer_two, buffer_two); 
    printf("[BEFORE] buffer_one is at %p and contains \'%s\'\n", buffer_one, buffer_one); 
    printf("[BEFORE] value is at %p and is %i (0x%08x)\n", &value, value, value); 

    printf("\n[STRCPY] copying %i bytes into buffer two\n\n", strlen(argv[1])); 
    strcpy(buffer_two, argv[1]); 

    printf("[AFTER] buffer_two is at %p and contains \'%s\'\n", buffer_two, buffer_two); 
    printf("[AFTER] buffer_one is at %p and contains \'%s\'\n", buffer_one, buffer_one); 
    printf("[AFTER] value is at %p and is %i (0x%08x)\n", &value, value, value); 
} 

在Mac上,如果我进入了“1234567890”作为命令行参数,90溢出到缓冲区中的一个,因为我所期望的,因为缓冲区8个字节由2

但是,如果我在我的Linux系统上运行它突破,它需要更多的字符缓冲区溢出。怎么来/为什么我可以放弃在Linux中缓冲缓冲区?

另外作为边注,在两个系统中,整个字符串将仍然在缓冲器两个印刷并仅在一个缓冲器溢出的物品。为什么会发生?剩下的角色怎么会不会进入下一个?如果这个问题表达不好,继承人一个例子:

如果我在我的mac上输入1234567890,1234567890将打印在缓冲区二,90将打印在缓冲区一。即使已经溢出了,90如何仍然能够放入缓冲区2中。 (它是在Linux上相同的概念,但它需要超过10个字节溢出)

回答

1

的方式也可以是“内部”是因为没有真正在“内部”的结尾停止。你要求一个长度为8的char[],你可以得到它,大概第二个就在它旁边(尽管编译器可以根据需要自由地重新排列这些东西)。然后你写入10个字符到第一个缓冲区。当你打印这个缓冲区时,它不知道它应该只有8个字符,它知道它在哪里开始和结束,直到达到一个NUL字符。

所以它会去打印整个字符串。在它旁边的另一个缓冲区也知道它的内存在哪里开始,恰好是字符串中的9溢出到其空间的位置。打印告诉它去第一个内存位置查找字符串并打印,直到达到NUL,在这种情况下为90

所以你很满意,对这个例子没有特别的破坏性或危险的方式。如果你在字符串中写入了更多的数据,你可以开始覆盖不仅仅是相邻的字符串缓冲区,而是覆盖其他可能重要的东西。

6

第一个问题的答案是,内存中变量的对齐是实现定义的。 (请参见C11 draft中的第6.2.8节“对齐对象”。)基本上,不同的编译器可能要求内存中两个对象之间的最小字节数不同。您在Mac上使用的编译器将两个8字节的缓冲区紧挨着放在堆栈中,这可能是因为char[]的对齐方式为8个或更少字节。您在Linux上使用的编译器在两个地址之间留下更多字节,可能是因为char[]的对齐方式为16个字节。

对于第二个问题,buffer_onebuffer_two只是程序可以访问的连续内存块中的两个地址。在这种情况下,由于层叠体的实施中,出现buffer_two在比存储器buffer_one低位地址,因此数据写入到buffer_two溢出到buffer_one。你buffer_two和“90后”从buffer_one打印“1234567890”的原因是,printf()开始在你给它,直到它显示一个空终止(0x00)地址读取字节。

所以,当你strcpy()“1234567890”到buffer_two,你实际上写了11个字节,包括字符串末尾的空终止符(0x00)。在你的Mac,buffer_twobuffer_one分别为8个字节分开,所以当printf()buffer_two读取,它看到了空终止符,这恰好是后指向的地址buffer_one之前读取10个字符。当printf()buffer_one读取时,它在看到空终止符之前读取2个字符。