tcc-stupidos/libtcc/memory.c

340 lines
5.9 KiB
C
Raw Normal View History

2025-02-11 12:07:04 +00:00
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif /* HAVE_CONFIG_H */
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <tcc.h>
#ifdef TCC_MEMORY_DEBUG
# undef tcc_free
# undef tcc_malloc
# undef tcc_mallocz
# undef tcc_realloc
# undef tcc_strdup
#endif /* TCC_MEMORY_DEBUG */
static void *
default_reallocator(void *ptr, size_t size)
{
void *ptr1;
if (size == 0)
{
free(ptr);
return (NULL);
}
ptr1 = realloc(ptr, size);
if (ptr1 == NULL)
{
fprintf(stderr, "memory full\n");
exit(EXIT_FAILURE);
}
return (ptr1);
}
static TCCReallocFunc *reallocator = default_reallocator;
void
tcc_set_realloc(TCCReallocFunc *my_realloc)
{
if (my_realloc == NULL)
{
reallocator = default_reallocator;
return;
}
reallocator = my_realloc;
}
void
tcc_free(void *ptr)
{
reallocator(ptr, 0);
}
void *
tcc_malloc(size_t size)
{
return (reallocator(NULL, size));
}
void *
tcc_mallocz(size_t size)
{
void *ptr;
ptr = tcc_malloc(size);
if (ptr == NULL)
{
return (NULL);
}
memset(ptr, 0, size);
return (ptr);
}
void *
tcc_realloc(void *ptr, size_t size)
{
return (reallocator(ptr, size));
}
char *
tcc_strdup(const char *str)
{
char *ptr;
ptr = tcc_malloc(strlen(str) + 1);
strcpy(ptr, str);
return (ptr);
}
#ifdef TCC_MEMORY_DEBUG
# define MEMORY_DEBUG_MAGIC1 0xFEEDDEB1
# define MEMORY_DEBUG_MAGIC2 0xFEEDDEB2
# define MEMORY_DEBUG_MAGIC3 0xFEEDDEB3
# define MEMORY_DEBUG_FILE_LEN 40
# define MEMORY_DEBUG_CHECK3(hdr) \
((MemoryDebugHeader *)((uint8_t *)hdr + header->size))->magic3
# define MEMORY_USER_PTR(hdr) \
((uint8_t *)header + offsetof(MemoryDebugHeader, magic3))
# define MEMORY_HEADER_PTR(ptr) \
(MemoryDebugHeader *)((uint8_t *)ptr - offsetof(MemoryDebugHeader, magic3))
typedef struct MemoryDebugHeader {
uint32_t magic1;
size_t size;
struct MemoryDebugHeader *prev;
struct MemoryDebugHeader *next;
int linenum;
char filename[MEMORY_DEBUG_FILE_LEN + 1];
uint32_t magic2;
__attribute__((aligned(16))) uint8_t magic3[4];
} MemoryDebugHeader;
TCC_SEM(static mem_sem);
static MemoryDebugHeader *mem_debug_chain;
static size_t mem_cur_size;
size_t mem_max_size;
static int nb_states;
static MemoryDebugHeader *
malloc_check(void *ptr, const char *msg)
{
MemoryDebugHeader *header;
header = MEMORY_HEADER_PTR(ptr);
if (header->magic1 != MEMORY_DEBUG_MAGIC1
|| header->magic2 != MEMORY_DEBUG_MAGIC2
|| read32le(MEMORY_DEBUG_CHECK3(header)) != MEMORY_DEBUG_MAGIC3
|| header->size == (size_t)-1)
{
fprintf(stderr, "%s check failed\n", msg);
if (header->magic1 == MEMORY_DEBUG_MAGIC1)
{
fprintf(stderr, "%s:%u: block allocated here.\n",
header->filename, header->linenum);
}
exit(EXIT_FAILURE);
}
return (header);
}
void
tcc_free_debug(void *ptr)
{
MemoryDebugHeader *header;
if (ptr == NULL)
{
return;
}
header = malloc_check(ptr, "tcc_free");
WAIT_SEM(&mem_sem);
mem_cur_size -= header->size;
header->size = (size_t)-1;
if (header->next)
{
header->next->prev = header->prev;
}
if (header->prev)
{
header->prev->next = header->next;
}
if (header == mem_debug_chain)
{
mem_debug_chain = header->next;
}
POST_SEM(&mem_sem);
tcc_free(header);
}
void *
tcc_malloc_debug(size_t size, const char *file, int line)
{
int ofs;
MemoryDebugHeader *header;
if (size == 0)
{
return (NULL);
}
header = tcc_malloc(sizeof(MemoryDebugHeader) + size);
header->magic1 = MEMORY_DEBUG_MAGIC1;
header->magic2 = MEMORY_DEBUG_MAGIC2;
header->size = size;
write32le(MEMORY_DEBUG_CHECK3(header), MEMORY_DEBUG_MAGIC3);
header->linenum = line;
ofs = strlen(file) - MEMORY_DEBUG_FILE_LEN;
strncpy(header->filename, file + (ofs > 0 ? ofs : 0), MEMORY_DEBUG_FILE_LEN);
header->filename[MEMORY_DEBUG_FILE_LEN] = 0;
WAIT_SEM(&mem_sem);
header->next = mem_debug_chain;
header->prev = NULL;
if (header->next)
{
header->next->prev = header;
}
mem_debug_chain = header;
mem_cur_size += size;
if (mem_cur_size > mem_max_size)
{
mem_max_size = mem_cur_size;
}
POST_SEM(&mem_sem);
return (MEMORY_USER_PTR(header));
}
void *
tcc_mallocz_debug(size_t size, const char *file, int line)
{
void *ptr;
ptr = tcc_malloc_debug(size, file, line);
if (ptr == NULL)
{
return (NULL);
}
memset(ptr, 0, size);
return (ptr);
}
void *
tcc_realloc_debug(void *ptr, size_t size, const char *file, int line)
{
MemoryDebugHeader *header;
int mem_debug_chain_update;
mem_debug_chain_update = 0;
if (ptr == NULL)
{
return (tcc_malloc_debug(size, file, line));
}
if (size == 0)
{
tcc_free_debug(ptr);
return (NULL);
}
header = malloc_check(ptr, "tcc_realloc");
WAIT_SEM(&mem_sem);
mem_cur_size -= header->size;
mem_debug_chain_update = (header == mem_debug_chain);
header = tcc_realloc(header, sizeof(MemoryDebugHeader) + size);
header->size = size;
write32le(MEMORY_DEBUG_CHECK3(header), MEMORY_DEBUG_MAGIC3);
if (header->next)
{
header->next->prev = header;
}
if (header->prev)
{
header->prev->next = header;
}
if (mem_debug_chain_update)
{
mem_debug_chain = header;
}
mem_cur_size += size;
if (mem_cur_size > mem_max_size)
{
mem_max_size = mem_cur_size;
}
POST_SEM(&mem_sem);
return (MEMORY_USER_PTR(header));
}
char *
tcc_strdup_debug(const char *str, const char *file, int line)
{
char *ptr;
ptr = tcc_malloc_debug(strlen(str) + 1, file, line);
strcpy(ptr, str);
return (ptr);
}
void
tcc_memcheck(int d)
{
MemoryDebugHeader *header;
WAIT_SEM(&mem_sem);
nb_states += d;
if (0 == nb_states && mem_cur_size)
{
header = mem_debug_chain;
fflush(stdout);
fprintf(stderr, "MEM_DEBUG: mem_leak= %d bytes, mem_max_size= %d bytes\n",
mem_cur_size, mem_max_size);
while (header)
{
fprintf(stderr, "%s:%u: error: %u bytes leaked\n",
header->filename, header->linenum, header->size);
header = header->next;
}
fflush(stderr);
mem_cur_size = 0;
mem_max_size = 0;
mem_debug_chain = NULL;
#if TCC_MEMORY_DEBUG-0 == 2
exit(2);
#endif /* TCC_MEMORY_DEBUG == 2 */
}
POST_SEM(&mem_sem);
}
#endif /* TCC_MEMORY_DEBUG */