Alloca()在堆栈上分配内存,而不是像malloc()那样在堆上分配内存。因此,当我从例程返回时,内存被释放。这实际上解决了动态分配内存的问题。通过malloc()释放分配的内存是一个非常令人头痛的问题,如果以某种方式错过释放会导致各种内存问题。

尽管有上述特性,为什么不鼓励使用alloca() ?


当前回答

alloca的一个缺陷是longjmp将它倒带。

也就是说,如果你用setjmp保存一个上下文,然后分配一些内存,然后longjmp到上下文,你可能会失去分配的内存。堆栈指针回到原来的位置,因此内存不再保留;如果你调用一个函数或执行另一个分配,你将破坏原来的分配。

为了澄清,我在这里特别提到的是一种情况,即longjmp不返回发生分配的函数!相反,函数使用setjmp保存上下文;然后使用alloca分配内存,最后在该上下文中执行longjmp。该函数的分配内存没有全部释放;就是从setjmp开始分配的所有内存。当然,我说的是观察到的行为;据我所知,任何分配都没有这样的要求。

The focus in the documentation is usually on the concept that alloca memory is associated with a function activation, not with any block; that multiple invocations of alloca just grab more stack memory which is all released when the function terminates. Not so; the memory is actually associated with the procedure context. When the context is restored with longjmp, so is the prior alloca state. It's a consequence of the stack pointer register itself being used for allocation, and also (necessarily) saved and restored in the jmp_buf.

顺便说一句,如果这样工作的话,这提供了一种合理的机制来故意释放使用alloca分配的内存。

我曾经遇到过这种情况,这是一个bug的根本原因。

其他回答

原因如下:

char x;
char *y=malloc(1);
char *z=alloca(&x-y);
*z = 1;

并不是说任何人都可以编写这段代码,但是您传递给alloca的size参数几乎肯定来自某种输入,它可能恶意地目的是让您的程序分配一个像这样巨大的值。毕竟,如果大小不是基于输入,或者不可能很大,为什么不声明一个小的、固定大小的本地缓冲区呢?

几乎所有使用alloca和/或C99 vlas的代码都有严重的错误,这些错误会导致崩溃(如果你幸运的话)或特权损害(如果你不那么幸运的话)。

其他答案都是正确的。但是,如果使用alloca()要分配的对象相当小,我认为这是一种比使用malloc()或其他方法更快、更方便的好技术。

换句话说,alloca(0x00ffffff)是危险的,可能会导致溢出,就像char hugeArray[0x00ffffff];是多少。小心谨慎,通情达理,你会没事的。

在我看来,分配和变长数组的最大风险是,如果分配的大小出乎意料地大,它可能会以非常危险的方式失败。

堆栈上的分配通常没有检入用户代码。

现代操作系统通常会在*下面放置一个保护页面,以检测堆栈溢出。当堆栈溢出时,内核可能会扩展堆栈或杀死进程。Linux在2017年将这个保护区域扩展到比页面大得多,但它的大小仍然是有限的。

因此,作为一条规则,在使用之前的分配之前,最好避免在堆栈上分配超过一个页面。使用分配或可变长度数组,很容易让攻击者在堆栈上进行任意大小分配,从而跳过任何保护页并访问任意内存。

*在当今最广泛的系统中,堆栈向下增长。

这里的大多数回答都忽略了一点:使用_alloca()可能比仅仅在堆栈中存储大对象更糟糕,这是有原因的。

自动存储和_alloca()之间的主要区别是,后者有一个额外的(严重的)问题:分配的块不受编译器控制,因此编译器无法优化或回收它。

比较:

while (condition) {
    char buffer[0x100]; // Chill.
    /* ... */
}

:

while (condition) {
    char* buffer = _alloca(0x100); // Bad!
    /* ... */
}

后者的问题应该是显而易见的。

进程只有有限的堆栈空间可用——远远小于malloc()可用的内存量。

通过使用alloca(),您将极大地增加获得Stack Overflow错误的机会(如果幸运的话,或者如果运气不好,则会出现莫名其妙的崩溃)。