1、现象、问题描述
最近调试过程中,程序概率性出现Unable to handle kernel NULL pointer dereference at virtual address 访问空指针错误
2、关键过程、根本原因分析
最常见的两类panic错误如下:
Unable to handle kernel NULL pointer dereference at virtual address 访问空指针
Unable to handle kernel paging request at virtual address 访问不存在的地址
这两类错误都是_do_kernel_fault打印的,都是访问一个异常地址,区别只是访问大于PAGE_SIZE的就是paging request,小于PAGE_SIZE的就是NULL pointer dereference,PAGE_SIZE是4096,所以对这两种错误的定位流程是一样的。
这里采用objdump工具反汇编出错函数所在的.o文件导出分析
打开test.txt文件,搜索发生panic错误时提示的mcc_recvmsg_thread函数
根据搜索结果结婚发生错误时的mcc_recvmsg_thread+0x74/0x400信息计算出代码行0x1350-0x138+0x74=0x128c,继续搜索0x128c,得到结果
到对应的c文件中找到对应代码如下
可知在if(g_hi1610_dev_map[i]->vdd_checked_success != DEVICE_CHECKED_FLAG)发生了内存错误,于是在这里增加了判断后尝试复现,当if(NULL == g_hi1610_dev_map[i])时打印出g_local_handler全局变量的值用于定位。
g_local_handler全局变量初始化后的值如下:
当复现时抓取出g_local_handler全局变量的几个成员值如下:
可以看出,全局变量的成员值相比初始化后的数值已经被改写了,但是全局变量的指针地址没有变。于是开始了惨痛定位流程,尝试找出内存被踩的地方,但没有定位出来,最后进行代码走读,发现如下一段代码,在不定义MCC_PROC_ENABLE宏的情况下,函数会执行pci_register_drv_err及之后的代码,并且在释放g_local_handle指针后没有置NULL,这里有两个错误:一个是从业务层面看,正常执行时不应该执行pci_register_drv_err后的代码;一个是编程规范层面看,释放全局变量指针后需要置NULL。
3、结论、解决方案及效果
问题很低级,通过修改代码执行流程解决,当定位耗时较长,主要在于程序中使用了野指针导致定位时按照从内存被踩的角度出发,思路跑偏了。其实只要在平时写代码过程中牢记编程规范在释放全局变量指针后置空,这个问题就好定位出来了。
下图是在释放全局变量指针地址后置NULL重新复现的结果,可以看见在出错时有很明显的空指针提示,很容易指导定位
阅读(2958) | 评论(0) | 转发(0) |