┌───────────────────────┐
│                       │
│                       │
│                       │
│                       │
│                       │
│                       │
│                       │
│                       │
│                       │
│                       │
│                       │
│                       │
│                       │
│                       │
│                       │
└───────────────────────┘
GLIBC Ptmalloc2 Dynamic Allocator Source Code Analysis
~ CuB3y0nd
# 


…… GLIBC 





……


 GLIBC 2.23 
 Civiled线
 2.29  2.28  key field prote
ction, 

_PS: ……
西
_

……

## Heap

 (Heap) 

线
——


:::note[History]
Linux  Doug Lea 线
线使
线使线使
Wolfram Gloger  Doug Lea 
使线 ptmalloc   glibc-2.3.x.
 glibc  ptmalloc2 

 Linux 使 glibc ptmalloc2 ptmalloc
2  malloc / free  pt
malloc2 
:::



1. 



2. 


:::tip
使Linux 访

使
使
:::

### 

#### malloc

```plaintext showLineNumbers=false
/*
  malloc(size_t n)
  Returns a pointer to a newly allocated chunk of at least n bytes, or null
  if no space is available. Additionally, on failure, errno is
  set to ENOMEM on ANSI C systems.

  If n is zero, malloc returns a minumum-sized chunk. (The minimum
  size is 16 bytes on most 32bit systems, and 24 or 32 bytes on 64bit
  systems.)  On most systems, size_t is an unsigned type, so calls
  with negative arguments are interpreted as requests for huge amounts
  of space, which will often fail. The maximum supported value of n
  differs across systems, but is in all cases less than the maximum
  representable value of a size_t.
*/
```

#### free

```plaintext showLineNumbers=false
/*
  free(void* p)
  Releases the chunk of memory pointed to by p, that had been previously
  allocated using malloc or a related routine such as realloc.
  It has no effect if p is null. It can have arbitrary (i.e., bad!)
  effects if p has already been freed.

  Unless disabled (using mallopt), freeing very large spaces will
  when possible, automatically trigger operations that give
  back unused memory to the system, thus reducing program footprint.
*/
```

### 

malloc  free  `(s)brk`
  `mmap`, `munmap` 

#### (s)brk

 `brk` glibc  `sbrk` 
 brk 

 `start_brk`  `brk` 
 ASLR

-  ASLR **start_brk**  **brk**  data / bss 
-  ASLR **start_brk**  **brk**  da
ta / bss 
```c
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

int main() {
  void *curr_brk, *tmp_brk = NULL;

  printf("Welcome to sbrk example: %dn", getpid());

  /* sbrk(0) gives current program break location */
  tmp_brk = curr_brk = sbrk(0);
  printf("Program Break Location1: %pn", curr_brk);
  getchar();

  /* brk(addr) increments/decrements program break location */
  brk(curr_brk + 4096);

  curr_brk = sbrk(0);
  printf("Program Break Location2: %pn", curr_brk);
  getchar();

  brk(tmp_brk);

  curr_brk = sbrk(0);
  printf("Program Break Location3: %pn", curr_brk);
  getchar();

  return 0;
}
```

#### mmap

malloc 使 mmap  0 
使

```c
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

void static inline errExit(const char *msg) {
  printf("%s failed. Exiting the processn", msg);
  exit(-1);
}

int main() {
  int ret = -1;
  printf("Welcome to private anonymous mapping example::PID:%dn", getpid());
  printf("Before mmapn");
  getchar();
  char *addr = NULL;
  addr = mmap(NULL, (size_t)132 * 1024, PROT_READ | PROT_WRITE,
              MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
  if (addr == MAP_FAILED)
    errExit("mmap");
  printf("After mmapn");
  getchar();

  /* Unmap mapped region. */
  ret = munmap(addr, (size_t)132 * 1024);
  if (ret == -1)
    errExit("munmap");
  printf("After munmapn");
  getchar();
  return 0;
}
```

### 线

 dlmalloc 线线
线线线
 glibc  ptmalloc 线访
线

```c
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>

void *threadFunc(void *arg) {
  printf("Before malloc in thread 1n");
  getchar();
  char *addr = (char *)malloc(1000);
  printf("After malloc and before free in thread 1n");
  getchar();
  free(addr);
  printf("After free in thread 1n");
  getchar();
}

int main() {
  pthread_t t1;
  void *s;
  int ret;
  char *addr;

  printf("Welcome to per thread arena example::%dn", getpid());
  printf("Before malloc in main threadn");
  getchar();
  addr = (char *)malloc(1000);
  printf("After malloc and before free in main threadn");
  getchar();
  free(addr);
  printf("After free in main threadn");
  getchar();
  ret = pthread_create(&t1, NULL, threadFunc, NULL);
  if (ret) {
    printf("Thread creation errorn");
    return -1;
  }
  ret = pthread_join(t1, &s);
  if (ret) {
    printf("Thread join errorn");
    return -1;
  }
  return 0;
}
```

线 heap  `0x555555559000     0x55555557a000 rw-p    21000   
   0 [heap]` 0x21000  1000 
便


```asm showLineNumbers=false ins={9} collapse={1-6, 12-33}
pwndbg> vmmap
LEGEND: STACK | HEAP | CODE | DATA | WX | RODATA
             Start                End Perm     Size Offset File (set vmmap-prefe
r-relpaths on)
    0x555555554000     0x555555555000 r--p     1000      0 test
    0x555555555000     0x555555556000 r-xp     1000   1000 test
    0x555555556000     0x555555557000 r--p     1000   2000 test
    0x555555557000     0x555555558000 r--p     1000   2000 test
    0x555555558000     0x555555559000 rw-p     1000   3000 test
    0x555555559000     0x55555557a000 rw-p    21000      0 [heap]
    0x7ffff7de6000     0x7ffff7de9000 rw-p     3000      0 [anon_7ffff7de6]
    0x7ffff7de9000     0x7ffff7e0e000 r--p    25000      0 /opt/glibc/2.29/64/li
b/libc-2.29.so
    0x7ffff7e0e000     0x7ffff7f55000 r-xp   147000  25000 /opt/glibc/2.29/64/li
b/libc-2.29.so
    0x7ffff7f55000     0x7ffff7f9e000 r--p    49000 16c000 /opt/glibc/2.29/64/li
b/libc-2.29.so
    0x7ffff7f9e000     0x7ffff7fa1000 r--p     3000 1b5000 /opt/glibc/2.29/64/li
b/libc-2.29.so
    0x7ffff7fa1000     0x7ffff7fa4000 rw-p     3000 1b8000 /opt/glibc/2.29/64/li
b/libc-2.29.so
    0x7ffff7fa4000     0x7ffff7fa8000 rw-p     4000      0 [anon_7ffff7fa4]
    0x7ffff7fa8000     0x7ffff7faf000 r--p     7000      0 /opt/glibc/2.29/64/li
b/libpthread-2.29.so
    0x7ffff7faf000     0x7ffff7fbe000 r-xp     f000   7000 /opt/glibc/2.29/64/li
b/libpthread-2.29.so
    0x7ffff7fbe000     0x7ffff7fc3000 r--p     5000  16000 /opt/glibc/2.29/64/li
b/libpthread-2.29.so
    0x7ffff7fc3000     0x7ffff7fc4000 r--p     1000  1a000 /opt/glibc/2.29/64/li
b/libpthread-2.29.so
    0x7ffff7fc4000     0x7ffff7fc5000 rw-p     1000  1b000 /opt/glibc/2.29/64/li
b/libpthread-2.29.so
    0x7ffff7fc5000     0x7ffff7fcb000 rw-p     6000      0 [anon_7ffff7fc5]
    0x7ffff7fcb000     0x7ffff7fcf000 r--p     4000      0 [vvar]
    0x7ffff7fcf000     0x7ffff7fd1000 r--p     2000      0 [vvar_vclock]
    0x7ffff7fd1000     0x7ffff7fd3000 r-xp     2000      0 [vdso]
    0x7ffff7fd3000     0x7ffff7fd4000 r--p     1000      0 /opt/glibc/2.29/64/li
b/ld-2.29.so
    0x7ffff7fd4000     0x7ffff7ff4000 r-xp    20000   1000 /opt/glibc/2.29/64/li
b/ld-2.29.so
    0x7ffff7ff4000     0x7ffff7ffc000 r--p     8000  21000 /opt/glibc/2.29/64/li
b/ld-2.29.so
    0x7ffff7ffc000     0x7ffff7ffd000 r--p     1000  29000 /opt/glibc/2.29/64/li
b/ld-2.29.so
    0x7ffff7ffd000     0x7ffff7ffe000 rw-p     1000  2a000 /opt/glibc/2.29/64/li
b/ld-2.29.so
    0x7ffff7ffe000     0x7ffff7fff000 rw-p     1000      0 [anon_7ffff7ffe]
    0x7ffffffde000     0x7ffffffff000 rw-p    21000      0 [stack]
0xffffffffff600000 0xffffffffff601000 --xp     1000      0 [vsyscall]
```

 0x21000  `arena`线
 `main_arena` arena 
 arena  brk arena 
 brk 

