```c // From https://github.com/bminor/glibc/blob/master/malloc/malloc.c
#if IS_IN (libc) void * __libc_malloc (size_t bytes) { mstate ar_ptr; void *victim;
_Static_assert (PTRDIFF_MAX <= SIZE_MAX / 2, "PTRDIFF_MAX is not more than half of SIZE_MAX");
if (!__malloc_initialized) ptmalloc_init (); #if USE_TCACHE /* int_free also calls request2size, be careful to not pad twice. */ size_t tbytes = checked_request2size (bytes); if (tbytes == 0) { __set_errno (ENOMEM); return NULL; } size_t tc_idx = csize2tidx (tbytes);
MAYBE_INIT_TCACHE ();
DIAG_PUSH_NEEDS_COMMENT; if (tc_idx < mp_.tcache_bins && tcache != NULL && tcache->counts[tc_idx] > 0) { victim = tcache_get (tc_idx); return tag_new_usable (victim); } DIAG_POP_NEEDS_COMMENT; #endif
if (SINGLE_THREAD_P) { victim = tag_new_usable (_int_malloc (&main_arena, bytes)); assert (!victim || chunk_is_mmapped (mem2chunk (victim)) || &main_arena == arena_for_chunk (mem2chunk (victim))); return victim; }
arena_get (ar_ptr, bytes);
victim = _int_malloc (ar_ptr, bytes); /* Retry with another arena only if we were able to find a usable arena before. */ if (!victim && ar_ptr != NULL) { LIBC_PROBE (memory_malloc_retry, 1, bytes); ar_ptr = arena_get_retry (ar_ptr, bytes); victim = _int_malloc (ar_ptr, bytes); }
if (ar_ptr != NULL) __libc_lock_unlock (ar_ptr->mutex);
victim = tag_new_usable (victim);
assert (!victim || chunk_is_mmapped (mem2chunk (victim)) || ar_ptr == arena_for_chunk (mem2chunk (victim))); return victim; }
Copy </details>
返されたポインタには常に `tag_new_usable` がタグ付けされることに注意してください。コードから:
```c
void *tag_new_usable (void *ptr)
Allocate a new random color and use it to color the user region of
a chunk; this may include data from the subsequent chunk's header
if tagging is sufficiently fine grained. Returns PTR suitably
recolored for accessing the memory there.
_int_malloc
これは、他のビンとトップチャンクを使用してメモリを割り当てる関数です。
リクエストされたメモリ空間が持つ必要のある実際のサイズを取得し、いくつかの変数を定義することから始まります:
Fast Bin
必要なサイズがFast Binsのサイズ内にある場合、fast binからチャンクを使用しようとします。基本的に、サイズに基づいて、有効なチャンクが存在するfast binインデックスを見つけ、もしあれば、その中の1つを返します。
さらに、tcacheが有効な場合、そのサイズのtcache binをfast binsで埋めます 。
これらのアクションを実行する際に、いくつかのセキュリティチェックがここで実行されます:
チャンクが不揃いの場合: malloc(): unaligned fastbin chunk detected 2
前方チャンクが不揃いの場合: malloc(): unaligned fastbin chunk detected
返されたチャンクのサイズがfast binのインデックスのために正しくない場合: malloc(): memory corruption (fast)
tcacheを埋めるために使用されたチャンクが不揃いの場合: malloc(): unaligned fastbin chunk detected 3
malloc_consolidate
小さなチャンクでなければ、大きなチャンクであり、この場合はメモリの断片化を避けるために malloc_consolidate
が呼び出されます。
未整理ビン
有効なチャンクを使用するために未整理ビンを確認する時が来ました。
開始
これは、大きなforループから始まり、bk
方向に未整理ビンをトラバースし、while ((victim = unsorted_chunks (av)->bk) != unsorted_chunks (av))
で最後(アリーナ構造体)に到達します。
さらに、新しいチャンクが考慮されるたびにいくつかのセキュリティチェックが行われます:
チャンクサイズが奇妙な場合(小さすぎるまたは大きすぎる):malloc(): invalid size (unsorted)
次のチャンクサイズが奇妙な場合(小さすぎるまたは大きすぎる):malloc(): invalid next size (unsorted)
次のチャンクによって示された前のサイズがチャンクのサイズと異なる場合:malloc(): mismatching next->prev_size (unsorted)
victim->bck->fd == victim
でないか、またはvictim->fd == av
(アリーナ)でない場合:malloc(): unsorted double linked list corrupted
常に最後のものをチェックしているため、fd
は常にアリーナ構造体を指している必要があります。
次のチャンクが前のチャンクが使用中でないことを示していない場合:malloc(): invalid next->prev_inuse (unsorted)
成功した場合は、チャンクを返して終了します。成功しなかった場合は、関数の実行を続けます...
サイズが等しい場合
要求されたサイズがチャンクのサイズと正確に一致する場合、ビンからチャンクを削除し続けます:
tcacheが満たされていない場合は、tcacheに追加し、使用可能なtcacheチャンクがあることを示し続けます
tcacheが満杯の場合は、それを使用して返します
_int_malloc
の制限
この時点で、使用可能な tcache にいくつかのチャンクが格納されていて、制限に達した場合は、単に tcache チャンクを返す 。
さらに、MAX_ITERS に達した場合は、ループを抜けて別の方法でチャンクを取得する(トップチャンク)。
return_cached
が設定されている場合は、より大きな検索を避けるために、単に tcache からチャンクを返す。
この目的に適したチャンクが見つからない場合は、続行します。
大きなビン(次の大きいもの)
正確な大きなビンに使用できるチャンクがなかった場合は、次の大きなビン(すぐに大きいものから始める)をループして、見つかるまで(あれば)続けます。
分割されたチャンクの残りは未ソートビンに追加され、last_reminderが更新され、同じセキュリティチェックが実行されます:
bck->fd-> bk != bck
: malloc(): corrupted unsorted chunks2
sysmalloc
sysmallocの開始
arenaがnullであるか、要求されたサイズが大きすぎる場合(かつ許可されたmmapsが残っている場合)、sysmalloc_mmap
を使用してスペースを割り当て、それを返します。
sysmalloc not main arena
最初に、このヒープのために前のヒープを拡張 しようとします。もし不可能な場合は、新しいヒープを割り当て て、使用できるようにポインタを更新しようとします。
最後に、それがうまくいかなかった場合は、**sysmalloc_mmap
**を呼び出そうとします。
sysmalloc メインアリーナの前のエラー 1
もし前回返された MORECORE_FAILURE
であれば、sysmalloc_mmap_fallback
を使用してメモリを再度割り当ててみてください。
sysmalloc finale
アリーナ情報を更新して割り当てを完了します。
Copy // From https://github.com/bminor/glibc/blob/f942a732d37a96217ef828116ebe64a644db18d7/malloc/malloc.c#L2921C3-L2943C12
if (( unsigned long ) av -> system_mem > ( unsigned long ) (av -> max_system_mem))
av -> max_system_mem = av -> system_mem;
check_malloc_state (av);
/* finally, do the allocation */
p = av -> top;
size = chunksize (p);
/* check that one of the above allocation paths succeeded */
if (( unsigned long ) (size) >= ( unsigned long ) (nb + MINSIZE))
{
remainder_size = size - nb;
remainder = chunk_at_offset (p , nb) ;
av -> top = remainder;
set_head (p , nb | PREV_INUSE | (av != & main_arena ? NON_MAIN_ARENA : 0 )) ;
set_head (remainder , remainder_size | PREV_INUSE) ;
check_malloced_chunk (av , p , nb) ;
return chunk2mem (p) ;
}
/* catch all failure paths */
__set_errno (ENOMEM);
return 0 ;
sysmalloc_mmap