Hacking püf noktalarını paylaşarak PR'ler göndererekHackTricks ve HackTricks Cloud github depolarına katkıda bulunun.
Temel Bilgiler
Parçaların nasıl depolandığındaki verimliliği artırmak için her parça sadece bir bağlı listede değil, birkaç türde depolanır. Bunlar "bins"lerdir ve 5 tür bin vardır: 62 küçük bins, 63 büyük bins, 1 sıralanmamış bin, 10 hızlı bins ve her iş parçacığı için 64 tcache bin'i vardır.
Sıralanmamış, küçük ve büyük bins'e her birinin başlangıç adresi aynı dizinin içindedir. İndeks 0 kullanılmaz, 1 sıralanmamış bin, 2-64 arası küçük bins ve 65-127 arası büyük bins'tir.
Tcache (İş Parçacığı Başına Önbellek) Bins
İş parçacıkları kendi belleğe sahip olmaya çalışsa da (bkz. Arenalar ve Alt bellekler), birçok iş parçacığına sahip bir işlem (örneğin bir web sunucusu) başka iş parçacıklarıyla belleği paylaşabilir. Bu durumda, ana çözüm kilitlerin kullanılmasıdır, bu da iş parçacıklarını önemli ölçüde yavaşlatabilir.
Bir iş parçacığı bir parçayı serbest bıraktığında, eğer tcache'e tahsis edilecek kadar büyük değilse ve ilgili tcache bin'i dolu değilse (zaten 7 parça), oraya tahsis edilecektir. Tcache'e gidemezse, genel bins'te serbest bırakma işlemini gerçekleştirebilmek için bellek kilidinin açılmasını beklemesi gerekir.
Bir parça tahsis edildiğinde, eğer Tcache'te ihtiyaç duyulan boyutta boş bir parça varsa onu kullanır, yoksa genel bins'te bir tane bulmak veya yeni bir tane oluşturabilmek için bellek kilidinin açılmasını beklemesi gerekir.
Bu durumda bir optimizasyon da vardır, bu durumda bellek kilidi açıkken, iş parçacığı istenen boyutta heap parçalarıyla (7) Tcache'ini dolduracaktır, böylece daha fazla ihtiyaç duyarsa onları Tcache'te bulacaktır.
Bir tcache parça örneği ekle
```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; }
Derleyin ve ana işlevden ret opcode'unda bir kesme noktası ile hata ayıklamayı yapın. Sonra gef ile kullanımda olan tcache binini görebilirsiniz:
```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 Yapıları ve Fonksiyonlar
Aşağıdaki kodda maksimum kovalar ve her indeks başına parçalar, çift serbest bırakmaları önlemek için oluşturulan tcache_entry yapısı ve her bir iş parçacığının kovanın her indeksine ait adresleri depolamak için kullandığı tcache_perthread_struct yapısı görülebilir.
```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>
`__tcache_init` işlevi, `tcache_perthread_struct` nesnesi için alan oluşturan ve ayıran işlevdir.
<details>
<summary>tcache_init kodu</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 İndeksleri
Tcache, her bir indeksin boyutuna ve başlangıç işaretçilerine bağlı olarak birkaç farklı bina sahiptir ve her indeks için ilk parçanın ve indeks başına düşen parça miktarının bir parça içinde bulunduğu anlamına gelir. Bu, bu bilgiyi içeren parçayı (genellikle ilk parçayı) bulmak, tüm tcache başlangıç noktalarını ve Tcache parça miktarını bulmayı mümkün kılar.
Hızlı Bins
Hızlı binalar, küçük parçalar için hafıza tahsili işlemini hızlandırmak için tasarlanmıştır ve son zamanlarda serbest bırakılan parçaları hızlı erişim yapısında tutarak. Bu binalar, Son Giren İlk Çıkar (LIFO) yaklaşımını kullanır, bu da demektir ki en son serbest bırakılan parça, yeni bir tahsis isteği olduğunda ilk olarak yeniden kullanılır. Bu davranış hız için avantajlıdır, çünkü bir yığının üstünden (LIFO) ekleme ve çıkarma yapmak, bir kuyruktan (FIFO) daha hızlıdır.
Ayrıca, hızlı binalar tek yönlü bağlı listeleri kullanır, çift yönlü değil, bu da hızı daha da artırır. Hızlı binalardaki parçalar komşularla birleştirilmediği için, ortadan kaldırma izni veren karmaşık bir yapıya ihtiyaç yoktur. Tek yönlü bağlı liste, bu işlemler için daha basit ve daha hızlıdır.
Temelde burada olan şey, başlık (kontrol edilecek ilk parçanın işaretçisi) her zaman o boyuttaki en son serbest bırakılan parçaya işaret eder. Dolayısıyla:
O boyutta yeni bir parça tahsis edildiğinde, başlık kullanılacak bir boş parçaya işaret eder. Bu boş parça, kullanılacak bir sonraki parçaya işaret ettiği için, bu adres başlıkta saklanır, böylece bir sonraki tahsis nereden kullanılabilir bir parça alacağını bilir
Bir parça serbest bırakıldığında, boş parça, mevcut kullanılabilir parçanın adresini kaydeder ve bu yeni serbest bırakılan parçanın adresi başlığa konur
Bağlı liste maksimum boyutu 0x80 ve bir 0x20 boyutundaki bir parça 0 indekste olacaktır, bir 0x30 boyutundaki bir parça 1 indekste olacaktır...
Hızlı binalardaki parçalar kullanılabilir olarak ayarlanmadığından, etraflarındaki diğer serbest parçalarla birleştirilebilme yeteneğine sahip olmaları yerine bir süre hızlı bina parçaları olarak tutulurlar.
// 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)
<özet> Hızlı bir blok örneği ekle </özet>
#include<stdlib.h>#include<stdio.h>intmain(void){char*chunks[8];int i;// Loop to allocate memory 8 timesfor (i =0; i <8; i++) {chunks[i] =malloc(24);if (chunks[i] ==NULL) { // Check if malloc failedfprintf(stderr,"Memory allocation failed at iteration %d\n", i);return1;}printf("Address of chunk %d: %p\n", i, (void*)chunks[i]);}// Loop to free the allocated memoryfor (i =0; i <8; i++) {free(chunks[i]);}return0;}
Not: Aynı boyutta 8 parça ayırdığımızı ve serbest bıraktığımızı ve bunların tcache'i doldurduğunu ve sekizincisinin hızlı parçada depolandığını gözlemleyin.
Bunu derleyin ve main fonksiyonundaki ret opcode'unda bir kesme noktası ile hata ayıklamayı başlatın. Sonra gef ile tcache bininin dolu olduğunu ve bir parçanın hızlı binde olduğunu görebilirsiniz:
Sıralanmamış kova, bellek tahsisini hızlandırmak için kullanılan bir önbellektir. İşleyişi şöyledir: Bir program bir parçayı serbest bıraktığında ve bu parça bir tcache veya hızlı kova içinde tahsis edilemiyorsa ve en üst parçayla çakışmıyorsa, bellek yöneticisi hemen onu belirli bir küçük veya büyük kovaya koymaz. Bunun yerine, öncelikle bitişik boş parçalarla birleştirmeye çalışarak daha büyük bir boş bellek bloğu oluşturur. Daha sonra, bu yeni parçayı "sıralanmamış kova" olarak adlandırılan genel bir kovaya yerleştirir.
Bir program bellek istediğinde, bellek yöneticisi sıralanmamış kovayı kontrol eder ve yeterli boyutta bir parça bulunup bulunmadığına bakar. Bir tane bulursa, hemen kullanır. Sıralanmamış kovada uygun bir parça bulamazsa, bu listedeki tüm parçaları boyutlarına göre küçük veya büyük kovalarına taşır.
Dikkat edilmesi gereken bir nokta, daha büyük bir parçanın 2 yarısına bölündüğü ve geri kalanın MINSIZE'dan büyük olduğu durumda, tekrar sıralanmamış kovaya yerleştirileceğidir.
Bu nedenle, sıralanmamış kova, son zamanlarda serbest bırakılan belleği hızlı bir şekilde yeniden kullanarak bellek tahsisini hızlandırmak ve zaman alıcı aramaları ve birleştirmeleri azaltmak için bir yöntemdir.
Farklı kategorilerden parçalar olsalar bile, mevcut bir parça başka bir mevcut parçayla çakışıyorsa (başlangıçta farklı kovalara ait olsalar bile), birleştirileceklerdir.
Bir sıralanmamış parça örneği ekleyin
```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; }
Not: Aynı boyutta 9 parça ayırdığımızı ve serbest bıraktığımızı **dikkate alın, bu şekilde tcache'i doldururuz** ve sekizincisi **fastbin için çok büyük olduğu için düzensiz kutuya depolanır** ve dokuzuncusu serbest bırakılmaz, bu yüzden dokuzuncu ve sekizinci **üst parça ile birleştirilmez**.
Derleyin ve `main` fonksiyonundaki `ret` opcode'unda bir kesme noktası ile hata ayıklamayı başlatın. Sonra `gef` ile tcache bininin dolu olduğunu ve bir parçanın düzensiz kutuda olduğunu görebilirsiniz:
```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.
Küçük Bins
Küçük bins'ler büyük bins'lerden daha hızlı ancak fast bins'lerden daha yavaştır.
62 bins'ten her biri aynı boyutta parçalara sahip olacaktır: 16, 24, ... (32 bit için maksimum 504 bayt ve 64 bit için 1024 bayt). Bu, bir alanın tahsis edilmesi gereken binin bulunmasında, bu listelerdeki girişlerin eklenmesi ve çıkarılmasında hız sağlar.
Küçük binin boyutu, binin indeksine göre nasıl hesaplandığı aşağıdaki gibidir:
En küçük boyut: 2*4*index (örneğin, indeks 5 -> 40)
En büyük boyut: 2*8*index (örneğin, indeks 5 -> 80)
#include<stdlib.h>#include<stdio.h>intmain(void){char*chunks[10];int i;// Loop to allocate memory 8 timesfor (i =0; i <9; i++) {chunks[i] =malloc(0x100);if (chunks[i] ==NULL) { // Check if malloc failedfprintf(stderr,"Memory allocation failed at iteration %d\n", i);return1;}printf("Address of chunk %d: %p\n", i, (void*)chunks[i]);}// Loop to free the allocated memoryfor (i =0; i <8; i++) {free(chunks[i]);}chunks[9] =malloc(0x110);return0;}
Not allokasyon ve serbest bırakma işlemlerini 9 aynı boyutta parça için nasıl yaptığımıza dikkat edin, böylece tcache'i doldururlar ve sekizincisi hızlı bin için çok büyük olduğu için düzensiz binde depolanır ve dokuzuncusu serbest bırakılmaz, bu nedenle dokuzuncu ve sekizinci üst parça ile birleştirilmez. Daha sonra 0x110 boyutunda daha büyük bir parça tahsis ederiz, bu da düzensiz bindeki parçanın küçük bine gitmesine neden olur.
Bunu derleyin ve main fonksiyonundaki ret opcode'unda bir kesme noktası ile hata ayıklamayı yapın. Ardından gef ile tcache bininin dolu olduğunu ve bir parçanın küçük binde olduğunu görebilirsiniz:
gef➤heapbins──────────────────────────────────────────────────────────────────────────────── 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]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 ────────────────────────────────────────────────────────────────────────
[+] 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.
Büyük kovalar
Küçük kovaların aksine, her büyük kova bir aralıkta parça boyutlarını yönetir. Bu daha esnek bir yapıya sahiptir, çeşitli boyutları ayrı bir kova gerektirmeden sistemde barındırabilir.
Bir bellek tahsis edici içinde büyük kovalar, küçük kovaların bittiği yerden başlar. Büyük kovalar için aralıklar giderek büyür, yani ilk kova 512 ile 576 bayt arasındaki parçaları kapsayabilirken, bir sonraki kova 576 ile 640 bayt arasındakileri kapsar. Bu desen devam eder ve en büyük kova 1MB üzerindeki tüm parçaları içerir.
Büyük kovalar, bir tahsis için en iyi uyumu bulmak için değişen parça boyutlarının listesinde sıralama ve arama yapmak zorunda kaldıkları için küçük kovalara göre daha yavaş çalışırlar. Bir parça büyük bir kovaya eklendiğinde sıralanmalı ve bellek tahsis edildiğinde sistem doğru parçayı bulmalıdır. Bu ekstra iş onları daha yavaş yapar, ancak büyük tahsisler küçük olanlardan daha az olduğu için kabul edilebilir bir takas yapılır.
Şunlar vardır:
64B aralığında 32 kova (küçük kovalarla çakışır)
512B aralığında 16 kova (küçük kovalarla çakışır)
4096B aralığında 8 kova (kısmen küçük kovalarla çakışır)
32768B aralığında 4 kova
262144B aralığında 2 kova
Geri kalan boyutlar için 1 kova
Büyük kova boyutları kodu
```c // From https://github.com/bminor/glibc/blob/a07e000e82cb71238259e674529c37c12dc7d423/malloc/malloc.c#L1711
</details>
<details>
<summary>Büyük bir parça örneği ekleyin</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 büyük tahsisat yapılır, ardından biri serbest bırakılır (bu, sırasız kutuya yerleştirilir) ve daha büyük bir tahsisat yapılır (serbest bırakılanı sırasız kutudan büyük kutuya taşır).
Bunu derleyin ve main fonksiyonundaki ret işlem kodunda bir kesme noktası ile hata ayıklamayı yapın. Ardından gef ile tcache kutusunun dolu olduğunu ve bir parçanın büyük kutuda olduğunu görebilirsiniz:
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.
En Üst Parça
// 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))
Temelde, şu anda mevcut olan heap'in tümünü içeren bir parçadır. Bir malloc işlemi gerçekleştirildiğinde, kullanılabilecek herhangi bir boş parça yoksa, bu üst parça gerekli alanı vererek boyutunu azaltacaktır.
Top Chunk'a işaret eden işaretçi, malloc_state yapısında saklanır.
Ayrıca, başlangıçta, üst parça olarak sırasız parçayı kullanmak mümkündür.
Üst Parça örneğini gözlemleyin
```c #include #include
int main(void) { char *chunk; chunk = malloc(24); printf("Address of the chunk: %p\n", (void *)chunk); gets(chunk); return 0; }
Top bloğun adresinin 0xaaaaaaac1ae0 olduğu görülebilir. Bu bir sürpriz değil çünkü en son ayrılan blok 0xaaaaaaac12a0 adresindeydi ve boyutu 0x410 idi ve 0xaaaaaaac12a0 + 0x410 = 0xaaaaaaac1ae0 olur.
Ayrıca, Top bloğun uzunluğu da blok başlığında görülebilir:
malloc kullanıldığında ve bir parça bölündüğünde (örneğin sıralanmamış bin veya üst parçadan), bölünmüş parçanın geri kalanından oluşturulan parçaya Son Kalan Parça denir ve işaretçisi malloc_state yapısında saklanır.