Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/rust/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Memory management 如果malloc';s可以失败,为什么堆栈变量初始化可以';t(至少我们没有检查这一点)?_Memory Management_Stack_Heap - Fatal编程技术网

Memory management 如果malloc';s可以失败,为什么堆栈变量初始化可以';t(至少我们没有检查这一点)?

Memory management 如果malloc';s可以失败,为什么堆栈变量初始化可以';t(至少我们没有检查这一点)?,memory-management,stack,heap,Memory Management,Stack,Heap,如果没有足够的内存来分配当前函数的堆栈(本地)变量,操作系统是否会在阈值之前向用户发送警告,然后应用程序将实际崩溃?如果堆栈空间不足,则进程将被操作系统终止 确切的机制是特定于操作系统的。例如,在Linux上耗尽堆栈空间会触发一个错误。是的,您将得到一个堆栈溢出运行时错误 旁注:有一个很受欢迎的网站就是以这个错误命名的 堆栈分配可能会失败,对此您无能为力 在现代操作系统上,堆栈开始时会占用大量内存(在Linux上,现在似乎是128k左右),并且会为堆栈增长保留一个虚拟地址范围(通常更大,例如在L

如果没有足够的内存来分配当前函数的堆栈(本地)变量,操作系统是否会在阈值之前向用户发送警告,然后应用程序将实际崩溃?

如果堆栈空间不足,则进程将被操作系统终止


确切的机制是特定于操作系统的。例如,在Linux上耗尽堆栈空间会触发一个错误。

是的,您将得到一个堆栈溢出运行时错误

旁注:有一个很受欢迎的网站就是以这个错误命名的

堆栈分配可能会失败,对此您无能为力

在现代操作系统上,堆栈开始时会占用大量内存(在Linux上,现在似乎是128k左右),并且会为堆栈增长保留一个虚拟地址范围(通常更大,例如在Linux上是8M,通常是可配置的)。如果超出提交的部分,提交更多内存可能会因内存不足而失败,并且程序将因
SIGSEGV
而崩溃。如果超出保留地址范围,您的程序肯定会失败,如果它最终覆盖堆栈地址范围下的其他数据,可能会导致灾难性的失败

解决方法是不要用堆栈做疯狂的事情。即使是Linux上的初始提交量(128k)也比您应该使用的堆栈空间更多。不要使用调用递归,除非您对调用级别的数量有一个对数界限,不要使用巨大的自动数组或结构(包括可能由用户提供的VLA维度产生的数组或结构),这样您就可以了

请注意,没有可移植且将来也没有安全的方法来测量当前堆栈使用情况和剩余可用性,因此您只需对其进行安全操作即可


编辑:关于堆栈分配,至少在真实系统上(没有拆分堆栈的攻击),您确实有一个保证,就是您已经验证过的堆栈空间不会神奇地消失。例如,如果您成功地从
b()
a()
main()
调用了一次
c()
,并且它们没有使用任何可能大小不同的VLA,那么在程序的同一实例中再次重复此调用模式不会失败。您还可以找到对某些程序(不使用函数指针和/或递归的程序)执行静态分析的工具,这些程序将确定程序所消耗的最大堆栈空间量,之后,您可以在程序启动时进行设置,以验证在继续之前您是否可以成功使用这么多的空间。

好的。。。从语义上讲,没有堆栈

从语言的角度来看,自动存储可以正常工作,而动态存储可能会以确定的方式失败(
malloc
返回
NULL
new
抛出
std::bad\u alloc

当然,实现通常会带来一个堆栈来实现自动存储,而且这个堆栈的大小是有限的。然而,这是一个实现细节,不必如此

例如,gcc允许您拥有一个按需增长的细分堆栈。这个技术对于C或C++是非常新近的,但是有连续的语言(成千上万的语言)和Haskell一样,这个内置和GO也有一个要点。
尽管如此,在某个时刻,如果你继续努力,记忆会耗尽。这实际上是未定义的行为,因为标准根本没有试图处理这一问题。在这种情况下,通常情况下,操作系统会向程序发送一个信号,该信号将关闭,堆栈不会展开。

虽然操作系统可能不会通知您堆栈空间不足,但您可以通过内联程序集上的一点自行检查:

unsigned long StackSpace()
{
    unsigned long retn = 0;
    unsigned long *rv = &retn;

    __asm
    {
        mov eax, FS:[0x08]
        sub eax, esp
        mov [rv], eax
    }

    return retn;
}
您可以通过参考窗口来确定FS:[*]的值


编辑:意味着从eax中减去esp,而不是ebx XD

您可以通过编写一个无停止条件的递归PHP函数来轻松检查这一点。您的PHP将有一个分段错误。@Eregrith:PHP是如何进入图片的?问题是标签<代码> [C] < /C>和 [C++] 。这不重要,因为它与C++和C++无关,更多的与汇编有关。@ DimMG:语言确实重要。在高级语言(Python、PHP甚至Java)中处理堆栈溢出的方式通常与在低级语言(C、C++)中处理堆栈溢出的方式非常不同。您是否曾经能够在不破坏堆栈的情况下在PHP中出现分段错误?通过这种方式,您可以确保堆栈已损坏,并且Segfault不是来自某些C代码中的其他地方。我没有在问题上看到
windows
标记,也没有在您的回答中提到这是不可移植的win32特定代码。请澄清,是否通过覆盖堆栈上的被调用方地址使此函数返回自身?OS层会发生什么?@Spidey代码所做的就是将堆栈底部的地址复制到EAX中,从EAX中减去ESP的当前值(即堆栈指针),然后将EAX的值写入'retn'变量。我如何覆盖回信地址?@R很公平,但它仍然有与他的问题相关的信息。另外,不难推断这是与windows相关的代码,只要看看我链接的Wikipedia文章。@Gogeta70我误解了,我以为你是在强迫某种递归或其他什么。但是我没有得到数学知识。您是否强制esp达到最大值?怎么用?我想你应该增加它,而不是减少它,来达到这个目的。操作系统可以释放正在运行的应用程序所使用的所有内存,不是吗?“从语义上讲,没有堆栈。”我认为有。必须有,它是存储返回地址的地方,所以当函数完成时,指令点