线 `0x7ffff75e6000     0x7ffff7de6000 rw-p   800
000      0 [anon_7ffff75e6]` 8 MB 线使 `limit` 
 8 MB

```asm showLineNumbers=false ins={11} collapse={1-8, 14-35}
pwndbg> vmmap
LEGEND: STACK | HEAP | CODE | DATA | WX | RODATA
             Start                End Perm     Size Offset File (set vmmap-prefe
r-relpaths on)
    0x555555554000     0x555555555000 r--p     1000      0 test
    0x555555555000     0x555555556000 r-xp     1000   1000 test
    0x555555556000     0x555555557000 r--p     1000   2000 test
    0x555555557000     0x555555558000 r--p     1000   2000 test
    0x555555558000     0x555555559000 rw-p     1000   3000 test
    0x555555559000     0x55555557a000 rw-p    21000      0 [heap]
    0x7ffff75e5000     0x7ffff75e6000 ---p     1000      0 [anon_7ffff75e5]
    0x7ffff75e6000     0x7ffff7de6000 rw-p   800000      0 [anon_7ffff75e6]
    0x7ffff7de6000     0x7ffff7de9000 rw-p     3000      0 [anon_7ffff7de6]
    0x7ffff7de9000     0x7ffff7e0e000 r--p    25000      0 /opt/glibc/2.29/64/li
b/libc-2.29.so
    0x7ffff7e0e000     0x7ffff7f55000 r-xp   147000  25000 /opt/glibc/2.29/64/li
b/libc-2.29.so
    0x7ffff7f55000     0x7ffff7f9e000 r--p    49000 16c000 /opt/glibc/2.29/64/li
b/libc-2.29.so
    0x7ffff7f9e000     0x7ffff7fa1000 r--p     3000 1b5000 /opt/glibc/2.29/64/li
b/libc-2.29.so
    0x7ffff7fa1000     0x7ffff7fa4000 rw-p     3000 1b8000 /opt/glibc/2.29/64/li
b/libc-2.29.so
    0x7ffff7fa4000     0x7ffff7fa8000 rw-p     4000      0 [anon_7ffff7fa4]
    0x7ffff7fa8000     0x7ffff7faf000 r--p     7000      0 /opt/glibc/2.29/64/li
b/libpthread-2.29.so
    0x7ffff7faf000     0x7ffff7fbe000 r-xp     f000   7000 /opt/glibc/2.29/64/li
b/libpthread-2.29.so
    0x7ffff7fbe000     0x7ffff7fc3000 r--p     5000  16000 /opt/glibc/2.29/64/li
b/libpthread-2.29.so
    0x7ffff7fc3000     0x7ffff7fc4000 r--p     1000  1a000 /opt/glibc/2.29/64/li
b/libpthread-2.29.so
    0x7ffff7fc4000     0x7ffff7fc5000 rw-p     1000  1b000 /opt/glibc/2.29/64/li
b/libpthread-2.29.so
    0x7ffff7fc5000     0x7ffff7fcb000 rw-p     6000      0 [anon_7ffff7fc5]
    0x7ffff7fcb000     0x7ffff7fcf000 r--p     4000      0 [vvar]
    0x7ffff7fcf000     0x7ffff7fd1000 r--p     2000      0 [vvar_vclock]
    0x7ffff7fd1000     0x7ffff7fd3000 r-xp     2000      0 [vdso]
    0x7ffff7fd3000     0x7ffff7fd4000 r--p     1000      0 /opt/glibc/2.29/64/li
b/ld-2.29.so
    0x7ffff7fd4000     0x7ffff7ff4000 r-xp    20000   1000 /opt/glibc/2.29/64/li
b/ld-2.29.so
    0x7ffff7ff4000     0x7ffff7ffc000 r--p     8000  21000 /opt/glibc/2.29/64/li
b/ld-2.29.so
    0x7ffff7ffc000     0x7ffff7ffd000 r--p     1000  29000 /opt/glibc/2.29/64/li
b/ld-2.29.so
    0x7ffff7ffd000     0x7ffff7ffe000 rw-p     1000  2a000 /opt/glibc/2.29/64/li
b/ld-2.29.so
    0x7ffff7ffe000     0x7ffff7fff000 rw-p     1000      0 [anon_7ffff7ffe]
    0x7ffffffde000     0x7ffffffff000 rw-p    21000      0 [stack]
0xffffffffff600000 0xffffffffff601000 --xp     1000      0 [vsyscall]
```

:::tip
 0x1000 (4 KB)  `---p`线 gua
rd page 

 Linux 线 guard page
访 SIGSEGV `
---p`  `----`
:::

线 malloc 线 heap  0x21000  
`0x7ffff0000000     0x7ffff0021000 rw-p    21000      0 [anon_7ffff0000]`
线 heap 线使 mmap  brk 
 `thread_arena`

```asm showLineNumbers=false ins={10} collapse={1-7, 13-37}
pwndbg> vmmap
LEGEND: STACK | HEAP | CODE | DATA | WX | RODATA
             Start                End Perm     Size Offset File (set vmmap-prefe
r-relpaths on)
    0x555555554000     0x555555555000 r--p     1000      0 test
    0x555555555000     0x555555556000 r-xp     1000   1000 test
    0x555555556000     0x555555557000 r--p     1000   2000 test
    0x555555557000     0x555555558000 r--p     1000   2000 test
    0x555555558000     0x555555559000 rw-p     1000   3000 test
    0x555555559000     0x55555557a000 rw-p    21000      0 [heap]
    0x7ffff0000000     0x7ffff0021000 rw-p    21000      0 [anon_7ffff0000]
    0x7ffff0021000     0x7ffff4000000 ---p  3fdf000      0 [anon_7ffff0021]
    0x7ffff75e5000     0x7ffff75e6000 ---p     1000      0 [anon_7ffff75e5]
    0x7ffff75e6000     0x7ffff7de6000 rw-p   800000      0 [anon_7ffff75e6]
    0x7ffff7de6000     0x7ffff7de9000 rw-p     3000      0 [anon_7ffff7de6]
    0x7ffff7de9000     0x7ffff7e0e000 r--p    25000      0 /opt/glibc/2.29/64/li
b/libc-2.29.so
    0x7ffff7e0e000     0x7ffff7f55000 r-xp   147000  25000 /opt/glibc/2.29/64/li
b/libc-2.29.so
    0x7ffff7f55000     0x7ffff7f9e000 r--p    49000 16c000 /opt/glibc/2.29/64/li
b/libc-2.29.so
    0x7ffff7f9e000     0x7ffff7fa1000 r--p     3000 1b5000 /opt/glibc/2.29/64/li
b/libc-2.29.so
    0x7ffff7fa1000     0x7ffff7fa4000 rw-p     3000 1b8000 /opt/glibc/2.29/64/li
b/libc-2.29.so
    0x7ffff7fa4000     0x7ffff7fa8000 rw-p     4000      0 [anon_7ffff7fa4]
    0x7ffff7fa8000     0x7ffff7faf000 r--p     7000      0 /opt/glibc/2.29/64/li
b/libpthread-2.29.so
    0x7ffff7faf000     0x7ffff7fbe000 r-xp     f000   7000 /opt/glibc/2.29/64/li
b/libpthread-2.29.so
    0x7ffff7fbe000     0x7ffff7fc3000 r--p     5000  16000 /opt/glibc/2.29/64/li
b/libpthread-2.29.so
    0x7ffff7fc3000     0x7ffff7fc4000 r--p     1000  1a000 /opt/glibc/2.29/64/li
b/libpthread-2.29.so
    0x7ffff7fc4000     0x7ffff7fc5000 rw-p     1000  1b000 /opt/glibc/2.29/64/li
b/libpthread-2.29.so
    0x7ffff7fc5000     0x7ffff7fcb000 rw-p     6000      0 [anon_7ffff7fc5]
    0x7ffff7fcb000     0x7ffff7fcf000 r--p     4000      0 [vvar]
    0x7ffff7fcf000     0x7ffff7fd1000 r--p     2000      0 [vvar_vclock]
    0x7ffff7fd1000     0x7ffff7fd3000 r-xp     2000      0 [vdso]
    0x7ffff7fd3000     0x7ffff7fd4000 r--p     1000      0 /opt/glibc/2.29/64/li
b/ld-2.29.so
    0x7ffff7fd4000     0x7ffff7ff4000 r-xp    20000   1000 /opt/glibc/2.29/64/li
b/ld-2.29.so
    0x7ffff7ff4000     0x7ffff7ffc000 r--p     8000  21000 /opt/glibc/2.29/64/li
b/ld-2.29.so
    0x7ffff7ffc000     0x7ffff7ffd000 r--p     1000  29000 /opt/glibc/2.29/64/li
b/ld-2.29.so
    0x7ffff7ffd000     0x7ffff7ffe000 rw-p     1000  2a000 /opt/glibc/2.29/64/li
b/ld-2.29.so
    0x7ffff7ffe000     0x7ffff7fff000 rw-p     1000      0 [anon_7ffff7ffe]
    0x7ffffffde000     0x7ffffffff000 rw-p    21000      0 [stack]
0xffffffffff600000 0xffffffffff601000 --xp     1000      0 [vsyscall]
```

线 heap  64 MB  `ano
n_7ffff0021` / heap guard线 malloc 
使 mmap 

:::important
 128 KB (mmap_threshold)  arena 
 mmap 线
线

```asm showLineNumbers=false
pwndbg> p/d mp_.mmap_threshold/1024
$1 = 128
```

:::

## GLIBC 2.29

### Core Macro Definitions



```c
#ifndef _GENERIC_MALLOC_ALIGNMENT_H
#define _GENERIC_MALLOC_ALIGNMENT_H

/* MALLOC_ALIGNMENT is the minimum alignment for malloc'ed chunks.  It
   must be a power of two at least 2 * SIZE_SZ, even on machines for
   which smaller alignments would suffice. It may be defined as larger
   than this though. Note however that code and data structures are
   optimized for the case of 8-byte alignment.  */
#define MALLOC_ALIGNMENT (2 * SIZE_SZ < __alignof__ (long double) 
     ? __alignof__ (long double) : 2 * SIZE_SZ)

#endif /* !defined(_GENERIC_MALLOC_ALIGNMENT_H) */

#ifndef _I386_MALLOC_ALIGNMENT_H
#define _I386_MALLOC_ALIGNMENT_H

#define MALLOC_ALIGNMENT 16

#endif /* !defined(_I386_MALLOC_ALIGNMENT_H) */

/*
    generic  32  MALLOC_ALIGNMENT  8,  glibc
    i386  MALLOC_ALIGNMENT  override  16

    generic 
    override  generic 

    64-bit  32-bit, MALLOC_ALIGNMENT  16 
 */

#ifndef INTERNAL_SIZE_T
# define INTERNAL_SIZE_T size_t
#endif

/* The corresponding word size.  */
#define SIZE_SZ (sizeof (INTERNAL_SIZE_T))

/* The corresponding bit mask value.  */
#define MALLOC_ALIGN_MASK (MALLOC_ALIGNMENT - 1)
```

### malloc_chunk

malloc  chunk,  `malloc_chunk` 

```c
/*
  This struct declaration is misleading (but accurate and necessary).
  It declares a "view" into memory allowing access to necessary
  fields at known offsets from a given base. See explanation below.
*/

struct malloc_chunk {
  INTERNAL_SIZE_T      mchunk_prev_size;  /* Size of previous chunk (if free).  
*/
  INTERNAL_SIZE_T      mchunk_size;       /* Size in bytes, including overhead. 
*/

  struct malloc_chunk* fd;                /* double links -- used only if free. 
*/
  struct malloc_chunk* bk;

  /* Only used for large blocks: pointer to next larger size.  */
  struct malloc_chunk* fd_nextsize;       /* double links -- used only if free. 
*/
  struct malloc_chunk* bk_nextsize;
};

typedef struct malloc_chunk* mchunkptr;
```

#### Size and alignment checks and conversions

```c
/* conversion from malloc headers to user pointers, and back */

#define chunk2mem(p)   ((void*)((char*)(p) + 2*SIZE_SZ))
#define mem2chunk(mem) ((mchunkptr)((char*)(mem) - 2*SIZE_SZ))

/* The smallest possible chunk */
#define MIN_CHUNK_SIZE        (offsetof(struct malloc_chunk, fd_nextsize))

/* The smallest size we can malloc is an aligned minimal chunk */

/*
   mask = align - 1
   (X + mask) & ~mask 
   MALLOC_ALIGNMENT 

    X + mask 
   (X + mask) & ~mask  X  align 
 */

#define MINSIZE  
  (unsigned long)(((MIN_CHUNK_SIZE+MALLOC_ALIGN_MASK) & ~MALLOC_ALIGN_MASK))

/* Check if m has acceptable alignment */

#define aligned_OK(m)  (((unsigned long)(m) & MALLOC_ALIGN_MASK) == 0)

#define misaligned_chunk(p) 
  ((uintptr_t)(MALLOC_ALIGNMENT == 2 * SIZE_SZ ? (p) : chunk2mem (p)) 
   & MALLOC_ALIGN_MASK)


/*
   Check if a request is so large that it would wrap around zero when
   padded and aligned. To simplify some other code, the bound is made
   low enough so that adding MINSIZE will also not wrap around zero.
 */

#define REQUEST_OUT_OF_RANGE(req)                                 
  ((unsigned long) (req) >=                                       
   (unsigned long) (INTERNAL_SIZE_T) (-2 * MINSIZE))

/* pad request bytes into a usable size -- internal version */

#define request2size(req)                                         
  (((req) + SIZE_SZ + MALLOC_ALIGN_MASK < MINSIZE)  ?             
   MINSIZE :                                                      
   ((req) + SIZE_SZ + MALLOC_ALIGN_MASK) & ~MALLOC_ALIGN_MASK)

/* Same, except also perform an argument and result check.  First, we check
   that the padding done by request2size didn't result in an integer
   overflow.  Then we check (using REQUEST_OUT_OF_RANGE) that the resulting
   size isn't so large that a later alignment would lead to another integer
   overflow.  */
#define checked_request2size(req, sz) 
({                                  
  (sz) = request2size (req);        
  if (((sz) < (req))                
      || REQUEST_OUT_OF_RANGE (sz)) 
    {                               
      __set_errno (ENOMEM);         
      return 0;                     
    }                               
})
```

#### Allocated Chunk

```plaintext showLineNumbers=false
    chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
            |             Size of previous chunk, if unallocated (P clear)  |
            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
            |             Size of chunk, in bytes                     |A|M|P|
      mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
            |             User data starts here...                          .
            .                                                               .
            .             (malloc_usable_size() bytes)                      .
            .                                                               |
nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
            |             (size of chunk, but used for application data)    |
            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
            |             Size of next chunk, in bytes                |A|0|1|
            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
```

 chunk  `chunk`  metadata (overhead) 
 chunk  `mchunk_prev_size`  chunk  `mchunk_size` (metada
ta size + user data size)mchunk_size  `MALLOC_ALIGNMENT` 
 MALLOC_ALIGNMENT  MALLOC_AL
