在《glibc内存malloc简要解析》就介绍了glibc的一些概念,简单来说就是将malloc返回的地址的前16字节叫做chunk header。
在我们操作系统中,遇到了一个非常奇怪的问题,那就是调用xcb的程序,总是在退出的时候,莫名其妙报glibc的错误,包含但不局限于如下
malloc_consolidate(): unaligned fastbin chunk detected double free or corruption (!prev) corrupted double-linked list malloc(): memory corruption
今天介绍这个问题
static lazyreply *get_index(xcb_connection_t *c, int idx) { if(c->ext.extensions_size < 0) c->ext.extensions_size = 0; if(idx > c->ext.extensions_size) { int new_size = idx << 1; lazyreply *new_extensions = realloc(c->ext.extensions, sizeof(lazyreply) * new_size); if(!new_extensions) return 0; memset(new_extensions + c->ext.extensions_size, 0, sizeof(lazyreply) * (new_size - c->ext.extensions_size)); c->ext.extensions = new_extensions; c->ext.extensions_size = new_size; } return c->ext.extensions + idx - 1; }
这里对于extensions_size是小于0的情况,强制置0
if(c->ext.extensions_size < 0) c->ext.extensions_size = 0;
我们可以看到get_index的代码,这里会将ext.extensions进行realloc,realloc之后,将新增的大小区域进行memset为0。那么问题就出现在memset上了。
memset(new_extensions + c->ext.extensions_size, 0, sizeof(lazyreply) * (new_size - c->ext.extensions_size));
我们假设extensions_size是-1,那么memset就会清空realloc申请的内存的chunk head结构体。
chunk的数据内容被清空了,那么程序可能正常,也可能在glibc的回收,规整,free,分配等操作中都会出现异常
根据这个问题现象,他是一个非常随机的问题,存在此问题的系统,会给人感觉系统非常不稳定。因为xcb的应用只要运行,就会随机出错,或者大概率退出的时候出错。而且出错的日志全部指向了glibc的内存管理。
而实际上此问题就是对某个内存地址,错误的将chunk head清空了导致的。
定位这个问题也比较困难,我们需要先了解glibc的内存管理相关逻辑,然后gdb找到崩溃现场。根据glibc的逻辑,他是使用双向循环链表来管理每个chunk的bin,所以推荐使用pwndbg工具,这个工具在定位链表上非常方便。
实际上,为了找到xcb的问题,我重编了glibc,mesa,xcb,dri,xorg。甚至我还找rk拿了mali so的符号版本。
同样的,为了前期排查问题,还使用了asan来寻找内存问题。当然,浪费时间了,自己asan学艺不精。