是否有一种程序化的方法来检查堆栈损坏

Alp*_*neo 9 c embedded stack multithreading itron

我正在使用多线程嵌入式应用程序.每个线程根据其功能分配堆栈大小.最近我们发现其中一个线程通过定义一个超过堆栈大小的局部变量数组来破坏堆栈.操作系统是uItron.

我的解决方案,我注册了一个10 mS的计时器,这个计时器将检查堆栈损坏.

堆栈损坏检查方法,1.用一些独特的模式初始化堆栈内存(我使用0x5A5A5A5A)2.从时间检查堆栈内存的顶部是否仍为0x5A5A5A5A

我的问题,

有没有更好的方法来检查这种类型的腐败

忘记添加,立即添加:操作系统:Itron,处理器:ARM9.编译器:不是GCC(特定于ARM9由处理器供应商提供)......并且没有内置支持堆栈检查......

lea*_*der 8

ARM9在片上有JTAG/ETM调试支持; 您应该能够设置一个数据访问观察点,覆盖堆栈顶部附近的64字节,然后触发数据中止,您可以在程序中或外部捕获.

(我使用的硬件仅支持2个读/写观察点,不确定这是否是片上内容或周围第三方调试工具的限制.)

本文档是关于如何与JTAG功能接口的极低级别描述,建议您阅读处理器的技术参考手册 - 我可以保证在第9章中有相当数量的高级信息("Debug"支持ARM946E-S r1p1 TRM.

在您深入了解所有这些内容之前(除非您只是为了娱乐/教育而做),请仔细检查您使用的硬件和软件是否已经无法为您管理断点/观察点.在我们使用的调试软件中,"观察点"的概念有点难以找到 - 它是添加断点对话框中标有"硬件"的标签.


另一种选择:你的编译器可能支持一个命令行选项,在函数的入口和出口点添加函数调用(某种"void enterFunc(const char*callingFunc)"和"void exitFunc(const char*callingFunc)") ,用于功能成本分析,更准确的堆栈跟踪或类似.然后,您可以编写这些函数来检查堆栈的金丝雀值.

(顺便说一下,在我们的例子中,我们实际上忽略了传入的函数名称(我希望我可以让链接器去除它们)并且只使用处理器的链接寄存器(LR)值来记录我们来自哪里.我们使用这是为了获得准确的调用跟踪以及分析信息;此时检查堆栈金丝雀也是微不足道的!)

问题是,当然,调用这些函数会稍微改变函数的寄存器和堆栈配置文件......在我们的实验中并不多,但有点.性能影响更严重,并且只要存在性能影响,程序中就会出现行为更改的可能性,这可能意味着您例如避免触发您之前可能遇到的深度递归情况......


更新很晚:如果你有一个基于clang + LLVM的管道,你可能可以使用Address Sanitizer(ASAN)来捕获其中一些.请注意编译器中的类似功能!(值得了解UBSAN和其他消毒杀菌剂.)


bri*_*gge 6

你用的是什么编译器?我猜一个特定于操作系统的.如果您正在使用GCC,您可以使用Stack-Smashing Protector.这可能是您的生产系统可以解决问题的解决方案,也可以让您在开发过程中检测它.

要有效地检查堆栈损坏,您需要检查可用的堆栈空间,在呼叫之前在堆栈参数的两侧放置防护,拨打电话,然后检查呼叫返回时的警卫.这种更改通常需要修改编译器生成的代码.

  • 请注意,如果你感觉特别阴险,你通常可以让GCC生成中间程序集,调整一下,然后让你的专有/封闭汇编程序咀嚼它.之前我已经完成了,因为GCC的asm生成比我在特定情况下使用的联赛更快. (2认同)

cig*_*man 4

最近在嵌入式平台上工作时,我四处寻找实现此目的的方法(这是在 ARM7 上)。

建议的解决方案是您已经想到的:使用已知模式初始化堆栈,并确保从函数返回后该模式存在。我认为同样的事情“必须有更好的方法”和“没有人自动化这个”。这两个问题的答案都是“否”,我必须像您所做的那样深入挖掘,试图找出腐败发生的地方。

我还为 data_abort 等“推出了我自己的”异常向量。网上有一些关于如何回溯调用堆栈的很好的示例。您可以使用 JTAG 调试器执行此操作,在发生任何这些中止向量时中断,然后调查堆栈。如果您只有 1 或 2 个断点(这似乎是 ARM JTAG 调试的标准),这会很有用。