【问题标题】:Could VS warn about possible stack overflow exceptions?VS 可以警告可能的堆栈溢出异常吗?
【发布时间】:2015-02-02 17:38:32
【问题描述】:

考虑以下代码(仅用于演示目的):

#include <iostream>

int main()
{
    char pixels[4][1280][720]; // Big enough to cause a stack overflow on my machine
    for (unsigned int i = 0; i < 4; i++)
    {
        for (unsigned int j = 0; j < 1280; j++)
        {
            for (unsigned int k = 0; k < 720; k++)
            {
                pixels[i][j][k] = i + j + k;
            }
        }
    }

    std::cout << pixels[2][640][360];
    return 0;
}

根据this question 上的回答,最大堆栈大小由Visual Studio 设置。

我是否正确假设它可以警告用户潜在的堆栈溢出? (我自己试过了,没有收到警告)

P.S:我问的唯一原因是因为我看到很多关于 SO 的问题可以通过这样的警告来避免(是的,我知道不是每个 SO 用户都使用 VS)。

【问题讨论】:

  • 评估复杂代码以准确了解它在不执行的情况下会做什么是圣杯之一。不要抱太大希望。
  • 你的意思是类似于 GCC -Wstack-usage=1234
  • @Fanael 我的意思是如果数组的大小(以字节为单位)大于堆栈限制,那么肯定会发生堆栈溢出。所以它可以就此发出警告。是的,似乎就是这样。
  • ​+1,当我打开带有大量 SIMD 对象的激进内联时,我总是遇到这个问题。我宁愿编译器在编译时警告我而不是在运行时崩溃。
  • 理论上是可以做到的。我这样做是为了在 IBM System/38 上实现 Pascal。问题是您实际上必须抛出异常,并且需要堆栈空间来处理,因此您必须为此“保留”大量堆栈。我发现如果你保留一半的堆栈用于异常处理,它确实只能以一种半途而废的方式发挥作用,而且,总的来说,在引发异常之前给应用程序更多的堆栈更有意义。

标签: c++ visual-studio stack-overflow


【解决方案1】:

编译器可以对几乎任何事情发出警告,但在这种情况下,编译器很难发出真正有意义的警告。

特别是,直到链接时间才真正选择堆栈大小。编译器在链接器之前运行,因此它基本上不可能知道您在运行链接器时可能选择的堆栈大小。因此,如果编译器要发出警告,它所能做的最好的事情就是假设将选择一些“合理”的堆栈大小,并将警告基于违反该大小。

一个足够智能的链接器可以发出这样的警告,但它需要相当多的智能。特别是,当链接器看到它时,堆栈分配看起来像(机器代码表示):

sub esp, 123456 ; or sub rsp, 123456 in 64-bit code.

链接器必须找到堆栈指针被操作的每个位置,并检查所涉及数字的大小以有意义地发出警告。为此,它基本上必须弄清楚什么是代码,什么是数据,然后反汇编和检查代码(但不是数据,这可能会反汇编成无意义的代码)。这一切都可能是可能的,但可能有点不重要,而且肯定远远超出了链接器通常做或处理的事情的范围。

【讨论】:

  • 我想知道是否有一个编译器选项会在单个函数使用过多堆栈时发出警告。因为当几级内联使编译器决定将大约 1000 个 SIMD 值放入堆栈时,我经常会破坏堆栈。
  • @Mysticial:正如 Andrew Medico 所指出的,/analyze 标志基本上按照我的第二段的建议:选择“合理”的大小,并在超出时警告您。大小默认为 16K,但您可以根据需要将其设置为其他大小,例如:/analyze:stacksize 65535,这将(显然)寻找 64K。
  • 我可能会尝试 1k 之类的东西,看看它抱怨什么。最大的烦恼是当编译器将大量内容内联到递归函数中时,我直到运行时才知道它。
  • 这个分析是有缺陷的,因为它忽略了合作的可能性。编译器可以实际发出堆栈使用数据,例如在单独的侧文件中。读取此文件的链接器可以创建部分调用图并确定已知调用图上的任何路径是否超过堆栈限制。挑战:循环——但这是我们理解的一个案例。即使只有一个变量,无限递归确实会导致堆栈溢出。
【解决方案2】:

在具有/analyze 标志可用的版本中已经这样做了:

C:\>cl /EHsc /analyze stack.cpp
Microsoft (R) C/C++ Optimizing Compiler Version 18.00.21005.1 for x64
Copyright (C) Microsoft Corporation.  All rights reserved.

stack.cpp
c:\stack.cpp(3) : warning C6262: Function uses '3686412' bytes of stack:  exceeds /analyze:stacksize '16384'.  Consider moving some data to heap.

DDK/WDK 附带的prefast 工具会产生类似的警告。

当然,这是一个非常简单的静态检查(如果函数的堆栈使用量高于某个阈值)。它不会尝试检测递归调用或通过调用链累加总静态使用量。

【讨论】:

  • Analyze 不是仅适用于 >$2,000 的版本吗?
  • 我相信以前的版本就是这种情况,但截至 VS 2013 all editions have it
猜你喜欢
  • 2021-04-07
  • 2018-07-24
  • 1970-01-01
  • 2010-11-27
  • 1970-01-01
  • 1970-01-01
  • 2016-02-19
相关资源
最近更新 更多