Linux上堆栈溢出被禁用了吗?

3

在Linux上,我有一段代码,在主函数内声明了一个大小为2MB+1字节的数组。

#include <stdio.h>
#include <stdlib.h>

#define MAX_DATA (2097152)  /* 2MB */

int main(int argc, char *argv[])
{
    /* Reserve 1 byte for null termination */
    char data[MAX_DATA + 1];

    printf("Bye\n");

    return 0;
}

当我在Linux上使用gcc编译时,可以无问题地运行。但是在Windows上,我遇到了运行时错误。在运行时,我有5GB的空闲内存。

为了解决Windows上的问题,我需要指定其他堆栈大小:

gcc -Wl,--stack,2097153 -o test.exe test.c

或者在主函数之外声明数据数组。

是因为在Linux上编译的程序链接时未更改堆栈大小吗?

为什么它在Linux上运行良好,但在Windows上失败? 我使用相同的源代码和相同的gcc指令:

gcc -Wall -O source.c -o source

因为 Linux 上的 malloc 实现可能不可靠,即使内存不可用也可以返回非空指针。
我认为在运行在 Linux 上的程序中,它可能会默默地忽略堆栈问题?
可能是因为在 Linux 上运行的程序没有链接更改堆栈大小,但不像 Windows 那样在运行时失败,而是默默地忽略了堆栈问题?
此外,为什么如果我将数组声明在主函数之外,在 Windows 上它可以正常工作?如果它使用堆,则为什么我不需要释放它?

2
最大堆栈大小取决于操作系统和设置。这方面没有标准可言。堆也是如此,但这些限制(通常)要大得多。 - Mat
运行时错误 -- 您是指 SIGSEGV 吗? - devnull
在Windows上,错误代码0xC00000FD表示STATUS_STACK_OVERFLOW。 - carlos
1
在这种情况下,由于函数不是递归的,您可以始终将 static 添加到数组的声明中。 - Harry Johnston
1个回答

9

为什么它在Linux上运行良好而在Windows上失败?

因为进程或线程的默认堆栈大小取决于系统:

  • 在Windows上,链接器使用的默认堆栈保留大小为1 MB。
  • 在Linux / Unix上,最大堆栈大小可以通过ulimit命令进行配置。此外,在创建新线程时可以配置堆栈大小。

我认为Linux上的malloc实现不可靠,因为即使没有可用内存也可以返回非空指针。

我想你在谈论过度提交问题。为了克服这个问题,您可以使用calloc并检查返回值。如果您在应用程序的最开始这样做,您可以立即退出并显示适当的错误消息。


今天我了解到Windows上默认的1MB堆栈大小。似乎在Linux上,这个大小通常比Windows大,如8MB。因此,如果在Linux上不崩溃,那就没问题了,我将不需要修补程序。谢谢。 - carlos
3
@carlos:是的,你只需要修补Windows而不是程序本身,就可以使其正常工作...;-) (翻译:是的,你只需要修补Windows而不是程序本身,就可以使其正常工作...;-)) - Brendan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接