c - 为什么这个字符串不会溢出缓冲区?

标签 c buffer

我在 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 就会溢出到缓冲区 1,因为 8 字节的缓冲区超出了 2。

但是,如果我在我的 Linux 系统上运行它,需要更多的字符才能溢出缓冲区。为什么我可以在 Linux 中执行缓冲区?

另请注意,在两个系统上,整个字符串仍将打印在缓冲区二中,只有溢出的项目打印在缓冲区一中。为什么会这样?为什么其他角色不直接去下一个?如果这个问题措辞不当,请举个例子:

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

最佳答案

第一个问题的答案是内存中变量的对齐是实现定义的。 (参见 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 打印“1234567890”和从 buffer_one 打印“90”的原因是 printf() 开始读取您提供的地址处的字节直到它读取一个空终止符 (0x00)。

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

关于c - 为什么这个字符串不会溢出缓冲区?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34036389/

相关文章:

c - 为什么我们应该在将缓冲区发送到函数之前使用它

c - 伯克利套接字的网络连接速度慢

c - C语言的基本封装

Linux:从 CIFS 读取的文件是否会缓存在内存中?

c - 我在 DbgView 中看不到日志,但在 DeviceTree 中可以看到过滤器

c - 为什么我的变量在我的 C 程序中递归调用时改变值?

c - 为什么要为 getline 或类似功能使用自己的缓冲区?

c++ - `clog` 是否已缓冲?

c - 如何在启动时将数组放置在特定地址

c - 使用多线程的消息队列