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

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


当前回答

这个“老”问题有很多有趣的答案,甚至一些相对较新的答案,但我没有找到任何提到这个....

当正确和小心使用时,alloca()的一致使用 (可能是整个应用程序)来处理小的可变长度分配 (或C99 VLAs,如果可用)会导致整体堆栈降低 增长比使用超大的等效实现要快 固定长度的本地数组。因此,如果您仔细使用alloca(),它可能对您的堆栈有好处。

我在....上找到了这句话好吧,这句话是我编的。但真的,想想看....

@j_random_hacker在其他答案下面的评论中是非常正确的:避免使用alloca()来支持超大的本地数组并不能使你的程序更安全,免受堆栈溢出(除非你的编译器足够老,允许使用alloca()的函数内联,在这种情况下你应该升级,或者除非你在循环中使用alloca(),在这种情况下你应该……不要在循环内部使用alloca()。

I've worked on desktop/server environments and embedded systems. A lot of embedded systems don't use a heap at all (they don't even link in support for it), for reasons that include the perception that dynamically allocated memory is evil due to the risks of memory leaks on an application that never ever reboots for years at a time, or the more reasonable justification that dynamic memory is dangerous because it can't be known for certain that an application will never fragment its heap to the point of false memory exhaustion. So embedded programmers are left with few alternatives.

alloca()(或VLAs)可能是完成这项工作的合适工具。

I've seen time & time again where a programmer makes a stack-allocated buffer "big enough to handle any possible case". In a deeply nested call tree, repeated use of that (anti-?)pattern leads to exaggerated stack use. (Imagine a call tree 20 levels deep, where at each level for different reasons, the function blindly over-allocates a buffer of 1024 bytes "just to be safe" when generally it will only use 16 or less of them, and only in very rare cases may use more.) An alternative is to use alloca() or VLAs and allocate only as much stack space as your function needs, to avoid unnecessarily burdening the stack. Hopefully when one function in the call tree needs a larger-than-normal allocation, others in the call tree are still using their normal small allocations, and the overall application stack usage is significantly less than if every function blindly over-allocated a local buffer.

但是如果你选择使用alloca()…

根据本页上的其他答案,VLAs似乎应该是安全的(如果从循环中调用,它们不会复合堆栈分配),但如果您正在使用alloca(),请注意不要在循环中使用它,并确保您的函数不能内联,如果它有任何可能在另一个函数的循环中调用。

其他回答

老问题了,但是没有人提到它应该被可变长度数组取代。

char arr[size];

而不是

char *arr=alloca(size);

它存在于标准C99中,并作为编译器扩展存在于许多编译器中。

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

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

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

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

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

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

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

正如在这篇新闻组帖子中提到的,有几个原因可以解释为什么使用alloca是困难和危险的:

并非所有编译器都支持alloca。 一些编译器对alloca的预期行为有不同的解释,因此即使在支持它的编译器之间也不能保证可移植性。 一些实现存在bug。

实际上,alloca并不保证使用堆栈。 事实上,gcc-2.95的alloca实现使用malloc本身从堆中分配内存。此外,这个实现是有bug的,它可能会导致内存泄漏和一些意想不到的行为,如果你在一个块内调用它进一步使用goto。并不是说您永远都不应该使用它,但有时alloca会导致比它从me中释放更多的开销。