[英]What's unsafe/legacy about brk/sbrk?
我聽說很多地方(musl郵件列表,macOS論壇等) brk()
和sbrk()
都不安全。 其中許多地方要么根本不作解釋,要么給出非常含糊的解釋。 例如, 這個鏈接指出“這些函數從根本上被打破”,並繼續說malloc
和sbrk
子系統完全被破壞,它們毀了堆,等等。
我的問題是:為什么會這樣? 如果malloc
以這樣一種方式使用,它分配一塊內存塊,其sbrk
足夠大,可以平息或大大減少進一步分配的需要,那么sbrk
和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
:
#include <unistd.h>
intptr_t brk(void *ptr)
{
if( (void *)syscall(SYS_brk, ptr) != ptr )
return -1;
else
return 0;
}
現實在很大程度上取決於實施,但這里有一些要素:
發明了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()函數是現代虛擬內存管理出現之前的傳統接口。
然后:
BUGS:將brk()或sbrk()與malloc(3),free(3)或類似函數混合將導致不可移植的程序行為。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.