内存合法性检查
使用场景
业务发生踩内存导致内存节点控制头被踩,长时间后才触发业务异常,业务逻辑复杂,难以定位发生踩内存的位置。
功能说明
开启该功能后,在动态内存申请接口中增加内存合法性检查,对动态内存池中所有节点控制头的合法性进行检查,若已发生动态内存节点被踩,及时触发异常,输出error信息,缩小问题定位范围。
使用方法
- 通过make menuconfig打开内存合法性检查。
- 发生踩内存后,下一次内存申请操作即触发异常,并给出被踩节点和前一节点信息,可初步分析定位是否是前一节点越界踩内存。踩内存发生范围为上一次内存申请和此次内存申请之间。异常信息可以通过执行Shell命令memcheck查看。
注意事项
该功能开启时,系统内存申请操作的性能下降明显,建议仅在定位问题时开启,默认关闭。
踩内存问题定位实例
通过构造超出内存长度的memset操作,构造越界踩内存,造成内存节点损坏,构造代码如下:
VOID SampleFunc(VOID *p) { memset(p, 0, 0x110); // 超出长度的memset,设置踩内存场景 } UINT32 Test(UINT32 argc, CHAR **args) { void *p1, *p2; p1 = LOS_MemAlloc((void*)OS_SYS_MEM_ADDR, 0x100); p2 = LOS_MemAlloc((void*)OS_SYS_MEM_ADDR, 0x100); dprintf("p1 = %p, p2 = %p \n", p1, p2); SampleFunc(p1); // 因为p1和p2相邻,当memset的长度超过p1的内存大小,就会越界踩到p2内存 LOS_MemFree(OS_SYS_MEM_ADDR, (void *)p1); LOS_MemFree(OS_SYS_MEM_ADDR, (void *)p2); return 0; }
执行上述代码后,执行Shell命令memcheck,其输出内容如下:
从上图可以看到打印了错误信息。
- 标记2所指“cur node:0x8034fbfc”表示该节点内存被踩,“pre node:0x8034faec”表示被踩节点前面的节点。标记3所示“pre node was allocated by task:SerialShellTask”表示在SerialShellTask任务中发生了踩内存。
- 标记1打印的是p1和p2内存的起始地址,“p2 = 0x8034fc0c”,减去控制头大小0x10,即p2-0x10=0x8034fbfc,就是cur node打印出的地址,即p2内存被踩。从代码可以看到p1和p2是两个相邻的节点(这也可以从打印的p1和p2地址看出来,即p1+p1的size+控制头大小=p2,0x8034fafc+0x100+0x10=0x8034fc0c),所以“pre node:0x8034faec”应该就是p1的地址,从标记1获取p1地址为“p1 = 0x8034fafc”,即pre node加上控制头大小0x10(0x8034faec+0x10=0x8034fafc)。