Da bi se poboljšala efikasnost načina na koji se delovi čuvaju, svaki deo nije samo u jednoj povezanoj listi, već postoji nekoliko tipova. To su kante i postoji 5 tipova kanti: 62 male kante, 63 velike kante, 1 neuređena kanta, 10 brzih kanti i 64 tcache kante po niti.
Početna adresa za svaku neuređenu, malu i veliku kantu je unutar istog niza. Indeks 0 se ne koristi, 1 je neuređena kanta, kante 2-64 su male kante, a kante 65-127 su velike kante.
Tcache (Per-Thread Cache) Bins
Iako niti pokušavaju da imaju svoj vlastiti heap (vidi Arenas i Subheaps), postoji mogućnost da proces sa puno niti (kao što je web server) će završiti deljenjem heap-a sa drugim nitima. U ovom slučaju, glavno rešenje je korišćenje zaključavanja, što može značajno usporiti niti.
Kada nit oslobodi deo, ako nije prevelik da bi se alocirao u tcache i odgovarajuća tcache kanta nije puna (već 7 delova), biće alociran tamo. Ako ne može da ide u tcache, moraće da čeka na zaključavanje heap-a da bi mogla da izvrši operaciju oslobađanja globalno.
Kada je deo alociran, ako postoji slobodan deo potrebne veličine u Tcache, koristiće ga, ako ne, moraće da čeka na zaključavanje heap-a da bi mogla da pronađe jedan u globalnim kantama ili da kreira novi.
Postoji i optimizacija, u ovom slučaju, dok ima zaključavanje heap-a, nit će napuniti svoj Tcache delovima iz heap-a (7) tražene veličine, tako da u slučaju da mu zatreba više, naći će ih u Tcache.
Add a tcache chunk example
```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; }
Kompajlirajte ga i debagujte sa tačkom prekida u ret opcode iz main funkcije. Tada sa gef možete videti tcache bin u upotrebi:
```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 strukture i funkcije
U sledećem kodu moguće je videti max bins i chunks per index, tcache_entry strukturu kreiranu da izbegne duple oslobađanja i tcache_perthread_struct, strukturu koju svaka nit koristi za čuvanje adresa za svaki indeks bin-a.
tcache_entry i 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>
Funkcija `__tcache_init` je funkcija koja kreira i alocira prostor za objekat `tcache_perthread_struct`
<details>
<summary>tcache_init kod</summary>
```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));
}
}
Tcache indeksi
Tcache ima nekoliko binova u zavisnosti od veličine, a inicijalni pokazivači na prvi deo svakog indeksa i količina delova po indeksu nalaze se unutar dela. To znači da lociranjem dela sa ovom informacijom (obično prvim), moguće je pronaći sve inicijalne tačke tcache-a i količinu Tcache delova.
Brzi binovi
Brzi binovi su dizajnirani da ubrza alokaciju memorije za male delove čuvajući nedavno oslobođene delove u strukturi brzog pristupa. Ovi binovi koriste pristup Last-In, First-Out (LIFO), što znači da je najnovije oslobođeni deo prvi koji će se ponovo koristiti kada postoji nova zahtev za alokaciju. Ovo ponašanje je korisno za brzinu, jer je brže umetati i uklanjati sa vrha steka (LIFO) u poređenju sa redom (FIFO).
Pored toga, brzi binovi koriste jednostruko povezane liste, a ne dvostruko povezane, što dodatno poboljšava brzinu. Pošto delovi u brzim binovima nisu spojeni sa susedima, nema potrebe za složenom strukturom koja omogućava uklanjanje iz sredine. Jednostruko povezana lista je jednostavnija i brža za ove operacije.
U suštini, ono što se ovde dešava je da je zaglavlje (pokazivač na prvi deo koji treba proveriti) uvek usmereno na najnovije oslobođeni deo te veličine. Tako:
Kada se alocira novi deo te veličine, zaglavlje pokazuje na slobodan deo koji se može koristiti. Pošto ovaj slobodan deo pokazuje na sledeći koji se može koristiti, ova adresa se čuva u zaglavlju tako da sledeća alokacija zna gde da pronađe dostupan deo.
Kada se deo oslobodi, slobodan deo će sačuvati adresu trenutnog dostupnog dela, a adresa ovog novog oslobođenog dela će biti stavljena u zaglavlje.
Maksimalna veličina povezane liste je 0x80 i organizovane su tako da će deo veličine 0x20 biti u indeksu 0, deo veličine 0x30 biće u indeksu 1...
Delovi u brzim binovima nisu postavljeni kao dostupni, tako da se čuvaju kao brzi binovi neko vreme umesto da mogu da se spoje sa drugim slobodnim delovima koji ih okružuju.
// 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)
Dodajte primer fastbin chunk-a
```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; }
Napomena kako alociramo i oslobađamo 8 delova iste veličine tako da popune tcache, a osmi se čuva u fast chunk.
Kompajlirajte to i debagujte sa breakpoint-om u `ret` opcode-u iz `main` funkcije. Tada sa `gef` možete videti da je tcache bin pun i da je jedan chunk u fast bin:
```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
Neuređeni bin
Neuređeni bin je keš koji koristi menadžer heap-a kako bi ubrzao alokaciju memorije. Evo kako to funkcioniše: Kada program oslobodi deo, i ako se taj deo ne može alocirati u tcache ili fast bin i ne sudara se sa vrhunskim delom, menadžer heap-a ga odmah ne stavlja u određeni mali ili veliki bin. Umesto toga, prvo pokušava da spoji ga sa bilo kojim susednim slobodnim delovima kako bi stvorio veći blok slobodne memorije. Zatim, stavlja ovaj novi deo u opšti bin nazvan "neuređeni bin."
Kada program traži memoriju, menadžer heap-a proverava neuređeni bin da vidi da li postoji deo dovoljno velike veličine. Ako ga pronađe, odmah ga koristi. Ako ne pronađe odgovarajući deo u neuređenom binu, premestiće sve delove u ovoj listi u njihove odgovarajuće bine, bilo male ili velike, na osnovu njihove veličine.
Napomena: ako se veći deo podeli na 2 polovine i ostatak je veći od MINSIZE, biće vraćen nazad u neuređeni bin.
Dakle, neuređeni bin je način da se ubrza alokacija memorije ponovnim korišćenjem nedavno oslobođene memorije i smanjenjem potrebe za vremenski zahtevnim pretragama i spajanjima.
Napomena: čak i ako su delovi različitih kategorija, ako se dostupan deo sudara sa drugim dostupnim delom (čak i ako prvobitno pripadaju različitim binovima), biće spojeni.
Dodaj primer neuređenog dela
```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; }
Napomena kako alociramo i oslobađamo 9 delova iste veličine tako da **popune tcache** i osmi se čuva u nesortiranom binu jer je **prevelik za fastbin**, a deveti nije oslobođen, tako da se deveti i osmi **ne spajaju sa vrhunskim delom**.
Kompajlirajte to i debagujte sa tačkom prekida u `ret` opcode-u iz `main` funkcije. Tada sa `gef` možete videti da je tcache bin pun i jedan deo je u nesortiranom binu:
```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.
Male Bine
Male bine su brže od velikih bina, ali sporije od brzih bina.
Svaki bin od 62 će imati komade iste veličine: 16, 24, ... (sa maksimalnom veličinom od 504 bajta u 32bita i 1024 u 64bita). Ovo pomaže u brzini pronalaženja bina gde bi prostor trebao biti dodeljen i umetanja i uklanjanja unosa na ovim listama.
Ovako se veličina malog bina izračunava prema indeksu bina:
Najmanja veličina: 2*4*indeks (npr. indeks 5 -> 40)
Najveća veličina: 2*8*indeks (npr. indeks 5 -> 80)
// 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; }
Napomena kako alociramo i oslobađamo 9 delova iste veličine tako da **popunimo tcache** i osmi se čuva u nesortiranom binu jer je **prevelik za fastbin** i deveti nije oslobođen, tako da se deveti i osmi **ne spajaju sa vrhunskim delom**. Zatim alociramo veći deo od 0x110 što čini da **deo u nesortiranom binu pređe u mali bin**.
Kompajlirajte to i debagujte sa tačkom prekida u `ret` opkodu iz `main` funkcije. Tada sa `gef` možete videti da je tcache bin pun i jedan deo je u malom binu:
```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.
Veliki kontejneri
Za razliku od malih kontejnera, koji upravljaju delovima fiksnih veličina, svaki veliki kontejner upravlja opsegom veličina delova. Ovo je fleksibilnije, omogućavajući sistemu da prilagodi različite veličine bez potrebe za posebnim kontejnerom za svaku veličinu.
U alokatoru memorije, veliki kontejneri počinju gde mali kontejneri završavaju. Opsezi za velike kontejneri postaju progresivno veći, što znači da prvi kontejner može pokrivati delove od 512 do 576 bajtova, dok sledeći pokriva od 576 do 640 bajtova. Ovaj obrazac se nastavlja, pri čemu najveći kontejner sadrži sve delove iznad 1MB.
Veliki kontejneri su sporiji za rad u poređenju sa malim kontejnerima jer moraju sortirati i pretraživati listu delova različitih veličina kako bi pronašli najbolju opciju za alokaciju. Kada se deo umetne u veliki kontejner, mora se sortirati, a kada se memorija alocira, sistem mora pronaći pravi deo. Ovaj dodatni rad ih čini sporijim, ali pošto su velike alokacije ređe od malih, to je prihvatljiva kompenzacija.
Postoje:
32 kontejnera opsega 64B (sukob sa malim kontejnerima)
16 kontejnera opsega 512B (sukob sa malim kontejnerima)
8 kontejnera opsega 4096B (delimično sukob sa malim kontejnerima)
4 kontejnera opsega 32768B
2 kontejnera opsega 262144B
1 kontejner za preostale veličine
Kod veličina velikih kontejnera
```c // From https://github.com/bminor/glibc/blob/a07e000e82cb71238259e674529c37c12dc7d423/malloc/malloc.c#L1711
</details>
<details>
<summary>Dodajte primer velike količine</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 velike alokacije se izvršavaju, zatim se jedna oslobađa (stavljajući je u nesortirani kontejner) i vrši se veća alokacija (premještajući oslobođenu iz nesortiranog kontejnera u veliki kontejner).
Kompajlirajte to i debagujte sa tačkom prekida u ret opkodu iz main funkcije. Tada sa gef možete videti da je tcache kontejner pun i da je jedan deo u velikom kontejneru:
gef➤heapbin────────────────────────────────────────────────────────────────────────────────Tcachebinsforthread1────────────────────────────────────────────────────────────────────────────────Alltcachebinsareempty─────────────────────────────────────────────────────────────────────────Fastbinsforarenaat0xfffff7f90b00─────────────────────────────────────────────────────────────────────────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───────────────────────────────────────────────────────────────────────UnsortedBinforarenaat0xfffff7f90b00───────────────────────────────────────────────────────────────────────[+] Found 0 chunks in unsorted bin.────────────────────────────────────────────────────────────────────────SmallBinsforarenaat0xfffff7f90b00────────────────────────────────────────────────────────────────────────[+] Found 0 chunks in 0 small non-empty bins.────────────────────────────────────────────────────────────────────────LargeBinsforarenaat0xfffff7f90b00────────────────────────────────────────────────────────────────────────[+] 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.
Top Chunk
// 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))
U suštini, ovo je deo koji sadrži sve trenutno dostupne heap-ove. Kada se izvrši malloc, ako ne postoji dostupni slobodni deo za korišćenje, ovaj gornji deo će smanjiti svoju veličinu kako bi dao potrebni prostor.
Pokazivač na Gornji Deo se čuva u malloc_state strukturi.
Pored toga, na početku, moguće je koristiti nesortirani deo kao gornji deo.
Posmatrajte primer Gornjeg Dea
```c #include #include
int main(void) { char *chunk; chunk = malloc(24); printf("Address of the chunk: %p\n", (void *)chunk); gets(chunk); return 0; }
После компајлирања и дебаговања са прекидном тачком у `ret` опкоду `main`, видео сам да је malloc вратио адресу `0xaaaaaaac12a0` и ово су делови:
```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
Gde se može videti da je gornji deo na adresi 0xaaaaaaac1ae0. To nije iznenađenje jer je poslednji alocirani deo bio na 0xaaaaaaac12a0 sa veličinom 0x410 i 0xaaaaaaac12a0 + 0x410 = 0xaaaaaaac1ae0.
Takođe je moguće videti dužinu gornjeg dela na njegovom zaglavlju dela:
Kada se koristi malloc i kada se deo deli (na primer, iz nesortiranog bin-a ili iz gornjeg dela), deo koji se stvara od ostatka podeljenog dela se naziva Poslednji Ostatak i njegov pokazivač se čuva u malloc_state strukturi.