不只是越界——泄漏、非法释放、未使用、未对齐一网打尽
系列二 · 第 4 篇
上篇认识了影子内存,它管的是"某个字节现在能不能碰"。但内存问题还有另一半:生命周期。一块 GM 什么时候申请的、该谁释放、到底用没用过——这些"时间线"上的问题,得靠另一套台账来盯。
msSanitizer 里负责记账的是堆块管理器(HeapBlockManager)。它干的事特别像小区物业:每一次 malloc 登记一笔"谁、多大、在哪",每一次 free 找对应的登记销账。就在这"登记—销账"之间,三种经典 bug 自己浮了出来。
如果 free 的时候翻半天账本找不到这笔记录——要么地址是假的,要么这笔已经释放过一遍了,这就是非法释放(illegal free)。如果程序跑完,账本上还摊着一堆没销掉的记录——这些内存从登记到终场都没人释放,就是内存泄漏(leak)。如果一笔内存在整个生命周期里登记了、也释放了,但中间一次都没被访问过——白占地方,就是"分配但未使用"。
那越界又怎么查?它靠的其实是一张"已分配区间表",源码里叫 BoundsCheck。别和影子内存搞混了:影子内存记状态,区间表记边界。每次访问,工具拿地址去区间表里比对,落在哪段已分配的区间内,就算合法;落在区间外面的字节数,就是越界的量。GM 的区间零散、还带读写权限,就用一种能合并、能切分的离散区间结构来管;UB、L1 这些片上空间每块大小固定,直接当一整个区间看,简单粗暴但管用。
还剩一条"未对齐"(misaligned)。昇腾的片上存储有对齐要求,地址不对齐的访问效率低甚至非法。这条最好查:拿访问地址对对齐大小取模,余数不为零就报警。所以工具把它单独拎成一个 AlignChecker,几乎不占多少逻辑,却常常最早上报。
看到这你会发现,内存检测其实是一堆小机制的分工协作:影子内存看状态,堆块台账看生命周期,区间表看边界,对齐检查看地址规整。为了不把这堆逻辑糊成一团,源码把它们抽象成几个统一动作——malloc、free、load、store,再算上内存拷贝,各干各的那份活,主流程清清爽爽。这种"策略模式"的拆法,后面聊架构时还会再见。
最后打个预防针。源码里有个枚举名叫 OUT_OF_BOUNDS,别被名字骗了——它查的其实是"多核踩踏",不是普通越界;普通越界叫 ILLEGAL_ADDR_READ / ILLEGAL_ADDR_WRITE。这个命名坑,正好引出下一篇的主角:多核踩踏。
- 点赞
- 收藏
- 关注作者
评论(0)