IGNMENT malloc  metadata  `mem` 


:::important
malloc  chunk ; free  chunk  bin
s  free chunk  free chunkbins 
 free chunks 
:::

#### Free Chunk

```plaintext showLineNumbers=false
    chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
            |             Size of previous chunk, if unallocated (P clear)  |
            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    `head:' |             Size of chunk, in bytes                     |A|0|P|
      mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
            |             Forward pointer to next chunk in list             |
            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
            |             Back pointer to previous chunk in list            |
            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
            |             Unused space (may be 0 bytes long)                .
            .                                                               .
            .                                                               |
nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    `foot:' |             Size of chunk, in bytes                           |
            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
            |             Size of next chunk, in bytes                |A|0|0|
            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
```

- **P (PREV_INUSE)**  ****  chunk 使free 
 0, allocated  1.  chunk  1
访`mchunk_prev_size`  chunk  free 
 chunk  chunk  data 
- **M (IS_MMAPPED)**  `mmap` 
 mmap  arena  free chunk 
- **A (NON_MAIN_ARENA)**  chunk  main arena, 1 0 
 main arena 
- free chunk 
  - **fd**  bin free chunk
  - **bk**  bin free chunk

#### Physical chunk operations

AMP 

```c
/* size field is or'ed with PREV_INUSE when previous adjacent chunk in use */
#define PREV_INUSE 0x1

/* extract inuse bit of previous chunk */
#define prev_inuse(p)       ((p)->mchunk_size & PREV_INUSE)


/* size field is or'ed with IS_MMAPPED if the chunk was obtained with mmap() */
#define IS_MMAPPED 0x2

/* check for mmap()'ed chunk */
#define chunk_is_mmapped(p) ((p)->mchunk_size & IS_MMAPPED)


/* size field is or'ed with NON_MAIN_ARENA if the chunk was obtained
   from a non-main arena.  This is only set immediately before handing
   the chunk to the user, if necessary.  */
#define NON_MAIN_ARENA 0x4

/* Check for chunk from main arena.  */
#define chunk_main_arena(p) (((p)->mchunk_size & NON_MAIN_ARENA) == 0)

/* Mark a chunk as not being on the main arena.  */
#define set_non_main_arena(p) ((p)->mchunk_size |= NON_MAIN_ARENA)


/*
   Bits to mask off when extracting size

   Note: IS_MMAPPED is intentionally not masked off from size field in
   macros for which mmapped chunks should never be seen. This should
   cause helpful core dumps to occur if it is tried by accident by
   people extending or adapting this malloc.
 */
#define SIZE_BITS (PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA)
```

chunk 

