Visual c++ 由于ntdll,在重试异常时发生堆栈溢出!RcConsolidateFrame(x64)

Visual c++ 由于ntdll,在重试异常时发生堆栈溢出!RcConsolidateFrame(x64),visual-c++,64-bit,try-catch,stack-overflow,rethrow,Visual C++,64 Bit,Try Catch,Stack Overflow,Rethrow,我正在努力处理堆栈溢出异常,该异常在重新触发另一个异常时发生。rethrown异常用于在递归函数调用自身超过一定次数后拆除调用堆栈。(防止发生堆栈溢出) 我设法写了一个小程序,再现了这个问题。只有当我使用x64(发布和调试)编译程序时,才会出现这种情况。 我用MSVS2012和MSVS2013测试了这个代码段(StackSize=1MB-默认值)。 对于G++来说,在大约5000次调用之后,同样的问题也会发生 代码: 注:框架尺寸位于下一行的第二列 ntdll的框架!RcConsolidateF

我正在努力处理堆栈溢出异常,该异常在重新触发另一个异常时发生。rethrown异常用于在递归函数调用自身超过一定次数后拆除调用堆栈。(防止发生堆栈溢出)

我设法写了一个小程序,再现了这个问题。只有当我使用x64(发布和调试)编译程序时,才会出现这种情况。
我用MSVS2012和MSVS2013测试了这个代码段(StackSize=1MB-默认值)。 对于G++来说,在大约
5000次调用之后,同样的问题也会发生

代码:

注:框架尺寸位于下一行的第二列
ntdll的框架!RcConsolidateFrames
的大小为
0xf7970
(1.014.128)字节,因此占1MB总可用堆栈大小的96%

最让我头疼的是,在调用堆栈用完之前,我可以(如剪报中所述)递归调用函数近10.600次,而另一次调用会导致堆栈溢出。但是,如果我在超过120次调用后使用exoption中止递归,我将再次得到堆栈溢出,这是此异常旨在防止的。
因此,使用更大的堆栈编译程序只会将问题转移到略高的常量。 如前所述,此问题仅在x64编译时出现。如果使用Win32编译,一旦抛出
std::exception
,程序就不会遇到堆栈溢出

在堆栈展开过程中分配的堆栈空间比释放的堆栈空间多,程序有什么意义?
我如何解决这个问题?
由于这只是一个非常简化的情况,我不能简单地用原始应用程序中的特殊返回值替换
抛出

编辑:Microsoft只是删除了该请求,没有提供任何帮助。我收到了以下答复,要求提供更多细节,但在我答复后一天,该请求被删除

谢谢你报道这个问题。虽然大堆栈使用率并不理想,但它是如何在Windows非x86平台上实现EH的一个重要结果。需要注意的一点是,RcConsolidateFrames下的堆栈用法有点误导。该函数的要点是使展开器隐藏一组中间帧,以便堆栈使用情况反映运行的EH机制的105个实例(每个执行的重试一个实例)以及所有递归子调用

您能否分享更多关于这种高堆栈使用正在阻止的真实场景的信息?解决这一问题可能并不容易,但如果我们能够对重要的场景做出一些简化假设,就有可能改进这一点

谢谢,
Neeraj Singh VC++编译器后端开发人员

同时,尽管我希望,问题将在于重新引用机制,它一次又一次地重新引用在堆栈上分配的相同异常对象。我想是其中一个

  • 复制异常并引发异常的副本
  • 正在引发异常,使用
    new

无法解决此问题,但结果没有差异。

的异常模型与x86的异常模型大不相同。您说过这是一个简单的例子,但我很难想象递归抛出异常可能是多么明智的设计。@CodyGray实际应用程序是一个语言解释器。如果解释的代码包含太多嵌套调用,无法释放调用堆栈并将控制权优雅地返回到顶级执行事件处理程序,则会引发异常。@HansPassant感谢对
\u resetstkoflw
的提示,我至少知道如何从堆栈溢出中恢复。您能否更具体地说明8KB的堆栈保留空间,以及这是什么意思?在解开105个调用堆栈后,我希望有超过8KB的可用空间。你是说可以递归调用的函数不能包含try-catch/rethrow吗?这似乎是对语言的严重限制。@HansPassant好的,所以我的代码在出现这种情况时没有展开任何帧。即使每个被调用函数的堆栈帧仍然在堆栈上,我也不明白为什么堆栈会溢出,因为在调用堆栈因递归调用而溢出之前,我最多可以调用递归函数10.600次。因此,当堆栈上有120个调用帧时,堆栈应最多使用2%。为什么在调用堆栈中重新调用异常时会发生如此显著的变化?所有这些空间都是用来做什么的?对不起,我一直在发布非常误导性的评论,太关注SO了。它似乎很难在嵌套帧中活动的catch子句之后展开帧。没有太多的合并。不漂亮。在VS2017中仍然是一个问题,因此从技术上讲,Microsoft支持可以帮助您深入挖掘根本问题。如果不是紧急情况,请使用connect.microsoft.com。
#include <iostream>
using namespace std;

void recursiveFunction(int childCalls) {
  cout << "Recursive call, left calls: " << childCalls << endl;
  if (childCalls == 0) {
    cout << "Throwing std::exception" << endl;
    throw std::exception("Target depth reached");
  }

  try {
    recursiveFunction(childCalls - 1);
  } catch (std::exception&) {
    cout << "Caught exception at level: " << childCalls << endl;
    throw; //Simply rethrow exception
  }
}

int main() {
  //How many calls cause a stack overflow during unwinding with x64
  const int calls = 120; 

  //How many recursive calls I can make before the call stack overflows due to recursive calls
  //const int calls = 10600; 

  cout << "Initiating " << calls << " recursive calls" << endl;
  recursiveFunction(calls);
}
Initiating 120 recursive calls
Recursive call, left calls: 120
Recursive call, left calls: 119
Recursive call, left calls: 118
...
Recursive call, left calls: 2
Recursive call, left calls: 1
Recursive call, left calls: 0
Throwing std::exception
Caught exception at level: 1
Caught exception at level: 2
Caught exception at level: 3
...
Caught exception at level: 104
Caught exception at level: 105  <-- Stack overflow here!!!
0:000> knf
 #   Memory  Child-SP          RetAddr           Call Site
00           00000065`d5c37260 00007ffc`5ac10658 MSVCR110D!_chkstk+0x37
01        18 00000065`d5c37278 00007ffc`5ac105bf MSVCR110D!write_nolock+0x18
02         8 00000065`d5c37280 00007ffc`5ab23db1 MSVCR110D!write+0x21f
...
0a        f0 00000065`d5c37710 00007ffc`5ac09150 Crashtest!`recursiveFunction'::`1'::catch$0+0x26
0b        40 00000065`d5c37750 00007ffc`5abf93f2 MSVCR110D!CallSettingFrame+0x20
0c        30 00000065`d5c37780 00007ffc`7dd3a193 MSVCR110D!_CxxCallCatchBlock+0x162
0d        a0 00000065`d5c37820 00007ff7`f14714ca ntdll!RcConsolidateFrames+0x3
0e     f7970 00000065`d5d2f190 00007ff7`f14714ca Crashtest!recursiveFunction+0xba
0f        60 00000065`d5d2f1f0 00007ff7`f14714ca Crashtest!recursiveFunction+0xba
...