简体   繁体   English

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

[英]How come this string doesn't overflow the buffer?

I ran this code on a mac and also on linux: 我在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);
}

On the mac, if i entered "1234567890" as a command line argument, the 90 overflowed into buffer one as I would expect because the buffer of 8 bytes was exceeded by 2. 在Mac上,如果我作为命令行参数输入“ 1234567890”,则90会像我期望的那样溢出到缓冲区1中,因为8字节的缓冲区超出了2。

However if I run it on my Linux system, it takes many more characters to overflow the buffer. 但是,如果我在Linux系统上运行它,则需要更多的字符来使缓冲区溢出。 How come/why can I get away with exeeding the buffer in Linux? 为什么/为什么要在Linux中超过缓冲区?

Also as A side note, on both systems, the entire string will still be printed in buffer two and only the overflowed items in buffer one. 另外,在两个系统上,整个字符串仍将打印在缓冲区2中,而溢出的项目仅打印在缓冲区1中。 Why would that happen? 为什么会这样? How come the rest of the characters wouldn't just go to the next? 剩下的角色怎么会不只是跳到下一个? If that question wasn't phrased well, heres an example: 如果这个问题的措辞不好,请举一个例子:

If I enter 1234567890 on my mac, the 1234567890 will be printed in buffer two and the 90 would be printed in buffer one. 如果我在Mac上输入1234567890,则1234567890将被打印在缓冲区2中,而90将被打印在缓冲区1中。 How can the 90 still fit inside buffer two even though it has overflowed. 即使溢出,90仍如何容纳在缓冲区2中。 (it is the same concept on linux but it takes more than 10 bytes to overflow) (在Linux上是相同的概念,但是溢出需要超过10个字节)

The answer to your first question is that the alignment of variables in memory is implementation-defined. 第一个问题的答案是内存中变量的对齐方式是实现定义的。 (See Section 6.2.8 "Alignment of objects" in the C11 draft .) Basically, different compilers may require a different minimum number of bytes to be between two objects in memory. (请参阅C11草案中的6.2.8节“对象的对齐”。)基本上,不同的编译器可能要求在内存中两个对象之间使用不同的最小字节数。 The compiler you used on the Mac packed the two 8-byte buffers right next to each other on the stack, likely because the alignment of char[] is 8 or less bytes. 在Mac上使用的编译器将两个8字节缓冲区紧挨着放在堆栈中,这可能是因为char[]的对齐方式是8个字节或更少。 The compiler you used on Linux left more bytes between the two addresses, probably because the alignment of char[] is 16 bytes. 您在Linux上使用的编译器在两个地址之间留出了更多字节,这可能是因为char[]的对齐方式为16个字节。

For your second question, buffer_one and buffer_two are just two addresses in a contiguous chunk of memory that your program has access to. 对于第二个问题, buffer_onebuffer_two只是程序可以访问的连续内存块中的两个地址。 In this case, due to the implementation of the stack, buffer_two appears at a lower address than buffer_one in memory, so data written to buffer_two overflows to buffer_one . 在这种情况下,由于堆栈的实现, buffer_two出现在内存中比buffer_one低的地址buffer_one ,因此写入buffer_two数据溢出到buffer_one The reason you print "1234567890" from buffer_two and "90" from buffer_one is that printf() starts reading bytes at the address you give it until it reads a null-terminator ( 0x00 ). buffer_two打印“ 1234567890”并从buffer_two打印“ 90”的buffer_one是, printf()开始在您提供的地址读取字节,直到它读取空终止符( 0x00 )。

So, when you strcpy() "1234567890" to buffer_two , you actually write 11 bytes, including the null-terminator ( 0x00 ) at the end of the string. 因此,当您将strcpy() “ 1234567890”写入buffer_two ,您实际上写入了11个字节,包括字符串末尾的空终止符( 0x00 )。 On your Mac, buffer_two and buffer_one were 8 bytes apart, so when printf() reads from buffer_two , it reads 10 characters before seeing the null-terminator, which happens to be after the address pointed to by buffer_one . 在Mac上, buffer_twobuffer_one相隔8个字节,因此,当printf()buffer_two读取时,它将读取10个字符,然后再看到空终止符,该终止符恰好在buffer_one指向的地址之后。 When printf() reads from buffer_one , it reads 2 characters before seeing the null-terminator. printf()buffer_one读取时,它会读取2个字符,然后才能看到空终止符。

The way it can be "inside" is because there isn't really a stop at the end of "inside". 之所以可以在“内部”进行,是因为在“内部”末尾并没有真正的止损。 You ask for a char[] of length 8 and you get it, presumably the second is right next to it (though the compiler is free to rearrange such things if it wants). 您要求一个长度为8的char[]并得到它,大概第二个就在它的旁边(尽管编译器可以根据需要随意重新排列这些内容)。 You then write, say, 10 chars into the first buffer. 然后,您将10个字符写入第一个缓冲区。 When you print that buffer it has no idea that it's supposed to only have 8 characters in it, it knows where it starts and goes until it gets to a NUL character. 当您打印该缓冲区时,它根本不知道应该只有8个字符,它知道它从哪里开始直到到达NUL字符。

So it will go and print the whole string. 这样它将打印整个字符串。 The other buffer that was right beside it also knows where its memory starts, which happens to be where the 9 from the string overflowed into its space. 在它旁边的另一个缓冲区也知道其内存从哪里开始,恰好是字符串中的9溢出到其空间的位置。 Printing that one tells it to go to the first memory location for its string and print until it gets to a NUL , which is 90 in this case. 打印该命令会告诉它转到其字符串的第一个存储位置并打印直到到达NUL ,在这种情况下为90

So you are overflowing, just not in a particularly destructive or dangerous way for this example. 因此,您正在溢出,只是对于本示例而言,不是特别破坏性或危险的方式。 If you wrote a lot more data into the string you could start overwriting not just the adjacent string buffer but other potentially important things on the stack. 如果您在字符串中写入了更多数据,则不仅可以覆盖相邻的字符串缓冲区,还可以覆盖堆栈中其他潜在的重要内容。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM