/*
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
*
* - Neither the name of Oracle nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* This source code is provided to illustrate the usage of a given feature
* or technique and has been deliberately simplified. Additional steps
* required for a production-quality application, such as security checks,
* input validation and proper error handling, might not be present in
* this sample code.
*/
/* **************************************************************************
*
* insert some extra words around each allocation for debugging purposes
* and also attempt to detect invalid uses of the malloc heap through
* various tricks like inserting clobber words at the head and tail of
* the user's area, delayed free() calls, and setting the memory to
* a fixed pattern on allocation and when freed. The allocations also
* can include warrants so that when an area is clobbered, this
* package can report where the allocation took place.
* The macros included are:
* malloc(size)
* realloc(ptr,size)
* calloc(nelem,elsize)
* strdup(s1)
* free(ptr)
* malloc_police() <--- Not a system function
* The above macros match the standard behavior of the system functions.
*
* They should be used through the include file "debug_malloc.h".
*
* IMPORTANT: All source files that call any of these macros
* should include debug_malloc.h. This package will
* not work if the memory isn't allocated and freed
* by the macros in debug_malloc.h. The important issue
* is that any malloc() from debug_malloc.h must be
* freed by the free() in debug_malloc.h.
*
* The macros in debug_malloc.h will override the normal use of
* malloc, realloc, calloc, strdup, and free with the functions below.
*
* These functions include:
* void *debug_malloc(size_t, void*, int);
* void *debug_realloc(void*, size_t, void*, int);
* void *debug_calloc(size_t, size_t, void*, int);
* void debug_free(void *, void*, int);
*
* In addition the function debug_malloc_police() can be called to
* tell you what memory has not been freed.
* void debug_malloc_police(void*, int);
* The function debug_malloc_police() is available through the macro
* malloc_police(). Normally you would want to call this at exit()
* time to find out what memory is still allocated.
*
* The variable malloc_watch determines if the warrants are generated.
* warrants are structures that include the filename and line number
* of the caller who allocated the memory. This structure is stored
* at the tail of the malloc space, which is allocated large enough
* to hold some clobber words at the head and tail, the user's request
* and the warrant record (if malloc_watch is non-zero).
*
* The macro LEFT_OVER_CHAR is what the trailing bytes of an allocation
* are set to (when the allocation is not a multiple of 8) on allocation.
* At free(0 time, these bytes are double checked to make sure they were
* not clobbered. To remove this feature #undef LEFT_OVER_CHAR.
*
* The memory freed will have the FREED_CHAR put into it. To remove this
* feature #undef FREED_CHAR.
*
* The memory allocated (not calloc'd) will have the ALLOC_CHAR put into it
* at the time of allocation. To remove this feature #undef ALLOC_CHAR.
*
* The macro MAX_FREE_DELAY_COUNT controls how many free blocks will
* be kept around before being freed. This creates a delayed affect
* so that free space that gets clobbered just might get detected.
* The free() call will immediately set the user space to the FREED_CHAR,
* leaving the clobber words and warrant in place (making sure they
* haven't been clobbered). Then the free() pointer is added to a
* queue of MAX_FREE_DELAY_COUNT long, and if the queue was full, the
* oldest free()'d memory is actually freed, getting it's entire
* memory length set to the FREED_CHAR.
*
* WARNING: This can significantly slow down an application, depending
* on how many allocations are made. Also the additional memory
* needed for the clobber words and the warrants can be significant
* again, depending on how many allocations are made.
* In addition, the delayed free calls can create situations
* where you might run out of memory prematurely.
*
* **************************************************************************
*/
#ifdef DEBUG
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdarg.h>
#include "hprof.h"
/* ***************************************************************************
* Space normally looks like (clobber Word is 64 bits and aligned to 8 bytes):
*
* -----------------
* -----------------
* User gets --->| user space |
* | |
* | | left_over | ---> left_over bytes will be <= 7
* -----------------
* | clobber Word | ---> contains -size requested by user
* -----------------
* | Warrant | ---> Optional (malloc_watch!=0)
* | | Contains filename and line number
* | | where allocation happened
* | |
* -----------------
***************************************************************************/
/*
* Flag that tells debug_malloc/debug_free/debug_realloc to police
*/
/* Character to stuff into freed space */
/* Character to stuff into allocated space */
/* Character to stuff into left over trailing bytes */
/* Number of 'free' calls that will be delayed until the end */
/* Maximum name of __FILE_ stored in each malloc'd area */
/* Macro to convert a user pointer to the malloc pointer */
/* Macro to convert a macro pointer to the user pointer */
/* Size of the warrant record (this is dynamic) */
/* Macro to round up a number of bytes to a multiple of sizeof(Word) bytes */
#define round_up_(n) \
/* Macro to calculate the needed malloc bytes from the user's request. */
/* Macro to get the -size stored in space through the malloc pointer */
/* Macro to get the -size stored in the tail of the space through */
/* the malloc pointer */
/* Macro to get the -size stored in space through the user pointer */
/* Macro to get the -size stored in the tail of the space through */
/* the user pointer */
/* Macro to get the int* of the last 32bit word of user space */
/* Macros to get at the warrant contents from the malloc pointer */
/* This struct is allocated after the tail clobber word if malloc_watch */
/* is true. */
typedef struct {
/* This should be one machine word and is also the clobber word struct */
typedef struct {
int nsize1;
int nsize2;
/* The first malloc pointer for the warrants */
/* Counter of allocations */
static int id_counter = 0;
static int largest_size = 0;
/* Used to isolate what the error is */
static char *debug_check;
static void *clobbered_ptr;
/* Minumum macro */
#define minimum(a,b) ((a)<(b)?(a):(b))
/* Message routine */
static void
{
}
/* This function prints out a memory error for the memory function
* 'name' which was called in file 'file' at line number 'line'. The malloc
* pointer with the error is in 'mptr'.
*/
static void
memory_error(void *mptr, const char *name, int mid, const char *mfile, int mline, const char *file, int line)
{
int len;
void *mptr_walk;
name = "UNKNOWN_NAME";
file = "UNKNOWN_FILE";
if ( debug_check!=NULL ) {
"%s The %s at %p appears to have been hit.",
}
error_message("Error: "
"%s The malloc space #%d is at %p [user size=%d(0x%x)],"
" and was allocated from file \"%s\" at line %d."
" [The debug function %s() detected this error "
"in file \"%s\" at line %d.]",
/* Print out contents of this allocation */
{
int i;
char *pmess;
for(i=0;i<(int)sizeof(temp);i++) {
} else {
*pmess++ = '\\';
*pmess++ = 'x';
pmess+=2;
}
}
*pmess = 0;
}
/* Try and print out table */
if (!malloc_watch) {
return;
}
error_message("Active allocations: "
"count=%d, largest_size=%d, address range (%p,%p)",
do {
int size1;
int size2;
char *mfile_walk;
error_message("Terminating list due to pointer corruption");
break;
}
error_message("#%d: addr=%p size1=%d size2=%d file=\"%.*s\" line=%d",
error_message("Terminating list due to size corruption");
break;
}
}
abort();
}
/* This function sets the clobber word and sets up the warrant for the input
* malloc pointer "mptr".
*/
static void
{
register int nbytes;
/*LINTED*/
/*LINTED*/
/*LINTED*/
/* Must be done first: */
#ifdef LEFT_OVER_CHAR
/* Fill in those few extra bytes just before the tail Word structure */
{
register int trailing_extra_bytes;
/* LINTED */
if ( trailing_extra_bytes > 0 ) {
register char *p;
register int i;
for (i = 0; i < trailing_extra_bytes; i++)
p[i] = LEFT_OVER_CHAR;
}
}
#endif
/* Fill out warrant */
if (malloc_watch) {
register void *p1,
*p2;
int start_pos = 0;
if ( len > WARRANT_NAME_MAX ) {
/*LINTED*/
}
/*LINTED*/
}
}
/* This function checks the clobber words at the beginning and end of the
* allocated space.
*/
static void
{
int neg_nbytes;
int nbytes;
debug_check = "pointer value itself";
/* Check both Word structures */
debug_check = "first beginning clobber word";
if (neg_nbytes >= 0)
debug_check = "second beginning clobber word";
debug_check = "first ending clobber word";
debug_check = "second ending clobber word";
/* Get a positive count of bytes */
nbytes = -neg_nbytes;
#ifdef LEFT_OVER_CHAR
{
/* Check those few extra bytes just before the tail Word structure */
register int trailing_extra_bytes;
register int i;
register char *p;
/* LINTED */
debug_check = "trailing left over area";
for (i = 0; i < trailing_extra_bytes; i++) {
clobbered_ptr = p+1;
if (p[i] != LEFT_OVER_CHAR) {
}
}
}
#endif
/* Make sure debug_check is cleared */
debug_check = NULL;
}
/* This function looks for the given malloc pointer in the police line up
* and removes it from the warrant list.
* mptr The pointer to the malloc space being removed
*/
static int
{
void *mptr1,
/* Free it up from the list */
int found;
found = 0;
last_mptr1 = NULL;
if (last_mptr1 == NULL)
else
found = 1;
break;
}
last_mptr1 = mptr1;
}
return found;
}
return 1;
}
static void
{
void *mptr;
const char *mfile;
int mline;
int mid;
return;
#ifdef FREED_CHAR
/* LINTED */
}
#endif
}
#ifdef MAX_FREE_DELAY_COUNT
static int free_delay_pos = 0;
static void
{
void *mptr;
return;
}
#ifdef FREED_CHAR
#endif
}
static void
{
int i;
for ( i=0; i< MAX_FREE_DELAY_COUNT; i++) {
free_delay[i] = NULL;
}
}
}
#endif
void
{
int mid = 0;
#ifdef MAX_FREE_DELAY_COUNT
#else
#endif
}
/* This function calls malloc(). */
void *
{
void *mptr;
void *uptr;
/*LINTED*/
if ((int)nbytes <= 0)
/* LINTED */
#ifdef ALLOC_CHAR
#endif
return uptr;
}
void *
{
void *mptr;
void *oldmptr;
void *newuptr;
oldnbytes = 0;
if ((int)nbytes <= 0)
}
/* LINTED */
} else {
/* LINTED */
}
#ifdef ALLOC_CHAR
#endif
return newuptr;
}
/* This function calls calloc(). */
void *
{
void *mptr;
/*LINTED*/
if ((int)nbytes <= 0)
/* LINTED */
return malloc2user_(mptr);
}
/* This function replaces strdup(). */
char *
{
void *mptr;
void *uptr;
/*LINTED*/
if ((int)nbytes < 0)
/* LINTED */
return (char*)uptr;
}
void
{
void *mptr;
#ifdef MAX_FREE_DELAY_COUNT
#endif
if (!malloc_watch) {
return;
}
/* Check all this memory first */
do {
}
}
/* Report outstanding space warrants to console. */
void
{
void *mptr;
#ifdef MAX_FREE_DELAY_COUNT
#endif
if (!malloc_watch) {
return;
}
/* Now issue warrants */
do {
error_message("Outstanding space warrant: %p (%d bytes) allocated by %s at line %d, allocation #%d",
}
}
#else
void
{
}
void
{
}
#endif