堆栈大小估计

jer*_*ble 29 c c++ embedded stack static-analysis

在多线程嵌入式软件(用C或C++编写)中,必须为线程提供足够的堆栈空间,以使其能够完成其操作而不会溢出.在某些实时嵌入式环境中,正确调整堆栈大小至关重要,因为(至少在我使用过的某些系统中),操作系统不会为您检测到这一点.

通常,在创建线程时(即在pthread_create()等的参数中)指定新线程(除主线程之外)的堆栈大小.通常,这些堆栈大小被硬编码为在最初编写或测试代码时已知良好的值.

但是,对代码的未来更改通常会破坏硬编码堆栈大小所基于的假设,并且在一个重要的日子里,您的线程进入其调用图的更深层分支之一并溢出堆栈 - 从而导致整个系统崩溃或者默默地腐蚀记忆.

在线程中执行的代码在堆栈上声明struct实例的情况下,我个人已经看到了这个问题.当结构体被扩充以容纳额外数据时,堆栈大小相应地膨胀,可能允许堆栈溢出发生.我想这对于已建立的代码库来说可能是一个巨大的问题,其中无法立即知道向结构添加字段的全部效果(太多的线程/函数来查找使用该结构的所有位置).

由于对"堆栈大小"问题的通常响应是"它们不可移植",因此我们假设编译器,操作系统和处理器都是此调查的已知数量.我们也假设没有使用递归,所以我们没有处理"无限递归"场景的可能性.

有哪些可靠的方法来估计线程所需的堆栈大小?我更喜欢离线(静态分析)和自动方法,但欢迎所有想法.

zig*_*tar 17

运行时,评估

在线方法是使用特定值绘制整个堆栈,如0xAAAA(或0xAA,无论宽度是多少).然后,您可以通过检查多少绘画未受影响来检查堆栈在过去的最大增长量.

请查看链接以获取说明的说明.

优点是它很简单.缺点是您不能确定您的堆栈大小最终不会超过测试期间使用的堆栈数量.

静态评估

有一些静态检查,我认为甚至存在一个黑客gcc版本试图这样做.我唯一可以告诉你的是,在一般情况下,静态检查很难做到.

还看看这个问题.


swe*_*egi 12

如果您的目标符合要求,您可以使用StackAnalyzer等静态分析工具.

  • 好吧,如果您的处理器不受支持,则会再次出现"不便携"问题. (2认同)

小智 5

如果您想花大笔钱,可以使用商业静态分析工具,如Klocwork.虽然Klocwork主要用于检测软件缺陷和安全漏洞.但是,它还有一个名为"kwstackoverflow"的工具,可用于检测任务或线程中的堆栈溢出.我正在使用我工作的嵌入式项目,并且我得到了积极的结果.我不认为这样的工具是完美的,但我相信这些商业工具非常好.我遇到的大多数工具都在使用函数指针.我也知道像Green Hills这样的许多编译器供应商现在可以在他们的编译器中构建类似的功能.这可能是最好的解决方案,因为编译器非常了解做出有关堆栈大小的准确决策所需的所有细节.

如果你有时间,我相信你可以使用脚本语言来制作自己的堆栈溢出分析工具.该脚本需要识别任务或线程的入口点,生成完整的函数调用树,然后计算每个函数使用的堆栈空间量.我怀疑可能有免费工具可以生成一个完整的函数调用树,以便更容易.如果您知道平台生成堆栈空间的细节,则每个函数使用都非常简单.例如,PowerPC函数的第一个汇编指令通常是具有更新指令的存储字,该指令将堆栈指针调整为函数所需的量.您可以从第一条指令中获取字节大小,这使得确定使用的总堆栈空间相对容易.

这些类型的分析都将为您提供堆栈使用的最坏情况上限的近似值,这正是您想要了解的内容.当然,专家(就像我合作的那些人)可能会抱怨你分配了太多的堆栈空间,但他们是恐龙,不关心良好的软件质量:)

另一种可能性,虽然它不计算堆栈使用量,但是使用处理器的内存管理单元(MMU)(如果有的话)来检测堆栈溢出.我使用PowerPC在VxWorks 5.4上完成了这项工作.这个想法很简单,只需将一页写保护内存放在堆栈的最顶层.如果溢出,将发生处理器执行,您将很快收到堆栈溢出问题的警报.当然,它并没有告诉你需要多少增加堆栈大小,但如果您对调试异常/核心文件有好处,那么至少可以找出溢出堆栈的调用序列.然后,您可以使用此信息来适当增加堆栈大小.

-djhaus