嵌入式系统中的堆溢出检测/预防

时间:2017-03-26 22:21:44

标签: c embedded

我最近因为在嵌入式系统上超越堆而被咬了几次。

这通常是由于写入在堆上声明的数组超过数组的大小,这必须超出其他堆声明的变量,然后导致非常不确定的行为 - 使根本原因难以追踪。

是否有任何方法可以检测/防止嵌入式系统上的这类堆溢出错误?我正在为STM32平台开发,但很高兴知道任何一般方法。我很高兴听到在运行时发现溢出的方法或在编译之前可以发现溢出的静态分析方法。

请注意,因为这是在嵌入式系统上运行的代码,所以malloc的使用很少 - 大多数堆变量是静态或全局声明的,而不使用malloc

3 个答案:

答案 0 :(得分:2)

我一直在问你的问题,直到你到达最后一段,似乎对你称之为“堆”的东西感到困惑。所以我假设大多数问题都是在访问数组边界外的内存时发生的,无论数组的内存实际驻留在哪里。

这是我通常尝试做的事情:

  1. 永远不要使用malloc。它通常不是在嵌入式微控制器代码中完成的。判断是否是好事或坏事。意见各不相同,但我只是远离它。最坏的情况分配会浪费一些内存,但一般来说,我发现针对微控制器的应用程序可以找到数组大小的合理界限。
  2. 尝试将系统特定于独立于平台。对于访问硬件等尤其如此。不要直接做;使用一些硬件层,目前通常由芯片制造商提供。
  3. 对于独立于平台的部分,您现在可以存根系统特定部分并编译代码以在桌面上运行。在那里,您可以访问各种工具来分析正在发生的事情。您可以访问不能在微控制器上运行的静态分析器。您还可以进行更好的代码覆盖率分析,更多的测试更容易实现自动化。您可能会遇到桌面和微控制器之间的可移植性问题,但我没有发现这是一个大问题。细致,便携的编码是关键。
  4. 现在,这是更多的工作,当然,考虑到这些想法,开始项目肯定会有所帮助。但是多年来我发现在我可以带来更好的工具而不是尝试改进嵌入式环境本身的环境中尝试运行嵌入式代码更容易。

答案 1 :(得分:0)

Malloc可以溢出堆使用,即使不使用也可能导致内存碎片,但是您的测试代码应该能够检测出内存不足错误。通过引用传递的递归函数调用可以溢出堆栈使用。如果使用设定值初始化整个堆栈/堆,则可以扫描它们以查看测试期间使用了多少(例如填充0x3F,测试后查看其中有多少已损坏' )。设置测试用例,最大限度地提高使用率,以获得不会溢出的信心。

1)如果内存充足,请扩展堆栈/堆的大小。

2)如果内存紧张,只考虑静态分配,不要使用malloc的库函数。减少函数深度并避免递归。考虑将较大的局部函数变量推送到全局变量。

答案 2 :(得分:0)

我同意不要在微控制器上尽可能使用malloc。尽管每个人都不这么认为,全局变量的大小是固定的,并且在编译时你知道你的用法是什么。局部变量和函数是极其内存有限的平台上的杀手,因此您必须仔细考虑您创建的每个局部变量以及函数的嵌套程度。只要你不进行递归,你就应该能够通过分析确定你的最坏情况函数嵌套路径,然后消耗多少堆栈。全局在编译时是固定的并且是已知的,但是如果太多而且每个函数都没有大量使用,那么它可能是浪费的。本地是动态的,如果你不这样做,你的分析可能会崩溃到.data或.bss,添加代码来检测只是因为你的闪存非常有限而且性能有限。

你可以尝试valgrind方法(通常用堆填充ram的未声明部分并使用已知值监视堆栈以查看堆栈深入到内存中并通过正常函数嵌套修改该ram)但可能不同,使用链接器脚本将缓冲区放在.data / .bss的顶部,其中堆通常会启动,在那里写一组已知的值,有一个中断快速检查以查看顶部值是否更改,崩溃/刻录/保释/如果是无限循环,走遍堆栈看看你如何嵌套你的方式。

或者只是使用很多全局变量而不必担心它。