为什么
来自
如果分配导致堆栈溢出,则程序行为是未定义的。……如果无法扩展堆栈帧,则没有错误指示。
为什么
我理解的方式是
堆区域由malloc,calloc,realloc和free管理,它们可能使用brk和sbrk系统调用来调整其大小
来自
alloca()函数在调用者的堆栈帧中分配大小字节的空间。
堆栈和堆沿着汇合方向增长,如此维基百科图表所示: (上图来自Wikimedia Commons,作者Dougct,发布在CC BY-SA 3.0下)
现在,
引用:
那么,为什么不能使用这样的代码来检查
这对我来说更加令人困惑,因为显然(s)brk可以进行这样的检查。从man 2 sbrk中得知:
brk()将数据段的末尾设置为addr指定的值,当该值合理、系统有足够的内存并且进程没有超过其最大数据大小(参见setrlimit(2))时。
所以如果(s)brk可以进行这样的检查,那么为什么alloca不能呢?
alloca
不检查是否可以分配内存?来自
man 3 alloca
:如果分配导致堆栈溢出,则程序行为是未定义的。……如果无法扩展堆栈帧,则没有错误指示。
为什么
alloca
不/不能检查是否可以分配更多内存?我理解的方式是
alloca
在堆栈上分配内存,而(s)brk
在堆上分配内存。 来自https://en.wikipedia.org/wiki/Data_segment#Heap :堆区域由malloc,calloc,realloc和free管理,它们可能使用brk和sbrk系统调用来调整其大小
来自
man 3 alloca
:alloca()函数在调用者的堆栈帧中分配大小字节的空间。
堆栈和堆沿着汇合方向增长,如此维基百科图表所示: (上图来自Wikimedia Commons,作者Dougct,发布在CC BY-SA 3.0下)
现在,
alloca
和(s)brk
都返回指向新分配内存的开头的指针,这意味着它们都必须知道当前时刻堆栈/堆的结束位置。实际上,从man 2 sbrk
中可以看到:引用:
调用增量为0的sbrk()可用于查找程序断点的当前位置。
因此,我的理解是,检查alloca
是否能够分配所需的内存基本上归结为检查当前堆栈末尾和堆末尾之间是否有足够的空间。如果在堆栈上分配所需的内存会使堆栈达到堆,则分配失败;否则,它成功。那么,为什么不能使用这样的代码来检查
alloca
是否可以分配内存呢?void *safe_alloca(size_t size)
{
if(alloca(0) - sbrk(0) < size) {
errno = ENOMEM;
return (void *)-1;
} else {
return alloca(size);
}
}
这对我来说更加令人困惑,因为显然(s)brk可以进行这样的检查。从man 2 sbrk中得知:
brk()将数据段的末尾设置为addr指定的值,当该值合理、系统有足够的内存并且进程没有超过其最大数据大小(参见setrlimit(2))时。
所以如果(s)brk可以进行这样的检查,那么为什么alloca不能呢?
alloca
一定会成功。在大多数情况下,堆栈大小限制将决定堆栈是否可以扩展。通常在用尽地址空间之前,这个限制就会被达到。 - Tom Karzes