`
mqzhuang
  • 浏览: 187585 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
文章分类
社区版块
存档分类
最新评论

Glibc内存管理--ptmalloc2源代码分析(十九)

阅读更多

5.5.2 ptmalloc_init()函数

 

ptmalloc_init() 函数比较长,将分段对这个函数做介绍。

 

static void
ptmalloc_init (void)
{
#if __STD_C
  const char* s;
#else
  char* s;
#endif
  int secure = 0;

  if(__malloc_initialized >= 0) return;
  __malloc_initialized = 0;

 首先检查全局变量 __malloc_initialized 是否大于等于 0 ,如果该值大于 0 ,表示 ptmalloc 已经初始化,如果改值为 0 ,表示 ptmalloc 正在初始化,全局变量 __malloc_initialized 用来保证全局只初始化 ptmalloc 一次。

#ifdef _LIBC
# if defined SHARED && !USE___THREAD
  /* ptmalloc_init_minimal may already have been called via
     __libc_malloc_pthread_startup, above.  */
  if (mp_.pagesize == 0)
# endif
#endif
    ptmalloc_init_minimal();

#ifndef NO_THREADS
# if defined _LIBC
  /* We know __pthread_initialize_minimal has already been called,
     and that is enough.  */
#   define NO_STARTER
# endif
# ifndef NO_STARTER
  /* With some threads implementations, creating thread-specific data
     or initializing a mutex may call malloc() itself.  Provide a
     simple starter version (realloc() won't work). */
  save_malloc_hook = __malloc_hook;
  save_memalign_hook = __memalign_hook;
  save_free_hook = __free_hook;
  __malloc_hook = malloc_starter;
  __memalign_hook = memalign_starter;
  __free_hook = free_starter;
#  ifdef _LIBC
  /* Initialize the pthreads interface. */
  if (__pthread_initialize != NULL)
    __pthread_initialize();
#  endif /* !defined _LIBC */
# endif /* !defined NO_STARTER */
#endif /* !defined NO_THREADS */

 为多线程版本的 ptmalloc pthread 初始化做准备,保存当前的 hooks 函数,并把 ptmalloc 为初始化时所有使用的分配 / 释放函数赋给 hooks 函数,因为在线程初始化一些私有实例时, ptmalloc 还没有初始化,所以需要做特殊处理。从这些 hooks 函数可以看出,在 ptmalloc 未初始化时,不能使用 remalloc 函数。在相关的 hooks 函数赋值以后,执行 pthread_initilaize() 初始化 pthread

  mutex_init(&main_arena.mutex);
  main_arena.next = &main_arena;

 初始化主分配区的 mutex ,并将主分配区的 next 指针指向自身组成环形链表。

#if defined _LIBC && defined SHARED
  /* In case this libc copy is in a non-default namespace, never use brk.
     Likewise if dlopened from statically linked program.  */
  Dl_info di;
  struct link_map *l;

  if (_dl_open_hook != NULL
      || (_dl_addr (ptmalloc_init, &di, &l, NULL) != 0
          && l->l_ns != LM_ID_BASE))
    __morecore = __failing_morecore;
#endif

 Ptmalloc需要保证只有主分配区才能使用 sbrk() 分配连续虚拟内存空间,如果有多个分配区使用 sbrk() 就不能获得连续的虚拟地址空间,大多数情况下 Glibc 库都是以动态链接库的形式加载的,处于默认命名空间,多个进程共用 Glibc 库, Glibc 库代码段在内存中只有一份拷贝,数据段在每个用户进程都有一份拷贝。但如果 Glibc 库不在默认名字空间,或是用户程序是静态编译的并调用了 dlopen 函数加载 Glibc 库中的 ptamalloc_init() ,这种情况下的 ptmalloc 不允许使用 sbrk() 分配内存,只需修改 __morecore 函数指针指向 __failing_morecore 就可以禁止使用 sbrk() 了, __morecore 默认指向 sbrk()

 mutex_init(&list_lock);
  tsd_key_create(&arena_key, NULL);
  tsd_setspecific(arena_key, (Void_t *)&main_arena);
  thread_atfork(ptmalloc_lock_all, ptmalloc_unlock_all, ptmalloc_unlock_all2);

 初始化全局锁 list_lock list_lock 主要用于同步分配区的单向循环链表。然后创建线程私有实例 arena_key ,该私有实例保存的是分配区( arena )的 malloc_state 实例指针。 arena_key 指向的可能是主分配区的指针,也可能是非主分配区的指针,这里将调用 ptmalloc_init() 的线程的 arena_key 绑定到主分配区上。意味着本线程首选从主分配区分配内存。

然后调用 thread_atfork() 设置当前进程在 fork 子线程( linux 下线程是轻量级进程,使用类似 fork 进程的机制创建)时处理 mutex 的回调函数,在本进程 fork 子线程时,调用 ptmalloc_lock_all() 获得所有分配区的锁,禁止所有分配区分配内存,当子线程创建完毕,父进程调用 ptmalloc_unlock_all() 重新 unlock 每个分配区的锁 mutex ,子线程调用 ptmalloc_unlock_all2() 重新初始化每个分配区的锁 mutex 。这几个回调函数将在 5.5.3 节介绍。

#ifndef NO_THREADS
# ifndef NO_STARTER
  __malloc_hook = save_malloc_hook;
  __memalign_hook = save_memalign_hook;
  __free_hook = save_free_hook;
# else
#  undef NO_STARTER
# endif
#endif

 当pthread 初始化完成后,将相应的 hooks 函数还原为原值。

#ifdef _LIBC
  secure = __libc_enable_secure;
  s = NULL;
  if (__builtin_expect (_environ != NULL, 1))
    {
      char **runp = _environ;
      char *envline;

      while (__builtin_expect ((envline = next_env_entry (&runp)) != NULL,
                               0))
        {
          size_t len = strcspn (envline, "=");

          if (envline[len] != '=')
            /* This is a "MALLOC_" variable at the end of the string
               without a '=' character.  Ignore it since otherwise we
               will access invalid memory below.  */
            continue;

          switch (len)
            {
            case 6:
              if (memcmp (envline, "CHECK_", 6) == 0)
                s = &envline[7];
              break;
            case 8:
              if (! secure)
                {
                  if (memcmp (envline, "TOP_PAD_", 8) == 0)
                    mALLOPt(M_TOP_PAD, atoi(&envline[9]));
                  else if (memcmp (envline, "PERTURB_", 8) == 0)
                    mALLOPt(M_PERTURB, atoi(&envline[9]));
                }
              break;
            case 9:
              if (! secure)
                {
                  if (memcmp (envline, "MMAP_MAX_", 9) == 0)
                    mALLOPt(M_MMAP_MAX, atoi(&envline[10]));
#ifdef PER_THREAD
                  else if (memcmp (envline, "ARENA_MAX", 9) == 0)
                    mALLOPt(M_ARENA_MAX, atoi(&envline[10]));
#endif
                }
              break;
#ifdef PER_THREAD
            case 10:
              if (! secure)
                {
                  if (memcmp (envline, "ARENA_TEST", 10) == 0)
                    mALLOPt(M_ARENA_TEST, atoi(&envline[11]));
                }
              break;
#endif
            case 15:
              if (! secure)
                {
                  if (memcmp (envline, "TRIM_THRESHOLD_", 15) == 0)
                    mALLOPt(M_TRIM_THRESHOLD, atoi(&envline[16]));
                  else if (memcmp (envline, "MMAP_THRESHOLD_", 15) == 0)
                    mALLOPt(M_MMAP_THRESHOLD, atoi(&envline[16]));
                }
              break;
            default:
              break;
            }
        }
    }
#else
  if (! secure)
    {
      if((s = getenv("MALLOC_TRIM_THRESHOLD_")))
        mALLOPt(M_TRIM_THRESHOLD, atoi(s));
      if((s = getenv("MALLOC_TOP_PAD_")))
        mALLOPt(M_TOP_PAD, atoi(s));
      if((s = getenv("MALLOC_PERTURB_")))
        mALLOPt(M_PERTURB, atoi(s));
      if((s = getenv("MALLOC_MMAP_THRESHOLD_")))
        mALLOPt(M_MMAP_THRESHOLD, atoi(s));
      if((s = getenv("MALLOC_MMAP_MAX_")))
        mALLOPt(M_MMAP_MAX, atoi(s));
    }
  s = getenv("MALLOC_CHECK_");
#endif
  if(s && s[0]) {
    mALLOPt(M_CHECK_ACTION, (int)(s[0] - '0'));
    if (check_action != 0)
      __malloc_check_init();
  }

 从环境变量中读取相应的配置参数值,这些参数包括 MALLOC_TRIM_THRESHOLD_ MALLOC_TOP_PAD_ MALLOC_PERTURB_ MALLOC_MMAP_THRESHOLD_ MALLOC_CHECK_ MALLOC_MMAP_MAX_ MALLOC_ ARENA_MAX,MALLOC_ ARENA_TEST, 如果这些选项中的某些项存在,调用 mallopt() 函数设置相应的选项。如果这段程序是在 Glibc 库初始化中执行的,会做更多的安全检查工作。

void (*hook) (void) = force_reg (__malloc_initialize_hook);
  if (hook != NULL)
    (*hook)();
  __malloc_initialized = 1;
}

 在ptmalloc_init() 函数结束处,查看是否存在 __malloc_initialize_hook 函数,如果存在,执行该 hook 函数。最后将全局变量 __malloc_initialized 设置为 1 ,表示 ptmalloc_init() 已经初始化完成。

 

 

 

分享到:
评论

相关推荐

    Glibc内存管理--ptmalloc2源代码分析(三十四)

    《Glibc内存管理--ptmalloc2源代码分析》 Glibc是GNU项目提供的C语言标准库,它在Linux系统中扮演着至关重要的角色。其中,内存管理是Glibc中的核心部分,它负责程序运行时的内存分配与释放,对系统的性能有着深远...

    glibc内存管理ptmalloc源代码分析PDF

    在分析glibc内存管理的ptmalloc源代码之前,我们需要先了解一些基础知识,包括操作系统对内存的分配和管理方法,以及glibc内存分配机制。 内存管理是操作系统的一个核心功能,它负责维护和管理计算机系统中的物理和...

    glibc内存管理ptmalloc源代码分析-高清PDF-pdf版

    《glibc内存管理ptmalloc源代码分析》是一份深入探讨Linux系统中glibc库内存管理机制的专业资料。glibc,全称GNU C Library,是Linux操作系统下广泛使用的C语言标准库,其中ptmalloc是glibc中负责动态内存分配的核心...

    glibc内存管理ptmalloc源代码分析.pdf

    glibc内存管理ptmalloc源代码分析

    glibc内存管理ptmalloc源代码分析@华庭1

    在深入探讨Glibc内存管理的Ptmalloc源代码之前,我们先来了解一下内存管理的基本概念。内存管理是操作系统和编程语言库中的核心组件,它负责有效地分配和回收内存,以确保程序的高效运行和资源的有效利用。 2.1 X86...

    Glibc内存管理Ptmalloc2源代码分析

    标题与描述中的关键词“Glibc内存管理Ptmalloc2源代码分析”指向了对Glibc中Ptmalloc2这一内存管理器的深入探讨。本文将围绕这一主题,详细解析Ptmalloc2的核心概念、设计原则、数据结构以及关键功能,同时结合给定...

    glibc内存管理ptmalloc源代码分析4.pdf

    通过对ptmalloc源代码的深入分析,可以找到潜在的优化点,如调整分配策略、改进数据结构设计等,以解决这些问题。 #### 13. 使用注意事项 虽然ptmalloc提供了强大的内存管理功能,但在使用过程中也需要注意一些事项...

    glibc内存管理ptmalloc源代码分析1

    在深入探讨Glibc内存管理的Ptmalloc源代码之前,我们先来了解一下内存管理的基本概念和Glibc中的Ptmalloc2。内存管理是操作系统和应用程序中的核心部分,它负责为程序分配和释放内存,以确保资源的有效利用和避免...

    glibc内存管理ptmalloc源代码分析

    ### glibc内存管理ptmalloc源代码分析 #### 1. 问题 在开发一款NoSQL系统的过程中,我们遇到一个令人头疼的问题:系统中使用的内存管理模块,在高并发、高负载的场景下,虽然已将内存释放给C运行时库(即glibc),...

    glibc内存管理ptmalloc源代码分析-清晰版.pdf

    ### glibc内存管理ptmalloc源代码分析-清晰版 #### 一、背景介绍与文档概览 本文档针对glibc中的ptmalloc2内存管理模块进行了深入的源代码分析,旨在帮助开发者更好地理解ptmalloc的工作原理及其内部机制。文档...

    Python-用于检测glibc堆ptmalloc的gdbpython库

    `glibc`是GNU项目提供的C标准库,而`ptmalloc`是它的一部分,负责程序的内存分配与管理。`ptmalloc`优化了内存分配效率,但在某些情况下也可能成为安全漏洞的来源。 `GDB`(GNU调试器)是一款强大的调试工具,它...

    内存管理与调试详细剖析

    本文将深入探讨内存管理的基本原理及其调试方法,特别关注于Linux环境下的Glibc内存管理库以及Ptmalloc2的具体实现。 #### 二、基础知识 ##### 2.1 X86平台Linux进程内存布局 **2.1.1 32位模式下进程内存经典布局...

    malloc源码分析glibc库

    通过对glibc库中的ptmalloc源代码进行深入分析,我们不仅了解了其内部实现机制,还能够针对实际应用中的内存管理问题提出有效的解决方案。这对于提升程序性能、减少内存碎片以及提高系统的整体稳定性具有重要意义。...

    pwn学习总结(八)—— 堆(持续更新)

    学习自《glibc内存管理ptmalloc源代码分析》庄明强 著 部分资料参考自互联网 chunk 描述: 当用户通过malloc等函数申请空间时,实际上是从堆中分配内存 目前 Linux 标准发行版中使用的是 glibc 中的堆分配器:...

    堆漏洞的利用技巧1

    《堆漏洞的利用技巧》 堆溢出是计算机安全领域中的一个重要...同时,阅读glibc内存管理的源代码分析对于提高理解和实践能力非常有帮助。通过这些知识的学习,不仅可以增强安全意识,也能提升在CTF竞赛中的攻防能力。

Global site tag (gtag.js) - Google Analytics