首页
社区
课程
招聘
PWN入门-23-LargeBin托梦
发表于: 2025-5-18 22:08 1080

PWN入门-23-LargeBin托梦

2025-5-18 22:08
1080

众所周知,程序申请堆内存一般可以分成两步,首先是通过GLibC封装的malloc等接口函数向GLibC提出堆内存的申请,最后GLibC会通过brk等系统调用向实际的物理资源管理者内核申请内存。

拿到的内存会落入top chunk中,然后GLibC再从top chunk中切割chunk给程序使用,至于程序释放chunk时,chunk会有两个出路,它们分别是进入空闲chunk的管理链表和重新合并进入top chunk

是否与top chunk合并,取决于被释放的chunk是否与top chunk相邻。

你不想将堆内存交给GLibC管理也不是不行,GLibC针对接口函数在内存申请其实也是依赖brkmmap等系统调用实现的,你可以直接通过系统调用去获取堆内存,避免堆内存落在GLibC的手中。

GLibC对于释放时不合入top chunk的chunk,会将它存入对应的链表中,进入链表需要分成两个阶段,在不考虑tcache机制的影响下,第一阶段GLibC会根据chunk的大小选择进入fastbinsYunsorted bin

第二阶段指的是chunk的迁移,迁移一般发生在_int_malloc中,即程序向GLibC申请堆内存的时候。

对于fast bin来讲,它只会在链表不为空且可用chunk空间紧张的时候,才会通过函数malloc_consolidate合并fast bin中的空闲chunk。

空闲chunk紧张的时机有两个,一是程序向GLibC提出属于large chunk的堆内存大小申请,二是top chunk空间不够,这时候GLibC都会检查have_fastchunks标志位,看是否有可以合并的fast chunk存在。

另一种迁移发生在函数_int_malloc通过遍历unsorted bin链表查找chunk的时候,当unsorted bin链表无法提供与申请要求匹配的chunk时,_int_malloc会将chunk从unsorted bin中取出,然后存入small binlarge bin中。

从上面可以看出,unsorted binsmall bin以及large bin三大链表的主要区别还是十分明显的。

unsorted binsmall chunklarge chunk在释放时的第一去处,只有当链表unsorted bin中chunk不能满足申请者的要求时,_int_malloc函数才会将空闲的chunk迁入small binlarge bin中。

unsorted binsmall bin以及large bin虽然使用共同使用bins数组,但是它们在使用区域上却有着严格的划分。

其中unsorted bin链表固定占用bin_at(M, 1)的位置。

你应该知道small chunklarge chunk之间的界限是由MIN_LARGE_SIZE的大小进行划分的,GLibC在bins数组使用区域上的划分上依旧延续了这个套路。

bin_at(M, 2)bin_at(M, 63)的区域是给small bin使用的,剩余的区域是留给large bin使用的。

large binsmall binunsorted bin还有一些差别。

unsorted bin中存储chunk的大小并不固定,small chunklarge chunk都是可能的,而bin_at(M, 2)bin_at(M, 63)所对应的small bin链表,同一链表中存储的chunk大小都是固定的,只有small bin链表不同时,链表中所存储的chunk大小才会有差异。

至于bin_at(M, 64)开始对应的large bin链表,如果仔细largebin_index宏就会发现,该宏会将某个大小范围内的chunk归类到bin_at(M, x)中,所以呢,单个链表large bin中所存放的chunk大小并不一定是相同的。

这也是malloc_chunk结构体中fd_nextsizebk_nextsize两个字段存在的原因,这两个字段专门帮助large bin链表链接同链表中不同大小的chunk。

一旦你对操作系统和GLibC的机制不熟悉,误认为通过free接口释放后,再读写被释放的内存就会出现SIGEGV(无效的内存访问)崩溃,那就大错特错了。

归还到GLibC手中的堆内存,GLibC并不会立即向内核提出抛弃内存的请求,所以这些内存仍然位于程序的内存布局中,对于程序来讲,释放堆内存后将对应的缓冲区变量设置成空指针才是正道。

针对UAF产生的攻击,最为常见的就是信息泄露了,由于GLibC对malloc_chunk结构体中fdxxbkxx在使用阶段和释放阶段的功能划分,导致了这些字段会在释放时写入新的内存地址数据。

假如程序并没有将缓冲区变量设置成空指针,那么fdxxbkxx在使用阶段位于数据区的特性,就会导致内存地址数据被泄露。

原来的数据区释放后摇身一变就成了可以影响chunk的功能区,一旦程序仍在操作缓冲区变量时,就相当于改写了GLibC管理空闲chunk的规则,那么造成的安全隐患当然不会止于信息泄露这一条了。

除了信息泄露之外,再比较常见的攻击方式就是任意地址读写了。

这种任意地址地址读写的漏洞,该问题也是因为fdxxbkxx四个在使用期和释放期中作用不明确的字段导致的。

当我们手握一个已释放chunk的读写权限,那么完成fd位置上内存地址的泄露当然不成问题,但想要完成任意地址读写环境的创建,还需要依赖GLibC的链表管理规则。

在GLibC的空闲chunk链表的规则中,最少会用一个fd字段链接其余的chunk,最多就如同large bin一样,会用完fdxxbkxx四个字段。

在GLibC的概念中,fdxxbkxx用于链接其他的chunk,程序发出堆内存的申请之后,GLibC会考虑从链表中取出chunk返回给程序使用,漏洞在这个时候会显现出来,当chunk被取出之后,GLibC有个很重要的任务就是更新链表。

更新链表的依据就是malloc_chunk中的fdxxbkxx四个字段,它会将根据字段上存放的地址A更新链表。当程序再次申请堆内存时,申请到的chunk就是地址A所对应的内存区域了。

根据链表的特性和可以修改已释放chunk的异常现象,我们可以控制fdxxbkxx四个字段,让它们指向特定的内存区域,当GLibC根据fdxxbkxx取出新地址并读写时,就完成了向我们指定的任意内存区域进行读写数据的操作。

对于GLibC来讲,就像是头上带了绿帽,孩子(被篡改的chunk)已经不是自己的了,还蒙在鼓中,尽心尽力的为了这个孩子提供服务,等孩子长大了(被移出链表)才发现,原来这个孩子是跟自己没有关系的。

并且这个孩子还可能会被刺自己,协助黑客破坏系统。

从上面可以看到修改fdxxbkxx指向任意的地址,使得取出的chunk指向特定的内存区域,然后再在该区域进行读写,就是任意地址读写形成的原因。

GLibC针对malloc_chunkfdxxbkxx四个字段的策略,为我们带来的任意地址读写的可能,这种可能性需要依赖UAF,毕竟要是程序员知道free接口的内存释放只是伪释放,那就一定会将变量设置成空指针,进而丧失对已释放chunk的操控能力。

GLibC早就注意到了任意地址读写的问题,这一问题产生源自于GLibC早前永远默认结构体malloc_chunkfdxxbkxx中保存的数值都是正确的。

所以现在GLibC不再保持这种默认正确的规则,它会在使用前对这些数据进行检查,只要发现数据有异常就会通过malloc_printerr抛出错误。

比较典型的就是unlink_chunk函数中的检查,该函数会根据当前释放chunk的内存地址pfd前一个入链chunk,以及bk获取后一个入链chunk。

按照GLibC的规则,p->fd的后一个入链chunk和p->bk的前一个入链chunk都应该指向新释放chunk的内存地址p,如果不是就说明p上的数据是有问题的。

这种依赖相邻chunk的检查,在一定程度上确保了安全性,但如果你连相邻chunk都能伪造或控制,那就不好说了。

这种任意地址读写的情况当然不止unlink_chunk这一处,只要fdxxbkxx可以被恶意控制的操作都是符合要求的。

比如程序通过_int_malloc申请chunk的时候,会尝试遍历unsorted bin链表,当_int_malloc发现申请内存的大小不属于small chunk,且最近没有被切割的chunk的时候,就会将unsorted bin链表中的bk保存的最早入链chunk的再晚一个入链的chunk取出,因为该victim->bk之后要么与申请大小相等直接返回给使用,要么就是移入small binlarge bin中,反正就是不在unsorted bin里面了。

在这个时候victim肯定是处于空闲状态的,假如这个时候victim还是可以被程序写入数据的,那么bck = victim->bk中的bck被赋值后,bck就会指向我们可以控制的内存区域。

后面将victim移除链表,并将bck更新成unsorted binbk链表的头成员时,就代表GLibC将我们设置的恶意地址看作成了新的chunk。

后面取出chunk时,取出的就是恶意地址对应的内存区域,程序拿到恶意地址后,就可以对该区域进行读写。

只不过可惜,现在已经是公元2025年了,GLibC早就针对这块进行了加固,加固的方案比较简单,仍然是根据chunk相连的特性进行检查。

在正常情况下bckfd保存的是victim,但如果bck是被篡改过的,那么它的fd上保存的就很难是victim,所以当bck->fd != victim时就会抛出错误。

针对large bin进行的攻击与上方介绍的任意地址读写颇有相似之处。

在GLibC对堆的管理概念中,程序申请的chunk不能通过unsorted bin链表匹配时,会将原来bk链表上的头成员victim取出,并将victim->bk更新为bk链表的头成员,被移出unsorted bin链表的victim,如果不能和申请大小nb完全匹配,那么victim进入small binlarge bin链表中。

进入small bin链表时的操作相对简单,可以自行阅读源代码,但当victim进入链表large bin中时,操作就会变得复杂起来。

变得复杂是因为large bin链表可以存储不同大小chunk的特殊性导致的。

victim的大小小于large bin链表最早入链的bck->bk时,GLibC会选择直接将victim插入large bin链表,作为最晚入链的chunk存在。

但当victim的大小大于等于large bin链表中原最早入链chunk时,处理操作就会变得复杂起来,主要原因是_int_malloc函数需要遍历large bin链表,找到一个比victim更小的chunk。

while循环语句中可以看到,fwd不断的根据fd_nextsize去更新,而循环中止的判断条件只是fwd小于等于victimsize时才会停止,那么GLibC就不怕找不到合适的chunk,导致这个循环一直进行产生死循环吗?

当然不用考虑!因为if ((size) < chunksize_nomask (bck->bk))已经告诉我们一个事情,那就是victimlarge bin链表中最小的chunk要大,所以在遍历字段fd_nextsize的过程中至少也会找到一个chunk小于victim

当根据fd_nextsize遍历large bin链表找到的fwd大小刚好等于victim的时候,GLibC会直接让fwd等于fwd->fdfwd->fd相当于找到比fwd更晚入链的chunk,这么做是因为GLibC会固定将victim插入第二的位置。

直接往fwd的前面插入不行吗,为什么是fwd维护的fd链表中第二的位置呢?

GLibC主要是为了避免给victim更新xx_nextsize,这是因为相同大小的chunk所在的链表中,只有头成员的xx_nextsize是起作用的。

如果fwd小于victim,由于前面也没有找到和victim相等chunk,所以可以知道victim对应的大小在链表中还是唯一的,所以接下来GLibC会更新fwdvictimxx_nextsize

从上面可以看到,当程序还握有已释放fwd的内存地址且可以修改它时,一共会产生三处风险代码,而这些风险代码就是与fwd->xx相关的赋值语句。

上面风险代码诞生于unsorted bin中的large chunk移动到large bin链表的时候,当我们篡改fwdmalloc_chunk结构体占用字段的数值为恶意地址时,会导致GLibC向恶意地址上写入victim的地址。

这个恶意地址当然是可以随意指定的,只要这片内存区域是可读可写的就可以,只不过与任意地址申请为chunk的场景有所不同,这里只能写入特定的内容。

前面提到过large bin链表和unsorted bin链表与其他链表有一个显著的区别,那就是large binunsorted bin允许链表中存放大小不相同的chunk。

unsorted binsmall chunklarge chunk被释放时的第一去处,该链表并不会对chunk按照大小进行排序。

那么large bin也是这样的吗?

当然不是,large bin会将入链的chunk按照大小进行排序。

large chunkunsorted bin链表移动到large bin链表的时机,其实就发生在函数_int_malloc的内部,当函数遍历unsroted bin链表,发现chunk不能匹配申请者要求的时候,就会将chunk移入small binlarge bin中。

下面列出了large chunk进入large bin链表时的全部分支,从分支的判断条件上,我们可以窥探出GLibC是如何排列large bin中的chunk的。

最先面临的判断是fwd != bck,因为fdbk两个字段所维护的都是循环链表,所以GLibC用了一个特殊的数据作为链表头,即&bins[i] - offset(fd),这个特殊的数据可以保证xx->fdxx->bk分别指向fd的链表头成员bins[i]bk的链表头成员bins[i + 1],所以当fwd == bck时,就说明链表是空的。

large bin链表为空时,直接将chunk插入就可以,但当链表不为空时,GLibC会检查bck->bk指向的链表头chunk是否大于待移入victim,如果是,那就更新fwdbck,此时的bck等于&bins[i] - offset(fd),后面插入victim时,会通过fwd->bkvictim插入bk链表头的位置。

从这里可以看出,fd链表和bk链表已经不止根据chunk入链时间维护链表了,还会根据chunk的大小进行维护,并且bk链表头上保存的永远都是链表中的最小chunk。

如果victim的大小比bk链表头成员要大,那就好遍历fd_nextsize字段,在链表中找到小于等于victim的chunk,然后完成插入。

至于bins数组中fd字段所在的位置,它与bk位置保存最小chunk的属性有所不同,该字段会保存链表中最大的chunk。

if (size == chunksize_nomask(fwd))对应的else分支可以知道,找到一个小于待插入的victim时就会进入else分支,如果victim是链表中最大的一个,那么bck = fwd->bk语句运行完后,bck就等于&bins[i] - offset(fd),从而使得最后插入时bck->fd的值等于bins[i],使得fd所在的位置被插入整个链表中最大的chunk。

向任意地址写入特定chunk地址的攻击,依赖于fdbkbk_nextsize三个属于结构体malloc_chunk的字段,将它们篡改后,_int_malloc函数的流程内部,就可能将它们改写。

不管是修改哪一个字段,都要求黑客迫使_int_malloc函数的执行流程进入chunk从链表unsorted bin中迁移到large bin链表的分支中。

unsorted bin中无法与申请大小匹配的victim的超过large bin链表中的空闲chunk时,就会开启基于bkbk_nextsize的利用,而当大小是相等时,则会轮到fd字段发挥可利用的作用。

在任意地址写入特定数据的攻击方式是一种较为古老的攻击方式,既然是古老的,那就代表它已经被GLibC修复掉了。

下面是GLibC的修复手法,依旧是我们非常熟悉的根据相邻chunk确认数据有效性。

上面介绍的向任意地址写入特定数据的漏洞,其实是忽略了GLibC的部分的代码的,只注意关注了else的部分,而忽略了if分支下的代码。

那么if分支下的代码是不是极其稳固呢?

答案是否定的。

在下方代码中可以看到,fwd->fd对应large bin链表中的最晚入链chunk,另一个fwd->fd->bk_nextsize则对应最晚入链chunk的bk_nextsize字段。

当程序可以控制large bin链表中最晚入链chunk的bk_nextsize字段时,赋值语句victim->bk_nextsize就会指向我们所设置的恶意地址。

victim->bk_nextsize->fd_nextsize = victim语句运行完后,恶意地址所指向内存区域偏移offset(fd_nextsize)的地址就会被写上victim存储的数据。

至于怎么样才能进入if所在的分支,那就需要做到以下几点。

首先unsorted bin链表中必须存在一个large chunk,且这个large chunk需要比large bin链表中的最早入链chunk小,其次就是程序发出的堆内存申请的大小不能和unsorted bin链表中large chunk相等。

做到上面的两点,就可以顺利的进入if分支了。

那么问题就又来了,类似的问题之前并非没有先例,作为业界顶级项目GLibC的维护者,难道他们就没有注意到这个问题吗?

是难以加固代码,还是根本就没有察觉呢?

fwd->fd->bk_nextsize指向比fwd->fd更小的chunk,而fd_nextsize则会指向比它更大的chunk,按照道理来讲,fwd->fd->bk_nextsize->fd_nextsize会重新指向fwd->fd,只要检查这个结果是否成立,就可以验证数据的正确性了。

但是GLibC为什么不进行检查呢?

而且GLibC中也不是没有这样的检查啊!

负责维护链表的fd_xxxxbk_xxxx的字段被篡改后,按照道理来讲,是可以影响程序申请chunk的流程的,但是事情真的能那么顺利吗?

程序想要从large bin中获取chunk,只有一个要求,那就是unsorted bin链表不能提供给申请者提供chunk,在结束unsorted bin链表的遍历之后,只要GLibC通过in_smallbin_range宏判断出申请大小不属于small chunk的范围,就会把它视为针对large chunk的申请。

此时会正式开始从large bin链表中获取large chunk

能不能从large bin链表中取出chunk,可不是申请大小符合large chunk的范围就可以了,GLibC有两点要求,一是large bin链表不为空,二是根据first取出链表中最大的victim跟申请大小nb进行判断,如果申请大小小于victim,才会从large bin链表中取出chunk,否则的话,也找不到能匹配的chunk。

在可以从large bin链表申请large chunk的时候,GLibC会获取当前链表中最小的chunk,如果该chunk大于申请大小就会拿来使用,否则则会继续按照从小到大的顺序遍历链表,直到找到大于申请大小nb的chunk。

找到chunk后,会先通过last宏判断victim是不是链表中最小的chunk,如果不是且victim的大小等于victim->fd的大小,那就会把victim->fd取出使用。

要记得前面插入时,也是将chunk插入第二的位置,这里是与之匹配的取出操作。

接下来,GLibC会通过unlink_chunk接口将victim移出链表。

最后GlibC会计算victim大小和申请大小的差值remainder_size,当发现差值小于chunk的最小要求值时,会将整个chunk返回给用户使用,反之则会先对chunk进行分割,然后将分割出来的部分返回,剩余的部分会插入unsorted bin链表中。

修改已释放large chunkbk_nextsize字段为恶意地址后,有几率填写恶意地址偏移offset(fd_nextsize)处的数值为chunk的地址当然是一种漏洞,但当GLibC进入函数_int_malloc的申请chunk流程时,则又会爆发任意地址申请的漏洞。

想要让任意地址申请顺利的通过,首先要避免victim获取到恶意地址后,GLibC检查当前chunk的mchunk_size比申请大小还要的情况,这里需要我们修改恶意地址所在内存区域偏移offset(mchunk_size)上的数值。

上面的循环绕过还算比较方便,但是接下来unlink_chunk函数的绕过可就困难了,因为不仅需要给伪造的chunk构造数据,还需要给伪造chunk的fdxxbkxx字段所链接的chunk构造数据,才能顺利的通过unlink_chunk函数的检查。

至于绕过unlink_chunk函数检查的详情,在OffByOne那节中已经有过详细的介绍,这里就不再进行过多的介绍了。

上面介绍了针对unsroted bin链表和large bin链表所产生的的攻击方式,虽然unsroted bin攻击已经被加固措施干掉了,但好在large bin攻击依然存在。

large bin攻击得以发生的原因,是因为victim->bk_nextsize会被写入当前链表中最大的fwd->fd成员的偏移offset(bk_nextsize)处保存的数值,当这个数值被篡改后,后面的victim->bk_nextsize->fd_nextsize = victim语句会将向恶意地址所在内存区域偏移offset(fd_nextsize)的地方写入victim的值。

large bin攻击得以存在的原因,是因为被插入的victim属于large bin链表中最小的chunk时,缺少针对fwd->fd->bk_nextsize的检查。

bins数组存储的三大了链表只剩下了small bin链表,那么small bin链表存在被攻击的可能性吗?

当然也是可以的,不过针对small bin产生的攻击需要留到下回在进行解析。

下面直接给出了程序的源代码。

从源代码可以看到漏洞发生在函数vuln中,vuln主动帮我们构造了一个large bin攻击的场景,在这里我们通过改写指针p1上偏移offset(bk_nextsize)的位置,让其指向变量vuln_addrtmp2完成申请后,vuln_addr会变到指针p2 - offset(fd)的位置上,此时就实现了向任意地址写入特定地址的操作。

由于vuln函数最后会调用system,在原本的流程中,system会调用msg上填充的ls,且msg上的数据也不会被改写,但有了large bin的漏洞,和read接口写p2指针的操作,就让改写vuln_addr->msg成了可能。

通过上面的分析构造出下面的exploit。

运行exploit成功获得Shell。

struct malloc_chumalloc_statenk {
    ......
    mfastbinptr fastbinsY[NFASTBINS];
    ......
    mchunkptr bins[NBINS * 2 - 2];
    ......
}
struct malloc_chumalloc_statenk {
    ......
    mfastbinptr fastbinsY[NFASTBINS];
    ......
    mchunkptr bins[NBINS * 2 - 2];
    ......
}
_int_free
    -> if ((size) <= get_max_fast())
        -> atomic_store_relaxed (&av->have_fastchunks, true);
        -> unsigned int idx = fastbin_index(size);
        -> fb = &fastbin (av, idx);
        -> p->fd = PROTECT_PTR (&p->fd, old);
        -> *fb = p;
    -> else if (!chunk_is_mmapped(p))
        -> _int_free_merge_chunk
            -> _int_free_create_chunk
                -> if (nextchunk != av->top)
                    -> mchunkptr bck = unsorted_chunks (av);
                    -> mchunkptr fwd = bck->fd;
                    -> p->fd = fwd;
                    -> p->bk = bck;
                    -> bck->fd = p;
                    -> fwd->bk = p;
_int_free
    -> if ((size) <= get_max_fast())
        -> atomic_store_relaxed (&av->have_fastchunks, true);
        -> unsigned int idx = fastbin_index(size);
        -> fb = &fastbin (av, idx);
        -> p->fd = PROTECT_PTR (&p->fd, old);
        -> *fb = p;
    -> else if (!chunk_is_mmapped(p))
        -> _int_free_merge_chunk
            -> _int_free_create_chunk
                -> if (nextchunk != av->top)
                    -> mchunkptr bck = unsorted_chunks (av);
                    -> mchunkptr fwd = bck->fd;
                    -> p->fd = fwd;
                    -> p->bk = bck;
                    -> bck->fd = p;
                    -> fwd->bk = p;
_int_malloc
    -> if (in_smallbin_range (nb))
    -> else
        -> if (atomic_load_relaxed (&av->have_fastchunks))
            -> malloc_consolidate (av);
    -> while ((victim = unsorted_chunks (av)->bk) != unsorted_chunks (av))
        -> if (in_smallbin_range (size))
            -> bck = bin_at (av, victim_index);
            -> fwd = bck->fd;
        -> else
            -> bck = bin_at (av, victim_index);
            -> fwd = bck->fd;
            -> xx->fd_nextsize = xxx
            -> xx->bk_nextsize = xxx
        -> victim->bk = bck;
        -> victim->fd = fwd;
        -> fwd->bk = victim;
        -> bck->fd = victim;
    -> use_top:
    -> if ((size) >= (nb + MINSIZE))
    -> else if (atomic_load_relaxed (&av->have_fastchunks))
        -> malloc_consolidate (av);
_int_malloc
    -> if (in_smallbin_range (nb))
    -> else
        -> if (atomic_load_relaxed (&av->have_fastchunks))
            -> malloc_consolidate (av);
    -> while ((victim = unsorted_chunks (av)->bk) != unsorted_chunks (av))
        -> if (in_smallbin_range (size))
            -> bck = bin_at (av, victim_index);
            -> fwd = bck->fd;
        -> else
            -> bck = bin_at (av, victim_index);
            -> fwd = bck->fd;
            -> xx->fd_nextsize = xxx
            -> xx->bk_nextsize = xxx
        -> victim->bk = bck;
        -> victim->fd = fwd;
        -> fwd->bk = victim;
        -> bck->fd = victim;
    -> use_top:
    -> if ((size) >= (nb + MINSIZE))
    -> else if (atomic_load_relaxed (&av->have_fastchunks))
        -> malloc_consolidate (av);
#define unsorted_chunks(M)      (bin_at (M, 1))
#define unsorted_chunks(M)      (bin_at (M, 1))
#define NSMALLBINS          64
#define SMALLBIN_WIDTH      MALLOC_ALIGNMENT
#define MIN_LARGE_SIZE      (NSMALLBINS * SMALLBIN_WIDTH)
 
#define in_smallbin_range(sz)   \
    ((unsigned long) (sz) < (unsigned long) MIN_LARGE_SIZE)
 
#define smallbin_index(sz) (((unsigned) (sz)) >> 4)
#define largebin_index(sz) largebin_index_64
#define NSMALLBINS          64
#define SMALLBIN_WIDTH      MALLOC_ALIGNMENT
#define MIN_LARGE_SIZE      (NSMALLBINS * SMALLBIN_WIDTH)
 
#define in_smallbin_range(sz)   \
    ((unsigned long) (sz) < (unsigned long) MIN_LARGE_SIZE)
 
#define smallbin_index(sz) (((unsigned) (sz)) >> 4)
#define largebin_index(sz) largebin_index_64
#define largebin_index_64(sz)                                                \
  (((((unsigned long) (sz)) >> 6) <= 48) ?  48 + (((unsigned long) (sz)) >> 6) :\
   ((((unsigned long) (sz)) >> 9) <= 20) ?  91 + (((unsigned long) (sz)) >> 9) :\
   ((((unsigned long) (sz)) >> 12) <= 10) ? 110 + (((unsigned long) (sz)) >> 12) :\
   ((((unsigned long) (sz)) >> 15) <= 4) ? 119 + (((unsigned long) (sz)) >> 15) :\
   ((((unsigned long) (sz)) >> 18) <= 2) ? 124 + (((unsigned long) (sz)) >> 18) :\
   126)
#define largebin_index_64(sz)                                                \
  (((((unsigned long) (sz)) >> 6) <= 48) ?  48 + (((unsigned long) (sz)) >> 6) :\
   ((((unsigned long) (sz)) >> 9) <= 20) ?  91 + (((unsigned long) (sz)) >> 9) :\
   ((((unsigned long) (sz)) >> 12) <= 10) ? 110 + (((unsigned long) (sz)) >> 12) :\
   ((((unsigned long) (sz)) >> 15) <= 4) ? 119 + (((unsigned long) (sz)) >> 15) :\
   ((((unsigned long) (sz)) >> 18) <= 2) ? 124 + (((unsigned long) (sz)) >> 18) :\
   126)
unlink_chunk
    -> mchunkptr fd = p->fd;
    -> mchunkptr bk = p->bk;
    -> if (__builtin_expect (fd->bk != p || bk->fd != p, 0))
        -> malloc_printerr ("corrupted double-linked list");
unlink_chunk
    -> mchunkptr fd = p->fd;
    -> mchunkptr bk = p->bk;
    -> if (__builtin_expect (fd->bk != p || bk->fd != p, 0))
        -> malloc_printerr ("corrupted double-linked list");
_int_malloc
    -> for (;;)
        -> while ((victim = unsorted_chunks (av)->bk) != unsorted_chunks (av))
            -> bck = victim->bk;
            -> if (in_smallbin_range (nb) && bck == unsorted_chunks (av) && victim == av->last_remainder && (unsigned long) (size) > (unsigned long) (nb + MINSIZE))
                -> ......
                -> return p;
            -> unsorted_chunks (av)->bk = bck;
            -> bck->fd = unsorted_chunks (av);
_int_malloc
    -> for (;;)
        -> while ((victim = unsorted_chunks (av)->bk) != unsorted_chunks (av))
            -> bck = victim->bk;
            -> if (in_smallbin_range (nb) && bck == unsorted_chunks (av) && victim == av->last_remainder && (unsigned long) (size) > (unsigned long) (nb + MINSIZE))
                -> ......
                -> return p;
            -> unsorted_chunks (av)->bk = bck;
            -> bck->fd = unsorted_chunks (av);
_int_malloc
    -> for (;;)
        -> while ((victim = unsorted_chunks (av)->bk) != unsorted_chunks (av))
            -> bck = victim->bk;
            -if (__glibc_unlikely (bck->fd != victim) || __glibc_unlikely (victim->fd != unsorted_chunks (av)))
                -> malloc_printerr ("malloc(): unsorted double linked list corrupted");
_int_malloc
    -> for (;;)
        -> while ((victim = unsorted_chunks (av)->bk) != unsorted_chunks (av))
            -> bck = victim->bk;
            -if (__glibc_unlikely (bck->fd != victim) || __glibc_unlikely (victim->fd != unsorted_chunks (av)))
                -> malloc_printerr ("malloc(): unsorted double linked list corrupted");
_int_malloc
    -> for (;;)
        -> while ((victim = unsorted_chunks (av)->bk) != unsorted_chunks (av))
            -> bck = victim->bk;
            -> size = chunksize (victim);
            -> ......
            -> unsorted_chunks (av)->bk = bck;
            -> bck->fd = unsorted_chunks (av);
            -> if (size == nb)
                -> ......
                -> return p;
            -> if (in_smallbin_range (size))
                -> ......
            -> else
                -> ......
_int_malloc
    -> for (;;)
        -> while ((victim = unsorted_chunks (av)->bk) != unsorted_chunks (av))
            -> bck = victim->bk;
            -> size = chunksize (victim);
            -> ......
            -> unsorted_chunks (av)->bk = bck;
            -> bck->fd = unsorted_chunks (av);
            -> if (size == nb)
                -> ......
                -> return p;
            -> if (in_smallbin_range (size))
                -> ......
            -> else
                -> ......
if (in_smallbin_range (size))
    -> ......
else
    -> victim_index = largebin_index (size);
    -> bck = bin_at (av, victim_index);
    -> fwd = bck->fd;
    -> if (fwd != bck)
        -> if ((size) < chunksize_nomask (bck->bk))
            -> fwd = bck;
            -> bck = bck->bk;
            -> xxx->xx_nextsize = xxxx
        -> else
            -> while (size < chunksize_nomask (fwd))
                -> fwd = fwd->fd_nextsize;
            -> if (size == chunksize_nomask (fwd))
                -> fwd = fwd->fd;
            -> else
                -> victim->fd_nextsize = fwd;
                -> victim->bk_nextsize = fwd->bk_nextsize;
                -> fwd->bk_nextsize = victim;
                -> victim->bk_nextsize->fd_nextsize = victim;
            -> bck = fwd->bk;
    -> else
        -> victim->fd_nextsize = victim->bk_nextsize = victim;
    -> victim->bk = bck;
    -> victim->fd = fwd;
    -> fwd->bk = victim;
    -> bck->fd = victim;
if (in_smallbin_range (size))
    -> ......
else
    -> victim_index = largebin_index (size);
    -> bck = bin_at (av, victim_index);
    -> fwd = bck->fd;
    -> if (fwd != bck)
        -> if ((size) < chunksize_nomask (bck->bk))
            -> fwd = bck;
            -> bck = bck->bk;
            -> xxx->xx_nextsize = xxxx
        -> else
            -> while (size < chunksize_nomask (fwd))
                -> fwd = fwd->fd_nextsize;
            -> if (size == chunksize_nomask (fwd))
                -> fwd = fwd->fd;
            -> else
                -> victim->fd_nextsize = fwd;
                -> victim->bk_nextsize = fwd->bk_nextsize;
                -> fwd->bk_nextsize = victim;

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

收藏
免费 0
支持
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回