printf 使用 sbrk,与自定义内存分配器冲突

printf uses sbrk, conflicting with custom memory allocator

您好,我已经编写了一个内存分配器,并且运行良好。我使用 sbrk/brk 进行页面分配和释放。 但是当我开始使用 printfs 打印信息时,一切都崩溃了。谷歌搜索显示 - printf 在内部也使用 sbrk。因此,另一个 glibc 函数 (printf) 意外地使用了 sbrk 修改的堆段 - 破坏了内存分配器正在进行的簿记。

参考:sbrk(0) value getting increased after calling printf 基本上,任何其他使用 sbrk 的 glibc 函数都会破坏我的内存分配器。 您能否提出可能的解决方案?

粘贴下面显示 printf 最终调用 sbrk 的回溯。即使在打印完成后,我看到,中断指针永远不会恢复到原来的位置。 printf 不应该在它最初位于堆段中的位置恢复中断指针吗?在这方面 printf 的任何替代方案?

(gdb) bt
0  __GI___sbrk (increment=135168) at sbrk.c:40
1  0x00007ffff7e68a99 in __GI___default_morecore (increment=<optimized out>) at morecore.c:47
2  0x00007ffff7e64297 in sysmalloc (nb=nb@entry=592, av=av@entry=0x7ffff7fb2c40 <main_arena>) at malloc.c:2480
3  0x00007ffff7e657b3 in _int_malloc (av=av@entry=0x7ffff7fb2c40 <main_arena>, bytes=bytes@entry=576) at malloc.c:4149
4  0x00007ffff7e65f25 in tcache_init () at malloc.c:2995
5  0x00007ffff7e66ba6 in tcache_init () at malloc.c:3050
6  __GI___libc_malloc (bytes=1024) at malloc.c:3050
7  0x00007ffff7e4f85c in __GI__IO_file_doallocate (fp=0x7ffff7fb3760 <_IO_2_1_stdout_>) at filedoalloc.c:101
8  0x00007ffff7e5f0b2 in __GI__IO_doallocbuf (fp=fp@entry=0x7ffff7fb3760 <_IO_2_1_stdout_>) at libioP.h:904
9  0x00007ffff7e5e198 in _IO_new_file_overflow (f=0x7ffff7fb3760 <_IO_2_1_stdout_>, ch=-1) at fileops.c:752
10 0x00007ffff7e5cbd5 in _IO_new_file_xsputn (n=13, data=<optimized out>, f=0x7ffff7fb3760 <_IO_2_1_stdout_>) at libioP.h:904
11 _IO_new_file_xsputn (f=0x7ffff7fb3760 <_IO_2_1_stdout_>, data=<optimized out>, n=13) at fileops.c:1204
12 0x00007ffff7e44e10 in __vfprintf_internal (s=0x7ffff7fb3760 <_IO_2_1_stdout_>, format=0x555555557334 "\nPage Size = %zu Bytes\n", ap=ap@entry=0x7fffffffdcc0,
mode_flags=mode_flags@entry=0) at ../libio/libioP.h:904
13 0x00007ffff7e308d8 in __printf (format=<optimized out>) at printf.c:33
14 0x000055555555677d in mm_print_memory_usage () at mm.c:613
15 0x00005555555552a9 in main (argc=1, argv=0x7fffffffdf18) at testapp.c:64

Ctx的评论:

This is not possible; sbrk() is used by the libc memory allocator internally, so many libc functions use it implicitly. Either do not use libc at all, or do your memory allocations with malloc() or mmap().

是正确的。如果不使用 malloc,则只能使用 sbrk,并且不知道是否使用 malloc,因为除非实现另有说明,否则 libc 中的任何内容都可能这样做。

如果你的 libc 支持替换 malloc(注意:大部分支持)那么你可以写一个完整的 malloc 替换(这包括所有 malloc 系列函数,而不仅仅是 malloc本身)要么不使用sbrk,要么配合你使用它,然后你就可以自由使用它了。但是否则,您根本无法使用 sbrk.

另请注意,在某些环境中,包括经常与位置无关的可执行文件 (PIE),sbrk 将只有很少或没有内存可供使用,并且在仅几次分配后或 none 完全没有,因为 运行 到内存映射为其他东西。 sbrk 的整个概念是倒退的,根本不应该在现代代码中使用。对于一些分配器策略,它作为后端的一种选择可能是有意义的,同时使用 mmap 或其他东西。但它永远不应该是你的分配器获得新内存的唯一方式,而且在我看来,支持它根本没有用。 mmap 几乎在所有方面都更好。