首页
社区
课程
招聘
[原创]musl 1.2.2 总结+源码分析 One
发表于: 2021-9-27 14:37 48299

[原创]musl 1.2.2 总结+源码分析 One

2021-9-27 14:37
48299

这里探索了很多方式,勘误之前的启动方式实际上存在一些问题,这里终于探索到了最完备的musl 调试环境,这里特别感谢我的学弟gxh为勘误做出的贡献

提示:

musl 的库函数就只有一个libc.so ,这个libc.so 既充当ld,又充当libc

最佳环境配置:

本机环境ubuntu:20.04

或:通过包管理器安装,

关于自己编译源码:

自己编译源码具体可以参考下面这篇文档

blog.fpliu.com/it/software/musl-libc

musl-dbgsym_1.2.2-1_amd64.ddeb

这里安装调试符号非常重要,关系到后面调试!!!

在安装调试符号后,即使musl 程序的libc.so不带调试信息,gdb 还是会从我们安装的调试符号中自动寻找匹配,还是能做到带符号调试!!!

安利xf1les 师傅编写的musl heap gdb 插件

Requirements:(环境需求)

Python 3.5.2+

GDB 7.11.1+ with python3 support

musl libc 1.2.1+

with debug symbols

安装后非常方便,可以很方便的看__malloc_context 结构体,和meta 链表的情况,还可以直接得到一些musl利用的必要函数的偏移

image-20220503001508991

替换默认环境下的libc.so

把下载的musl的默认libc.so 换为指定的libc.so, 默认路径:/usr/lib/x86_64-linux-musl/libc.so ,这里可以先备份再替换

p = process(rbin) 直接启动程序,他会自动使用默认的libc

地址空间布局效果图

这个才是正确的布局,之前因为第五空间的题远程靶机启动方式错误被误导了,导致从开始学习的时候,就是按照错误方式启动的

(之前的文章介绍的错误方式,对不住各位师傅们)

image-20220503002753363

或者:patchelf

把libc.so 当作ld 来patch (这种方式也可以)

此方式经过测试也是与直接替换默认的libc.so 的结果是相同的

image-20220503002736734

因为安装了musl libc debug symbols 所以我们可以直接p __malloc_context 查看meta 堆管理器结构体

可以利用xf1les 师傅的gdb 插件,直接查看当前的chunk 被nontrivial_free()释放的结果,对于利用dequeue 进行地址互写非常方便直观看见结果

image-20220503003242388

致歉:再次强调

chunk->group->meta 分析顺序

先从musl 的基本数据结构 这里我选择从小到大来理解,因为在源码里它就是从小到大索引的

从chunk 一路索引到 meta。

首先介绍chunk

每个chunk 都有个4 字节的chunk头记录 idx 和 offset

(第一个chunk 比较特殊,因为它上面是 group结构 + chunk 头=0x10 )

很多没有遇见过的问题:且不是实验内容类的,比如虚拟机网卡,服务器环境,实验难度

在释放后 chunk 头的 idx会变成0xff offset 会清零

image-20210919150053764

这里 offset 和 idx 比较重要

细节:和glibc 的chunk 类似 glibc chunk 可以占用下一个chunk 的prev_size 空间

而musl 可以使用 下一个chunk 头的低4B 来储存数据

image-20210919011425177

从chunk 索引到 group:

源码:

根据源码我们可以知道 从chunk 索引到group 起始地址的计算式子为

group_addr = chunk_addr - 0x10 * offset - 0x10

补充

offset = p[-2] (这里的p 就是代指chunk)

index 从 get_slot_index(p)中得到

其中如果这个meta 前后都没有,那么它的prev next 就指向它自己

avail_mask,free_mask 是bitmap 的形式体现 chunk 的状态

这里例子是我申请了3个 0x30的chunk1、2、3, 然后free 掉chunk2

image-20210919020006738

image-20210919015741708

avail_mask == b"01111000" (最前面那个0 不算只是为了对齐)

在 avail_mask 中 2 进制的 0 表示不可分配 1表示可分配,顺序是从后到前

如01111000 中最后的 3个0 , 表示第1、2、3个 chunk 是不可分配的 前面4个chunk 是可以分配的

free_mask == 2 =0010

在 free_mask 中的 1 表示已经被释放

如第二个chunk2已经被释放:free_mask =b"0010"

last_idx 可以表示最多可用堆块的数量 最多数量=last_idx+1(因为是从0 - last_idx)

freeable=1根据源码 代表meta否可以被回收 freeable=0 代表不可以 =1 代表可以

sizeclass=3 表示由0x3这个group进行管理这一类的大小的chunk

maplen

maplen >= 1表示这个meta里的group 是新mmap出来的,长度为多少

meta->maplen = (needed+4095)/4096;

并且这个group 不在size_classes里

maplen =0 表示group 不是新mmap 出来的在size_classes里

细节:

meta 一般申请的是堆空间brk 分配的,有可能是mmap 映射的,而group 都是使用的mmap 的空间

由于bitmap的限制, 因此一个group中最多只能有32个chunk

meta_area 是管理meta的合集 meta_area 以页为单位分配 所以计算地址如下

meta_area_addr = meta & ( -4096 )

const struct meta_area area = (void )((uintptr_t)meta & -4096)

check:是个校验数字 保护meta_area 里的meta,防止meta被 伪造

meta_area *next 指向下一个meta_area 如果没有 就默认为0

nslots: meta 槽的数量

细节:在这个meta_area 页被使用的时候 上一个临近的页 会被设置为不可写

是为了防止 使用者覆盖check 校验值

image-20210919151955253

是musl libc 记录结构状态的表,记录各个meta 和 secret 队列信息等

image-20210919154755122

小总结一下

image-20210920011323565

(如果不想看源码 可以跳下面看总结)

源码路径

/src/malloc/mallocng/malloc.c

源码:

!!!! 关键: 一般分配先进入这个循环

一、判断是否超过size 阈值

二、分配chunk

如果active 对应size的meta 位置上为空,没找到那么尝试先找size更大的meta

如果active 对应size的meta位置上有对应的meta,尝试从这个meta中的group找到可用的chunk(这里malloc 那个循环:for (;;)

这里不清楚建议看malloc源码分析那里)

仔细观察分配的过程,我们也可以看出为什么free 的chunk不能立即回收使用,因为有空闲的chunk的时候,分配chunk是直接设置meta->avail_mask

然后直接enframe() 直接从group中取出 chunk即可,不会设置meta->freed

源码路径

/src/malloc/mallocng/malloc.c

free

细节:!!!

get_meta

关于nontrivial_free()函数很重要 ,这里尽量详细说明

dequeue 触发条件

image-20210920171255661

self = 1 << idx

下面是几种简单的触发情况

1.avail_mask 表示只有一个chunk 被使用 ,freed_mask=0,而free 刚好要free 一个chunk

满足 okay_to_free() 条件 就可以进入dequeue 进行出队操作

如add(1,0x20) 再free(1) 就会使得meta 被回收

2.avail_mask=0, freed_mask 表示只有 1个 chunk 没被 释放,这时释放的chunk 就应该是那最后一个chunk

如下面情况 avail_mask ==0 free_mask=63=00111111 last_idx = 6

已经释放6 个chunk 还有最后一个chunk没被释放 在释放最后一个chunk 时会触发dequeue使得对应meta出队

image-20210920171918336

3.如果发现这个group中所有的chunk要么被free, 要么是可用的, 那么就会回收掉这个group,调用dequeue从队列中出队

一般有如下几种利用方法,核心原理都是构造假的chunk 索引到假的group 从而所引导假的meta

或覆盖group 中指向meta 的指针 覆盖为假的meta ,然后使得假的meta dequeue 最终实现unlink

(构造fake_meta 需要先泄露 secret 校验值)

一、

通过构造假的meta 满足各种条件 通过以下流程

free()->nontrivial_free()->dequeue

image-20210920175246340

这里通过free 到 dequeue

二、

通过realloc 里也带有free

realloc()->free(old)->nontrivial_free()->dequeue

注意: musl 是没有malloc_hook和 free_hook 这种一般的hook 位

且musl 程序的IO_FILE 结构体格式和libc 不一样 没有IO_jump_t的vtable

但是存在read,write,seek,close 四个函数指针

image-20210920180511605

讲一下思路

通过任意地址互写指针,向stdout_used 写入我们伪造的fake_stdout地址, 通过IO_FILE 劫持程序执行流

到我们布置好的fake_stdout 上,可以找IO_FILE 里的一些函数exit puts在fake_stdout上布置rop_chain然后通过栈迁移的gadget 利用FSOP 劫持程序到布置的fake_stdout上

在利用指针互写 修改fake_meta 中的mem(mem 就是group 区域) ,把mem 修改为我们想要的地址,

然后让fake_meta 通过queue 入队,可以实现任意地址分配的,然后同样是打 IO_FILE 通过修改stdout stdin 和stderr 结构体 劫持程序流

前面提到过

处于这两种状态的group 对应的meta 会被dequeue 出队

一些特殊的地方:

若:group 中chunk都被使用了,只有一个被free的chunk, 在再次malloc 申请相同size chunk时:

meta 结构体有prev,next 指针。同一size的chunk 对应同一类meta。再queue 后,同一类meta被链接,实际上是个链表结构

若:当前meta 对应group 中无可用chunk,则在alloc_slot 中,会在链表上的寻找下一个meta的group中是否有可用的chunk

借助DefCon Quals 2021的mooosl学习musl mallocng(源码审计篇)

musl-1.2.x堆部分源码分析

 
 
 
 
sudo dpkg -i musl_1.2.2-1_amd64.deb
sudo dpkg -i musl_1.2.2-1_amd64.deb
sudo apt-get install -y musl musl-dev
sudo apt-get install -y musl musl-dev
 
 
sudo dpkg -i musl-dbgsym_1.2.2-1_amd64.ddeb
sudo dpkg -i musl-dbgsym_1.2.2-1_amd64.ddeb
 
git clone https://github.com/xf1les/muslheap.git
git clone https://github.com/xf1les/muslheap.git
echo "source /path/to/muslheap.py" >> ~/.gdbinit
echo "source /path/to/muslheap.py" >> ~/.gdbinit
 
 
 
patchelf --set-interpreter ./libc.so ./rbin
patchelf --set-interpreter ./libc.so ./rbin
 
dir /path/to/musl-1.2.2/src/malloc/dir /path/to/musl-1.2.2/src/malloc/mallocng便可
dir /path/to/musl-1.2.2/src/malloc/dir /path/to/musl-1.2.2/src/malloc/mallocng便可
io = process([libc.so,rbin]) 这种启动方式是错误的!!!!
io = process([libc.so,rbin]) 这种启动方式是错误的!!!!
 
 
 
struct chunk{
 char prev_user_data[];
    uint8_t idx;  //5bit为idx第几个chunk
    uint16_t offset; //与第一个chunk起始地址的偏移,实际地址偏移为offset * UNIT,详细请看get_meta源码中得到group地址的而过程!
    char data[];
};
struct chunk{
 char prev_user_data[];
    uint8_t idx;  //5bit为idx第几个chunk
    uint16_t offset; //与第一个chunk起始地址的偏移,实际地址偏移为offset * UNIT,详细请看get_meta源码中得到group地址的而过程!
    char data[];
};
 
 
 
 
 
 
 
#define UNIT 16
#define IB 4
struct group {
    struct meta *meta;
    unsigned char active_idx:5;
    char pad[UNIT - sizeof(struct meta *) - 1];//padding=0x10B
    unsigned char storage[];// chunks
};
#define UNIT 16
#define IB 4
struct group {
    struct meta *meta;
    unsigned char active_idx:5;
    char pad[UNIT - sizeof(struct meta *) - 1];//padding=0x10B
    unsigned char storage[];// chunks
};
 
#musl-1.2.2\src\malloc\mallocng\meta.h line129
static inline struct meta *get_meta(const unsigned char *p)
{
    assert(!((uintptr_t)p & 15));
    int offset = *(const uint16_t *)(p - 2);
    int index = get_slot_index(p);
    if (p[-4]) {
        assert(!offset);
        offset = *(uint32_t *)(p - 8);
        assert(offset > 0xffff);
    }
    const struct group *base = (const void *)(p - UNIT*offset - UNIT);// base 指向的就是group 地址
  ............
}
#musl-1.2.2\src\malloc\mallocng\meta.h line129
static inline struct meta *get_meta(const unsigned char *p)
{
    assert(!((uintptr_t)p & 15));
    int offset = *(const uint16_t *)(p - 2);
    int index = get_slot_index(p);
    if (p[-4]) {
        assert(!offset);
        offset = *(uint32_t *)(p - 8);
        assert(offset > 0xffff);
    }
    const struct group *base = (const void *)(p - UNIT*offset - UNIT);// base 指向的就是group 地址
  ............
}
 
 
 
 
static inline int get_slot_index(const unsigned char *p)
{
    return p[-3] & 31;
}
static inline int get_slot_index(const unsigned char *p)
{
    return p[-3] & 31;
}
struct meta {
    struct meta *prev, *next;//双向链表
    struct group *mem;// 这里指向管理的group 地址
    volatile int avail_mask, freed_mask;
    uintptr_t last_idx:5;
    uintptr_t freeable:1;
    uintptr_t sizeclass:6;
    uintptr_t maplen:8*sizeof(uintptr_t)-12;
};
struct meta {
    struct meta *prev, *next;//双向链表
    struct group *mem;// 这里指向管理的group 地址
    volatile int avail_mask, freed_mask;
    uintptr_t last_idx:5;
    uintptr_t freeable:1;
    uintptr_t sizeclass:6;
    uintptr_t maplen:8*sizeof(uintptr_t)-12;
};
 
 
 
 
 
 
 
 
 
#musl-1.2.2\src\malloc\mallocng\free.c line 38
static int okay_to_free(struct meta *g)
{
    int sc = g->sizeclass;
 
    if (!g->freeable) return 0;
    ...........
}
#musl-1.2.2\src\malloc\mallocng\free.c line 38
static int okay_to_free(struct meta *g)
{
    int sc = g->sizeclass;
 
    if (!g->freeable) return 0;
    ...........
}
const uint16_t size_classes[] = {
    1, 2, 3, 4, 5, 6, 7, 8,
    9, 10, 12, 15,
    18, 20, 25, 31,
    36, 42, 50, 63,
    72, 84, 102, 127,
    146, 170, 204, 255,
    292, 340, 409, 511,
    584, 682, 818, 1023,
    1169, 1364, 1637, 2047,
    2340, 2730, 3276, 4095,
    4680, 5460, 6552, 8191,
};
const uint16_t size_classes[] = {
    1, 2, 3, 4, 5, 6, 7, 8,
    9, 10, 12, 15,
    18, 20, 25, 31,
    36, 42, 50, 63,
    72, 84, 102, 127,
    146, 170, 204, 255,
    292, 340, 409, 511,
    584, 682, 818, 1023,
    1169, 1364, 1637, 2047,
    2340, 2730, 3276, 4095,
    4680, 5460, 6552, 8191,
};
 
 
 
 
struct meta_area {
    uint64_t check;
    struct meta_area *next;
    int nslots;
    struct meta slots[];
};
struct meta_area {
    uint64_t check;
    struct meta_area *next;
    int nslots;
    struct meta slots[];
};
 
 
 
 
 
 
 
struct malloc_context {
    uint64_t secret;// 和meta_area 头的check 是同一个值 就是校验值
#ifndef PAGESIZE
    size_t pagesize;
#endif
    int init_done;//是否初始化标记
    unsigned mmap_counter;// 记录有多少mmap 的内存的数量
    struct meta *free_meta_head;// 被free 的meta 头 这里meta 管理使用了队列和双向循环链表
    struct meta *avail_meta;//指向可用meta数组
    size_t avail_meta_count, avail_meta_area_count, meta_alloc_shift;
    struct meta_area *meta_area_head, *meta_area_tail;
    unsigned char *avail_meta_areas;
    struct meta *active[48];// 记录着可用的meta
    size_t u sage_by_class[48];
    uint8_t unmap_seq[32], bounces[32];
    uint8_t seq;
    uintptr_t brk;
};
struct malloc_context {
    uint64_t secret;// 和meta_area 头的check 是同一个值 就是校验值
#ifndef PAGESIZE
    size_t pagesize;
#endif
    int init_done;//是否初始化标记
    unsigned mmap_counter;// 记录有多少mmap 的内存的数量
    struct meta *free_meta_head;// 被free 的meta 头 这里meta 管理使用了队列和双向循环链表
    struct meta *avail_meta;//指向可用meta数组
    size_t avail_meta_count, avail_meta_area_count, meta_alloc_shift;
    struct meta_area *meta_area_head, *meta_area_tail;
    unsigned char *avail_meta_areas;
    struct meta *active[48];// 记录着可用的meta
    size_t u sage_by_class[48];
    uint8_t unmap_seq[32], bounces[32];
    uint8_t seq;
    uintptr_t brk;
};
 
 
void *malloc(size_t n)
{
    if (size_overflows(n)) return 0;// 最大申请空间限制
    struct meta *g;
    uint32_t mask, first;
    int sc;
    int idx;
    int ctr;
 
    if (n >= MMAP_THRESHOLD) {// size >= 阈值 会直接通过mmap 申请空间
        size_t needed = n + IB + UNIT; //UNIT 0x10 IB 4 定义在meta.h 里 这里UNIT + IB 是一个基本头的大小
        void *p = mmap(0, needed, PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_ANON, -1, 0);//新mmap group 空间
        if (p==MAP_FAILED) return 0;
        wrlock();
        step_seq();
        g = alloc_meta();
        if (!g) { // 如果申请meta 失败 会把刚刚mmap 出来的group 回收
            unlock();
            munmap(p, needed);// 回收group
            return 0;
        }
        g->mem = p;// mem = group 地址
        g->mem->meta = g; //group 头部 指向meta (g 为 meta)
        g->last_idx = 0;//mmap的group last_idx默认值=0
        g->freeable = 1;
        g->sizeclass = 63; // mmap 的申请的 sizeclass 都为63
        g->maplen = (needed+4095)/4096;
        g->avail_mask = g->freed_mask = 0;
        ctx.mmap_counter++;// mmap 内存记载数量++
        idx = 0;
        goto success;
    }
    //否则直接根据传入size,转换成size_classes的对应大小的 下标,
    sc = size_to_class(n);
 
    rdlock();
    g = ctx.active[sc]; // 从现有的active中取出对应sc 的 meta ,不同sc 对应不同的meta
 
  /*
    如果从ctx.active 中没找到对应的meta 会执行下面的if分支
    这里!g<=> g==0 ,说明ctx.active[sc] 没有对应的meta
    */
    if (!g && sc>=4 && sc<32 && sc!=6 && !(sc&1) && !ctx.usage_by_class[sc]) {
        size_t usage = ctx.usage_by_class[sc|1];// 如果在 ctx.active 没找到 就使用更大size group 的meta
        // if a new group may be allocated, count it toward
        // usage in deciding if we can use coarse class.
        if (!ctx.active[sc|1] || (!ctx.active[sc|1]->avail_mask
            && !ctx.active[sc|1]->freed_mask))
            usage += 3;
        if (usage <= 12)
            sc |= 1;
        g = ctx.active[sc];
    }
 
    for (;;) {
        mask = g ? g->avail_mask : 0;
        first = mask&-mask;
        if (!first) break;
        if (RDLOCK_IS_EXCLUSIVE || !MT)
            g->avail_mask = mask-first;
        else if (a_cas(&g->avail_mask, mask, mask-first)!=mask)
            continue;
        idx = a_ctz_32(first);
        goto success;
    }
    upgradelock();
 
    idx = alloc_slot(sc, n);
  /*
  如果当前group 不满足就会来到这里:
      alloc_slot 从group 中取出对应大小chunk 的idx
      这里先从对应sc 的ctx.active[sc] 中找对应的meta的group 有无空闲chunk可以使用
        再从队列中其他meta的group 中找
      如果队列中其他meta的group 有可利用的chunk,就使用
      如果没有就重新分配一个新的group
  */
    if (idx < 0) {
        unlock();
        return 0;
    }
    g = ctx.active[sc];// 取出 sc 对应active meta
 
success:
    ctr = ctx.mmap_counter;
    unlock();
    return enframe(g, idx, n, ctr);// 从对应meta 中的group 取出 第idx号chunk  n = size
}
void *malloc(size_t n)
{
    if (size_overflows(n)) return 0;// 最大申请空间限制
    struct meta *g;
    uint32_t mask, first;
    int sc;
    int idx;
    int ctr;
 
    if (n >= MMAP_THRESHOLD) {// size >= 阈值 会直接通过mmap 申请空间
        size_t needed = n + IB + UNIT; //UNIT 0x10 IB 4 定义在meta.h 里 这里UNIT + IB 是一个基本头的大小
        void *p = mmap(0, needed, PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_ANON, -1, 0);//新mmap group 空间
        if (p==MAP_FAILED) return 0;
        wrlock();
        step_seq();
        g = alloc_meta();
        if (!g) { // 如果申请meta 失败 会把刚刚mmap 出来的group 回收
            unlock();
            munmap(p, needed);// 回收group
            return 0;
        }
        g->mem = p;// mem = group 地址
        g->mem->meta = g; //group 头部 指向meta (g 为 meta)
        g->last_idx = 0;//mmap的group last_idx默认值=0
        g->freeable = 1;
        g->sizeclass = 63; // mmap 的申请的 sizeclass 都为63
        g->maplen = (needed+4095)/4096;
        g->avail_mask = g->freed_mask = 0;
        ctx.mmap_counter++;// mmap 内存记载数量++
        idx = 0;
        goto success;
    }
    //否则直接根据传入size,转换成size_classes的对应大小的 下标,
    sc = size_to_class(n);
 
    rdlock();
    g = ctx.active[sc]; // 从现有的active中取出对应sc 的 meta ,不同sc 对应不同的meta
 
  /*
    如果从ctx.active 中没找到对应的meta 会执行下面的if分支
    这里!g<=> g==0 ,说明ctx.active[sc] 没有对应的meta
    */
    if (!g && sc>=4 && sc<32 && sc!=6 && !(sc&1) && !ctx.usage_by_class[sc]) {
        size_t usage = ctx.usage_by_class[sc|1];// 如果在 ctx.active 没找到 就使用更大size group 的meta
        // if a new group may be allocated, count it toward
        // usage in deciding if we can use coarse class.
        if (!ctx.active[sc|1] || (!ctx.active[sc|1]->avail_mask
            && !ctx.active[sc|1]->freed_mask))
            usage += 3;
        if (usage <= 12)
            sc |= 1;
        g = ctx.active[sc];
    }
 
    for (;;) {
        mask = g ? g->avail_mask : 0;
        first = mask&-mask;
        if (!first) break;
        if (RDLOCK_IS_EXCLUSIVE || !MT)
            g->avail_mask = mask-first;
        else if (a_cas(&g->avail_mask, mask, mask-first)!=mask)
            continue;
        idx = a_ctz_32(first);
        goto success;
    }
    upgradelock();
 
    idx = alloc_slot(sc, n);
  /*
  如果当前group 不满足就会来到这里:
      alloc_slot 从group 中取出对应大小chunk 的idx
      这里先从对应sc 的ctx.active[sc] 中找对应的meta的group 有无空闲chunk可以使用
        再从队列中其他meta的group 中找
      如果队列中其他meta的group 有可利用的chunk,就使用
      如果没有就重新分配一个新的group
  */
    if (idx < 0) {
        unlock();
        return 0;
    }
    g = ctx.active[sc];// 取出 sc 对应active meta
 
success:
    ctr = ctx.mmap_counter;
    unlock();
    return enframe(g, idx, n, ctr);// 从对应meta 中的group 取出 第idx号chunk  n = size
}
for (;;) {
    mask = g ? g->avail_mask : 0; //先检查g所指meta是否存在,若存在mask = g->avail_mask
    first = mask&-mask;                     //这里只有mask=0时,first才会为0
    if (!first) break;                        //mask为0,first=0,无可用空闲chunk,跳出循环
    if (RDLOCK_IS_EXCLUSIVE || !MT)//如果是排它锁, 那么下面保证成功
        g->avail_mask = mask-first;
    else if (a_cas(&g->avail_mask, mask, mask-first)!=mask) //成功找到并设置avail_mask之后,continue 后设置idx,然后跳出
        continue;
    idx = a_ctz_32(first);
    goto success;
}
    upgradelock();
    如果
 
    idx = alloc_slot(sc, n);
