更新时间:2021-07-08 GMT+08:00
分享

内存合法性检查

使用场景

业务发生踩内存导致内存节点控制头被踩,长时间后才触发业务异常,业务逻辑复杂,难以定位发生踩内存的位置。

功能说明

开启该功能后,在动态内存申请接口中增加内存合法性检查,对动态内存池中所有节点控制头的合法性进行检查,若已发生动态内存节点被踩,及时触发异常,输出error信息,缩小问题定位范围。

使用方法

  1. 通过make menuconfig打开内存合法性检查。
    功能依赖LOSCFG_BASE_MEM_NODE_INTEGRITY_CHECK,使用时在菜单项中开启“Enable integrity check or not”:
    Debug  ---> Enable a Debug Version ---> Enable MEM Debug ---> Enable integrity check or not
  2. 发生踩内存后,下一次内存申请操作即触发异常,并给出被踩节点和前一节点信息,可初步分析定位是否是前一节点越界踩内存。踩内存发生范围为上一次内存申请和此次内存申请之间。异常信息可以通过执行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)。

相关文档