Alloca()在堆栈上分配内存,而不是像malloc()那样在堆上分配内存。因此,当我从例程返回时,内存被释放。这实际上解决了动态分配内存的问题。通过malloc()释放分配的内存是一个非常令人头痛的问题,如果以某种方式错过释放会导致各种内存问题。
尽管有上述特性,为什么不鼓励使用alloca() ?
Alloca()在堆栈上分配内存,而不是像malloc()那样在堆上分配内存。因此,当我从例程返回时,内存被释放。这实际上解决了动态分配内存的问题。通过malloc()释放分配的内存是一个非常令人头痛的问题,如果以某种方式错过释放会导致各种内存问题。
尽管有上述特性,为什么不鼓励使用alloca() ?
当前回答
正如在这篇新闻组帖子中提到的,有几个原因可以解释为什么使用alloca是困难和危险的:
并非所有编译器都支持alloca。 一些编译器对alloca的预期行为有不同的解释,因此即使在支持它的编译器之间也不能保证可移植性。 一些实现存在bug。
其他回答
原因如下:
char x;
char *y=malloc(1);
char *z=alloca(&x-y);
*z = 1;
并不是说任何人都可以编写这段代码,但是您传递给alloca的size参数几乎肯定来自某种输入,它可能恶意地目的是让您的程序分配一个像这样巨大的值。毕竟,如果大小不是基于输入,或者不可能很大,为什么不声明一个小的、固定大小的本地缓冲区呢?
几乎所有使用alloca和/或C99 vlas的代码都有严重的错误,这些错误会导致崩溃(如果你幸运的话)或特权损害(如果你不那么幸运的话)。
Alloca()很好,很有效……但它也被深深打破了。
broken scope behavior (function scope instead of block scope) use inconsistant with malloc (alloca()-ted pointer shouldn't be freed, henceforth you have to track where you pointers are coming from to free() only those you got with malloc()) bad behavior when you also use inlining (scope sometimes goes to the caller function depending if callee is inlined or not). no stack boundary check undefined behavior in case of failure (does not return NULL like malloc... and what does failure means as it does not check stack boundaries anyway...) not ansi standard
在大多数情况下,您可以使用局部变量和主要大小来替换它。如果它用于大型对象,将它们放在堆上通常是一个更安全的想法。
如果你真的需要它,你可以使用VLA(在c++中没有VLA,太糟糕了)。在作用域行为和一致性方面,它们比alloca()要好得多。在我看来,VLA是一种正确的分配。
当然,使用所需空间的主要部分的本地结构或数组仍然更好,如果没有这样的主要堆分配,则使用普通malloc()可能是明智的。 我没有看到你真的真的需要alloca()或VLA的用例。
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的根本原因。
在我看来,alloca()在可用的情况下,应该仅以受约束的方式使用。就像“goto”的使用一样,相当多理智的人不仅对alloca()的使用非常反感,而且对它的存在也非常反感。
对于嵌入式使用,其中堆栈大小是已知的,并且可以通过对分配大小的约定和分析施加限制,并且编译器不能升级到支持C99+,使用alloca()是很好的,而且我已经知道使用它。
When available, VLAs may have some advantages over alloca(): The compiler can generate stack limit checks that will catch out-of-bounds access when array style access is used (I don't know if any compilers do this, but it can be done), and analysis of the code can determine whether the array access expressions are properly bounded. Note that, in some programming environments, such as automotive, medical equipment, and avionics, this analysis has to be done even for fixed size arrays, both automatic (on the stack) and static allocation (global or local).
在堆栈上存储数据和返回地址/帧指针的架构上(据我所知,这就是它们的全部),任何堆栈分配变量都可能是危险的,因为变量的地址可以被取走,未检查的输入值可能会允许各种各样的恶作剧。
在嵌入式领域,可移植性不是一个太大的问题,但是它是反对在严格控制的环境之外使用alloca()的一个很好的理由。
在嵌入式空间之外,我主要在日志记录和格式化函数中使用alloca()以提高效率,并在非递归词法扫描器中使用,其中临时结构(使用alloca()在标记化和分类期间创建,然后在函数返回之前填充持久对象(通过malloc()分配)。对较小的临时结构使用alloca()可以在分配持久对象时极大地减少碎片。
我认为没有人提到过这一点,但是alloca也有一些严重的安全问题,不一定是malloc所存在的(尽管这些问题也会出现在任何基于堆栈的数组中,无论是否是动态的)。由于内存是在堆栈上分配的,缓冲区溢出/下溢的后果比仅仅使用malloc要严重得多。
In particular, the return address for a function is stored on the stack. If this value gets corrupted, your code could be made to go to any executable region of memory. Compilers go to great lengths to make this difficult (in particular by randomizing address layout). However, this is clearly worse than just a stack overflow since the best case is a SEGFAULT if the return value is corrupted, but it could also start executing a random piece of memory or in the worst case some region of memory which compromises your program's security.