Ili kuboresha ufanisi wa jinsi vipande vinavyohifadhiwa, kila kipande sio tu kwenye orodha moja iliyounganishwa, bali kuna aina kadhaa. Hizi ni vitengo vya kumbukumbu na kuna aina 5 za vitengo: 62 vitengo vidogo, 63 vitengo vikubwa, 1 kikapu kisichopangwa, 10 vitengo vya haraka na vitengo vya tcache 64 kwa kila mnyororo.
Anwani ya awali ya kila kikapu kisichopangwa, kidogo na kikubwa iko ndani ya safu moja. Indeksi 0 haifai, 1 ni kikapu kisichopangwa, vikapu 2-64 ni vitengo vidogo na vikapu 65-127 ni vitengo vikubwa.
Vitengo vya Tcache (Akiba kwa Kila Mnyororo)
Ingawa nyuzi zinajaribu kuwa na kumbukumbu yao wenyewe (angalia Arenas na Subheaps), kuna uwezekano kwamba mchakato na nyuzi nyingi (kama seva ya wavuti) itamaliza kushiriki kumbukumbu na nyuzi nyingine. Katika kesi hii, suluhisho kuu ni matumizi ya kifungio, ambacho kinaweza kupunguza kwa kiasi kikubwa kasi ya nyuzi.
Wakati nyuzi inaachilia kipande, ikiwa sio kikubwa sana kuweza kupangwa kwenye tcache na kikapu cha tcache hakijajaa (tayari kuna vipande 7), itapangwa hapo. Ikiwa haitaweza kwenda kwenye tcache, italazimika kusubiri kifungio cha kumbukumbu ili iweze kufanya operesheni ya kuachilia kwa jumla.
Wakati kipande kinapopangwa, ikiwa kuna kipande cha bure cha saizi inayohitajika kwenye Tcache itakitumia, la sivyo, italazimika kusubiri kifungio cha kumbukumbu ili iweze kupata moja kwenye vitengo vya jumla au kuunda mpya.
Kuna pia uboreshaji, katika kesi hii, wakati wa kuwa na kifungio cha kumbukumbu, nyuzi itajaza Tcache yake na vipande vya kumbukumbu (7) vya kumbukumbu ya ombi ya saizi, hivyo ikihitaji zaidi, itavipata kwenye Tcache.
Ongeza mfano wa kipande cha tcache
```c #include #include
int main(void) { char *chunk; chunk = malloc(24); printf("Address of the chunk: %p\n", (void *)chunk); gets(chunk); free(chunk); return 0; }
Fanya kompile na uishe na kosa katika opcode ya ret kutoka kwenye kazi kuu. Kisha kwa kutumia gef unaweza kuona tcache bin inayotumiwa:
```bash
gef➤ heap bins
──────────────────────────────────────────────────────────────────────────────── Tcachebins for thread 1 ────────────────────────────────────────────────────────────────────────────────
Tcachebins[idx=0, size=0x20, count=1] ← Chunk(addr=0xaaaaaaac12a0, size=0x20, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA)
Tcache Miundo na Kazi
Katika msimbo ufuatao inawezekana kuona max bins na vipande kwa kila index, miundo ya tcache_entry iliyoanzishwa ili kuepuka kufuta mara mbili na tcache_perthread_struct, miundo ambayo kila mnyororo hutumia kuhifadhi anwani za kila index ya bakuli.
tcache_entry na tcache_perthread_struct
```c // From https://github.com/bminor/glibc/blob/f942a732d37a96217ef828116ebe64a644db18d7/malloc/malloc.c
/* We want 64 entries. This is an arbitrary limit, which tunables can reduce. */
/* With rounding and alignment, the bins are... idx 0 bytes 0..24 (64-bit) or 0..12 (32-bit) idx 1 bytes 25..40 or 13..20 idx 2 bytes 41..56 or 21..28 etc. */
/* This is another arbitrary limit, which tunables can change. Each tcache bin will hold at most this number of chunks. */
define TCACHE_FILL_COUNT 7
/* Maximum chunks in tcache bins for tunables. This value must fit the range of tcache->counts[] entries, else they may overflow. */
define MAX_TCACHE_COUNT UINT16_MAX
[...]
typedef struct tcache_entry { struct tcache_entry next; / This field exists to detect double frees. */ uintptr_t key; } tcache_entry;
/* There is one of these for each thread, which contains the per-thread cache (hence "tcache_perthread_struct"). Keeping overall size low is mildly important. Note that COUNTS and ENTRIES are redundant (we could have just counted the linked list each time), this is for performance reasons. */ typedef struct tcache_perthread_struct { uint16_t counts[TCACHE_MAX_BINS]; tcache_entry *entries[TCACHE_MAX_BINS]; } tcache_perthread_struct;
</details>
Kazi ya `__tcache_init` ni kazi inayounda na kutenga nafasi kwa ajili ya obj ya `tcache_perthread_struct`
```c
// From https://github.com/bminor/glibc/blob/f942a732d37a96217ef828116ebe64a644db18d7/malloc/malloc.c#L3241C1-L3274C2
static void
tcache_init(void)
{
mstate ar_ptr;
void *victim = 0;
const size_t bytes = sizeof (tcache_perthread_struct);
if (tcache_shutting_down)
return;
arena_get (ar_ptr, bytes);
victim = _int_malloc (ar_ptr, bytes);
if (!victim && ar_ptr != NULL)
{
ar_ptr = arena_get_retry (ar_ptr, bytes);
victim = _int_malloc (ar_ptr, bytes);
}
if (ar_ptr != NULL)
__libc_lock_unlock (ar_ptr->mutex);
/* In a low memory situation, we may not be able to allocate memory
- in which case, we just keep trying later. However, we
typically do this very early, so either there is sufficient
memory, or there isn't enough memory to do non-trivial
allocations anyway. */
if (victim)
{
tcache = (tcache_perthread_struct *) victim;
memset (tcache, 0, sizeof (tcache_perthread_struct));
}
}
Viashiria vya Tcache
Tcache ina viashiria kadhaa kulingana na ukubwa na viashiria vya awali kwa kila kipande cha kwanza cha kila kiashiria na idadi ya vipande kwa kila kiashiria vimehifadhiwa ndani ya kipande. Hii inamaanisha kwamba kwa kutambua kipande chenye habari hii (kawaida cha kwanza), ni rahisi kupata viashiria vyote vya tcache na idadi ya vipande vya Tcache.
Bins za Haraka
Bins za haraka zimeundwa ili kuongeza kasi ya kutengwa kwa kumbukumbu kwa vipande vidogo kwa kuweka vipande vilivyotolewa hivi karibuni katika muundo wa kupata haraka. Bins hizi hutumia njia ya Mwisho-Kuingia, Mwanzo-Kutoka (LIFO), ambayo inamaanisha kwamba kipande kilichotolewa hivi karibuni zaidi ndicho kwanza kutumika tena wakati kuna ombi jipya la kutengwa. Tabia hii ni faida kwa kasi, kwani ni haraka kuweka na kuondoa kutoka juu ya rundo (LIFO) ikilinganishwa na foleni (FIFO).
Kwa kuongezea, bins za haraka hutumia orodha za viungo moja tu, sio viungo vya mara mbili, ambavyo vinaboresha kasi zaidi. Kwa kuwa vipande katika bins za haraka havijunganishwi na majirani, hakuna haja ya muundo tata unaoruhusu kuondolewa katikati. Orodha ya viungo moja ni rahisi na haraka kwa operesheni hizi.
Kimsingi, kinachotokea hapa ni kwamba kichwa (kiashiria cha kipande cha kwanza cha kuangalia) kila wakati kinaelekeza kwenye kipande kilichotolewa hivi karibuni zaidi cha ukubwa huo. Kwa hivyo:
Wakati kipande kipya kinatengwa cha ukubwa huo, kichwa kinatazama kipande huru cha kutumia. Kwa kuwa kipande hiki huru kinatazama kipande kinachofuata kutumika, anwani hii imehifadhiwa kwenye kichwa ili kutambua wapi kupata kipande kinachopatikana
Wakati kipande kinapotolewa, kipande huru kitahifadhi anwani ya kipande kinachopatikana kwa sasa na anwani ya kipande hiki kilichotolewa hivi karibuni itawekwa kwenye kichwa
Ukubwa wa juu wa orodha ya viungo ni 0x80 na zimepangwa ili kipande cha ukubwa wa 0x20 kiwe katika kiashiria 0, kipande cha ukubwa wa 0x30 kingekuwa katika kiashiria 1...
Vipande katika bins za haraka havijawekwa kama vinavyopatikana kwa hivyo vinabaki kama vipande vya bins za haraka kwa muda fulani badala ya kuweza kuunganishwa na vipande vingine huru vinavyowazunguka.
// From https://github.com/bminor/glibc/blob/a07e000e82cb71238259e674529c37c12dc7d423/malloc/malloc.c#L1711/*FastbinsAn array of lists holding recently freed small chunks. Fastbinsare not doubly linked. It is faster to single-link them, andsince chunks are never removed from the middles of these lists,double linking is not necessary. Also, unlike regular bins, theyare not even processed in FIFO order (they use faster LIFO) sinceordering doesn't much matter in the transient contexts in whichfastbins are normally used.Chunks in fastbins keep their inuse bit set, so they cannotbe consolidated with other free chunks. malloc_consolidatereleases all chunks in fastbins and consolidates them withother free chunks.*/typedefstruct malloc_chunk *mfastbinptr;#definefastbin(ar_ptr, idx) ((ar_ptr)->fastbinsY[idx])/* offset 2 to use otherwise unindexable first 2 bins */#definefastbin_index(sz) \((((unsignedint) (sz)) >> (SIZE_SZ ==8?4:3)) -2)/* The maximum fastbin request size we support */#defineMAX_FAST_SIZE (80* SIZE_SZ /4)#defineNFASTBINS (fastbin_index (request2size (MAX_FAST_SIZE)) +1)
Ongeza mfano wa kipande cha fastbin
```c #include #include
int main(void) { char *chunks[8]; int i;
// Loop to allocate memory 8 times for (i = 0; i < 8; i++) { chunks[i] = malloc(24); if (chunks[i] == NULL) { // Check if malloc failed fprintf(stderr, "Memory allocation failed at iteration %d\n", i); return 1; } printf("Address of chunk %d: %p\n", i, (void *)chunks[i]); }
// Loop to free the allocated memory for (i = 0; i < 8; i++) { free(chunks[i]); }
return 0; }
Tambua jinsi tunavyo allocate na free vipande 8 vya saizi ileile ili wajaze tcache na cha nane kuhifadhiwa kwenye kisanduku cha haraka.
Sakinisha na ukague kwa kusitisha kwenye opcode ya `ret` kutoka kwenye kazi ya `main`. Kisha kwa kutumia `gef` unaweza kuona kuwa kisanduku cha tcache kimejaa na kipande kimoja kipo kwenye kisanduku cha haraka:
```bash
gef➤ heap bins
──────────────────────────────────────────────────────────────────────────────── Tcachebins for thread 1 ────────────────────────────────────────────────────────────────────────────────
Tcachebins[idx=0, size=0x20, count=7] ← Chunk(addr=0xaaaaaaac1770, size=0x20, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA) ← Chunk(addr=0xaaaaaaac1750, size=0x20, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA) ← Chunk(addr=0xaaaaaaac1730, size=0x20, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA) ← Chunk(addr=0xaaaaaaac1710, size=0x20, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA) ← Chunk(addr=0xaaaaaaac16f0, size=0x20, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA) ← Chunk(addr=0xaaaaaaac16d0, size=0x20, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA) ← Chunk(addr=0xaaaaaaac12a0, size=0x20, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA)
───────────────────────────────────────────────────────────────────────── Fastbins for arena at 0xfffff7f90b00 ─────────────────────────────────────────────────────────────────────────
Fastbins[idx=0, size=0x20] ← Chunk(addr=0xaaaaaaac1790, size=0x20, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA)
Fastbins[idx=1, size=0x30] 0x00
Bakuli lisilo na mpangilio
Bakuli lisilo na mpangilio ni akiba inayotumiwa na meneja wa bakuli ili kufanya mgawanyo wa kumbukumbu uwe haraka zaidi. Hapa ndivyo inavyofanya kazi: Wakati programu inaachilia kipande, na ikiwa kipande hiki hakiwezi kupewa katika akiba ya tcache au bakuli la haraka na haligongani na kipande cha juu, meneja wa bakuli hauweki mara moja katika bakuli maalum la kipande kidogo au kikubwa. Badala yake, kwanza inajaribu kulifunga na vipande vingine vya bure vya jirani ili kuunda kibodi kubwa ya kumbukumbu ya bure. Kisha, inaweka kipande kipya hiki katika bakuli la jumla linaloitwa "bakuli lisilo na mpangilio."
Wakati programu inahitaji kumbukumbu, meneja wa bakuli huchunguza bakuli lisilo na mpangilio kuona ikiwa kuna kipande cha ukubwa wa kutosha. Ikiipata, inakitumia mara moja. Ikiwa haitapata kipande kinachofaa katika bakuli lisilo na mpangilio, inahamisha vipande vyote katika orodha hii kwenye bakuli zao husika, iwe ni kipande kidogo au kikubwa, kulingana na ukubwa wao.
Tafadhali kumbuka kwamba ikiwa kipande kikubwa kimegawanywa katika sehemu 2 na sehemu iliyobaki ni kubwa kuliko MINSIZE, itarudishwa tena kwenye bakuli lisilo na mpangilio.
Kwa hivyo, bakuli lisilo na mpangilio ni njia ya kuharakisha mgawanyo wa kumbukumbu kwa haraka kutumia tena kumbukumbu iliyotolewa hivi karibuni na kupunguza haja ya kutafuta na kufunga kwa muda mrefu.
Tafadhali kumbuka kwamba hata ikiwa vipande ni vya makundi tofauti, ikiwa kipande kinachopatikana kinagongana na kipande kingine kinachopatikana (hata ikiwa awali zilikuwa katika bakuli tofauti), vitafungwa pamoja.
Ongeza mfano wa kipande kilichochanganyikana
```c #include #include
int main(void) { char *chunks[9]; int i;
// Loop to allocate memory 8 times for (i = 0; i < 9; i++) { chunks[i] = malloc(0x100); if (chunks[i] == NULL) { // Check if malloc failed fprintf(stderr, "Memory allocation failed at iteration %d\n", i); return 1; } printf("Address of chunk %d: %p\n", i, (void *)chunks[i]); }
// Loop to free the allocated memory for (i = 0; i < 8; i++) { free(chunks[i]); }
return 0; }
Tazama jinsi tunavyo alokei na kuachilia vipande 9 vya saizi ile ile ili vijaze tcache na cha nane kuhifadhiwa kwenye unsorted bin kwa sababu ni kubwa mno kwa fastbin na cha tisa hakijaachiliwa hivyo cha tisa na cha nane havijunganishwa na top chunk.
Sakinisha na uisashe na kuvunja kwa kizuizi katika opcode ya `ret` kutoka kwenye kazi ya `main`. Kisha kwa kutumia `gef` unaweza kuona kuwa tcache bin imejaa na kipande kimoja kipo kwenye unsorted bin:
```bash
gef➤ heap bins
──────────────────────────────────────────────────────────────────────────────── Tcachebins for thread 1 ────────────────────────────────────────────────────────────────────────────────
Tcachebins[idx=15, size=0x110, count=7] ← Chunk(addr=0xaaaaaaac1d10, size=0x110, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA) ← Chunk(addr=0xaaaaaaac1c00, size=0x110, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA) ← Chunk(addr=0xaaaaaaac1af0, size=0x110, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA) ← Chunk(addr=0xaaaaaaac19e0, size=0x110, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA) ← Chunk(addr=0xaaaaaaac18d0, size=0x110, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA) ← Chunk(addr=0xaaaaaaac17c0, size=0x110, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA) ← Chunk(addr=0xaaaaaaac12a0, size=0x110, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA)
───────────────────────────────────────────────────────────────────────── Fastbins for arena at 0xfffff7f90b00 ─────────────────────────────────────────────────────────────────────────
Fastbins[idx=0, size=0x20] 0x00
Fastbins[idx=1, size=0x30] 0x00
Fastbins[idx=2, size=0x40] 0x00
Fastbins[idx=3, size=0x50] 0x00
Fastbins[idx=4, size=0x60] 0x00
Fastbins[idx=5, size=0x70] 0x00
Fastbins[idx=6, size=0x80] 0x00
─────────────────────────────────────────────────────────────────────── Unsorted Bin for arena at 0xfffff7f90b00 ───────────────────────────────────────────────────────────────────────
[+] unsorted_bins[0]: fw=0xaaaaaaac1e10, bk=0xaaaaaaac1e10
→ Chunk(addr=0xaaaaaaac1e20, size=0x110, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA)
[+] Found 1 chunks in unsorted bin.
Vifurushi Vidogo
Vifurushi vidogo ni haraka kuliko vifurushi vikubwa lakini polepole kuliko vifurushi vya haraka.
Kila kifurushi kati ya 62 kitakuwa na vipande vya saizi ile ile: 16, 24, ... (na saizi ya juu ya 504 baiti katika bits 32 na 1024 katika bits 64). Hii husaidia katika kasi ya kupata kifurushi ambapo nafasi inapaswa kutengwa na kuingiza na kuondoa vipande kwenye orodha hizi.
Hivi ndivyo saizi ya kifurushi kidogo inavyohesabiwa kulingana na index ya kifurushi:
// Loop to allocate memory 8 times for (i = 0; i < 9; i++) { chunks[i] = malloc(0x100); if (chunks[i] == NULL) { // Check if malloc failed fprintf(stderr, "Memory allocation failed at iteration %d\n", i); return 1; } printf("Address of chunk %d: %p\n", i, (void *)chunks[i]); }
// Loop to free the allocated memory for (i = 0; i < 8; i++) { free(chunks[i]); }
chunks[9] = malloc(0x110);
return 0; }
Tambua jinsi tunavyo tenganisha na kuachilia vipande 9 vya saizi ile ile ili **kujaza tcache** na cha nane kuhifadhiwa kwenye sanduku lisilo na mpangilio kwa sababu ni **kubwa sana kwa fastbin** na cha tisa hakijatolewa hivyo cha tisa na cha nane **haviunganishwi na kipande cha juu**. Kisha tunatenga kipande kikubwa cha 0x110 ambacho kinasababisha **kipande kwenye sanduku lisilo na mpangilio kuingia kwenye sanduku dogo**.
Sakinisha na ugundue kwa kuweka kizuizi katika opcode ya `ret` kutoka kwenye kazi ya `main`. Kisha kwa kutumia `gef` unaweza kuona kuwa sanduku la tcache limejaa na kipande kimoja kipo kwenye sanduku dogo:
```bash
gef➤ heap bins
──────────────────────────────────────────────────────────────────────────────── Tcachebins for thread 1 ────────────────────────────────────────────────────────────────────────────────
Tcachebins[idx=15, size=0x110, count=7] ← Chunk(addr=0xaaaaaaac1d10, size=0x110, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA) ← Chunk(addr=0xaaaaaaac1c00, size=0x110, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA) ← Chunk(addr=0xaaaaaaac1af0, size=0x110, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA) ← Chunk(addr=0xaaaaaaac19e0, size=0x110, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA) ← Chunk(addr=0xaaaaaaac18d0, size=0x110, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA) ← Chunk(addr=0xaaaaaaac17c0, size=0x110, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA) ← Chunk(addr=0xaaaaaaac12a0, size=0x110, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA)
───────────────────────────────────────────────────────────────────────── Fastbins for arena at 0xfffff7f90b00 ─────────────────────────────────────────────────────────────────────────
Fastbins[idx=0, size=0x20] 0x00
Fastbins[idx=1, size=0x30] 0x00
Fastbins[idx=2, size=0x40] 0x00
Fastbins[idx=3, size=0x50] 0x00
Fastbins[idx=4, size=0x60] 0x00
Fastbins[idx=5, size=0x70] 0x00
Fastbins[idx=6, size=0x80] 0x00
─────────────────────────────────────────────────────────────────────── Unsorted Bin for arena at 0xfffff7f90b00 ───────────────────────────────────────────────────────────────────────
[+] Found 0 chunks in unsorted bin.
──────────────────────────────────────────────────────────────────────── Small Bins for arena at 0xfffff7f90b00 ────────────────────────────────────────────────────────────────────────
[+] small_bins[16]: fw=0xaaaaaaac1e10, bk=0xaaaaaaac1e10
→ Chunk(addr=0xaaaaaaac1e20, size=0x110, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA)
[+] Found 1 chunks in 1 small non-empty bins.
Bins kubwa
Tofauti na bins ndogo, ambazo hushughulikia vipande vya saizi iliyowekwa, kila bin kubwa hushughulikia safu ya saizi za vipande. Hii ni ya kubadilika zaidi, ikiruhusu mfumo kuzoea saizi tofauti bila kuhitaji bin tofauti kwa kila saizi.
Katika mpangishaji wa kumbukumbu, bins kubwa huanza pale ambapo bins ndogo zinaishia. Safu za bins kubwa hukua kwa ukubwa kwa mfululizo, maana bin ya kwanza inaweza kufunika vipande kutoka 512 hadi 576 baiti, wakati inayofuata inafunika 576 hadi 640 baiti. Mtindo huu unaendelea, na bin kubwa zaidi ina vipande vyote zaidi ya 1MB.
Bins kubwa ni polepole kufanya kazi ikilinganishwa na bins ndogo kwa sababu lazima zipange na kutafuta kupitia orodha ya saizi tofauti za vipande ili kupata saizi bora kwa mgawo. Wakati kipande kinawekwa kwenye bin kubwa, lazima kipangwe, na wakati kumbukumbu inapogawiwa, mfumo lazima upate kipande sahihi. Kazi hii ya ziada inawafanya kuwa polepole, lakini kwa kuwa mgawo wa kubwa ni nadra kuliko vipande vidogo, ni sawa kufanya hivyo.
Kuna:
Bins 32 za safu ya 64B (zinagongana na bins ndogo)
Bins 16 za safu ya 512B (zinagongana na bins ndogo)
Bins 8 za safu ya 4096B (sehemu inagongana na bins ndogo)
Bins 4 za safu ya 32768B
Bins 2 za safu ya 262144B
Bin 1 kwa saizi zilizosalia
Msimbo wa Saizi za Bins Kubwa
```c // From https://github.com/bminor/glibc/blob/a07e000e82cb71238259e674529c37c12dc7d423/malloc/malloc.c#L1711
</details>
<details>
<summary>Wekeza mfano wa kipande kikubwa</summary>
```c
#include <stdlib.h>
#include <stdio.h>
int main(void)
{
char *chunks[2];
chunks[0] = malloc(0x1500);
chunks[1] = malloc(0x1500);
free(chunks[0]);
chunks[0] = malloc(0x2000);
return 0;
}
2 alokesheni kubwa zinafanywa, kisha moja inaachiliwa (ikiwekwa kwenye sanduku lisilo na mpangilio) na alokesheni kubwa zaidi inafanywa (ikihamisha ile iliyofutwa kutoka kwenye sanduku lisilo na mpangilio kwenda kwenye sanduku kubwa).
Sakinisha na uisashe na kizuizi katika opcode ya ret kutoka kwenye kazi ya kuu. kisha kwa kutumia gef unaweza kuona kuwa sanduku la tcache limejaa na kipande kimoja kipo kwenye sanduku kubwa:
gef➤heapbin──────────────────────────────────────────────────────────────────────────────── Tcachebins for thread 1 ────────────────────────────────────────────────────────────────────────────────
Alltcachebinsareempty───────────────────────────────────────────────────────────────────────── Fastbins for arena at 0xfffff7f90b00 ─────────────────────────────────────────────────────────────────────────
Fastbins[idx=0,size=0x20]0x00Fastbins[idx=1,size=0x30]0x00Fastbins[idx=2,size=0x40]0x00Fastbins[idx=3,size=0x50]0x00Fastbins[idx=4,size=0x60]0x00Fastbins[idx=5,size=0x70]0x00Fastbins[idx=6,size=0x80]0x00─────────────────────────────────────────────────────────────────────── Unsorted Bin for arena at 0xfffff7f90b00 ───────────────────────────────────────────────────────────────────────
[+] Found 0 chunks in unsorted bin.──────────────────────────────────────────────────────────────────────── Small Bins for arena at 0xfffff7f90b00 ────────────────────────────────────────────────────────────────────────
[+] Found 0 chunks in 0 small non-empty bins.──────────────────────────────────────────────────────────────────────── Large Bins for arena at 0xfffff7f90b00 ────────────────────────────────────────────────────────────────────────
[+] large_bins[100]: fw=0xaaaaaaac1290, bk=0xaaaaaaac1290→Chunk(addr=0xaaaaaaac12a0, size=0x1510, flags=PREV_INUSE|IS_MMAPPED|NON_MAIN_ARENA)[+] Found 1 chunks in 1 large non-empty bins.
Kipande cha Juu
// From https://github.com/bminor/glibc/blob/a07e000e82cb71238259e674529c37c12dc7d423/malloc/malloc.c#L1711/*TopThe top-most available chunk (i.e., the one bordering the end ofavailable memory) is treated specially. It is never included inany bin, is used only if no other chunk is available, and isreleased back to the system if it is very large (seeM_TRIM_THRESHOLD). Because top initiallypoints to its own bin with initial zero size, thus forcingextension on the first malloc request, we avoid having any specialcode in malloc to check whether it even exists yet. But we stillneed to do so when getting memory from system, so we makeinitial_top treat the bin as a legal but unusable chunk during theinterval between initialization and the first call tosysmalloc. (This is somewhat delicate, since it relies onthe 2 preceding words to be zero during this interval as well.)*//* Conveniently, the unsorted bin can be used as dummy top on first call */#defineinitial_top(M) (unsorted_chunks (M))
Kimsingi, hii ni kipande kinachojumuisha kila kipande cha heap kinachopatikana kwa sasa. Wakati malloc inafanywa, ikiwa hakuna kipande cha bure kinachopatikana kutumika, kipande hiki cha juu kitapunguza ukubwa wake kutoa nafasi inayohitajika. Pointer kwa Kipande cha Juu kuhifadhiwa katika muundo wa malloc_state.
Zaidi ya hayo, mwanzoni, ni sawa kutumia kipande kilichochanganyika kama kipande cha juu.
Angalia mfano wa Kipande cha Juu
```c #include #include
int main(void) { char *chunk; chunk = malloc(24); printf("Address of the chunk: %p\n", (void *)chunk); gets(chunk); return 0; }
Baada ya kuiandaa na kuibugia na kivinjari katika opcode ya `ret` ya `main` niliona kwamba malloc ilirudisha anwani `0xaaaaaaac12a0` na hizi ni vipande:
```bash
gef➤ heap chunks
Chunk(addr=0xaaaaaaac1010, size=0x290, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA)
[0x0000aaaaaaac1010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................]
Chunk(addr=0xaaaaaaac12a0, size=0x20, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA)
[0x0000aaaaaaac12a0 41 41 41 41 41 41 41 00 00 00 00 00 00 00 00 00 AAAAAAA.........]
Chunk(addr=0xaaaaaaac12c0, size=0x410, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA)
[0x0000aaaaaaac12c0 41 64 64 72 65 73 73 20 6f 66 20 74 68 65 20 63 Address of the c]
Chunk(addr=0xaaaaaaac16d0, size=0x410, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA)
[0x0000aaaaaaac16d0 41 41 41 41 41 41 41 0a 00 00 00 00 00 00 00 00 AAAAAAA.........]
Chunk(addr=0xaaaaaaac1ae0, size=0x20530, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA) ← top chunk
Mahali ambapo inaweza kuonekana kuwa kipande cha juu kiko kwenye anwani 0xaaaaaaac1ae0. Hii si mshangao kwa sababu kipande cha mwisho kilichotengwa kilikuwa kwenye 0xaaaaaaac12a0 na ukubwa wa 0x410 na 0xaaaaaaac12a0 + 0x410 = 0xaaaaaaac1ae0.
Pia ni sawa kuona urefu wa kipande cha Juu kwenye kichwa chake cha kipande:
Wakati malloc inapotumiwa na kipande kinagawanywa (kutoka kwa sanduku lisilo na mpangilio au kutoka kwa kipande cha juu kwa mfano), kipande kilichoundwa kutoka kwa sehemu iliyobaki ya kipande kilichogawanywa huitwa Kukaa Mwisho na pointer yake hifadhiwa katika muundo wa malloc_state.