我在很多地方(音乐邮件列表,macOS论坛等)都听说brk()
和sbrk()
是不安全的。这些地方中的许多要么根本不给出解释,要么给出非常模糊的解释。例如,this链接指出“这些功能从根本上被破坏了”,并继续说malloc
和sbrk
子系统被彻底破坏了,它们破坏了堆,等等。
我的问题是:为什么会这样?如果使用malloc
来分配sbrk
足够大的内存块,以平息或实质上减少了进一步分配的需要,那么sbrk
和{{ 1}}使用起来安全吗?
这是我对brk
和sbrk
的实现:
brk
:
sbrk
#include <unistd.h>
#include <stddef.h>
void *sbrk(intptr_t inc)
{
intptr_t curbrk = syscall(SYS_brk, NULL);
if( inc == 0 ) goto ret;
if( curbrk < 0 ) return (void *)-1;
curbrk((void *)(curbrk+inc));
ret:
return (void *)curbrk;
}
:
brk
答案 0 :(得分:3)
现实高度依赖于实现,但这是一些要素:
brk
/ sbrk
来允许进程从系统请求更多内存,并在单个连续段中释放它。这样,它们被许多malloc
和free
实现使用。问题在于,当它返回一个唯一的段时,由于(同一过程的)多个模块直接使用它,会出错。由于竞争条件,在多线程进程中情况变得更糟。假设有2个线程想要添加新的内存。他们将使用sbrk(0)
查看当前的最高地址,看到相同的地址,使用brk
或sbrk
请求新的内存,并且由于竞争条件,它们都将使用相同的内存
即使在单线程进程中,某些malloc
和free
实现也假定只允许它们使用低级s/brk
接口,并且其他任何代码也应使用它们。在这种情况下,如果内部保留的中断片段的图像不再是假定值,那么事情将会出错。他们应该猜测该段的某些部分被“保留”用于其他用途,可能会破坏释放任何内存的能力。
因此,用户代码永远不要直接使用brk
/ sbrk
,而只能依靠malloc
/ free
。当且仅当您正在编写包含malloc
/ realloc
/ calloc
/ free
的标准库的实现时,才能安全地使用brk
/ sbrk
在现代系统上,mmap
可以更好地使用虚拟内存管理。您可以根据需要使用任意数量的动态内存段,而无需它们之间的交互。因此,在现代系统上,除非您特别需要使用brk
/ sbrk
进行内存分配,否则应使用mmap
。
brk
和sbrk
的FreeBSD参考说明:
brk()和sbrk()函数是自 现代虚拟内存管理的出现。
及更高版本:
错误: 将brk()或sbrk()与malloc(3),free(3)或类似函数混合使用 导致程序无法移植。