Page 1 of 1

IDF4.2.1的编译器优化bug导致panic,可能涉及所有idf版本。[IDFGH-5389]

Posted: Thu Jun 10, 2021 12:36 pm
by QQ26750452
芯片:ESP32-D0WDQ6
IDF版本:v4.2.1
开发环境:tools for windows,cmake。


这几天在写一个项目,同时用到uart和ota功能。当uart发送数据时,同时进行ota升级,就会产生panic。
经过长时间的追踪和分析,已经确认了bug原因,并采取了临时补救措施。
下面是错误分析过程:
esp\esp-idf\components\driver\uart.c
这个文件里有uart_rx_intr_handler_default函数,它是布局在IRAM里的代码,这是为了在cache禁用期间能处理uart中断请求。
它有一个分支,执行了uart_hal_is_tx_idle宏(其实这个宏是uart_ll_is_tx_idle的别名),请看下面:
esp\esp-idf\components\soc\include\hal\uart_hal.h

Code: Select all

#define uart_hal_is_tx_idle(hal)  uart_ll_is_tx_idle((hal)->dev)
而uart_ll_is_tx_idle定义在如下文件:
esp\esp-idf\components\soc\src\esp32\include\hal\uart_ll.h

Code: Select all

static inline bool uart_ll_is_tx_idle(uart_dev_t *hw)
{
    typeof(hw->status) status = hw->status;
    return ((status.txfifo_cnt == 0) && (status.st_utx_out == 0));
}
它是一个inline函数。我们都认为inline关键字,会告诉编译器内联此函数,于是它的代码会被展开到调用方函数体内,
比如uart_rx_intr_handler_default函数在IRAM内,那么uart_ll_is_tx_idle的逻辑也就在IRAM里,事实上这是理想状态而已。
就是这个假设引起了bug!
我观察的现象为:uart.c里有三处代码调用了uart_ll_is_tx_idle内联函数,但是在编译器配置为-Os的情况下,它自作聪明地把uart_ll_is_tx_idle函数编译成非内联函数!估计3处调用,编译为非内联可以节省空间吧?于是uart_ll_is_tx_idle函数实体就被默认安排在flash地址空间了,不再是安全的IRAM里!这就导致uart中断里执行了flash代码,而同时ota禁用cache的话就发生panic了。
bug复现方式就是把sdkconfig文件里优化配置为CONFIG_COMPILER_OPTIMIZATION_SIZE=y,然后观察uart_ll_is_tx_idle是否内联;在readelf -s导出的标号里,也能看到uart_ll_is_tx_idle,并且是在flash地址段。
我的临时解决方法是:在uart.c文件里加一行声明,强制uart_ll_is_tx_idle内联(它比关键字inline靠谱!)

Code: Select all

static inline bool uart_ll_is_tx_idle(uart_dev_t *hw) __attribute((always_inline));
或者把CONFIG_COMPILER_OPTIMIZATION_SIZE取消,设置为CONFIG_COMPILER_OPTIMIZATION_PERF=y也行。
但是通过改编译优化等级来解决问题并不科学,这说明代码经不起优化,而且指不定引入其它隐秘的bug呢?
所以我期待乐鑫技术团队能更新idf,用__attribute((always_inline))代替并非强制的inline关键字。
描述提交bug很累人,但作为乐鑫开发者,不得不反馈bug,这是双赢的好事。谢谢!

Re: 【BUG提交】IDF4.2.1的编译器优化bug导致panic,可能涉及所有idf版本。

Posted: Fri Jun 11, 2021 2:53 am
by ESP_Gargamel
非常感谢你的反馈,已让内部同事确认。

Re: 【BUG提交】IDF4.2.1的编译器优化bug导致panic,可能涉及所有idf版本。[IDFGH-5389]

Posted: Fri Jun 11, 2021 10:40 am
by QQ26750452
如果需要我排错过程中的截图,可以在这里找到
https://www.esp32.com/viewtopic.php?f=25&t=21379
祝工作愉快,端午Happy!

Re: 【BUG提交】IDF4.2.1的编译器优化bug导致panic,可能涉及所有idf版本。[IDFGH-5389]

Posted: Mon Jun 14, 2021 1:36 pm
by QQ26750452
补充编译器版本:
xtensa-esp32-elf@esp-2020r3-8.4.0
我上网查了一下资料,都说C/C++的inline关键字不是强制内联,而是由编译器根据不同的优化等级、函数大小、调用次数来决定的
这在其它系统上不会造成问题,但是在ESP32平台上是不允许的!因为在IDF中,各外设驱动代码的中断处理函数必须在IRAM中,这样才能在cache禁用期间处理中断请求。ISR调用了大量的inline函数,如果这些inline函数最终没有被内联,就会被安排在flash中。于是就导致在cache禁用期间,中断代码执行了flash中的代码,从而引起panic。