桌面操作系统上的 C 编译器使用多少内存页来检测堆栈溢出?

发布于 2024-10-29 07:40:04 字数 416 浏览 5 评论 0原文

这个问题与this one有关C99中的可变长度数组相关但不同。

答案指出,在堆栈中分配可变长度数组(或只是固定大小的大数组)的一个危险是分配可能会默默失败,而不是调用malloc,后者明确告诉调用者分配是否成功。

现代非嵌入式编译平台使用无效内存区域来检测某些堆栈溢出,而无需额外成本(这些检查只是 MMU 已经免费进行的检查)。这并不能 100% 避免上述问题,因为非常大的本地数组可能会导致堆栈指针跳过无效区域。

有谁知道通常为该检测分配多少页?我猜它至少是 4KiB,但也可能更多。这是编译器还是操作系统做出的选择,在这两种情况下,有没有办法改变它?

This question is related to but different from this one about variable length arrays in C99.

The answers point out that one danger with allocating variable length arrays (or just large arrays of a fixed size) in the stack is that the allocation may fail silently, as opposed to, say, calling malloc, which explicitly tells the caller whether allocation succeeded.

Modern non-embedded compilation platforms use an invalid memory zone to detect some stack overflows at no additional cost (the checks are only the checks already made for free by the MMU). This doesn't protect at 100% from the above problem because a very large local array may cause the stack pointer to jump over the invalid area.

Does any one know how many pages are typically allocated for this detection? I guess it would be at least 4KiB, but it could be more. Is that a choice made by the compiler or the OS, and in either case, is there a way to change it?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

梦里寻她 2024-11-05 07:40:04

我很确定最常见的做法是仅使用一页,通常是 4k。然而,一个好的编译器会顺序尝试访问大于函数入口(或 VLA/alloca 分配)页面大小的堆栈帧的每个页面,以确保命中保护页面。 GCC 可以选择这样做;请参阅: http://gcc.gnu.org /onlinedocs/gcc/Code-Gen-Options.html#Code-Gen-Options-fstack-check 选项。

I'm pretty sure the most common practice is using just one page, usually 4k. A good compiler, however, will sequentially attempt to access each page of a stack frame larger than the page size on function entry (or on VLA/alloca allocation) to ensure that a guard page is hit. GCC can optionally do this; see: http://gcc.gnu.org/onlinedocs/gcc/Code-Gen-Options.html#Code-Gen-Options and the -fstack-check option.

如梦亦如幻 2024-11-05 07:40:04

在 Windows 上,它是一个 4KB 页面(至少在 x86 上):请参阅基于 Windows NT 的应用程序的堆栈检查说明

这种自动增长方法使用
保护页,保留的,未提交的,
与以下连续的内存页
内存的已提交部分。什么时候
应用程序触及防护装置
页,操作系统提交
该页面和下一个未提交的页面
页面成为新的保护页面。
自动堆栈增长仅适用于
保护页和堆栈内存必须
以 4K 或一页增量增长。
如果应用程序接触到另一个应用程序
保留但未提交的堆栈页
在接触守卫之前的记忆
页,正常的页错误异常
发生不可预测的行为
结果。

...

为了防止该错误,编译器
分别调用 __chkstk() 函数
当本地分配超过4K时。
Windows NT __chkstk() 函数
不显式检查堆栈
与 MS-DOS 版本一样的溢出。
它只是触及内存地址
当前堆栈中的每 4K
指向请求的指针位置
分配。这会触发守卫
页面按正确的顺序排列,并且
向堆栈提交额外的内存
根据需要。

对于 GCC,GCC 堆栈检查

我不确定 C99 的 VLA 如何/是否会改变 WinNT行为。

On Windows, it's one 4KB page (at least on x86): See Description of the stack checking for Windows NT-based applications.

This automatic growth method uses a
guard page, a reserved, uncommitted,
memory page that is contiguous with
the committed portion of memory. When
the application touches the guard
page, the operating system commits
that page and the next uncommitted
page becomes the new guard page.
Automatic stack growth works only for
the guard page and stack memory must
grow in 4K, or one page, increments.
If the application touches another
reserved but uncommitted page of stack
memory before it touches the guard
page, a normal page fault exception
occurs and unpredictable behavior can
result.

...

To prevent the fault, the compiler
calls the __chkstk() function each
time the local allocation exceeds 4K.
The Windows NT __chkstk() function
does not explicitly check for stack
overflow as the MS-DOS version does.
It simply touches memory addresses
every 4K from the current stack
pointer location to the requested
allocation. This triggers the guard
pages in the proper sequence and
commits additional memory to the stack
as required.

For GCC, GCC Stack checking

I'm not sure how/if C99's VLA's would change the WinNT behaviour.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文