(No se explican verificaciones en este resumen y algunos casos han sido omitidos por brevedad)
__libc_malloc intenta obtener un chunk del tcache, si no lo hace llama a _int_malloc
_int_malloc :
Intenta generar la arena si no hay ninguna
Si hay algún chunk de fast bin del tamaño correcto, úsalo
Llena el tcache con otros chunks rápidos
Si hay algún chunk de small bin del tamaño correcto, úsalo
Llena el tcache con otros chunks de ese tamaño
Si el tamaño solicitado no es para small bins, consolida fast bin en unsorted bin
Verifica el unsorted bin, usa el primer chunk con suficiente espacio
Si el chunk encontrado es más grande, divídelo para devolver una parte y agrega el resto de nuevo al unsorted bin
Si un chunk es del mismo tamaño que el tamaño solicitado, úsalo para llenar el tcache en lugar de devolverlo (hasta que el tcache esté lleno, luego devuelve el siguiente)
Para cada chunk de tamaño menor verificado, colócalo en su respectivo small o large bin
Verifica el large bin en el índice del tamaño solicitado
Comienza a buscar desde el primer chunk que sea más grande que el tamaño solicitado, si se encuentra alguno devuélvelo y agrega los restos al small bin
Verifica los large bins desde los siguientes índices hasta el final
Desde el siguiente índice más grande verifica si hay algún chunk, divide el primer chunk encontrado para usarlo para el tamaño solicitado y agrega el resto al unsorted bin
Si no se encuentra nada en los bins anteriores, obtén un chunk del top chunk
Si el top chunk no era lo suficientemente grande, amplíalo con sysmalloc
__libc_malloc
La función malloc en realidad llama a __libc_malloc. Esta función verificará el tcache para ver si hay algún chunk disponible del tamaño deseado. Si lo hay, lo usará y si no, verificará si es un hilo único y en ese caso llamará a _int_malloc en la arena principal, y si no, llamará a _int_malloc en la arena del hilo.
Código de __libc_malloc
```c // From https://github.com/bminor/glibc/blob/master/malloc/malloc.c
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);
</details>
Nota cómo siempre etiquetará el puntero devuelto con `tag_new_usable`, del código:
```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
Esta es la función que asigna memoria utilizando los otros bins y el top chunk.
Inicio
Comienza definiendo algunas variables y obteniendo el tamaño real que el espacio de memoria solicitado necesita tener:
Fast Bin
Si el tamaño necesario está dentro de los tamaños de Fast Bins, intenta usar un chunk del fast bin. Básicamente, según el tamaño, encontrará el índice del fast bin donde deberían estar los chunks válidos, y si hay alguno, devolverá uno de esos.
Además, si tcache está habilitado, llenará el tcache bin de ese tamaño con fast bins.
Mientras se realizan estas acciones, se ejecutan algunas verificaciones de seguridad aquí:
Si el chunk está desalineado: malloc(): unaligned fastbin chunk detected 2
Si el chunk hacia adelante está desalineado: malloc(): unaligned fastbin chunk detected
Si el chunk devuelto tiene un tamaño que no es correcto debido a su índice en el fast bin: malloc(): memory corruption (fast)
Si algún chunk utilizado para llenar el tcache está desalineado: malloc(): unaligned fastbin chunk detected 3
malloc_consolidate
Si no era un pequeño fragmento, es un gran fragmento, y en este caso se llama a malloc_consolidate para evitar la fragmentación de memoria.
Unsorted bin
Es hora de revisar el bin no ordenado en busca de un posible chunk válido para usar.
Start
Esto comienza con un gran bucle for que recorrerá el bin no ordenado en la dirección bk hasta llegar al final (la estructura arena) con while ((victim = unsorted_chunks (av)->bk) != unsorted_chunks (av))
Además, se realizan algunas verificaciones de seguridad cada vez que se considera un nuevo chunk:
Si el tamaño del chunk es extraño (demasiado pequeño o demasiado grande): malloc(): invalid size (unsorted)
Si el tamaño del siguiente chunk es extraño (demasiado pequeño o demasiado grande): malloc(): invalid next size (unsorted)
Si el tamaño anterior indicado por el siguiente chunk difiere del tamaño del chunk: malloc(): mismatching next->prev_size (unsorted)
Si no victim->bck->fd == victim o no victim->fd == av (arena): malloc(): unsorted double linked list corrupted
Como siempre estamos verificando el último, su fd debería estar apuntando siempre a la estructura arena.
Si el siguiente chunk no indica que el anterior está en uso: malloc(): invalid next->prev_inuse (unsorted)
Si esto fue exitoso, devuelve el chunk y se acabó, si no, continúa ejecutando la función...
si el tamaño es igual
Continúa eliminando el chunk del bin, en caso de que el tamaño solicitado sea exactamente el del chunk:
Si el tcache no está lleno, agrégalo al tcache y continúa indicando que hay un chunk de tcache que podría ser utilizado
Si el tcache está lleno, simplemente úsalo devolviéndolo
Límites de _int_malloc
En este punto, si algún chunk fue almacenado en el tcache que se puede usar y se alcanza el límite, simplemente devuelve un chunk del tcache.
Además, si se alcanza MAX_ITERS, sal del bucle y obtén un chunk de una manera diferente (chunk superior).
Si return_cached fue establecido, simplemente devuelve un chunk del tcache para evitar búsquedas más grandes.
Si no se encuentra un trozo adecuado para esto, continúa
Gran Bin (siguiente más grande)
Si en el gran bin exacto no había ningún trozo que pudiera ser utilizado, comienza a recorrer todos los siguientes grandes bins (comenzando por el inmediatamente más grande) hasta que se encuentre uno (si es que hay).
El recordatorio del trozo dividido se agrega en el bin no ordenado, last_reminder se actualiza y se realiza la misma verificación de seguridad:
bck->fd-> bk != bck: malloc(): corrupted unsorted chunks2
sysmalloc
sysmalloc inicio
Si arena es nula o el tamaño solicitado es demasiado grande (y quedan mmaps permitidos), utiliza sysmalloc_mmap para asignar espacio y devolverlo.
sysmalloc no arena principal
Primero intentará extender el montón anterior para este montón. Si no es posible, intentará asignar un nuevo montón y actualizar los punteros para poder usarlo.
Finalmente, si eso no funcionó, intentará llamar a sysmalloc_mmap.
sysmalloc error anterior de la arena principal 1
Si el anterior devolvió MORECORE_FAILURE, intenta nuevamente asignar memoria usando sysmalloc_mmap_fallback
sysmalloc finale
Termina la asignación actualizando la información de la arena.
// From https://github.com/bminor/glibc/blob/f942a732d37a96217ef828116ebe64a644db18d7/malloc/malloc.c#L2921C3-L2943C12if ((unsignedlong) av->system_mem > (unsignedlong) (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 ((unsignedlong) (size) >= (unsignedlong) (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);returnchunk2mem (p);}/* catch all failure paths */__set_errno (ENOMEM);return0;