Logo Search packages:      
Sourcecode: fhist version File versions

cmalloc.c

/*
 *    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 <ac/errno.h>
#include <ac/stdlib.h>
#include <ac/stddef.h>

#include <cmalloc.h>
#include <error.h>

#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;
}

Generated by  Doxygen 1.6.0   Back to index