/* * fhist - file history and comparison tools * Copyright (C) 1991-1994, 1998, 2000-2002 Peter Miller; * All rights reserved. * * Derived from a work * Copyright (C) 1990 David I. Bell. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. * * MANIFEST: functions to isolate malloc * * Malloc interludes which allow for releasing of all used memory blocks. * Just call cm_reset whenever you want to free all allocated memory. * This is convenient when reinitializing a program which allocates memory. * * Note: You must make sure that old stale pointers are not referenced, * such as static pointers which were 0 when the program started but * won't be later. In other words, to be safe you should not assume any * variables have been initialized, even for zero values. */ #include #include #include #include #include #undef malloc #undef realloc #undef free #undef calloc #define MAGIC 54928347L /* * This is to protect DOS. * On a 16-bit machine, this will be 65535, * exactly right for small-memory-model doc programs. * * but on a 32-bit machine, like most unixes, * this is essentially infinity. */ #define BIG ((unsigned int)-1) typedef struct chunk CHUNK; struct chunk { CHUNK *next; /* next chunk in chain */ CHUNK *prev; /* previous chunk in chain */ long magic; /* magic value */ double data[1]; /* data storage (varying size) */ }; #define CHUNKSIZE(size) (sizeof(CHUNK) + (size) - sizeof(double)) #define DPTOCP(dp) \ ((CHUNK *)(void*)(((char *)(dp)) - offsetof(CHUNK, data[0]))) static CHUNK head = {&head, &head}; /* * Actual calls to malloc, realloc, calloc, and free. * Users must be sure not to intermix these calls with the ones above. */ void * r_alloc(size_t size) { void *result; if (size > BIG) { errno = EINVAL; return 0; } errno = 0; result = malloc((unsigned int) size); if (!result && !errno) errno = ENOMEM; return result; } void * r_realloc(void *dp, size_t size) { void *result; if (size > BIG) { errno = EINVAL; return 0; } errno = 0; result = realloc(dp, (unsigned int) size); if (!result && !errno) errno = ENOMEM; return result; } void * r_realloc_and_check(void *a, size_t b) { void *result; result = r_realloc(a, b); if (!result) nfatal_raw("realloc(%lu)", (unsigned long)b); return result; } void r_free(void *dp) { free(dp); } void * r_alloc_and_check(size_t n) { void *result; result = r_alloc(n); if (!result) nfatal_raw("malloc(%lu)", (unsigned long)n); return result; } /* * Allocate some memory. */ void * cm_alloc(size_t size) { CHUNK *cp; if (size > BIG) { errno = EINVAL; return 0; } cp = (CHUNK *)r_alloc((size_t)CHUNKSIZE(size)); if (!cp) return 0; cp->magic = MAGIC; cp->next = head.next; cp->next->prev = cp; cp->prev = &head; head.next = cp; return (void *)cp->data; } void * cm_alloc_and_check(size_t n) { void *result; result = cm_alloc(n); if (!result) nfatal_raw("malloc(%lu)", (unsigned long)n); return result; } /* * Reallocate memory. */ void * cm_realloc(void *dp, size_t size) { CHUNK *cp; if (!dp || size > BIG) { errno = EINVAL; return 0; } cp = DPTOCP(dp); if (cp->magic != MAGIC) { error_raw ( "%s: %d: bad realloc %08lX (bug)", __FILE__, __LINE__, (unsigned long)dp ); errno = EINVAL; return 0; } cp = (CHUNK *)r_realloc(cp, (size_t)CHUNKSIZE(size)); if (!cp) return 0; cp->next->prev = cp; cp->prev->next = cp; return (void *)cp->data; } void * cm_realloc_and_check(void *a, size_t b) { void *result; result = cm_realloc(a, b); if (!result) nfatal_raw("malloc(%lu)", (unsigned long)b); return result; } /* * Allocate zeroed memory. */ void * cm_calloc(size_t nelem, size_t elsize) { size_t totalsize; CHUNK *cp; if (nelem > BIG || elsize > BIG) { errno = EINVAL; return 0; } totalsize = CHUNKSIZE(nelem * elsize); if (totalsize > BIG) { errno = EINVAL; return 0; } cp = (CHUNK *)r_alloc(totalsize); if (!cp) return 0; cp->magic = MAGIC; cp->next = head.next; cp->next->prev = cp; cp->prev = &head; head.next = cp; return (void *)cp->data; } void * cm_calloc_and_check(size_t a, size_t b) { void *result; result = cm_calloc(a, b); if (!result) nfatal_raw("malloc(%lu)", (unsigned long)b); return result; } /* * Free memory. */ void cm_free(void *dp) { CHUNK *cp; if (!dp) return; cp = DPTOCP(dp); if (cp->magic != MAGIC) { error_raw ( "%s: %d: bad free %08lX (bug)", __FILE__, __LINE__, (unsigned long)dp ); return; } cp->prev->next = cp->next; cp->next->prev = cp->prev; cp->next = 0; cp->prev = 0; cp->magic = 0; r_free(cp); } /* * Reset the whole memory arena. * This frees all memory allocated since the last cm_reset call. */ void cm_reset(void) { CHUNK *cp; while (head.next != &head) { cp = head.next; if (cp->magic != MAGIC) { error_raw ( "%s: %d: bad cm_reset %08lX (bug)", __FILE__, __LINE__, (unsigned long)cp ); break; } head.next = cp->next; cp->next = 0; cp->prev = 0; cp->magic = 0; r_free(cp); } head.next = &head; head.prev = &head; }