alloca 如何从栈中分配内存?
How do functions like alloca allocate memory from the stack?

之前我聊过编译器如何确保大型栈分配不会跳过保护页,Shawn Van Ness 好奇 _alloca 是否也会进行必要的 _chkstk 探测。答案是肯定的:_alloca 函数在调整栈指针分配内存前,同样会调用 _chkstk 进行探测。通过 x86-64 的汇编示例可以看到,无论是创建局部帧还是执行 alloca,都会复用同一个 __chkstk 函数来确保栈空间安全。
是的,_alloca() 函数会调用同样的 _chkstk() 函数,在调整栈指针为分配的内存之前探测栈。
- uecker
没人该用 alloca。如果你非要在栈上分配缓冲区,那就用 VLA,它是标准化的,拥有正确的作用域绑定生命周期,而且类型能记住确切的大小。是的,我知道 MSVC 不支持它。那就别用这个编译器。(该给谁荣誉就给谁:MSVC 比 GCC 和 clang 早得多就实现了栈探测,而 clang 则非常晚才跟上)。
在 gcc 中,你可以用 -fstack-clash-protection 获得栈探测功能,它类似于 _chkstk,但 GCC 会将栈探测内联。
VLA 的名声不好是因为栈冲突攻击,但如果没有栈冲突保护,即使不用 VLA 也会出现这类攻击(而且最早的攻击实际上利用的是固定大小数组),如果你启用了这种保护,在我看来就没有太多理由要避免使用 VLA 了。
如果你需要小的可变大小缓冲区,VLA 几乎总是优于任何替代方案。alloca 各方面都更差(见上文),使用最坏情况边界定义的普通数组相比 VLA 会增加栈的使用量,而且无法编码正确的动态大小,导致边界检查更弱;将缓冲区移到堆上则更慢且让代码更复杂。
如果你无法准确计算放在栈上的东西的大小,并担心 VLA 超出限制(但再次强调,使用最坏情况大小的普通数组相比 VLA 会增加栈使用量),在 GCC 上你可以使用 -Wvla-larger-than 来确保每个 VLA 的大小都在限定范围内。
- pjmlp
这是那些实际上无法在标准 C 中实现的函数之一,要么需要编译器支持,要么必须用纯汇编编写以操作栈寄存器,属于 C 语言的“微运行时”特性之一。
从 UNIX 第 7 版一直到 C99 引入 VLA,随后在 C11 中变为可选,而 C23 更新仍然不支持自动 VLA,仅支持作为函数参数,因此这一点依然成立。
- stkdump
那又怎样?如果有几个函数,每个函数使用不到 4KB,它们相互调用,而在以某种方式使用栈变量时,第一次访问跨过了一个页面呢?
- kjellsbells
有一件事让我有点担心:是否还有年轻一代的开发者,比如 25 到 40 岁之间,能够并且愿意接过 Windows 内部专家的大旗。
我的意思是,Chen 脑子里有几十年的 Windows 内部知识。微软多年来一直在削减人员。当 Petzold 和 Chen 这一代退休时,微软是否还拥有一批能从底层硬件层面理解 Windows 的核心人才?
- eska
推荐阅读相关文章: