selph
selph
发布于 2024-01-04 / 98 阅读
0
0

[libc 2.35 源码学习] 申请内存 fastbin

_int_malloc

申请tcachebin的函数是__libc_malloc,如果tcachebin分配不了,就会调用_int_malloc进行接下来的分配

_int_malloc优先分配fastbin中的chunk:

    /*
       If the size qualifies as a fastbin, first check corresponding bin.
       This code is safe to execute even if av is not yet initialized, so we
       can try it without checking, which saves some time on this fast path.
     */

#define REMOVE_FB(fb, victim, pp)                                          \
    do                                                                     \
    {                                                                      \
        victim = pp;                                                       \
        if (victim == NULL)                                                \
            break;                                                         \
        pp = REVEAL_PTR(victim->fd);                                       \
        if (__glibc_unlikely(pp != NULL && misaligned_chunk(pp)))          \
            malloc_printerr("malloc(): unaligned fastbin chunk detected"); \
    } while ((pp = catomic_compare_and_exchange_val_acq(fb, pp, victim)) != victim);
  
    // 检查申请大小是否在fastbin范围内
    if ((unsigned long)(nb) <= (unsigned long)(get_max_fast()))
    {
        // 从申请大小获取fastbin索引
        idx = fastbin_index(nb);
        // 获取fastbin
        mfastbinptr *fb = &fastbin(av, idx);
        mchunkptr pp;
        victim = *fb;
        // 如果对应索引的fastbin存在
        if (victim != NULL)
        {
            // fastbin top 地址对齐检查
            if (__glibc_unlikely(misaligned_chunk(victim)))
                malloc_printerr("malloc(): unaligned fastbin chunk detected 2");
            // 解密fd指针,fb指向该解密的指针,fb指向下一个成员,其实就是单链表断链操作
            if (SINGLE_THREAD_P)
                *fb = REVEAL_PTR(victim->fd);
            else
                REMOVE_FB(fb, pp, victim);
    
            if (__glibc_likely(victim != NULL))
            {
                // 从fastbin第一个chunk获取fastbin索引,这两个索引需要是一样的
                // 这里是个安全检查,检查申请的chunk和目标fastbin的索引是否一致
                size_t victim_idx = fastbin_index(chunksize(victim));
                if (__builtin_expect(victim_idx != idx, 0))
                    malloc_printerr("malloc(): memory corruption (fast)");
                check_remalloced_chunk(av, victim, nb);
#if USE_TCACHE
                /* While we're here, if we see other chunks of the same size,
                stash them in the tcache.  */
                // 如果有其他相同大小的chunk,保存到tcache中
                // 计算tcache索引
                size_t tc_idx = csize2tidx(nb);
                // 如果tcache满足要求
                if (tcache && tc_idx < mp_.tcache_bins)
                {
                    mchunkptr tc_victim;

                    /* While bin not empty and tcache not full, copy chunks.  */
                    // tcachebin没满,fastbin有内容
                    // 就从fastbin中取出,放到tcache中
                    while (tcache->counts[tc_idx] < mp_.tcache_count && (tc_victim = *fb) != NULL)
                    {
                        // 即将放入的chunk进行对齐检查 
                        if (__glibc_unlikely(misaligned_chunk(tc_victim)))
                            malloc_printerr("malloc(): unaligned fastbin chunk detected 3");
                        // 指针解密,断链首个成员取出来
                        if (SINGLE_THREAD_P)
                            *fb = REVEAL_PTR(tc_victim->fd);
                        else
                        {
                            REMOVE_FB(fb, pp, tc_victim);
                            if (__glibc_unlikely(tc_victim == NULL))
                                break;
                        }
                        // 存入tcache中
                        tcache_put(tc_victim, tc_idx);
                    }
                }
#endif
                // 返回mem地址,chunk地址加header size
                void *p = chunk2mem(victim);
                alloc_perturb(p, bytes);
                return p;
            }
        }
    }

主要内容:

  1. 检查申请大小是否满足fastbin大小要求(小于fastbin最大大小)

  2. 寻找对应大小的fastbin,取出首个成员,内存对齐检查

  3. 解密fd指针,单链表断链首个成员修改fastbin头指针

  4. 大小检查:检查目标fastbin首个成员的大小和申请内存的大小对应的索引是否不同,不同就报错

  5. 如果启用了tcache:

    1. 如果tcachebin里没装满,同大小的fastbin里有内容,就把fastbin里的chunk转移到tcache里

主要进行的检查就是大小检查


评论