问题描述
我有一个带有linux 2.6内核的debian,我试图了解堆的工作方式/与malloc()和free()的行为.我试图搜索malloc()和free()算法和堆结构,但我找不到任何有用的东西.不幸的是,我对Linux和记忆的工作方式太少,了解free()和malloc()的源代码.
这是一个示例代码:
int main(int argc, char **argv) { char *a, *b, *c; a = malloc(32); b = malloc(32); c = malloc(32); strcpy(a, argv[1]); strcpy(b, argv[2]); strcpy(c, argv[3]); free(c); free(b); free(a); }
与gdb和run AAAA BBBB CCCC我可以检查堆.这是strcpys之后的状态,但在frees之前:
之前(gdb) x/32x 0x804c000 0x804c000: 0x00000000 0x00000029 0x41414141 0x00000000 0x804c010: 0x00000000 0x00000000 0x00000000 0x00000000 0x804c020: 0x00000000 0x00000000 0x00000000 0x00000029 0x804c030: 0x42424242 0x00000000 0x00000000 0x00000000 0x804c040: 0x00000000 0x00000000 0x00000000 0x00000000 0x804c050: 0x00000000 0x00000029 0x43434343 0x00000000 0x804c060: 0x00000000 0x00000000 0x00000000 0x00000000 0x804c070: 0x00000000 0x00000000 0x00000000 0x00000f89
你可以看到char阵列非常好.然后我试图弄清楚为什么有<强> 0x29 (12月41日).我会期待像 0x20 (12月32日)或 0x24 (12月36日)这样的东西.
- 为什么malloc算法废物这个空间?
- 它如何决定它是0x29?
- ,最终的 0xf89 是什么?
- 程序如何跟踪分配的内容以及免费的内容?
(gdb) x/32x 0x804c000 0x804c000: 0x00000000 0x00000029 0x0804c028 0x00000000 0x804c010: 0x00000000 0x00000000 0x00000000 0x00000000 0x804c020: 0x00000000 0x00000000 0x00000000 0x00000029 0x804c030: 0x0804c050 0x00000000 0x00000000 0x00000000 0x804c040: 0x00000000 0x00000000 0x00000000 0x00000000 0x804c050: 0x00000000 0x00000029 0x00000000 0x00000000 0x804c060: 0x00000000 0x00000000 0x00000000 0x00000000 0x804c070: 0x00000000 0x00000000 0x00000000 0x00000f89
- 为什么char数组替换为此特定的地址?
- 伪代码是什么免费的?
看这个例子:
(gdb) run AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADDDDD BBBB CCCC ... (gdb) x/32x 0x804c000 0x804c000: 0x00000000 0x00000029 0x41414141 0x41414141 0x804c010: 0x41414141 0x41414141 0x41414141 0x41414141 0x804c020: 0x41414141 0x41414141 0x44444444 0x00000044 0x804c030: 0x42424242 0x00000000 0x00000000 0x00000000 0x804c040: 0x00000000 0x00000000 0x00000000 0x00000000 0x804c050: 0x00000000 0x00000029 0x43434343 0x00000000 0x804c060: 0x00000000 0x00000000 0x00000000 0x00000000 0x804c070: 0x00000000 0x00000000 0x00000000 0x00000f89 ... (gdb) c Program exited with code 021.
我已覆盖0x29,但程序正常退出. 但是当我添加另一个字节时,我遇到了分段错误:
(gdb) run AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADDDDD BBBB CCCC ... (gdb) x/32x 0x804c000 0x804c000: 0x00000000 0x00000029 0x41414141 0x41414141 0x804c010: 0x41414141 0x41414141 0x41414141 0x41414141 0x804c020: 0x41414141 0x41414141 0x44444444 0x00004444 0x804c030: 0x42424242 0x00000000 0x00000000 0x00000000 0x804c040: 0x00000000 0x00000000 0x00000000 0x00000000 0x804c050: 0x00000000 0x00000029 0x43434343 0x00000000 0x804c060: 0x00000000 0x00000000 0x00000000 0x00000000 0x804c070: 0x00000000 0x00000000 0x00000000 0x00000f89 ... (gdb) c Program received signal SIGSEGV, Segmentation fault. 0x080498b9 in free (mem=0x804c030) at common/malloc.c:3631
我最重要的问题是:
- 为什么在覆盖更多字节时,您会在free()中获得分段错误?
- 以及free()算法如何工作?
- 以及Malloc和免费跟踪地址轨道?
非常感谢你的阅读, 亲切的问候
推荐答案
大多数malloc()实现通过跟踪堆本身内的堆的状态,右//或在分配的内存块之前和/或之后.超越分配的块使得该数据损坏 - 其中一些数据可以包括指针或长度,并且损坏这些数据会导致实现尝试访问无效的内存位置.
如何依赖于您使用的系统和libc的详细信息.如果您正在使用Glibc(可能是您在Linux上的话),那么它就有一个很好的解释它在这里如何运行:
http://gee.cs.oswego.edu/dl/html/malloc.html
假设这是这种情况,你看到的0x29可能是块大小(32 = 0x20)和一些标志.这是可能的,因为所有堆分配都舍入到最接近的16个字节(或更多!),因此始终可以假定八位的大小为零.
其他推荐答案
我完全不知道细节.但一般来说,它的工作方式如下:
较大的malloc() S通过mmap()处理,因此我们专注于较小的.您可以在某个位置设置阈值.较小的malloc() s在数据段的末尾处理.可以通过GLIBC处理并调整大小,并使用系统调用brk()和sbrk().
在malloc()一个存储块之后,必须保持才能知道,当调用free()时,必须保留与下一个块的指针才能找到所有和将它们连锁在一起.
在<结束时的存储器块之后,数据段减小了sbrk().在free() ING最终的块之后,将该块添加到空闲列表中.这是一个可用内存块的链接列表,以便重用它们.
0x29是41,是您分配的内存块大小加上一位存储器来保存所需8个字节的字段(大小和下一个指针). 9日是什么,但我不知道,但它可能与对齐有关.
如果您编写超过"承诺"32字节,则会破坏此链接列表和与之关联的指针.因此,free()具有错误的数据,它信任并尝试在不允许的地方写入,这导致SIGSEGV.
其他推荐答案
为什么在覆盖更多字节时,您会在免费()中获得分段错误?
一旦传递您要求的空间结束,您就可以在技术上调用未定义的行为等.最终,您将在内部数据结构中打击指针或大小字段,并且此损坏可能会或可能不会导致引用野生,以便引用不存在的整个页面.
即,分段错误是页面保护的结果.这效果很好地保护一个完整的程序从另一个不相关的程序保护一个整个程序,并且是操作系统使用的工具,以限制对单个用户模式地址空间的损坏.这种机制与内部数据结构不密切地同步.有效指针和有效页面之间存在粗略的对应,但没有任何精确.
以及免费()算法如何工作?
当Malloc()返回块时,创建内部数据结构,以便在将该精确块传递到Free()时,将被识别并链接到空闲列表中.如果可能的话,它将与相邻的免费块组合.
以及Malloc如何在地址上跟踪?
由于您正在运行Linux源代码可用并读取它将自然会导致最精确的答案.但是,一般答案是保留目录.此目录可以是单独的数据结构,或者它可以是链接列表的形式,其中元数据保存在返回的实际地址前面.
为什么有浪费空间?
它没有精确浪费.某些空间可以用于目录,并且可以通过保持在缓存边界上对齐的块来交易某些空间.图像一个小块,尺寸等同于缓存行,或者可能更小.如果此块重叠高速缓存行边界,则将其保存在缓存中,将需要两倍于需要的空间.如果发生这种情况到处都发生了缓存会有效地是大小的一半,命中率较低. (嗯,除了实际需要邻近地址的情况. > 内部碎片 ,它实际上可能在稳定状态下整体使用较少的内存,其中malloc()和free()调用在长期运行过程中平衡.