/* ************************************************************************** */ /* */ /* ::: :::::::: */ /* ft_realloc.c :+: :+: :+: */ /* +:+ +:+ +:+ */ /* By: thrieg < thrieg@student.42mulhouse.fr> +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2025/11/25 11:47:23 by thrieg #+# #+# */ /* Updated: 2025/12/08 16:02:18 by thrieg ### ########.fr */ /* */ /* ************************************************************************** */ #include "../includes/ft_malloc.h" // returns non-0 (1) is the zone changes type to a higher type (tiny to small or small to large) static bool is_upgraded(size_t size, t_type current_type) { if (size > SMALL_SIZE_MAX && current_type != E_LARGE) return (1); else if (size > TINY_SIZE_MAX && current_type != E_SMALL) return (1); else return (0); } void *realloc(void *ptr, size_t size) { if (size == 0) { free(ptr); return (NULL); } else if (!ptr) { return (malloc(size)); } size_t original_size = size; if (size % ALLIGN_BYTES) size = ((size / ALLIGN_BYTES) + 1) * ALLIGN_BYTES; void *ret = NULL; pthread_mutex_lock(&g_mut); if (!g_state.is_init) { init_env_variables(); // realloc shouldn't ever be called first with a non-NULL ptr return (NULL); // should I just let it segfault here like the real realloc? } t_header *header = ((t_header *)ptr) - 1; if (header->zone->type == E_LARGE) { pthread_mutex_unlock(&g_mut); ret = malloc(size); if (!ret) return (NULL); pthread_mutex_lock(&g_mut); if (original_size > header->size) ft_memcpy(ret, ptr, header->size); // if grow, copy the entire last buffer else ft_memcpy(ret, ptr, original_size); // if shrink, copy the new amount of bytes from older buffer pthread_mutex_unlock(&g_mut); free(ptr); pthread_mutex_lock(&g_mut); } else if (is_upgraded(size, header->zone->type)) { pthread_mutex_unlock(&g_mut); ret = malloc(size); if (!ret) return (NULL); pthread_mutex_lock(&g_mut); if (original_size > header->size) ft_memcpy(ret, ptr, header->size); // if grow, copy the entire last buffer else ft_memcpy(ret, ptr, original_size); // if shrink, copy the new amount of bytes from older buffer pthread_mutex_unlock(&g_mut); free(ptr); pthread_mutex_lock(&g_mut); } else if (header->zone->type == E_SMALL || header->zone->type == E_TINY) { t_header *next_header = (t_header *)(((char *)header) + sizeof(t_header) + header->size); if ((char *)next_header > (((char *)header->zone) + header->zone->size - sizeof(t_header))) next_header = NULL; // next header out of the zone if (size > header->size) { if (next_header && !next_header->occupied && (header->size + next_header->size + sizeof(t_header)) >= size) { const size_t available_space = (header->size + next_header->size + sizeof(t_header)); const size_t original_space = header->size; if (available_space - size > sizeof(t_header)) { // Split the block: create a new header in the remaining space char *new_addr = (char *)(header + 1) + size; t_header *newhdr = (t_header *)new_addr; newhdr->size = available_space - size - sizeof(t_header); newhdr->occupied = false; newhdr->zone = header->zone; header->size = size; } else { header->size = available_space; } pthread_mutex_unlock(&g_mut); // doesn't need to stay locked because the user is not supposed to free or realloc this ptr or change its content before this realloc returns if (g_state.patern) ft_memset((char *)ptr + original_space, g_state.patern, header->size - original_space); // should I use original_size to only perturb the actually requested bytes instead of the bytes I allocate? return (ptr); } else { pthread_mutex_unlock(&g_mut); ret = malloc(size); if (!ret) return (NULL); pthread_mutex_lock(&g_mut); if (original_size > header->size) ft_memcpy(ret, ptr, header->size); // if grow, copy the entire last buffer else ft_memcpy(ret, ptr, original_size); // if shrink, copy the new amount of bytes from older buffer pthread_mutex_unlock(&g_mut); free(ptr); pthread_mutex_lock(&g_mut); } } else { ret = ptr; // in all case we just return the original ptr, rest is just internal logic size_t available_space = header->size - size; // zones are defragmented so all available contiguous space must be in a single header if (next_header && !next_header->occupied) available_space += next_header->size + sizeof(t_header); if (available_space > sizeof(t_header)) { if (available_space > sizeof(t_header)) { // Split the block: create a new header in the remaining space char *new_addr = (char *)(header + 1) + size; t_header *newhdr = (t_header *)new_addr; newhdr->size = available_space - sizeof(t_header); newhdr->occupied = false; newhdr->zone = header->zone; header->size = size; } else { header->size = available_space; } } } } pthread_mutex_unlock(&g_mut); return (ret); }