为什么会出现调试异常原因:堆栈金丝雀观察点已触发(主要)?
Why do I get the Debug exception reason: Stack canary watchpoint triggered (main)?
我正在使用 esp-idf-v3.0
为 esp32-wroom-32
编写程序。
我正在尝试添加日志,这些日志将保存在 fatfs.
在一些日志之后我得到:
21:54:21.306 -> Debug exception reason: Stack canary watchpoint triggered (main)
21:54:21.306 -> Register dump:
21:54:21.306 -> PC : 0x40089827 PS : 0x00060b36 A0 : 0x40082179 A1 : 0x3ffd3860
21:54:21.340 -> A2 : 0x3ff40000 A3 : 0x00000033 A4 : 0x00000033 A5 : 0x00000000
21:54:21.340 -> A6 : 0x00000024 A7 : 0xff000000 A8 : 0xe37fc000 A9 : 0x0000007e
21:54:21.340 -> A10 : 0x00000000 A11 : 0xffffffff A12 : 0x00000004 A13 : 0x00000001
21:54:21.340 -> A14 : 0x00000005 A15 : 0x00000000 SAR : 0x00000004 EXCCAUSE: 0x00000001
21:54:21.340 -> EXCVADDR: 0x00000000 LBEG : 0x400014fd LEND : 0x4000150d LCOUNT : 0xfffffff6
为什么会发生在 main 上?
FreeRTOS 任务堆栈深度
这很可能是由您的 FreeRTOS 任务中的堆栈溢出引起的。
增加堆栈深度
我要做的第一件事是 增加 FreeRTOS 任务的堆栈深度。例如,如果您创建的任务的堆栈大小为 configMINIMAL_STACK_SIZE
,这可能低至 768 字节 - 这不足以满足许多常见要求。
堆栈深度增加多少?
回答这个问题并不容易,但是 - 在这种情况下 - 简单地增加它可能就足够了,直到你不再有堆栈溢出。如果您担心不会不必要地浪费内存,FreeRTOS includes a mechanism 可以让您知道任务即将溢出其堆栈的程度。
缓冲区和金丝雀
A canary 只是缓冲区末尾的标记 - 会定期检查。如果它从默认值更改,则意味着程序已尝试写入超出缓冲区的末尾 - 即存在缓冲区 溢出.
通过更改配置中的两个选项(在 Component Config
-> FreeRTOS
部分下),在 ESP IDF 中启用使用金丝雀检测堆栈溢出:
- 'Check for stack overflow' -> 'using canary bytes'
- 'Set a debug watchpoint as a stack overflow check' -> 启用
如果您禁用第二个选项,您将收到 Guru Meditation 错误 - LoadProhibited
异常 - 在堆栈溢出的情况下。
xTaskCreate()
和堆栈深度
请记住,ESP IDF 中 xTaskCreate()
的版本与原始 FreeRTOS 中的不同。在原始的 FreeRTOS 中,堆栈深度为 specified in words. In the ESP IDF, it's specified in bytes。 非常 重要的区别!
我正在使用 esp-idf-v3.0
为 esp32-wroom-32
编写程序。
我正在尝试添加日志,这些日志将保存在 fatfs.
在一些日志之后我得到:
21:54:21.306 -> Debug exception reason: Stack canary watchpoint triggered (main)
21:54:21.306 -> Register dump:
21:54:21.306 -> PC : 0x40089827 PS : 0x00060b36 A0 : 0x40082179 A1 : 0x3ffd3860
21:54:21.340 -> A2 : 0x3ff40000 A3 : 0x00000033 A4 : 0x00000033 A5 : 0x00000000
21:54:21.340 -> A6 : 0x00000024 A7 : 0xff000000 A8 : 0xe37fc000 A9 : 0x0000007e
21:54:21.340 -> A10 : 0x00000000 A11 : 0xffffffff A12 : 0x00000004 A13 : 0x00000001
21:54:21.340 -> A14 : 0x00000005 A15 : 0x00000000 SAR : 0x00000004 EXCCAUSE: 0x00000001
21:54:21.340 -> EXCVADDR: 0x00000000 LBEG : 0x400014fd LEND : 0x4000150d LCOUNT : 0xfffffff6
为什么会发生在 main 上?
FreeRTOS 任务堆栈深度
这很可能是由您的 FreeRTOS 任务中的堆栈溢出引起的。
增加堆栈深度
我要做的第一件事是 增加 FreeRTOS 任务的堆栈深度。例如,如果您创建的任务的堆栈大小为 configMINIMAL_STACK_SIZE
,这可能低至 768 字节 - 这不足以满足许多常见要求。
堆栈深度增加多少?
回答这个问题并不容易,但是 - 在这种情况下 - 简单地增加它可能就足够了,直到你不再有堆栈溢出。如果您担心不会不必要地浪费内存,FreeRTOS includes a mechanism 可以让您知道任务即将溢出其堆栈的程度。
缓冲区和金丝雀
A canary 只是缓冲区末尾的标记 - 会定期检查。如果它从默认值更改,则意味着程序已尝试写入超出缓冲区的末尾 - 即存在缓冲区 溢出.
通过更改配置中的两个选项(在 Component Config
-> FreeRTOS
部分下),在 ESP IDF 中启用使用金丝雀检测堆栈溢出:
- 'Check for stack overflow' -> 'using canary bytes'
- 'Set a debug watchpoint as a stack overflow check' -> 启用
如果您禁用第二个选项,您将收到 Guru Meditation 错误 - LoadProhibited
异常 - 在堆栈溢出的情况下。
xTaskCreate()
和堆栈深度
请记住,ESP IDF 中 xTaskCreate()
的版本与原始 FreeRTOS 中的不同。在原始的 FreeRTOS 中,堆栈深度为 specified in words. In the ESP IDF, it's specified in bytes。 非常 重要的区别!