简体   繁体   English

malloc()与堆溢出说明

[英]malloc() with heap overflow explanation

I have the following code: 我有以下代码:

int main(int argc, char *argv[]) {

    int bufferSize = 8;
    //Setting the buffer size here, which can cause a heap overflow
    char *argsStr = malloc(bufferSize);
    char *anotherStr = malloc(bufferSize);

    //If argv[1] is greater than the buffer size, we will have an overflow
    strcpy(argsStr, argv[1]);

    printf("String 1: %s String 2: %s", argsStr, anotherStr);

}

I want to cause a heap overflow, so I import the param 'testtesttesttesttesttesttesttesttest'. 我想导致堆溢出,所以我导入参数'testtesttesttesttesttesttesttesttest'。

I would expect, since argsStr is only of size 8, it would be 'testtest' and the rest would overflow into anotherStr (for 8 bytes), but instead I see: 我希望,因为argsStr只有大小为8,它将是'testtest',其余的将溢出到anotherStr(8个字节),但我看到: 在此输入图像描述

so argsStr is 'testtesttesttesttesttesttesttesttest' and anotherStr is 'testtesttesttesttest' 所以argsStr是'testtesttesttesttesttesttesttesttest'而另一个是'testtesttesttesttest'

Why is this? 为什么是这样? Am I missing something with heap overflows or malloc() ? 我错过了堆溢出或malloc()吗?

printf() doesn't know or care how much memory you allocated for the buffers. printf()不知道或关心你为缓冲区分配了多少内存。 When it's printing a string with %s format, it keeps printing until it reaches the terminating zero byte. 当它打印一个%s格式的字符串时,它会一直打印,直到到达终止零字节。 So when it's printing argsStr , it prints the entire thing, even though it overflows the 8 bytes that were allocated. 因此,当它打印argsStr ,它会打印整个内容,即使它溢出了已分配的8个字节。 This is why buffer overflows are a problem -- C pointers don't include any information about how much memory is allocated, so you can easily access memory outside the allocated space if you don't check your lengths correctly. 这就是缓冲区溢出问题的原因 - C指针不包含有关分配内存量的任何信息,因此如果不正确检查长度,则可以轻松访问分配空间外的内存。

The memory for anotherStr was apparently allocated 16 bytes after the memory for argsStr . anotherStr的内存显然是在argsStr的内存之后分配了16个字节。 So when you printed that, it started from the location of argsStr[16] , and printed the last 20 bytes of that string. 因此,当您打印它时,它从argsStr[16]的位置开始,并打印该字符串的最后20个字节。

This is all undefined behavior, of course, so you can't depend on any specific result. 当然,这是所有未定义的行为,因此您不能依赖任何特定结果。

I would expect, since argsStr is only of size 8, it would be testtest and the rest would overflow into anotherStr 我所期望的,因为argsStr仅仅是尺寸为8,将它testtest ,其余的将溢出到anotherStr

In order for the argsStr string to stop after 8 characters on printing, 9-th character must be '\\0' . 为了使argsStr字符串在打印后8个字符后停止,第9个字符必须为'\\0' Your string does not have it, hence printf does not know to stop after printing the first 8 characters on %s . 你的字符串没有它,因此printf不知道在打印%s上的前8个字符后停止。

You got your heap overflow, because strcpy blew past the allocated size. 你的堆溢出了,因为strcpy超过了分配的大小。 It also blew through the "bookkeeping info" stored by malloc , and spills into the next allocation. 它还会破坏malloc存储的“簿记信息”,并进入下一个分配。 Of course it does not have to go into the next allocated block, because it's undefined behavior; 当然它不必进入下一个已分配的块,因为它是未定义的行为; it just happened to do it on your particular system. 它碰巧在你的特定系统上做到了。

You can tell that there was a heap overflow by running your program through valgrind . 您可以通过valgrind运行程序来判断存在堆溢出。 Chances are, your program is going to crash when you add calls to free the memory that you allocated. 有可能,当您添加调用以free您分配的内存时,您的程序将崩溃。

As you know, when you do a malloc, it gives you a pointer to a block of memory in the heap. 如您所知,当您执行malloc时,它会为您提供指向堆中内存块的指针。 The exact structure of the heap is implementation dependent. 堆的确切结构取决于实现。 As others have observed, you may or may not get sequential memory and you may or may not get exactly the amount of memory you asked for. 正如其他人所观察到的那样,您可能会或可能不会获得顺序记忆,您可能会或可能不会得到您要求的内存量。 There are debug implementations malloc that give you the memory you asked for plus a big area at the end with markers to allow finding when you overwrite the end of your allocated block. 有一些调试实现malloc可以为您提供所需的内存以及最后一个带有标记的大区域,以便在覆盖已分配块的末尾时查找。 Something else to keep in mind is the second malloc could be either before or after the memory for the first malloc. 要记住的其他事情是第二个malloc可以在第一个malloc的内存之前或之后。 Like MM observed, you could do a %p to see where the blocks are located to get an idea if they can run into each other. 像MM观察到的那样,你可以做%p来查看块的位置,以便了解它们是否可以相互碰撞。

This is what is called undefined behavior. 这就是所谓的未定义行为。 Exploring undefined behavior is great fun and allows you to get insights into the implementation but don't be surprised if it changes with a different version. 探索未定义的行为非常有趣,并且允许您深入了解实现,但如果它使用不同的版本进行更改,请不要感到惊讶。 You can almost be guaranteed that it will change substantially on different systems, even with the same (GCC) compiler. 几乎可以保证,即使使用相同的(GCC)编译器,它也会在不同的系统上发生重大变化。

If you are really interested, you could find the source for the GCC run time library malloc routine on the web and see what goes on inside. 如果您真的感兴趣,可以在网上找到GCC运行时库malloc例程的源代码,看看里面发生了什么。 I just searched for "gcc runtime library malloc source" and found something that will take more than a few minutes examination to make sense out of. 我刚刚搜索了“gcc运行时库malloc源代码”,并发现了一些需要花费几分钟时间才能理解的内容。 It is pretty awesome code. 这是非常棒的代码。 A lot of very smart people spent a long time working on it. 许多非常聪明的人花了很长时间来研究它。

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

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