有没有办法在运行时检测堆栈溢出? (c++)

Posted

技术标签:

【中文标题】有没有办法在运行时检测堆栈溢出? (c++)【英文标题】:Is there a way to detect a stack overflow during runtime? (c++) 【发布时间】:2021-11-10 02:38:01 【问题描述】:

我有一个 massive 递归函数,它可以根据用户输入轻松溢出系统,我想知道是否有方法可以检测您是否即将用完调用堆栈空间运行。有没有办法检查我是否要炸毁堆栈,以便我可以终止/做其他事情?

【问题讨论】:

在 linux 上,如果你 #include <sys/resource.h> 并说 struct rlimit l; getrlimit(RLIMIT_STACK, &l); std::cout << l.rlim_cur; 它会给你堆栈空间。也许使用这个大小来查看用户输入是否大于这个? (我不确定是否有确定堆栈空间的标准)。或者使用带有大小限制的std::stack<> 你能把函数重写为非递归的吗?您应该可以使用循环和std::stack @Galik 我已经编写了该函数的非递归版本。这是出于学习目的。我只是想知道有没有可能。 @NeonFire 我目前使用的是 Windows 系统,但无论如何这都是有用的信息。谢谢! 在进行软件设计时,您还应该考虑要将哪些资源(内存/堆栈空间/....)分配给软件的哪些部分。所以我能想到的最简单的方法是不检测而是预防。首先考虑一下您想要“吃掉”多少堆栈内存,然后为您的递归深度设置一个最大值,并将其添加到您的递归结束条件中。如果您可以更好地预先计​​算递归深度,因为这样您就可以阻止递归甚至开始,将所有这些资源留给系统中的其他事物。 【参考方案1】:

在某些情况下,我们更喜欢使用递归函数。但是,如果递归函数在某些环境中过于深入,例如在 Visual C++ 代码中,可能会出现不需要的结果,例如堆栈溢出。与您的相同,只是我们将递归函数转换为带有堆栈的 while 循环。你可以检查实现here

实际上并没有通用的方法来检测系统堆栈大小,因为每个编译器都有不同的堆栈大小,其中一些具有可调整的堆栈大小。

您可以检查不同的尺寸如下:

glibc i386, x86_64: 7.4 MB
Tru64 5.1: 5.2 MB
Cygwin: 1.8 MB
Solaris 7..10: 1 MB
MacOS X 10.5: 460 KB
AIX 5: 98 KB
OpenBSD 4.0: 64 KB
HP-UX 11: 16 KB

由于它是运行时错误,因此您也无法使用try-catch 语句捕获,但您可以实现预防逻辑。

#include <stdio.h>

// These will be set at the top of main()
static char * _topOfStack;
static int _maxAllowedStackUsage;

int GetCurrentStackSize()

   char localVar;
   int curStackSize = (&localVar)-_topOfStack;
   if (curStackSize < 0) curStackSize = -curStackSize;  // in case the stack is growing down
   return curStackSize;


void MyRecursiveFunction()

   int curStackSize = GetCurrentStackSize();
   printf("MyRecursiveFunction:  curStackSize=%i\n", curStackSize);

   if (curStackSize < _maxAllowedStackUsage) MyRecursiveFunction();
   else
   
      printf("    Can't recurse any more, the stack is too big!\n");
   


int main(int, char **)

   char topOfStack;
   _topOfStack = &topOfStack;
   _maxAllowedStackUsage = 4096;  // or whatever amount you feel comfortable allowing

   MyRecursiveFunction();
   return 0;

【讨论】:

根据问题下的 cmets,OP 已经知道他们可以将其函数转换为使用堆栈对象而不是系统堆栈。 请注意,用不相关对象的地址减去一个对象的地址的行为在技术上是未定义的。【参考方案2】:

有没有办法在运行时检测堆栈溢出? (c++)

没有标准的方法可以知道有多少可用的堆栈空间,也没有标准的方法可以知道已经消耗了多少堆栈,也没有标准的方法可以知道函数调用将如何消耗堆栈。

总结:没有检测潜在堆栈溢出的标准方法。

【讨论】:

以上是关于有没有办法在运行时检测堆栈溢出? (c++)的主要内容,如果未能解决你的问题,请参考以下文章

如何在 c / c++ 程序中检测可能/潜在的堆栈溢出问题?

预先在运行时检测堆栈溢出

堆栈缓冲区溢出(Windows,C++):如何检测罪魁祸首?

使用 c++ 偶尔检测到 *** 堆栈粉碎***

怎么防止堆栈溢出

怎么解决 LINUX 堆栈溢出内存的问题