for (;;) {
    mask = g ? g->avail_mask : 0; //先检查g所指meta是否存在,若存在mask = g->avail_mask
    first = mask&-mask;                     //这里只有mask=0时,first才会为0
    if (!first) break;                        //mask为0,first=0,无可用空闲chunk,跳出循环
    if (RDLOCK_IS_EXCLUSIVE || !MT)//如果是排它锁, 那么下面保证成功
        g->avail_mask = mask-first;
    else if (a_cas(&g->avail_mask, mask, mask-first)!=mask) //成功找到并设置avail_mask之后,continue 后设置idx,然后跳出
        continue;
    idx = a_ctz_32(first);
    goto success;
}
    upgradelock();
    如果
 
    idx = alloc_slot(sc, n);
static int alloc_slot(int sc, size_t req)
{    // 尝试从限制active 中找到合适可用的
    uint32_t first = try_avail(&ctx.active[sc]);
    if (first) return a_ctz_32(first);
 
  // 如果没找到 重新创造一个meta,然后重新分配一个size大小对应sc的group,给这个新分配的meta
    struct meta *g = alloc_group(sc, req);
    if (!g) return -1;
 
    g->avail_mask--;
    queue(&ctx.active[sc], g); //把新meta 加入队列
    return 0;
}
static int alloc_slot(int sc, size_t req)
{    // 尝试从限制active 中找到合适可用的
    uint32_t first = try_avail(&ctx.active[sc]);
    if (first) return a_ctz_32(first);
 
  // 如果没找到 重新创造一个meta,然后重新分配一个size大小对应sc的group,给这个新分配的meta
    struct meta *g = alloc_group(sc, req);

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

最后于 2022-5-14 21:46 被0xRGz编辑 ,原因: 更新错误
收藏
免费 9
支持
分享
最新回复 (5)
雪    币: 4168
活跃值: (15932)
能力值: ( LV9,RANK:710 )
在线值:
发帖
回帖
粉丝
2
目前musl源码解析还是比较少的,支持!
2021-9-30 12:47
0
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
3
师傅,函数调用图使用什么软件生成的呀
2021-10-13 16:30
0
雪    币: 1446
活跃值: (846)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
4
函数调用图是 understand 吾爱上的破解
2021-10-13 17:58
0
雪    币: 380
活跃值: (840)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
5
woc zgr!
2022-4-26 08:59
1
雪    币: 262
活跃值: (758)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
6
group 不一定都是mmap分配 的吧
2022-10-8 00:00
0
游客
登录 | 注册 方可回帖
返回
//