背景
最近公司有一次开始折腾新平台,这时上面找到我帮忙给这个平台适配一颗艾维的功放。相比较于其他家的功放,艾维的功放会提供全套参考源码和移植方法(rtos 到 安卓全平台都有),基本上只需要简单地修改一些对接函数就可以实现驱动地适配,在适配地过程中,出现了只要准备出声就会跑飞的问题。
排查过程
现象确认
平台特性,只要跑飞,就会一直打印乱码信息,有这个信息,一下就锁定了是跑飞了。
问题点排查
抓到的log显示是跑到了未分配的区域,结合跑飞信息,进一步分析跑飞时的系统栈信息,发现跑飞在一个无厘头的位置(跑飞位置是函数调用入口位置),从此位置并不能看出明显的内存异常
从跑飞位置看,没看出明显异常,此时观察跑飞前的打印,发现打印信息在栈信息指定的最后一次调用的函数内部实现位置,此时怀疑原厂提供的看栈信息的接口并未将最后一级信息给出。遂使用不管后续功能,直接屏蔽代码的方式进行夹代码,最终夹到这么一段
int aw882xx_device_start(struct aw_device *aw_dev) { ... if (aw_dev->ops.aw_reg_force_set) { aw_dev->ops.aw_reg_force_set(aw_dev); } ... return 0; }
此时再去全局搜索aw_reg_force_set,发现此功放对应的初始化此函数,而再看这个操作入口的内容,才发现原来是因为calloc被我改成了pvPortMalloc的实现,但未memset而导致的问题。
int aw882xx_pid_2013_dev_init(void *aw882xx_val) { ... // aw_pa = calloc(1, sizeof(struct aw_device)); aw_pa = pvPortMalloc(sizeof(struct aw_device)); if (aw_pa == NULL) { aw_dev_err(aw882xx->dev_index, "dev kalloc failed"); return -ENOMEM; } ... return ret; }
解决方法
问题点确认了,其实解决方法也就简单了,calloc和malloc的区别仅仅是calloc在申请完内存后,会把申请到的内存空间初始化成全0,因此解决方法就是在pvPortMalloc成功后,再去memset就可以规避问题
反思
不依赖标准库方案开发久了,对于标准库的接口实现具体细节很容易忘记,在平时编码过程中,一定要注意对旧知识点的复习和尝试新平台,在不断强化过程中降低出现问题的概率