c++堆栈溢出问题?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了c++堆栈溢出问题?相关的知识,希望对你有一定的参考价值。

首先是一个MFC应用程序(typedef unsigned char BYTE),出现问题的函数的定义是int PatternMatch2(BYTE *lp, BYTE *lp, BYTE *lpAll, int *lpScore)
点击按钮执行这个函数:
PatternMatch2(lp1, lp2, lpAll2, &score);
实参定义:
BYTE lp1[430];
BYTE lp2[430];
BYTE lpAll2[1000*1000];
int score;
提示:0x002B2139 处有未经处理的异常(在 StaticFPSys.exe 中): 0xC00000FD: Stack overflow (参数: 0x00000000, 0x036F2000)。
调试过,只有lp1、lp2的地址传进去了,鼠标放上去有地址,lpAll和score两个参数鼠标放上去没用地址显示出来。
试过网上将堆栈保留大小改大的方法,要扩大到20M才可以,有没有其他方法?这样会不会有什么弊端?

这个代码导致堆栈溢出的语句是:
BYTE lpAll2[1000 * 1000],共100万字节
你可以用new 分配,这样堆栈里只放一个指针,不会有溢出的问题
BYTE *lpAll2 = new BYTE[1000 * 1000];
另外,反思一下是否真的需要这么大的数组,感觉上是可以优化的。
参考技术A 正常情况下这种大块的内存应该动态申请

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

【中文标题】有没有办法在运行时检测堆栈溢出? (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++)

C++ 堆栈溢出初始化数组

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

我在 C++ 程序中遇到堆栈溢出异常

过深的 C++ 类层次结构会导致堆栈溢出吗?