Select Git revision
ram-smalloc.c
-
Per Cederqvist authoredPer Cederqvist authored
ram-smalloc.c 8.46 KiB
/*
* $Id: ram-smalloc.c,v 0.30 1999/05/24 09:34:35 ceder Exp $
* Copyright (C) 1991-1996, 1998-1999 Lysator Academic Computer Association.
*
* This file is part of the LysKOM server.
*
* LysKOM 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 1, or (at your option)
* any later version.
*
* LysKOM 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 LysKOM; see the file COPYING. If not, write to
* Lysator, c/o ISY, Linkoping University, S-581 83 Linkoping, SWEDEN,
* or the Free Software Foundation, Inc., 675 Mass Ave, Cambridge,
* MA 02139, USA.
*
* Please mail bug reports to bug-lyskom@lysator.liu.se.
*/
/*
* smalloc.c
*
* Contains memory allocator routines
*
* TEST VERSION by ceder
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
/*
* Finding memory leaks
* ====================
*
* This code contains some stubs that can be useful when hunting for
* memory leaks. To use it, you must configure with
* --with-traced-allocations and recompile. You actually only need to
* recompile ram-smalloc.c, ramkomd.c and the programs in testsuite
* after changing it, so "make -t; rm src/server/ram-smalloc.o \
* src/server/ramkomd.o src/server/testsuite/test-*.o; make" is the
* fastest way to change between tracing and a normal compile.
*
* Run the resulting lyskomd under gdb, like this:
* bash$ gdb lyskomd
* (gdb) source trace-mem.gdb
* (gdb) run
* Where does the trace want to go today? [stderr] RET
* gdb will print a backtrace and continue whenever memory is
* allocated, reallocated or released. The program itself will also
* print out some information. The result is a long log file.
*
* Run M-x resolve-trace (from handle-malloc-dump.el on the resulting
* output. Look in the *Result* buffer for the result.
*
* Using the test suite to find memory leaks
* =========================================
*
* This code can also be used together with the test suite, even
* though that is slightly more complicated. Begin by starting a gdb
* whose output is saved, for example by running it in a shell buffer
* in emacs (note: do not use M-x gdb -- that will slow down the
* process and it is slow enough as it is):
* bash$ gdb lyskomd
* (gdb) source trace-mem.gdb
* (gdb) shell tty
* /dev/ttypd
* Insert the following two statements in the *.exp script before the
* call to lyskomd_start that you want to trace:
* set attach 1
* set MEMTRACE /dev/ttypd
* MEMTRACE should be set to the tty where gdb is running. Start the
* test suite:
* bash$ runtest --tool lyskomd leaks.0/99.exp
* [...]
* Please attach to lyskomd pid 4711 and hit RETURN
* Attach to the process:
* (gdb) attach 4711
* (gdb) continue
* Press enter to resume the test suite. Lots of output should appear
* from gdb.
*
*/
static const char *
rcsid = "$Id: ram-smalloc.c,v 0.30 1999/05/24 09:34:35 ceder Exp $";
#include "rcs.h"
USE(rcsid);
#ifdef HAVE_STDLIB_H
# include <stdlib.h>
#endif
#include <stdio.h>
#include <sys/types.h>
#include <assert.h>
#include <errno.h>
#include "exp.h"
#include "s-string.h"
#include "kom-types.h"
#include "lyskomd.h"
#include "server/smalloc.h"
#ifdef TRACED_ALLOCATIONS
# include "trace-alloc.h"
#endif
static int no_of_allocated_blocks = 0;
#ifdef TRACED_ALLOCATIONS
static FILE *malloc_fp = NULL;
void
trace_alloc_file(const char *loc)
{
if (loc[0] == '\0')
malloc_fp = stderr;
else
malloc_fp = fopen(loc, "w");
if (malloc_fp == NULL)
restart_kom("init_malloc_fp failed: %s, %d\n", loc, errno);
fprintf(malloc_fp, "A new trace from lyskomd starts here\n");
}
static void
trace_smalloc(size_t size,
void *result)
{
assert(malloc_fp != NULL);
fprintf(malloc_fp, "smalloc:\nArg: 0x%lx\nRes: 0x%lx\n",
(long)size, (long)result);
fprintf(malloc_fp, "==== end ====\n");
fflush(malloc_fp);
}
#endif
/*
* "safe" malloc. Handles the case when malloc returns NULL.
* smalloc cannot fail.
*/
EXPORT void *
smalloc(size_t size)
{
unsigned int *p;
p = (unsigned int *) malloc(size + 2*sizeof(unsigned int) + 2);
if (p == NULL)
restart_kom("Can't allocate %lu bytes.\n", (unsigned long)size);
++no_of_allocated_blocks;
*p++ = SMALLOC_MAGIC_ALLOC;
*p++ = size;
((unsigned char *) p)[size] = 0x89;
((unsigned char *) p)[size+1] = 0xA7;
#ifdef TRACED_ALLOCATIONS
trace_smalloc(size, p);
#endif
return (void *) p;
}
#ifdef TRACED_ALLOCATIONS
static void
trace_free(void *block)
{
assert(malloc_fp != NULL);
fprintf(malloc_fp, "sfree:\nArg: 0x%lx\n", (long)block);
fprintf(malloc_fp, "==== end ====\n");
fflush(malloc_fp);
}
#endif
EXPORT void
sfree(void * ptr) /* it is legal to sfree a NULL pointer */
{
unsigned int *ip;
if ( ptr != NULL )
{
#ifdef TRACED_ALLOCATIONS
trace_free(ptr);
#endif
ip = (unsigned int *) ptr;
ip -= 2;
switch (*ip)
{
case SMALLOC_MAGIC_ALLOC:
if (((unsigned char *) (ip+2))[ip[1]] != 0x89 ||
((unsigned char *) (ip+2))[ip[1]+1] != 0xA7)
restart_kom("SFREE: Buffer overflow, bsize = %ul\n", ip[1]);
--no_of_allocated_blocks;
*ip = SMALLOC_MAGIC_FREE;
free( ip );
break;
case SMALLOC_MAGIC_FREE:
restart_kom("SFREE: Trying to free already freed block\n");
default:
restart_kom("SFREE: Illegal magic number\n");
}
}
}
#ifdef TRACED_ALLOCATIONS
static void
trace_srealloc(size_t size,
void *arg,
void *result)
{
assert(malloc_fp != NULL);
fprintf(malloc_fp, "srealloc:\nSize: 0x%lx\nArg: 0x%lx\nRes: 0x%lx\n",
(long)size, (long)arg, (long)result);
fprintf(malloc_fp, "==== end ====\n");
fflush(malloc_fp);
}
#endif
EXPORT void *
srealloc(void * ptr, size_t size) /* Never fails. It is legal to */
{ /* realloc the NULL ptr. */
unsigned int * ip;
unsigned int * new_ptr;
if ( ptr == NULL )
return smalloc(size);
ip = (unsigned int *) ptr;
ip -= 2;
switch (*ip)
{
case SMALLOC_MAGIC_ALLOC:
break;
case SMALLOC_MAGIC_FREE:
restart_kom("SREALLOC: Trying to realloc freed block\n");
default:
restart_kom("SREALLOC: Illegal magic number\n");
}
if (((unsigned char *) (ip+2))[ip[1]] != 0x89 ||
((unsigned char *) (ip+2))[ip[1]+1] != 0xA7)
restart_kom("SREALLOC: Buffer overflow, osize = %ul, nsize = %lu.\n",
ip[1], (unsigned long)size);
*ip = SMALLOC_MAGIC_FREE;
if ( (new_ptr = (unsigned int *) realloc((void *) ip,
size+2*sizeof(unsigned int)+2) ) == NULL )
{
restart_kom("Out of memory - can't realloc. ptr = %lu size = %lu.\n",
(unsigned long)ptr, (unsigned long)size);
}
*new_ptr++ = SMALLOC_MAGIC_ALLOC;
*new_ptr++ = size;
((unsigned char *) new_ptr)[size] = 0x89;
((unsigned char *) new_ptr)[size+1] = 0xA7;
#ifdef TRACED_ALLOCATIONS
trace_srealloc(size, ptr, new_ptr);
#endif
return (void *) new_ptr;
}
/*
* Allocate temporary memory, which is automatically freed after this
* atomic call.
*/
static void **tmp_alloc_table = NULL;
static int tmp_alloc_table_size = 0; /* Size */
static int tmp_alloc_table_use = 0; /* Used size */
EXPORT void *
tmp_alloc(unsigned long size)
{
if ( tmp_alloc_table_size <= tmp_alloc_table_use )
{
/* Need to increas table. */
tmp_alloc_table = srealloc (tmp_alloc_table,
((++tmp_alloc_table_size)
* sizeof (void *)));
}
return (tmp_alloc_table[ tmp_alloc_table_use++ ]
= smalloc (size));
}
/*
* Free all core which is allocated with tmp_alloc(). This is called from
* end_of_atomic().
*/
EXPORT void
free_tmp(void)
{
int i;
for ( i = 0; i < tmp_alloc_table_use; i++ )
{
sfree ( tmp_alloc_table[ i ] );
tmp_alloc_table[ i ] = NULL;
}
tmp_alloc_table_use = 0;
}
EXPORT void
free_all_tmp(void)
{
free_tmp();
sfree( tmp_alloc_table );
tmp_alloc_table = NULL;
tmp_alloc_table_size = 0;
}
EXPORT void
dump_smalloc_counts(FILE *stat_file)
{
fprintf(stat_file, "---ram-smalloc.c:\n%s%d\n",
"\tAllocated blocks (grand total): ",
no_of_allocated_blocks);
}