new version of MAD

Steef Boerrigter sxmboer at sci.kun.nl
Mon Jul 30 19:06:32 UTC 2001


Hi Pavel,


> Returning to our discussion 3 weeks ago about the editor killing files
> when using F11 menu because of incorrect interpretation of "%b".
Marvelous, this really beefs up mc for the mc-editor die hards like
myself.


> http://www.red-bean.com/~proski/mc/ (we probably need a better place for
> them in the long run).
Why don't we put the code on the GNU savannah site?
(http://savannah.gnu.org)
It's especially designed for projects like these, and after all, mc is
already a GNU package.


Anyway, this mail was really intended to bring up the improved version
of mad.c. As I promised you earlier this month, I have made a new mad.c
which fixes a few problems I encountered using it for different programs
and platforms.

I started merging the differences, but find it difficult and time
consuming as I worked on a mad.c which branched off of mc over two years
ago. Moreover, you may not like the chances, which would render my work
useless altogether.
Before I take it any further and possibly waste a lot of time, Pavel,
could you do me a favor and checkout the version as it is now and point
out which features you like and which you don't?

The main features/differences are:
- dynamic memory area handles (instead of static # 20000)
- separate END/START signatures
- MAD_QUICK option
- Support for SGI Indy (and probably more RISC and or MIPS platforms)
which need 8 byte aligned blocks for double variables. Currently, there
is no way to find out which datatype is malloced so the proper alignment
cannot be chosen. I think every datatype has it's own alignment,
actually (ie double:8, long:4, integer:4, char:1) On intel x86 family,
things are much easier as I found no such requirements whatsoever.

There's one more bug which I need to fix: calloc is now defined as
mad_alloc which simply does malloc. This is not correct, since calloc
resets (initializes to zeros) all the allocated bytes. Programs that
rely on that feature usually crash, obviously. One cannot trivially
replace the malloc with the calloc commands, however, since the
alignment and start/end-sigs have to be considered for proper operation.


I understand you're working towards bug-free ;-) version 4.5.55, so
please don't hurry looking into this subject, only do it if you can
spare the time.

Steef

P.S.
By the way, I'm sending you the full files as the 'diff -u' files are
bigger than the original files and I don't want you to confuse these
files with actual patches.

-- 
------------------------------------------------------------------------
Drs. S.X.M. Boerrigter
RIM Laboratory of Solid State Chemistry, University of Nijmegen
Toernooiveld 1, 6525 ED  Nijmegen, The Netherlands
Telephone: (+31)-(0)24-3652831    Fax:(+31)-(0)24-3653067
email: sxmboer at sci.kun.nl         http://savannah.gnu.org/users/sxmboer
------------------------------------------------------------------------
Quidquid latine dictum sit, altum viditur.
"Unix was not designed to stop people from doing stupid things,
 because that would also stop them from doing clever things." --Doug
Gwyn
Murphy's law: Anyt<Warning: Mail system error: Unexpected End Of File>
-------------- next part --------------
/* The Memory Allocation Debugging system
   Copyright (C) 1994 Janne Kukonlehto.
   Made useful (C:-) 2001 Steef Boerrigter.

   To use MAD define USE_MAD and include "mad.h" in every .c file you want to
   debug.

   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., 675 Mass Ave, Cambridge, MA 02139, USA.  */

#undef MAD_PRINTBLOCKS

/* alignment is necessary on some platforms (e.g. Indy:8!) because some
   data can only be addressed on aligned positions by the processor.
   Replacing data of these types to 'odd' addresses generates a BUS ERROR
   and we don't want that, do we? */

#undef MAD_ALIGN
#define MAD_ALIGN_BYTES (sizeof (double))

#undef MAD_QUICK

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <signal.h>	/* For kill() */
#ifdef HAVE_UNISTD_H
# include <unistd.h>	/* For getpid() */
#endif

#define MAD_AREA_INCREASE 1000
/* now a fully dynamically allocated datastructure, MAD_AREA_INCREASE can be changed for tuning MAD */

/* Maximum file name length */
#define MAD_MAX_FILE 50

/* Signatures for detecting overwrites */
/*#define MAD_START_SIGNATURE (('M'<<24)|('A'<<16)|('D'<<8)|('s'))
#define MAD_END_SIGNATURE (('e'<<24)|('n'<<16)|('d'<<8)|('S'))*/
/*#define MAD_START_SIGNATURE "MADSTART"
#define MAD_END_SIGNATURE   "mad_end."*/

/* "BITS" is nonsense, but you know what I mean; DO NOT change its definition!!!*/
#define MAD_ALIGN_BITS (MAD_ALIGN_BYTES-1)


typedef struct {
    int in_use;
    double *start_sig;
    char file [MAD_MAX_FILE];
    int line;
    void *data;
    double *end_sig;
} mad_mem_area;

mad_mem_area *mem_areas = NULL;
int mad_allocated_area_counter = 0;

const char MAD_START_SIGNATURE[8]="MADSTART";
const char MAD_END_SIGNATURE[8]= "mad_end.";

/*double mad_start_sig = (double) *MAD_START_SIGNATURE;
double mad_end_sig = *MAD_END_SIGNATURE;*/

/* This function is only called by the mad_check function */
static void mad_abort (char *message, int area, char *file, int line)
{
    fprintf (stderr, "MAD: %s in area %d.\r\n", message, area);
    fprintf (stderr, "     Allocated in file \"%s\" at line %d.\r\n",
	     mem_areas [area].file, mem_areas [area].line);
    fprintf (stderr, "     Discovered in file \"%s\" at line %d.\r\n",
	     file, line);
#if 0 /* always crash out */
    fprintf (stderr, "MAD: Core dumping...\r\n");
    kill (getpid (), 3);
#endif
}

/* Checks all the allocated memory areas.
   This is called everytime memory is allocated or freed.
   You can also call it anytime you think memory might be corrupted. */
void mad_check (char *file, int line)
{
    int i;

    /* fprintf(stderr, "MAD: checking all memory blocks...\n");*/
    for (i = 0; i < mad_allocated_area_counter; i++){
 	if (! mem_areas [i].in_use)
	    continue;
	if (*(mem_areas [i].start_sig) != (double) *MAD_START_SIGNATURE)
	    mad_abort ("Overwrite error: Bad start signature", i, file, line);
	if (*(mem_areas [i].end_sig) != (double) *MAD_END_SIGNATURE)
	    mad_abort ("Overwrite error: Bad end signature", i, file, line);
    }
}

/* Checks the allocated memory area.
   This is called if the MAD_QUICK option is chosen and realloc or
   free is called. */
void mad_checkthis (int i, char *file, int line)
{
	if (*(mem_areas [i].start_sig) != (double) *MAD_START_SIGNATURE)
	    mad_abort ("Overwrite error: Bad start signature", i, file, line);
	if (*(mem_areas [i].end_sig) != (double) *MAD_END_SIGNATURE)
	    mad_abort ("Overwrite error: Bad end signature", i, file, line);
}

/* Allocates a memory area. Used instead of malloc and calloc. */
void *mad_alloc (unsigned int size, char *file, int line)
{
    int i,j;
    char *area;

#ifndef MAD_QUICK
    mad_check (file, line);
#endif
/* technically, allocating a block of zero length is possible, but it doesn't
   really make any sense to do so */
    if (!size)
      fprintf(stderr, "MAD: WARNING allocating 0 bytes in %s, line %d...\n" ,file, line);

    for (i = 0; i < mad_allocated_area_counter; i++){
	if (! mem_areas [i].in_use)
	    break;
    }
    if (i >= mad_allocated_area_counter){
/* either create or reallocate the mem_area list */
            mad_allocated_area_counter+=MAD_AREA_INCREASE;
        if (!mem_areas)
            mem_areas = (mad_mem_area*) malloc (sizeof(mad_mem_area)*mad_allocated_area_counter);
         else
            mem_areas = (mad_mem_area*) realloc (mem_areas, sizeof(mad_mem_area)*mad_allocated_area_counter);
        fprintf(stderr, "MAD: Increasing number of memory area handles to %d...\r\n", mad_allocated_area_counter);
/* maybe the newly created mem_areas have to be initialized, sxm*/
        for (j=i;j<mad_allocated_area_counter;j++) mem_areas[j].in_use=0;        

/*
	fprintf (stderr, "MAD: Out of memory area handles. Increase the value of MAD_MAX_AREAS.\r\n");
	fprintf (stderr, "     Discovered in file \"%s\" at line %d.\r\n",
		 file, line);
	fprintf (stderr, "MAD: Aborting...\r\n");
	abort ();
*/
    }

    mem_areas [i].in_use = 1;
#ifdef MAD_ALIGN
    size = (size + MAD_ALIGN_BITS) & (~MAD_ALIGN_BITS); /* Alignment */
#endif
/*      fprintf(stderr, "MAD: allocating %i bytes in %s, line %d...\n" ,size, file, line);*/
    area = (char*) malloc (size + 2 * sizeof (double));
    if (!area){
	fprintf (stderr, "MAD: Out of memory.\r\n");
	fprintf (stderr, "     Discovered in file \"%s\" at line %d.\r\n",
		 file, line);
	fprintf (stderr, "MAD: Aborting...\r\n");
	abort ();
    }

    mem_areas [i].start_sig = (void*) area;
    mem_areas [i].data = (char*)(&(area[sizeof (double)]));
    mem_areas [i].end_sig = (void*) (&(area[size + sizeof(double)]));
    *(mem_areas [i].start_sig) = (double) *MAD_START_SIGNATURE;
    *(mem_areas [i].end_sig) = (double) *MAD_END_SIGNATURE;

#ifdef MAD_PRINTBLOCKS
fprintf(stderr, "MAD:   alloc block %6i: start_sig 0x%x  data 0x%x  end_sig 0x%x\n" ,i,mem_areas [i].start_sig,mem_areas [i].data,mem_areas [i].end_sig);
#endif
    if (strlen (file) >= MAD_MAX_FILE)
	file [MAD_MAX_FILE - 1] = 0;
    strcpy (mem_areas [i].file, file);
    mem_areas [i].line = line;

    return mem_areas [i].data;
}


void *mad_calloc (unsigned int size, unsigned int n, char *file, int line)
{
    int i,j;
    char *area;

#ifndef MAD_QUICK
    mad_check (file, line);
#endif
    if (!(size*n))
      fprintf(stderr, "MAD: WARNING allocating %i blocks of %i bytes in %s, line %d...\n" ,size, n, file, line);

    for (i = 0; i < mad_allocated_area_counter; i++){
	if (! mem_areas [i].in_use)
	    break;
    }
    if (i >= mad_allocated_area_counter){
/* either create or reallocate the mem_area list */
            mad_allocated_area_counter+=MAD_AREA_INCREASE;
        if (!mem_areas)
            mem_areas = (mad_mem_area*) malloc (sizeof(mad_mem_area)*mad_allocated_area_counter);
         else
            mem_areas = (mad_mem_area*) realloc (mem_areas, sizeof(mad_mem_area)*mad_allocated_area_counter);
        fprintf(stderr, "MAD: Increasing number of memory area handles to %d...\r\n", mad_allocated_area_counter);
        for (j=i;j<mad_allocated_area_counter;j++) mem_areas[j].in_use=0;

/*
	fprintf (stderr, "MAD: Out of memory area handles. Increase the value of MAD_MAX_AREAS.\r\n");
	fprintf (stderr, "     Discovered in file \"%s\" at line %d.\r\n",
		 file, line);
	fprintf (stderr, "MAD: Aborting...\r\n");
	abort ();
*/
    }

    mem_areas [i].in_use = 1;
    size *= n;
#ifdef MAD_ALIGN
    size = (size + MAD_ALIGN_BITS) & (~MAD_ALIGN_BITS); /* Alignment */
#endif
    area = (char*) malloc (size + 2 * sizeof (double));
    if (!area){
	fprintf (stderr, "MAD: Out of memory.\r\n");
	fprintf (stderr, "     Discovered in file \"%s\" at line %d.\r\n",
		 file, line);
	fprintf (stderr, "MAD: Aborting...\r\n");
	abort ();
    }

/* data block should be initialized to 0 as is normally done by calloc! */

    mem_areas [i].start_sig = (void*) area;
    mem_areas [i].data = (char*)(&area[sizeof (double)]);
    mem_areas [i].end_sig = (void*) (&area[size + sizeof (double)]);
    *(mem_areas [i].start_sig) = (double) *MAD_START_SIGNATURE;
    *(mem_areas [i].end_sig) = (double) *MAD_END_SIGNATURE;

#ifdef MAD_PRINTBLOCKS
fprintf(stderr, "MAD:  calloc block %6i: start_sig 0x%x  data 0x%x  end_sig 0x%x\n" ,i,mem_areas [i].start_sig,mem_areas [i].data,mem_areas [i].end_sig);
#endif

    if (strlen (file) >= MAD_MAX_FILE)
	file [MAD_MAX_FILE - 1] = 0;
    strcpy (mem_areas [i].file, file);
    mem_areas [i].line = line;

    return mem_areas [i].data;
}



/* Reallocates a memory area. Used instead of realloc. */
void *mad_realloc (void *ptr, unsigned int newsize, char *file, int line)
{
    int i;
    char *area;

    if (!ptr)
        return (mad_alloc (newsize, file, line));

#ifndef MAD_QUICK
    mad_check (file, line);
#endif

    for (i = 0; i < mad_allocated_area_counter; i++){
 	if (mem_areas [i].in_use && (mem_areas [i].data == ptr))
	    break;
    }
    if (i >= mad_allocated_area_counter){
	fprintf (stderr, "MAD: Attempted to realloc unallocated pointer: %p.\r\n", ptr);
	fprintf (stderr, "     Discovered in file \"%s\" at line %d.\r\n",
		 file, line);
	fprintf (stderr, "MAD: Aborting...\r\n");
	abort ();
    }
#ifdef MAD_ALIGN
    newsize = (newsize + MAD_ALIGN_BITS) & (~MAD_ALIGN_BITS); /* Alignment */
#endif

#ifdef MAD_PRINTBLOCKS
fprintf(stderr, "MAD: realloc block %6i: start_sig 0x%x  data 0x%x  end_sig 0x%x into\n", i,mem_areas [i].start_sig,mem_areas [i].data,mem_areas [i].end_sig);
#endif

#ifdef MAD_QUICK
    mad_checkthis (i, file, line);
#endif

    area = (char*) realloc (mem_areas [i].start_sig, newsize + 2 * sizeof (double));
/*  area = (char*) malloc (newsize + 2 * sizeof (long));*/
    if (!area){
	fprintf (stderr, "MAD: Out of memory.\r\n");
	fprintf (stderr, "     Discovered in file \"%s\" at line %d.\r\n",
		 file, line);
	fprintf (stderr, "MAD: Aborting...\r\n");
	abort ();
    }

    mem_areas [i].start_sig = (void*) area;
    mem_areas [i].data = (char*)(&area[sizeof (double)]);
    mem_areas [i].end_sig = (void*) (&area[newsize + sizeof (double)]);
    *(mem_areas [i].start_sig) = (double) *MAD_START_SIGNATURE;
    *(mem_areas [i].end_sig) = (double) *MAD_END_SIGNATURE;

#ifdef MAD_PRINTBLOCKS
fprintf(stderr, "             block %6i: start_sig 0x%x  data 0x%x  end_sig 0x%x\n", i,mem_areas [i].start_sig,mem_areas [i].data,mem_areas [i].end_sig);
#endif


    if (strlen (file) >= MAD_MAX_FILE)
	file [MAD_MAX_FILE - 1] = 0;
    strcpy (mem_areas [i].file, file);
    mem_areas [i].line = line;

    return mem_areas [i].data;
}

/* Duplicates a character string. Used instead of strdup. */
char *mad_strdup (const char *s, char *file, int line)
{
    char *t;

#ifdef MAD_PRINTBLOCKS
fprintf(stderr, "MAD:  strdup::\n");
#endif
    t = (char *) mad_alloc (strlen (s) + 1, file, line);
    strcpy (t, s);
    return t;
}

/* Frees a memory area. Used instead of free. */
void mad_free (void *ptr, char *file, int line)
{
    int i;

#ifndef MAD_QUICK
    mad_check (file, line);
#endif

    if (ptr == NULL){
	fprintf (stderr, "MAD: Attempted to free a NULL pointer in file \"%s\" at line %d.\n",
		 file, line);
	return;
    }

    for (i = 0; i < mad_allocated_area_counter; i++){
 	if (mem_areas [i].in_use && (mem_areas [i].data == ptr))
	    break;
    }

    if (i >= mad_allocated_area_counter){
	fprintf (stderr, "MAD: Attempted to free an unallocated pointer: %p.\r\n", ptr);
	fprintf (stderr, "     Discovered in file \"%s\" at line %d.\r\n",
		 file, line);
	fprintf (stderr, "MAD: Aborting...\r\n");
	abort ();
    }
#ifdef MAD_PRINTBLOCKS
fprintf(stderr, "MAD:    free block %6i: start_sig 0x%x  data 0x%x  end_sig 0x%x\n" ,i,mem_areas [i].start_sig,mem_areas [i].data,mem_areas [i].end_sig);
#endif

#ifdef MAD_QUICK
    mad_checkthis (i, file, line);
#endif

    free (mem_areas [i].start_sig);
    mem_areas [i].in_use = 0;
}

/* Outputs a list of unfreed memory areas,
   to be called as a last thing before exiting */
void mad_finalize (char *file, int line)
{
    int i;
    
    mad_check (file, line);

    for (i = 0; i < mad_allocated_area_counter; i++){
 	if (! mem_areas [i].in_use)
	    continue;
	fprintf (stderr, "MAD: Unfreed pointer: %p.\n", mem_areas [i].data);
	fprintf (stderr, "     Allocated in file \"%s\" at line %d.\r\n",
		 mem_areas [i].file, mem_areas [i].line);
	fprintf (stderr, "     Discovered in file \"%s\" at line %d.\r\n",
		 file, line);
    }
}
-------------- next part --------------
#ifdef USE_MAD

#ifndef __MAD_H
# define __MAD_H

/* make sure inline isn't used with MAD */
#ifdef INLINE
# define INLINE 
#endif

/* The Memory Allocation Debugging system */

/* GNU headers define these as macros */
#ifdef malloc
# undef malloc
#endif

#ifdef calloc
# undef calloc
#endif

#ifdef realloc
# undef realloc
#endif

#ifdef xmalloc
# undef xmalloc
#endif

#ifdef strdup
# undef strdup
#endif

#ifdef free
# undef free
#endif

#define malloc(x)	mad_alloc (x, __FILE__, __LINE__)
#define calloc(x, y)	mad_calloc (x, y, __FILE__, __LINE__)
#define realloc(x, y)	mad_realloc (x, y, __FILE__, __LINE__)
#define xmalloc(x, y)	mad_alloc (x, __FILE__, __LINE__)
#define strdup(x)	mad_strdup (x, __FILE__, __LINE__)
#define free(x)		mad_free (x, __FILE__, __LINE__)

void mad_check (char *file, int line);
void *mad_alloc (unsigned int size, char *file, int line);
void *mad_calloc (unsigned int size, unsigned int n, char *file, int line);
void *mad_realloc (void *ptr, unsigned int newsize, char *file, int line);
char *mad_strdup (const char *s, char *file, int line);
void mad_free (void *ptr, char *file, int line);
void mad_finalize (char *file, int line);
#else

#define mad_finalize(x, y)
#define mad_check(file,line)

# endif /* __MAD_H */
#endif /* USE_MAD */


More information about the mc-devel mailing list