【问题标题】:Stack overflow happening when changing a line which is never reached - why and how to prevent it?更改从未到达的行时发生堆栈溢出 - 为什么以及如何防止它?
【发布时间】:2020-05-08 16:04:41
【问题描述】:

我正在使用 Zephyr 在嵌入式环境中开发一些东西。

基本上我正在处理由堆栈溢出引起的引导循环。当我在 main 内部更改函数调用的 unused 参数时,堆栈溢出消失了。为了确保问题不在函数内部,我将其实现硬编码为return 0;

这样的违规行会创建一个引导循环:

uint8_t port;
ret = foo(&port, NULL, NULL);

但是缺少取消引用端口的那行代码运行正常:

uint8_t port;
ret = foo(NULL, NULL, NULL);

请注意,正如我已经说过的,foo 的实现被硬编码为返回 0。参数在任何时候都没有使用。此外,我确信在运行时(在这种情况下)实际上永远不会到达这条线,因为它存在于一些需要我的交互实际通过的条件之后。

我已经开始放弃并将事情归咎于内存故障或 ESD 损坏,但是当我在备用硬件上尝试相同的代码并进行相同的更改时,同样的事情发生了。我错过了什么?我真的不知道我还能做些什么来找出为什么会发生这种情况以及如何解决它。我无法访问此微控制器 (SAMD21) 的调试器,所以我有点不知所措……有什么想法(或至少同情)吗?

【问题讨论】:

  • 您是否尝试查看汇编代码?由于某种原因,编译器可能生成了完全不同的代码。
  • 查看汇编程序,在堆栈上放置一个哨兵,看看您离溢出有多近,并仔细查看您的映射文件以确保一切都符合您在内存中的想法。如果事情真的非常接近溢出,那么减少大小或重组内存。
  • 你可以在运行时检查标记值,仔细使用 printf() :)
  • @MichaelDorgan 在这种情况下它不起作用,因为引导循环会阻止 printf() 甚至执行!
  • 通常未定义的行为,尤其是堆栈溢出,往往会导致当您更改不相关的代码行时,您会暴露或隐藏问题。但这并不意味着特定线路是违规者,问题可能在任何地方。在像 SAMD 这样的现代 M0+ + 一个不错的调试器上,应该可以在堆栈底部设置一个写断点,然后你会确切地看到代码出错的地方,包括指令跟踪。这意味着您将在 20 分钟而不是 1 周内解决错误。

标签: c pointers embedded stack-overflow


【解决方案1】:

当您删除该参数时,它是否运行没有任何错误或是否有其他错误?如果您在程序中的某处写入错误的内存(例如分配大小为零的内存),则更改程序代码的不相关部分,例如更改结构的大小或函数的参数,可能会改变发生致命错误的位置以及致命错误的类型。

【讨论】:

    【解决方案2】:

    没关系,我找到了罪魁祸首 - 一个简单的堆栈溢出。在将 uint8_t port 变量声明添加到 main 之前,我离它只有一个字节。在foo() 中未用作参数时的变量已被编译器优化掉。调用堆栈上少一个字节显然足以防止溢出。

    解决方案:增加堆栈大小并更加小心地用不必要的项目堵塞它。

    【讨论】:

      猜你喜欢
      • 2010-09-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-07-01
      • 1970-01-01
      • 2014-09-19
      • 1970-01-01
      • 2012-02-03
      相关资源
      最近更新 更多