```c
/* Get size, ignoring use bits */
#define chunksize(p) (chunksize_nomask (p) & ~(SIZE_BITS))

/* Like chunksize, but do not mask SIZE_BITS.  */
#define chunksize_nomask(p)         ((p)->mchunk_size)

/* Ptr to next physical malloc_chunk. */
#define next_chunk(p) ((mchunkptr) (((char *) (p)) + chunksize (p)))

/* Size of the chunk below P.  Only valid if !prev_inuse (P).  */
#define prev_size(p) ((p)->mchunk_prev_size)

/* Set the size of the chunk below P.  Only valid if !prev_inuse (P).  */
#define set_prev_size(p, sz) ((p)->mchunk_prev_size = (sz))

/* Ptr to previous physical malloc_chunk.  Only valid if !prev_inuse (P).  */
#define prev_chunk(p) ((mchunkptr) (((char *) (p)) - prev_size (p)))

/* Treat space at ptr + offset as a chunk */
#define chunk_at_offset(p, s)  ((mchunkptr) (((char *) (p)) + (s)))

/* extract p's inuse bit */
#define inuse(p)                                                              
  ((((mchunkptr) (((char *) (p)) + chunksize (p)))->mchunk_size) & PREV_INUSE)

/* set/clear chunk as being inuse without otherwise disturbing */
#define set_inuse(p)                                                          
  ((mchunkptr) (((char *) (p)) + chunksize (p)))->mchunk_size |= PREV_INUSE

#define clear_inuse(p)                                                        
  ((mchunkptr) (((char *) (p)) + chunksize (p)))->mchunk_size &= ~(PREV_INUSE)


/* check/set/clear inuse bits in known places */
#define inuse_bit_at_offset(p, s)                                             
  (((mchunkptr) (((char *) (p)) + (s)))->mchunk_size & PREV_INUSE)

#define set_inuse_bit_at_offset(p, s)                                         
  (((mchunkptr) (((char *) (p)) + (s)))->mchunk_size |= PREV_INUSE)

#define clear_inuse_bit_at_offset(p, s)                                       
  (((mchunkptr) (((char *) (p)) + (s)))->mchunk_size &= ~(PREV_INUSE))


/* Set size at head, without disturbing its use bit */
#define set_head_size(p, s)  ((p)->mchunk_size = (((p)->mchunk_size & SIZE_BITS)
 | (s)))

/* Set size/use field */
#define set_head(p, s)       ((p)->mchunk_size = (s))

/* Set size at footer (only when chunk is not in use) */
#define set_foot(p, s)       (((mchunkptr) ((char *) (p) + (s)))->mchunk_prev_si
ze = (s))
```

### arena

线 arena  heap heap  `heap
_info` heap 

线 arena   heap

```c
/* A heap is a single contiguous memory region holding (coalesceable)
   malloc_chunks.  It is allocated with mmap() and always starts at an
   address aligned to HEAP_MAX_SIZE.  */

typedef struct _heap_info
{
  mstate ar_ptr; /* Arena for this heap. */
  struct _heap_info *prev; /* Previous heap. */
  size_t size;   /* Current size in bytes. */
  size_t mprotect_size; /* Size in bytes that has been mprotected
                           PROT_READ|PROT_WRITE.  */
  /* Make sure the following data is properly aligned, particularly
     that sizeof (heap_info) + 2 * SIZE_SZ is a multiple of
     MALLOC_ALIGNMENT. */
  char pad[-6 * SIZE_SZ & MALLOC_ALIGN_MASK];
} heap_info;
```

线 `arena`, 线 arena 
 `main_arena`, 线 arena  `thread_arena`

arena  `malloc_state` 

```c
struct malloc_state
{
  /* Serialize access.  */
  __libc_lock_define (, mutex);

  /* Flags (formerly in max_fast).  */
  int flags;

  /* Set if the fastbin chunks contain recently inserted free blocks.  */
  /* Note this is a bool but not all targets support atomics on booleans.  */
  int have_fastchunks;

  /* Fastbins */
  mfastbinptr fastbinsY[NFASTBINS];

  /* Base of the topmost chunk -- not otherwise kept in a bin */
  mchunkptr top;

  /* The remainder from the most recent split of a small request */
  mchunkptr last_remainder;

  /* Normal bins packed as described above */
  mchunkptr bins[NBINS * 2 - 2];

  /* Bitmap of bins */
  unsigned int binmap[BINMAPSIZE];

  /* Linked list */
  struct malloc_state *next;

  /* Linked list for free arenas.  Access to this field is serialized
     by free_list_lock in arena.c.  */
  struct malloc_state *next_free;

  /* Number of threads attached to this arena.  0 if the arena is on
     the free list.  Access to this field is serialized by
     free_list_lock in arena.c.  */
  INTERNAL_SIZE_T attached_threads;

  /* Memory allocated from the system in this arena.  */
  INTERNAL_SIZE_T system_mem;
  INTERNAL_SIZE_T max_system_mem;
};

typedef struct malloc_state *mstate;
```

-  free
  -  chunk 
  -  chunk  P  0 chunk 
- fastbin/tcache free
  -  chunk 
  -  chunk  P  chunk  inuse chunk 
  -  chunk  P  1 chunk  inuse
 chunk