|
Packit |
3f21c4 |
/* Copyright (C) 2001-2012 Artifex Software, Inc.
|
|
Packit |
3f21c4 |
All Rights Reserved.
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
This software is provided AS-IS with no warranty, either express or
|
|
Packit |
3f21c4 |
implied.
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
This software is distributed under license and may not be copied,
|
|
Packit |
3f21c4 |
modified or distributed except as expressly authorized under the terms
|
|
Packit |
3f21c4 |
of the license contained in the file LICENSE in this distribution.
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
Refer to licensing information at http://www.artifex.com or contact
|
|
Packit |
3f21c4 |
Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134, San Rafael,
|
|
Packit |
3f21c4 |
CA 94903, U.S.A., +1(415)492-9861, for further information.
|
|
Packit |
3f21c4 |
*/
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
/* Inspired by Fortify by Simon P Bullen. */
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
/* Set the following if you're only looking for leaks, not memory overwrites
|
|
Packit |
3f21c4 |
* to speed the operation */
|
|
Packit |
3f21c4 |
/* #define MEMENTO_LEAKONLY */
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
#ifndef MEMENTO_STACKTRACE_METHOD
|
|
Packit |
3f21c4 |
#ifdef __GNUC__
|
|
Packit |
3f21c4 |
#define MEMENTO_STACKTRACE_METHOD 1
|
|
Packit |
3f21c4 |
#endif
|
|
Packit |
3f21c4 |
#endif
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
/* Don't keep blocks around if they'd mean losing more than a quarter of
|
|
Packit |
3f21c4 |
* the freelist. */
|
|
Packit |
3f21c4 |
#define MEMENTO_FREELIST_MAX_SINGLE_BLOCK (MEMENTO_FREELIST_MAX/4)
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
#define COMPILING_MEMENTO_C
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
#ifdef MEMENTO_GS_HACKS
|
|
Packit |
3f21c4 |
/* For GS we include malloc_.h. Anyone else would just include memento.h */
|
|
Packit |
3f21c4 |
#include "malloc_.h"
|
|
Packit |
3f21c4 |
#ifdef __MACH__
|
|
Packit |
3f21c4 |
#include <string.h>
|
|
Packit |
3f21c4 |
#else
|
|
Packit |
3f21c4 |
#ifndef memset
|
|
Packit |
3f21c4 |
void *memset(void *, int, size_t);
|
|
Packit |
3f21c4 |
#endif
|
|
Packit |
3f21c4 |
#endif
|
|
Packit |
3f21c4 |
int atexit(void (*)(void));
|
|
Packit |
3f21c4 |
#else
|
|
Packit |
3f21c4 |
#include "memento.h"
|
|
Packit |
3f21c4 |
#include <stdio.h>
|
|
Packit |
3f21c4 |
#include <stdlib.h>
|
|
Packit |
3f21c4 |
#endif
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
#if defined(__linux__)
|
|
Packit |
3f21c4 |
#define MEMENTO_HAS_FORK
|
|
Packit |
3f21c4 |
#elif defined(__APPLE__) && defined(__MACH__)
|
|
Packit |
3f21c4 |
#define MEMENTO_HAS_FORK
|
|
Packit |
3f21c4 |
#endif
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
/* Define the underlying allocators, just in case */
|
|
Packit |
3f21c4 |
void *MEMENTO_UNDERLYING_MALLOC(size_t);
|
|
Packit |
3f21c4 |
void MEMENTO_UNDERLYING_FREE(void *);
|
|
Packit |
3f21c4 |
void *MEMENTO_UNDERLYING_REALLOC(void *, size_t);
|
|
Packit |
3f21c4 |
void *MEMENTO_UNDERLYING_CALLOC(size_t, size_t);
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
/* And some other standard functions we use. We don't include the header
|
|
Packit |
3f21c4 |
* files, just in case they pull in unexpected others. */
|
|
Packit |
3f21c4 |
int atoi(const char *);
|
|
Packit |
3f21c4 |
char *getenv(const char *);
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
/* How far to search for pointers in each block when calculating nestings */
|
|
Packit |
3f21c4 |
/* mupdf needs at least 34000ish (sizeof(fz_shade))/ */
|
|
Packit |
3f21c4 |
#define MEMENTO_PTRSEARCH 65536
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
#ifndef MEMENTO_MAXPATTERN
|
|
Packit |
3f21c4 |
#define MEMENTO_MAXPATTERN 0
|
|
Packit |
3f21c4 |
#endif
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
#ifdef MEMENTO
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
#ifdef MEMENTO_GS_HACKS
|
|
Packit |
3f21c4 |
#include "valgrind.h"
|
|
Packit |
3f21c4 |
#else
|
|
Packit |
3f21c4 |
#ifdef HAVE_VALGRIND
|
|
Packit |
3f21c4 |
#include "valgrind/memcheck.h"
|
|
Packit |
3f21c4 |
#else
|
|
Packit |
3f21c4 |
#define VALGRIND_MAKE_MEM_NOACCESS(p,s) do { } while (0==1)
|
|
Packit |
3f21c4 |
#define VALGRIND_MAKE_MEM_UNDEFINED(p,s) do { } while (0==1)
|
|
Packit |
3f21c4 |
#define VALGRIND_MAKE_MEM_DEFINED(p,s) do { } while (0==1)
|
|
Packit |
3f21c4 |
#endif
|
|
Packit |
3f21c4 |
#endif
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
enum {
|
|
Packit |
3f21c4 |
Memento_PreSize = 16,
|
|
Packit |
3f21c4 |
Memento_PostSize = 16
|
|
Packit |
3f21c4 |
};
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
enum {
|
|
Packit |
3f21c4 |
Memento_Flag_OldBlock = 1,
|
|
Packit |
3f21c4 |
Memento_Flag_HasParent = 2,
|
|
Packit |
3f21c4 |
Memento_Flag_BreakOnFree = 4,
|
|
Packit |
3f21c4 |
Memento_Flag_BreakOnRealloc = 8
|
|
Packit |
3f21c4 |
};
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
/* When we list leaked blocks at the end of execution, we search for pointers
|
|
Packit |
3f21c4 |
* between blocks in order to be able to give a nice nested view.
|
|
Packit |
3f21c4 |
* Unfortunately, if you have are running your own allocator (such as
|
|
Packit |
3f21c4 |
* ghostscripts chunk allocator) you can often find that the header of the
|
|
Packit |
3f21c4 |
* block always contains pointers to next or previous blocks. This tends to
|
|
Packit |
3f21c4 |
* mean the nesting displayed is "uninteresting" at best :)
|
|
Packit |
3f21c4 |
*
|
|
Packit |
3f21c4 |
* As a hack to get around this, we have a define MEMENTO_SKIP_SEARCH that
|
|
Packit |
3f21c4 |
* indicates how many bytes to skip over at the start of the chunk.
|
|
Packit |
3f21c4 |
* This may cause us to miss true nestings, but such is life...
|
|
Packit |
3f21c4 |
*/
|
|
Packit |
3f21c4 |
#ifndef MEMENTO_SEARCH_SKIP
|
|
Packit |
3f21c4 |
#ifdef MEMENTO_GS_HACKS
|
|
Packit |
3f21c4 |
#define MEMENTO_SEARCH_SKIP (2*sizeof(void *))
|
|
Packit |
3f21c4 |
#else
|
|
Packit |
3f21c4 |
#define MEMENTO_SEARCH_SKIP 0
|
|
Packit |
3f21c4 |
#endif
|
|
Packit |
3f21c4 |
#endif
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
typedef struct Memento_BlkHeader Memento_BlkHeader;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
struct Memento_BlkHeader {
|
|
Packit |
3f21c4 |
size_t rawsize;
|
|
Packit |
3f21c4 |
int sequence;
|
|
Packit |
3f21c4 |
int lastCheckedOK;
|
|
Packit |
3f21c4 |
int flags;
|
|
Packit |
3f21c4 |
Memento_BlkHeader *next;
|
|
Packit |
3f21c4 |
Memento_BlkHeader *parent; /* Only used while printing out nested list */
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
const char *label;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
/* Entries for nesting display calculations */
|
|
Packit |
3f21c4 |
Memento_BlkHeader *child;
|
|
Packit |
3f21c4 |
Memento_BlkHeader *sibling;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
char preblk[Memento_PreSize];
|
|
Packit |
3f21c4 |
};
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
/* In future this could (should) be a smarter data structure, like, say,
|
|
Packit |
3f21c4 |
* splay trees. For now, we use a list.
|
|
Packit |
3f21c4 |
*/
|
|
Packit |
3f21c4 |
typedef struct Memento_Blocks {
|
|
Packit |
3f21c4 |
Memento_BlkHeader *head;
|
|
Packit |
3f21c4 |
Memento_BlkHeader **tail;
|
|
Packit |
3f21c4 |
} Memento_Blocks;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
/* And our global structure */
|
|
Packit |
3f21c4 |
static struct {
|
|
Packit |
3f21c4 |
int inited;
|
|
Packit |
3f21c4 |
Memento_Blocks used;
|
|
Packit |
3f21c4 |
Memento_Blocks free;
|
|
Packit |
3f21c4 |
size_t freeListSize;
|
|
Packit |
3f21c4 |
int sequence;
|
|
Packit |
3f21c4 |
int paranoia;
|
|
Packit |
3f21c4 |
int paranoidAt;
|
|
Packit |
3f21c4 |
int countdown;
|
|
Packit |
3f21c4 |
int lastChecked;
|
|
Packit |
3f21c4 |
int breakAt;
|
|
Packit |
3f21c4 |
int failAt;
|
|
Packit |
3f21c4 |
int failing;
|
|
Packit |
3f21c4 |
int nextFailAt;
|
|
Packit |
3f21c4 |
int squeezeAt;
|
|
Packit |
3f21c4 |
int squeezing;
|
|
Packit |
3f21c4 |
int segv;
|
|
Packit |
3f21c4 |
int pattern;
|
|
Packit |
3f21c4 |
int nextPattern;
|
|
Packit |
3f21c4 |
int patternBit;
|
|
Packit |
3f21c4 |
size_t maxMemory;
|
|
Packit |
3f21c4 |
size_t alloc;
|
|
Packit |
3f21c4 |
size_t peakAlloc;
|
|
Packit |
3f21c4 |
size_t totalAlloc;
|
|
Packit |
3f21c4 |
size_t numMallocs;
|
|
Packit |
3f21c4 |
size_t numFrees;
|
|
Packit |
3f21c4 |
size_t numReallocs;
|
|
Packit |
3f21c4 |
} globals;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
#define MEMENTO_EXTRASIZE (sizeof(Memento_BlkHeader) + Memento_PostSize)
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
/* Round up size S to the next multiple of N (where N is a power of 2) */
|
|
Packit |
3f21c4 |
#define MEMENTO_ROUNDUP(S,N) ((S + N-1)&~(N-1))
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
#define MEMBLK_SIZE(s) MEMENTO_ROUNDUP(s + MEMENTO_EXTRASIZE, MEMENTO_MAXALIGN)
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
#define MEMBLK_FROMBLK(B) (&((Memento_BlkHeader*)(void *)(B))[-1])
|
|
Packit |
3f21c4 |
#define MEMBLK_TOBLK(B) ((void*)(&((Memento_BlkHeader*)(void*)(B))[1]))
|
|
Packit |
3f21c4 |
#define MEMBLK_POSTPTR(B) \
|
|
Packit |
3f21c4 |
(&((char *)(void *)(B))[(B)->rawsize + sizeof(Memento_BlkHeader)])
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
void
|
|
Packit |
3f21c4 |
Memento_breakpoint(void)
|
|
Packit |
3f21c4 |
{
|
|
Packit |
3f21c4 |
/* A handy externally visible function for breakpointing */
|
|
Packit |
3f21c4 |
#if 0 /* Enable this to force automatic breakpointing */
|
|
Packit |
3f21c4 |
#ifdef DEBUG
|
|
Packit |
3f21c4 |
#ifdef _MSC_VER
|
|
Packit |
3f21c4 |
__asm int 3;
|
|
Packit |
3f21c4 |
#endif
|
|
Packit |
3f21c4 |
#endif
|
|
Packit |
3f21c4 |
#endif
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
static void
|
|
Packit |
3f21c4 |
Memento_addBlockHead(Memento_Blocks *blks, Memento_BlkHeader *b, int type)
|
|
Packit |
3f21c4 |
{
|
|
Packit |
3f21c4 |
if (blks->tail == &blks->head) {
|
|
Packit |
3f21c4 |
/* Adding into an empty list, means the tail changes too */
|
|
Packit |
3f21c4 |
blks->tail = &b->next;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
b->next = blks->head;
|
|
Packit |
3f21c4 |
blks->head = b;
|
|
Packit |
3f21c4 |
#ifndef MEMENTO_LEAKONLY
|
|
Packit |
3f21c4 |
memset(b->preblk, MEMENTO_PREFILL, Memento_PreSize);
|
|
Packit |
3f21c4 |
memset(MEMBLK_POSTPTR(b), MEMENTO_POSTFILL, Memento_PostSize);
|
|
Packit |
3f21c4 |
#endif
|
|
Packit |
3f21c4 |
VALGRIND_MAKE_MEM_NOACCESS(MEMBLK_POSTPTR(b), Memento_PostSize);
|
|
Packit |
3f21c4 |
if (type == 0) { /* malloc */
|
|
Packit |
3f21c4 |
VALGRIND_MAKE_MEM_UNDEFINED(MEMBLK_TOBLK(b), b->rawsize);
|
|
Packit |
3f21c4 |
} else if (type == 1) { /* free */
|
|
Packit |
3f21c4 |
VALGRIND_MAKE_MEM_NOACCESS(MEMBLK_TOBLK(b), b->rawsize);
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
VALGRIND_MAKE_MEM_NOACCESS(b, sizeof(Memento_BlkHeader));
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
static void
|
|
Packit |
3f21c4 |
Memento_addBlockTail(Memento_Blocks *blks, Memento_BlkHeader *b, int type)
|
|
Packit |
3f21c4 |
{
|
|
Packit |
3f21c4 |
VALGRIND_MAKE_MEM_DEFINED(blks->tail, sizeof(Memento_BlkHeader *));
|
|
Packit |
3f21c4 |
*blks->tail = b;
|
|
Packit |
3f21c4 |
blks->tail = &b->next;
|
|
Packit |
3f21c4 |
b->next = NULL;
|
|
Packit |
3f21c4 |
VALGRIND_MAKE_MEM_NOACCESS(blks->tail, sizeof(Memento_BlkHeader *));
|
|
Packit |
3f21c4 |
#ifndef MEMENTO_LEAKONLY
|
|
Packit |
3f21c4 |
memset(b->preblk, MEMENTO_PREFILL, Memento_PreSize);
|
|
Packit |
3f21c4 |
memset(MEMBLK_POSTPTR(b), MEMENTO_POSTFILL, Memento_PostSize);
|
|
Packit |
3f21c4 |
#endif
|
|
Packit |
3f21c4 |
VALGRIND_MAKE_MEM_NOACCESS(MEMBLK_POSTPTR(b), Memento_PostSize);
|
|
Packit |
3f21c4 |
if (type == 0) { /* malloc */
|
|
Packit |
3f21c4 |
VALGRIND_MAKE_MEM_UNDEFINED(MEMBLK_TOBLK(b), b->rawsize);
|
|
Packit |
3f21c4 |
} else if (type == 1) { /* free */
|
|
Packit |
3f21c4 |
VALGRIND_MAKE_MEM_NOACCESS(MEMBLK_TOBLK(b), b->rawsize);
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
VALGRIND_MAKE_MEM_NOACCESS(b, sizeof(Memento_BlkHeader));
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
typedef struct BlkCheckData {
|
|
Packit |
3f21c4 |
int found;
|
|
Packit |
3f21c4 |
int preCorrupt;
|
|
Packit |
3f21c4 |
int postCorrupt;
|
|
Packit |
3f21c4 |
int freeCorrupt;
|
|
Packit |
3f21c4 |
int index;
|
|
Packit |
3f21c4 |
} BlkCheckData;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
static int
|
|
Packit |
3f21c4 |
Memento_Internal_checkAllocedBlock(Memento_BlkHeader *b, void *arg)
|
|
Packit |
3f21c4 |
{
|
|
Packit |
3f21c4 |
#ifndef MEMENTO_LEAKONLY
|
|
Packit |
3f21c4 |
int i;
|
|
Packit |
3f21c4 |
char *p;
|
|
Packit |
3f21c4 |
int corrupt = 0;
|
|
Packit |
3f21c4 |
BlkCheckData *data = (BlkCheckData *) arg;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
p = b->preblk;
|
|
Packit |
3f21c4 |
i = Memento_PreSize;
|
|
Packit |
3f21c4 |
do {
|
|
Packit |
3f21c4 |
corrupt |= (*p++ ^ (char)MEMENTO_PREFILL);
|
|
Packit |
3f21c4 |
} while (--i);
|
|
Packit |
3f21c4 |
if (corrupt) {
|
|
Packit |
3f21c4 |
data->preCorrupt = 1;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
p = MEMBLK_POSTPTR(b);
|
|
Packit |
3f21c4 |
i = Memento_PreSize;
|
|
Packit |
3f21c4 |
do {
|
|
Packit |
3f21c4 |
corrupt |= (*p++ ^ (char)MEMENTO_POSTFILL);
|
|
Packit |
3f21c4 |
} while (--i);
|
|
Packit |
3f21c4 |
if (corrupt) {
|
|
Packit |
3f21c4 |
data->postCorrupt = 1;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
if ((data->freeCorrupt | data->preCorrupt | data->postCorrupt) == 0) {
|
|
Packit |
3f21c4 |
b->lastCheckedOK = globals.sequence;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
data->found |= 1;
|
|
Packit |
3f21c4 |
#endif
|
|
Packit |
3f21c4 |
return 0;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
static int
|
|
Packit |
3f21c4 |
Memento_Internal_checkFreedBlock(Memento_BlkHeader *b, void *arg)
|
|
Packit |
3f21c4 |
{
|
|
Packit |
3f21c4 |
#ifndef MEMENTO_LEAKONLY
|
|
Packit |
3f21c4 |
int i;
|
|
Packit |
3f21c4 |
char *p;
|
|
Packit |
3f21c4 |
BlkCheckData *data = (BlkCheckData *) arg;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
p = MEMBLK_TOBLK(b);
|
|
Packit |
3f21c4 |
i = b->rawsize;
|
|
Packit |
3f21c4 |
/* Attempt to speed this up by checking an (aligned) int at a time */
|
|
Packit |
3f21c4 |
do {
|
|
Packit |
3f21c4 |
if (((size_t) p) & 1) {
|
|
Packit |
3f21c4 |
if (*p++ != (char)MEMENTO_FREEFILL)
|
|
Packit |
3f21c4 |
break;
|
|
Packit |
3f21c4 |
i--;
|
|
Packit |
3f21c4 |
if (i == 0)
|
|
Packit |
3f21c4 |
break;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
if ((i >= 2) && (((size_t) p) & 2)) {
|
|
Packit |
3f21c4 |
if (*(short *)p != (short)(MEMENTO_FREEFILL | (MEMENTO_FREEFILL << 8)))
|
|
Packit |
3f21c4 |
goto mismatch;
|
|
Packit |
3f21c4 |
p += 2;
|
|
Packit |
3f21c4 |
i -= 2;
|
|
Packit |
3f21c4 |
if (i == 0)
|
|
Packit |
3f21c4 |
break;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
i -= 4;
|
|
Packit |
3f21c4 |
while (i >= 0) {
|
|
Packit |
3f21c4 |
if (*(int *)p != (MEMENTO_FREEFILL | (MEMENTO_FREEFILL << 8) | (MEMENTO_FREEFILL << 16) | (MEMENTO_FREEFILL << 24)))
|
|
Packit |
3f21c4 |
goto mismatch;
|
|
Packit |
3f21c4 |
p += 4;
|
|
Packit |
3f21c4 |
i -= 4;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
i += 4;
|
|
Packit |
3f21c4 |
if ((i >= 2) && (((size_t) p) & 2)) {
|
|
Packit |
3f21c4 |
if (*(short *)p != (short)(MEMENTO_FREEFILL | (MEMENTO_FREEFILL << 8)))
|
|
Packit |
3f21c4 |
goto mismatch;
|
|
Packit |
3f21c4 |
p += 2;
|
|
Packit |
3f21c4 |
i -= 2;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
mismatch:
|
|
Packit |
3f21c4 |
while (i) {
|
|
Packit |
3f21c4 |
if (*p++ != (char)MEMENTO_FREEFILL)
|
|
Packit |
3f21c4 |
break;
|
|
Packit |
3f21c4 |
i--;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
} while (0);
|
|
Packit |
3f21c4 |
if (i) {
|
|
Packit |
3f21c4 |
data->freeCorrupt = 1;
|
|
Packit |
3f21c4 |
data->index = b->rawsize - i;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
return Memento_Internal_checkAllocedBlock(b, arg);
|
|
Packit |
3f21c4 |
#else
|
|
Packit |
3f21c4 |
return 0;
|
|
Packit |
3f21c4 |
#endif
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
static void
|
|
Packit |
3f21c4 |
Memento_removeBlock(Memento_Blocks *blks, Memento_BlkHeader *b)
|
|
Packit |
3f21c4 |
{
|
|
Packit |
3f21c4 |
Memento_BlkHeader *head = blks->head;
|
|
Packit |
3f21c4 |
Memento_BlkHeader *prev = NULL;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
while ((head) && (head != b)) {
|
|
Packit |
3f21c4 |
VALGRIND_MAKE_MEM_DEFINED(head, sizeof(*head));
|
|
Packit |
3f21c4 |
prev = head;
|
|
Packit |
3f21c4 |
head = head->next;
|
|
Packit |
3f21c4 |
VALGRIND_MAKE_MEM_NOACCESS(prev, sizeof(*prev));
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
if (head == NULL) {
|
|
Packit |
3f21c4 |
/* FAIL! Will have been reported to user earlier, so just exit. */
|
|
Packit |
3f21c4 |
return;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
VALGRIND_MAKE_MEM_DEFINED(blks->tail, sizeof(*blks->tail));
|
|
Packit |
3f21c4 |
if (*blks->tail == head) {
|
|
Packit |
3f21c4 |
/* Removing the tail of the list */
|
|
Packit |
3f21c4 |
if (prev == NULL) {
|
|
Packit |
3f21c4 |
/* Which is also the head */
|
|
Packit |
3f21c4 |
blks->tail = &blks->head;
|
|
Packit |
3f21c4 |
} else {
|
|
Packit |
3f21c4 |
/* Which isn't the head */
|
|
Packit |
3f21c4 |
blks->tail = &prev->next;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
if (prev == NULL) {
|
|
Packit |
3f21c4 |
/* Removing from the head of the list */
|
|
Packit |
3f21c4 |
VALGRIND_MAKE_MEM_DEFINED(head, sizeof(*head));
|
|
Packit |
3f21c4 |
blks->head = head->next;
|
|
Packit |
3f21c4 |
VALGRIND_MAKE_MEM_NOACCESS(head, sizeof(*head));
|
|
Packit |
3f21c4 |
} else {
|
|
Packit |
3f21c4 |
/* Removing from not-the-head */
|
|
Packit |
3f21c4 |
VALGRIND_MAKE_MEM_DEFINED(head, sizeof(*head));
|
|
Packit |
3f21c4 |
VALGRIND_MAKE_MEM_DEFINED(prev, sizeof(*prev));
|
|
Packit |
3f21c4 |
prev->next = head->next;
|
|
Packit |
3f21c4 |
VALGRIND_MAKE_MEM_NOACCESS(head, sizeof(*head));
|
|
Packit |
3f21c4 |
VALGRIND_MAKE_MEM_NOACCESS(prev, sizeof(*prev));
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
static int
|
|
Packit |
3f21c4 |
Memento_Internal_makeSpace(size_t space)
|
|
Packit |
3f21c4 |
{
|
|
Packit |
3f21c4 |
/* If too big, it can never go on the freelist */
|
|
Packit |
3f21c4 |
if (space > MEMENTO_FREELIST_MAX_SINGLE_BLOCK)
|
|
Packit |
3f21c4 |
return 0;
|
|
Packit |
3f21c4 |
/* Pretend we added it on. */
|
|
Packit |
3f21c4 |
globals.freeListSize += space;
|
|
Packit |
3f21c4 |
/* Ditch blocks until it fits within our limit */
|
|
Packit |
3f21c4 |
while (globals.freeListSize > MEMENTO_FREELIST_MAX) {
|
|
Packit |
3f21c4 |
Memento_BlkHeader *head = globals.free.head;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
VALGRIND_MAKE_MEM_DEFINED(head, sizeof(*head));
|
|
Packit |
3f21c4 |
globals.free.head = head->next;
|
|
Packit |
3f21c4 |
globals.freeListSize -= MEMBLK_SIZE(head->rawsize);
|
|
Packit |
3f21c4 |
MEMENTO_UNDERLYING_FREE(head);
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
/* Make sure we haven't just completely emptied the free list */
|
|
Packit |
3f21c4 |
/* (This should never happen, but belt and braces... */
|
|
Packit |
3f21c4 |
if (globals.free.head == NULL)
|
|
Packit |
3f21c4 |
globals.free.tail = &globals.free.head;
|
|
Packit |
3f21c4 |
return 1;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
static int
|
|
Packit |
3f21c4 |
Memento_appBlocks(Memento_Blocks *blks, int (*app)(Memento_BlkHeader *, void *), void *arg)
|
|
Packit |
3f21c4 |
{
|
|
Packit |
3f21c4 |
Memento_BlkHeader *head = blks->head;
|
|
Packit |
3f21c4 |
Memento_BlkHeader *next;
|
|
Packit |
3f21c4 |
int result;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
while (head) {
|
|
Packit |
3f21c4 |
VALGRIND_MAKE_MEM_DEFINED(head, sizeof(Memento_BlkHeader));
|
|
Packit |
3f21c4 |
VALGRIND_MAKE_MEM_DEFINED(MEMBLK_TOBLK(head), head->rawsize + Memento_PostSize);
|
|
Packit |
3f21c4 |
result = app(head, arg);
|
|
Packit |
3f21c4 |
next = head->next;
|
|
Packit |
3f21c4 |
VALGRIND_MAKE_MEM_NOACCESS(MEMBLK_POSTPTR(head), Memento_PostSize);
|
|
Packit |
3f21c4 |
VALGRIND_MAKE_MEM_NOACCESS(head, sizeof(Memento_BlkHeader));
|
|
Packit |
3f21c4 |
if (result)
|
|
Packit |
3f21c4 |
return result;
|
|
Packit |
3f21c4 |
head = next;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
return 0;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
static int
|
|
Packit |
3f21c4 |
Memento_appBlock(Memento_Blocks *blks, int (*app)(Memento_BlkHeader *, void *), void *arg, Memento_BlkHeader *b)
|
|
Packit |
3f21c4 |
{
|
|
Packit |
3f21c4 |
Memento_BlkHeader *head = blks->head;
|
|
Packit |
3f21c4 |
Memento_BlkHeader *next;
|
|
Packit |
3f21c4 |
int result;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
while (head && head != b) {
|
|
Packit |
3f21c4 |
VALGRIND_MAKE_MEM_DEFINED(head, sizeof(Memento_BlkHeader));
|
|
Packit |
3f21c4 |
next = head->next;
|
|
Packit |
3f21c4 |
VALGRIND_MAKE_MEM_NOACCESS(MEMBLK_POSTPTR(head), Memento_PostSize);
|
|
Packit |
3f21c4 |
head = next;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
if (head == b) {
|
|
Packit |
3f21c4 |
VALGRIND_MAKE_MEM_DEFINED(head, sizeof(Memento_BlkHeader));
|
|
Packit |
3f21c4 |
VALGRIND_MAKE_MEM_DEFINED(MEMBLK_TOBLK(head), head->rawsize + Memento_PostSize);
|
|
Packit |
3f21c4 |
result = app(head, arg);
|
|
Packit |
3f21c4 |
VALGRIND_MAKE_MEM_NOACCESS(MEMBLK_POSTPTR(head), Memento_PostSize);
|
|
Packit |
3f21c4 |
VALGRIND_MAKE_MEM_NOACCESS(head, sizeof(Memento_BlkHeader));
|
|
Packit |
3f21c4 |
return result;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
return 0;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
static void
|
|
Packit |
3f21c4 |
showBlock(Memento_BlkHeader *b, int space)
|
|
Packit |
3f21c4 |
{
|
|
Packit |
3f21c4 |
fprintf(stderr, "0x%p:(size=%d,num=%d)", MEMBLK_TOBLK(b), (int)b->rawsize, b->sequence);
|
|
Packit |
3f21c4 |
if (b->label)
|
|
Packit |
3f21c4 |
fprintf(stderr, "%c(%s)", space, b->label);
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
static void
|
|
Packit |
3f21c4 |
blockDisplay(Memento_BlkHeader *b, int n)
|
|
Packit |
3f21c4 |
{
|
|
Packit |
3f21c4 |
n++;
|
|
Packit |
3f21c4 |
while (n > 0) {
|
|
Packit |
3f21c4 |
int i = n;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
if (i > 32)
|
|
Packit |
3f21c4 |
i = 32;
|
|
Packit |
3f21c4 |
n -= i;
|
|
Packit |
3f21c4 |
fprintf(stderr, "%s", &" "[32 - i]);
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
showBlock(b, '\t');
|
|
Packit |
3f21c4 |
fprintf(stderr, "\n");
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
static int
|
|
Packit |
3f21c4 |
Memento_listBlock(Memento_BlkHeader *b, void *arg)
|
|
Packit |
3f21c4 |
{
|
|
Packit |
3f21c4 |
int *counts = (int *)arg;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
blockDisplay(b, 0);
|
|
Packit |
3f21c4 |
counts[0]++;
|
|
Packit |
3f21c4 |
counts[1] += b->rawsize;
|
|
Packit |
3f21c4 |
return 0;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
static void
|
|
Packit |
3f21c4 |
doNestedDisplay(Memento_BlkHeader *b, int depth)
|
|
Packit |
3f21c4 |
{
|
|
Packit |
3f21c4 |
blockDisplay(b, depth);
|
|
Packit |
3f21c4 |
for (b = b->child; b; b = b->sibling)
|
|
Packit |
3f21c4 |
doNestedDisplay(b, depth + 1);
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
static int
|
|
Packit |
3f21c4 |
ptrcmp(const void *a_, const void *b_)
|
|
Packit |
3f21c4 |
{
|
|
Packit |
3f21c4 |
const char **a = (const char **)a_;
|
|
Packit |
3f21c4 |
const char **b = (const char **)b_;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
return (int)(*a - *b);
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
static int
|
|
Packit |
3f21c4 |
Memento_listBlocksNested(void)
|
|
Packit |
3f21c4 |
{
|
|
Packit |
3f21c4 |
int count, size, i;
|
|
Packit |
3f21c4 |
Memento_BlkHeader *b;
|
|
Packit |
3f21c4 |
void **blocks, *minptr, *maxptr;
|
|
Packit |
3f21c4 |
long mask;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
/* Count the blocks */
|
|
Packit |
3f21c4 |
count = 0;
|
|
Packit |
3f21c4 |
size = 0;
|
|
Packit |
3f21c4 |
for (b = globals.used.head; b; b = b->next) {
|
|
Packit |
3f21c4 |
size += b->rawsize;
|
|
Packit |
3f21c4 |
count++;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
/* Make our block list */
|
|
Packit |
3f21c4 |
blocks = MEMENTO_UNDERLYING_MALLOC(sizeof(void *) * count);
|
|
Packit |
3f21c4 |
if (blocks == NULL)
|
|
Packit |
3f21c4 |
return 1;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
/* Populate our block list */
|
|
Packit |
3f21c4 |
b = globals.used.head;
|
|
Packit |
3f21c4 |
minptr = maxptr = MEMBLK_TOBLK(b);
|
|
Packit |
3f21c4 |
mask = (long)minptr;
|
|
Packit |
3f21c4 |
for (i = 0; b; b = b->next, i++) {
|
|
Packit |
3f21c4 |
void *p = MEMBLK_TOBLK(b);
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
mask &= (long)p;
|
|
Packit |
3f21c4 |
if (p < minptr)
|
|
Packit |
3f21c4 |
minptr = p;
|
|
Packit |
3f21c4 |
if (p > maxptr)
|
|
Packit |
3f21c4 |
maxptr = p;
|
|
Packit |
3f21c4 |
blocks[i] = p;
|
|
Packit |
3f21c4 |
b->flags &= ~Memento_Flag_HasParent;
|
|
Packit |
3f21c4 |
b->child = NULL;
|
|
Packit |
3f21c4 |
b->sibling = NULL;
|
|
Packit |
3f21c4 |
b->parent = NULL;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
qsort(blocks, count, sizeof(void *), ptrcmp);
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
/* Now, calculate tree */
|
|
Packit |
3f21c4 |
for (b = globals.used.head; b; b = b->next) {
|
|
Packit |
3f21c4 |
char *p = MEMBLK_TOBLK(b);
|
|
Packit |
3f21c4 |
int end = (b->rawsize < MEMENTO_PTRSEARCH ? b->rawsize : MEMENTO_PTRSEARCH);
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
for (i = MEMENTO_SEARCH_SKIP; i < end; i += sizeof(void *)) {
|
|
Packit |
3f21c4 |
void *q = *(void **)(&p[i]);
|
|
Packit |
3f21c4 |
void **r;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
/* Do trivial checks on pointer */
|
|
Packit |
3f21c4 |
if ((mask & (int)q) != mask || q < minptr || q > maxptr)
|
|
Packit |
3f21c4 |
continue;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
/* Search for pointer */
|
|
Packit |
3f21c4 |
r = bsearch(&q, blocks, count, sizeof(void *), ptrcmp);
|
|
Packit |
3f21c4 |
if (r) {
|
|
Packit |
3f21c4 |
/* Found child */
|
|
Packit |
3f21c4 |
Memento_BlkHeader *child = MEMBLK_FROMBLK(*r);
|
|
Packit |
3f21c4 |
Memento_BlkHeader *parent;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
/* We're assuming tree structure, not graph - ignore second
|
|
Packit |
3f21c4 |
* and subsequent pointers. */
|
|
Packit |
3f21c4 |
if (child->parent != NULL)
|
|
Packit |
3f21c4 |
continue;
|
|
Packit |
3f21c4 |
if (child->flags & Memento_Flag_HasParent)
|
|
Packit |
3f21c4 |
continue;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
/* We're also assuming acyclicness here. If this is one of
|
|
Packit |
3f21c4 |
* our parents, ignore it. */
|
|
Packit |
3f21c4 |
parent = b->parent;
|
|
Packit |
3f21c4 |
while (parent != NULL && parent != child)
|
|
Packit |
3f21c4 |
parent = parent->parent;
|
|
Packit |
3f21c4 |
if (parent == child)
|
|
Packit |
3f21c4 |
continue;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
child->sibling = b->child;
|
|
Packit |
3f21c4 |
b->child = child;
|
|
Packit |
3f21c4 |
child->parent = b;
|
|
Packit |
3f21c4 |
child->flags |= Memento_Flag_HasParent;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
/* Now display with nesting */
|
|
Packit |
3f21c4 |
for (b = globals.used.head; b; b = b->next) {
|
|
Packit |
3f21c4 |
if ((b->flags & Memento_Flag_HasParent) == 0)
|
|
Packit |
3f21c4 |
doNestedDisplay(b, 0);
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
fprintf(stderr, " Total number of blocks = %d\n", count);
|
|
Packit |
3f21c4 |
fprintf(stderr, " Total size of blocks = %d\n", size);
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
MEMENTO_UNDERLYING_FREE(blocks);
|
|
Packit |
3f21c4 |
return 0;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
void
|
|
Packit |
3f21c4 |
Memento_listBlocks(void)
|
|
Packit |
3f21c4 |
{
|
|
Packit |
3f21c4 |
fprintf(stderr, "Allocated blocks:\n");
|
|
Packit |
3f21c4 |
if (Memento_listBlocksNested()) {
|
|
Packit |
3f21c4 |
int counts[2];
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
counts[0] = 0;
|
|
Packit |
3f21c4 |
counts[1] = 0;
|
|
Packit |
3f21c4 |
Memento_appBlocks(&globals.used, Memento_listBlock, &counts[0]);
|
|
Packit |
3f21c4 |
fprintf(stderr, " Total number of blocks = %d\n", counts[0]);
|
|
Packit |
3f21c4 |
fprintf(stderr, " Total size of blocks = %d\n", counts[1]);
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
static int
|
|
Packit |
3f21c4 |
Memento_listNewBlock(Memento_BlkHeader *b, void *arg)
|
|
Packit |
3f21c4 |
{
|
|
Packit |
3f21c4 |
if (b->flags & Memento_Flag_OldBlock)
|
|
Packit |
3f21c4 |
return 0;
|
|
Packit |
3f21c4 |
b->flags |= Memento_Flag_OldBlock;
|
|
Packit |
3f21c4 |
return Memento_listBlock(b, arg);
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
void
|
|
Packit |
3f21c4 |
Memento_listNewBlocks(void)
|
|
Packit |
3f21c4 |
{
|
|
Packit |
3f21c4 |
int counts[2];
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
counts[0] = 0;
|
|
Packit |
3f21c4 |
counts[1] = 0;
|
|
Packit |
3f21c4 |
fprintf(stderr, "Blocks allocated and still extant since last list:\n");
|
|
Packit |
3f21c4 |
Memento_appBlocks(&globals.used, Memento_listNewBlock, &counts[0]);
|
|
Packit |
3f21c4 |
fprintf(stderr, " Total number of blocks = %d\n", counts[0]);
|
|
Packit |
3f21c4 |
fprintf(stderr, " Total size of blocks = %d\n", counts[1]);
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
static void
|
|
Packit |
3f21c4 |
Memento_endStats(void)
|
|
Packit |
3f21c4 |
{
|
|
Packit |
3f21c4 |
fprintf(stderr, "Total memory malloced = %u bytes\n", (unsigned int)globals.totalAlloc);
|
|
Packit |
3f21c4 |
fprintf(stderr, "Peak memory malloced = %u bytes\n", (unsigned int)globals.peakAlloc);
|
|
Packit |
3f21c4 |
fprintf(stderr, "%u mallocs, %u frees, %u reallocs\n", (unsigned int)globals.numMallocs, (unsigned int)globals.numFrees, (unsigned int)globals.numReallocs);
|
|
Packit |
3f21c4 |
fprintf(stderr, "Average allocation size %u bytes\n", (unsigned int)
|
|
Packit |
3f21c4 |
(globals.numMallocs != 0 ? globals.totalAlloc / globals.numMallocs : 0));
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
void
|
|
Packit |
3f21c4 |
Memento_stats(void)
|
|
Packit |
3f21c4 |
{
|
|
Packit |
3f21c4 |
fprintf(stderr, "Current memory malloced = %u bytes\n", (unsigned int)globals.alloc);
|
|
Packit |
3f21c4 |
Memento_endStats();
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
static void
|
|
Packit |
3f21c4 |
Memento_fin(void)
|
|
Packit |
3f21c4 |
{
|
|
Packit |
3f21c4 |
Memento_checkAllMemory();
|
|
Packit |
3f21c4 |
Memento_endStats();
|
|
Packit |
3f21c4 |
if (globals.used.head != NULL) {
|
|
Packit |
3f21c4 |
Memento_listBlocks();
|
|
Packit |
3f21c4 |
Memento_breakpoint();
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
if (globals.segv) {
|
|
Packit |
3f21c4 |
fprintf(stderr, "Memory dumped on SEGV while squeezing @ %d\n", globals.failAt);
|
|
Packit |
3f21c4 |
} else if (globals.squeezing) {
|
|
Packit |
3f21c4 |
if (globals.pattern == 0)
|
|
Packit |
3f21c4 |
fprintf(stderr, "Memory squeezing @ %d complete\n", globals.squeezeAt);
|
|
Packit |
3f21c4 |
else
|
|
Packit |
3f21c4 |
fprintf(stderr, "Memory squeezing @ %d (%d) complete\n", globals.squeezeAt, globals.pattern);
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
if (globals.failing) {
|
|
Packit |
3f21c4 |
fprintf(stderr, "MEMENTO_FAILAT=%d\n", globals.failAt);
|
|
Packit |
3f21c4 |
fprintf(stderr, "MEMENTO_PATTERN=%d\n", globals.pattern);
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
if (globals.nextFailAt != 0) {
|
|
Packit |
3f21c4 |
fprintf(stderr, "MEMENTO_NEXTFAILAT=%d\n", globals.nextFailAt);
|
|
Packit |
3f21c4 |
fprintf(stderr, "MEMENTO_NEXTPATTERN=%d\n", globals.nextPattern);
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
static void
|
|
Packit |
3f21c4 |
Memento_inited(void)
|
|
Packit |
3f21c4 |
{
|
|
Packit |
3f21c4 |
/* A good place for a breakpoint */
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
static void
|
|
Packit |
3f21c4 |
Memento_init(void)
|
|
Packit |
3f21c4 |
{
|
|
Packit |
3f21c4 |
char *env;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
memset(&globals, 0, sizeof(globals));
|
|
Packit |
3f21c4 |
globals.inited = 1;
|
|
Packit |
3f21c4 |
globals.used.head = NULL;
|
|
Packit |
3f21c4 |
globals.used.tail = &globals.used.head;
|
|
Packit |
3f21c4 |
globals.free.head = NULL;
|
|
Packit |
3f21c4 |
globals.free.tail = &globals.free.head;
|
|
Packit |
3f21c4 |
globals.sequence = 0;
|
|
Packit |
3f21c4 |
globals.countdown = 1024;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
env = getenv("MEMENTO_FAILAT");
|
|
Packit |
3f21c4 |
globals.failAt = (env ? atoi(env) : 0);
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
env = getenv("MEMENTO_PARANOIA");
|
|
Packit |
3f21c4 |
globals.paranoia = (env ? atoi(env) : 0);
|
|
Packit |
3f21c4 |
if (globals.paranoia == 0)
|
|
Packit |
3f21c4 |
globals.paranoia = 1024;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
env = getenv("MEMENTO_PARANOIDAT");
|
|
Packit |
3f21c4 |
globals.paranoidAt = (env ? atoi(env) : 0);
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
env = getenv("MEMENTO_SQUEEZEAT");
|
|
Packit |
3f21c4 |
globals.squeezeAt = (env ? atoi(env) : 0);
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
env = getenv("MEMENTO_PATTERN");
|
|
Packit |
3f21c4 |
globals.pattern = (env ? atoi(env) : 0);
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
env = getenv("MEMENTO_MAXMEMORY");
|
|
Packit |
3f21c4 |
globals.maxMemory = (env ? atoi(env) : 0);
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
atexit(Memento_fin);
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
Memento_inited();
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
#ifdef MEMENTO_HAS_FORK
|
|
Packit |
3f21c4 |
#include <unistd.h>
|
|
Packit |
3f21c4 |
#include <sys/wait.h>
|
|
Packit |
3f21c4 |
#ifdef MEMENTO_STACKTRACE_METHOD
|
|
Packit |
3f21c4 |
#if MEMENTO_STACKTRACE_METHOD == 1
|
|
Packit |
3f21c4 |
#include <signal.h>
|
|
Packit |
3f21c4 |
#endif
|
|
Packit |
3f21c4 |
#endif
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
/* FIXME: Find some portable way of getting this */
|
|
Packit |
3f21c4 |
/* MacOSX has 10240, Ubuntu seems to have 256 */
|
|
Packit |
3f21c4 |
#define OPEN_MAX 10240
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
/* stashed_map[j] = i means that filedescriptor i-1 was duplicated to j */
|
|
Packit |
3f21c4 |
int stashed_map[OPEN_MAX];
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
extern size_t backtrace(void **, int);
|
|
Packit |
3f21c4 |
extern void backtrace_symbols_fd(void **, size_t, int);
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
static void
|
|
Packit |
3f21c4 |
Memento_signal(void)
|
|
Packit |
3f21c4 |
{
|
|
Packit |
3f21c4 |
fprintf(stderr, "SEGV after Memory squeezing @ %d\n", globals.squeezeAt);
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
#ifdef MEMENTO_STACKTRACE_METHOD
|
|
Packit |
3f21c4 |
#if MEMENTO_STACKTRACE_METHOD == 1
|
|
Packit |
3f21c4 |
{
|
|
Packit |
3f21c4 |
void *array[100];
|
|
Packit |
3f21c4 |
size_t size;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
size = backtrace(array, 100);
|
|
Packit |
3f21c4 |
fprintf(stderr, "------------------------------------------------------------------------\n");
|
|
Packit |
3f21c4 |
fprintf(stderr, "Backtrace:\n");
|
|
Packit |
3f21c4 |
backtrace_symbols_fd(array, size, 2);
|
|
Packit |
3f21c4 |
fprintf(stderr, "------------------------------------------------------------------------\n");
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
#endif
|
|
Packit |
3f21c4 |
#endif
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
exit(1);
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
static int
|
|
Packit |
3f21c4 |
squeeze(void)
|
|
Packit |
3f21c4 |
{
|
|
Packit |
3f21c4 |
pid_t pid;
|
|
Packit |
3f21c4 |
int i, status;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
if (globals.patternBit < 0)
|
|
Packit |
3f21c4 |
return 1;
|
|
Packit |
3f21c4 |
if (globals.squeezing && globals.patternBit >= MEMENTO_MAXPATTERN)
|
|
Packit |
3f21c4 |
return 1;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
if (globals.patternBit == 0)
|
|
Packit |
3f21c4 |
globals.squeezeAt = globals.sequence;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
if (!globals.squeezing) {
|
|
Packit |
3f21c4 |
fprintf(stderr, "Memory squeezing @ %d\n", globals.squeezeAt);
|
|
Packit |
3f21c4 |
} else
|
|
Packit |
3f21c4 |
fprintf(stderr, "Memory squeezing @ %d (%x,%x)\n", globals.squeezeAt, globals.pattern, globals.patternBit);
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
/* When we fork below, the child is going to snaffle all our file pointers
|
|
Packit |
3f21c4 |
* and potentially corrupt them. Let's make copies of all of them before
|
|
Packit |
3f21c4 |
* we fork, so we can restore them when we restart. */
|
|
Packit |
3f21c4 |
for (i = 0; i < OPEN_MAX; i++) {
|
|
Packit |
3f21c4 |
if (stashed_map[i] == 0) {
|
|
Packit |
3f21c4 |
int j = dup(i);
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
stashed_map[j] = i + 1;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
pid = fork();
|
|
Packit |
3f21c4 |
if (pid == 0) {
|
|
Packit |
3f21c4 |
/* Child */
|
|
Packit |
3f21c4 |
signal(SIGSEGV, Memento_signal);
|
|
Packit |
3f21c4 |
/* In the child, we always fail the next allocation. */
|
|
Packit |
3f21c4 |
if (globals.patternBit == 0) {
|
|
Packit |
3f21c4 |
globals.patternBit = 1;
|
|
Packit |
3f21c4 |
} else
|
|
Packit |
3f21c4 |
globals.patternBit <<= 1;
|
|
Packit |
3f21c4 |
globals.squeezing = 1;
|
|
Packit |
3f21c4 |
return 1;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
/* In the parent if we hit another allocation, pass it (and record the
|
|
Packit |
3f21c4 |
* fact we passed it in the pattern. */
|
|
Packit |
3f21c4 |
globals.pattern |= globals.patternBit;
|
|
Packit |
3f21c4 |
globals.patternBit <<= 1;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
/* Wait for pid to finish */
|
|
Packit |
3f21c4 |
waitpid(pid, &status, 0);
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
if (status != 0) {
|
|
Packit |
3f21c4 |
fprintf(stderr, "Child status=%d\n", status);
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
/* Put the files back */
|
|
Packit |
3f21c4 |
for (i = 0; i < OPEN_MAX; i++) {
|
|
Packit |
3f21c4 |
if (stashed_map[i] != 0) {
|
|
Packit |
3f21c4 |
dup2(i, stashed_map[i] - 1);
|
|
Packit |
3f21c4 |
close(i);
|
|
Packit |
3f21c4 |
stashed_map[i] = 0;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
return 0;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
#else
|
|
Packit |
3f21c4 |
#include <signal.h>
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
static void
|
|
Packit |
3f21c4 |
Memento_signal(void)
|
|
Packit |
3f21c4 |
{
|
|
Packit |
3f21c4 |
globals.segv = 1;
|
|
Packit |
3f21c4 |
/* If we just return from this function the SEGV will be unhandled, and
|
|
Packit |
3f21c4 |
* we'll launch into whatever JIT debugging system the OS provides. At
|
|
Packit |
3f21c4 |
* least output something useful first. If MEMENTO_NOJIT is set, then
|
|
Packit |
3f21c4 |
* just exit to avoid the JIT (and get the usual atexit handling). */
|
|
Packit |
3f21c4 |
if (getenv("MEMENTO_NOJIT"))
|
|
Packit |
3f21c4 |
exit(1);
|
|
Packit |
3f21c4 |
else
|
|
Packit |
3f21c4 |
Memento_fin();
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
int
|
|
Packit |
3f21c4 |
squeeze(void)
|
|
Packit |
3f21c4 |
{
|
|
Packit |
3f21c4 |
fprintf(stderr, "Memento memory squeezing disabled as no fork!\n");
|
|
Packit |
3f21c4 |
return 0;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
#endif
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
static void
|
|
Packit |
3f21c4 |
Memento_startFailing(void)
|
|
Packit |
3f21c4 |
{
|
|
Packit |
3f21c4 |
if (!globals.failing) {
|
|
Packit |
3f21c4 |
fprintf(stderr, "Starting to fail...\n");
|
|
Packit |
3f21c4 |
fflush(stderr);
|
|
Packit |
3f21c4 |
globals.failing = 1;
|
|
Packit |
3f21c4 |
globals.failAt = globals.sequence;
|
|
Packit |
3f21c4 |
globals.nextFailAt = globals.sequence + 1;
|
|
Packit |
3f21c4 |
globals.pattern = 0;
|
|
Packit |
3f21c4 |
globals.patternBit = 0;
|
|
Packit |
3f21c4 |
signal(SIGSEGV, Memento_signal);
|
|
Packit |
3f21c4 |
signal(SIGABRT, Memento_signal);
|
|
Packit |
3f21c4 |
Memento_breakpoint();
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
static void
|
|
Packit |
3f21c4 |
Memento_event(void)
|
|
Packit |
3f21c4 |
{
|
|
Packit |
3f21c4 |
globals.sequence++;
|
|
Packit |
3f21c4 |
if ((globals.sequence >= globals.paranoidAt) && (globals.paranoidAt != 0)) {
|
|
Packit |
3f21c4 |
globals.paranoia = 1;
|
|
Packit |
3f21c4 |
globals.countdown = 1;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
if (--globals.countdown == 0) {
|
|
Packit |
3f21c4 |
Memento_checkAllMemory();
|
|
Packit |
3f21c4 |
globals.countdown = globals.paranoia;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
if (globals.sequence == globals.breakAt) {
|
|
Packit |
3f21c4 |
fprintf(stderr, "Breaking at event %d\n", globals.breakAt);
|
|
Packit |
3f21c4 |
Memento_breakpoint();
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
int
|
|
Packit |
3f21c4 |
Memento_breakAt(int event)
|
|
Packit |
3f21c4 |
{
|
|
Packit |
3f21c4 |
globals.breakAt = event;
|
|
Packit |
3f21c4 |
return event;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
void *
|
|
Packit |
3f21c4 |
Memento_label(void *ptr, const char *label)
|
|
Packit |
3f21c4 |
{
|
|
Packit |
3f21c4 |
Memento_BlkHeader *block;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
if (ptr == NULL)
|
|
Packit |
3f21c4 |
return NULL;
|
|
Packit |
3f21c4 |
block = MEMBLK_FROMBLK(ptr);
|
|
Packit |
3f21c4 |
block->label = label;
|
|
Packit |
3f21c4 |
return ptr;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
int
|
|
Packit |
3f21c4 |
Memento_failThisEvent(void)
|
|
Packit |
3f21c4 |
{
|
|
Packit |
3f21c4 |
int failThisOne;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
if (!globals.inited)
|
|
Packit |
3f21c4 |
Memento_init();
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
Memento_event();
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
if ((globals.sequence >= globals.failAt) && (globals.failAt != 0))
|
|
Packit |
3f21c4 |
Memento_startFailing();
|
|
Packit |
3f21c4 |
if ((globals.sequence >= globals.squeezeAt) && (globals.squeezeAt != 0)) {
|
|
Packit |
3f21c4 |
return squeeze();
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
if (!globals.failing)
|
|
Packit |
3f21c4 |
return 0;
|
|
Packit |
3f21c4 |
failThisOne = ((globals.patternBit & globals.pattern) == 0);
|
|
Packit |
3f21c4 |
/* If we are failing, and we've reached the end of the pattern and we've
|
|
Packit |
3f21c4 |
* still got bits available in the pattern word, and we haven't already
|
|
Packit |
3f21c4 |
* set a nextPattern, then extend the pattern. */
|
|
Packit |
3f21c4 |
if (globals.failing && ((~(globals.patternBit - 1) & globals.pattern) == 0) && (globals.patternBit != 0) && globals.nextPattern == 0) {
|
|
Packit |
3f21c4 |
/* We'll fail this one, and set the 'next' one to pass it. */
|
|
Packit |
3f21c4 |
globals.nextFailAt = globals.failAt;
|
|
Packit |
3f21c4 |
globals.nextPattern = globals.pattern | globals.patternBit;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
globals.patternBit = (globals.patternBit ? globals.patternBit << 1 : 1);
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
return failThisOne;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
void *
|
|
Packit |
3f21c4 |
Memento_malloc(size_t s)
|
|
Packit |
3f21c4 |
{
|
|
Packit |
3f21c4 |
Memento_BlkHeader *memblk;
|
|
Packit |
3f21c4 |
size_t smem = MEMBLK_SIZE(s);
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
if (Memento_failThisEvent())
|
|
Packit |
3f21c4 |
return NULL;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
if (s == 0)
|
|
Packit |
3f21c4 |
return NULL;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
globals.numMallocs++;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
if (globals.maxMemory != 0 && globals.alloc + s > globals.maxMemory)
|
|
Packit |
3f21c4 |
return NULL;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
memblk = MEMENTO_UNDERLYING_MALLOC(smem);
|
|
Packit |
3f21c4 |
if (memblk == NULL)
|
|
Packit |
3f21c4 |
return NULL;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
globals.alloc += s;
|
|
Packit |
3f21c4 |
globals.totalAlloc += s;
|
|
Packit |
3f21c4 |
if (globals.peakAlloc < globals.alloc)
|
|
Packit |
3f21c4 |
globals.peakAlloc = globals.alloc;
|
|
Packit |
3f21c4 |
#ifndef MEMENTO_LEAKONLY
|
|
Packit |
3f21c4 |
memset(MEMBLK_TOBLK(memblk), MEMENTO_ALLOCFILL, s);
|
|
Packit |
3f21c4 |
#endif
|
|
Packit |
3f21c4 |
memblk->rawsize = s;
|
|
Packit |
3f21c4 |
memblk->sequence = globals.sequence;
|
|
Packit |
3f21c4 |
memblk->lastCheckedOK = memblk->sequence;
|
|
Packit |
3f21c4 |
memblk->flags = 0;
|
|
Packit |
3f21c4 |
memblk->label = 0;
|
|
Packit |
3f21c4 |
memblk->child = NULL;
|
|
Packit |
3f21c4 |
memblk->sibling = NULL;
|
|
Packit |
3f21c4 |
Memento_addBlockHead(&globals.used, memblk, 0);
|
|
Packit |
3f21c4 |
return MEMBLK_TOBLK(memblk);
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
void *
|
|
Packit |
3f21c4 |
Memento_calloc(size_t n, size_t s)
|
|
Packit |
3f21c4 |
{
|
|
Packit |
3f21c4 |
void *block = Memento_malloc(n * s);
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
if (block)
|
|
Packit |
3f21c4 |
memset(block, 0, n * s);
|
|
Packit |
3f21c4 |
return block;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
static int
|
|
Packit |
3f21c4 |
checkBlock(Memento_BlkHeader *memblk, const char *action)
|
|
Packit |
3f21c4 |
{
|
|
Packit |
3f21c4 |
#ifndef MEMENTO_LEAKONLY
|
|
Packit |
3f21c4 |
BlkCheckData data;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
memset(&data, 0, sizeof(data));
|
|
Packit |
3f21c4 |
Memento_appBlock(&globals.used, Memento_Internal_checkAllocedBlock, &data, memblk);
|
|
Packit |
3f21c4 |
if (!data.found) {
|
|
Packit |
3f21c4 |
/* Failure! */
|
|
Packit |
3f21c4 |
fprintf(stderr, "Attempt to %s block ", action);
|
|
Packit |
3f21c4 |
showBlock(memblk, 32);
|
|
Packit |
3f21c4 |
Memento_breakpoint();
|
|
Packit |
3f21c4 |
return 1;
|
|
Packit |
3f21c4 |
} else if (data.preCorrupt || data.postCorrupt) {
|
|
Packit |
3f21c4 |
fprintf(stderr, "Block ");
|
|
Packit |
3f21c4 |
showBlock(memblk, ' ');
|
|
Packit |
3f21c4 |
fprintf(stderr, " found to be corrupted on %s!\n", action);
|
|
Packit |
3f21c4 |
if (data.preCorrupt) {
|
|
Packit |
3f21c4 |
fprintf(stderr, "Preguard corrupted\n");
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
if (data.postCorrupt) {
|
|
Packit |
3f21c4 |
fprintf(stderr, "Postguard corrupted\n");
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
fprintf(stderr, "Block last checked OK at allocation %d. Now %d.\n", memblk->lastCheckedOK, globals.sequence);
|
|
Packit |
3f21c4 |
Memento_breakpoint();
|
|
Packit |
3f21c4 |
return 1;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
#endif
|
|
Packit |
3f21c4 |
return 0;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
void
|
|
Packit |
3f21c4 |
Memento_free(void *blk)
|
|
Packit |
3f21c4 |
{
|
|
Packit |
3f21c4 |
Memento_BlkHeader *memblk;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
if (!globals.inited)
|
|
Packit |
3f21c4 |
Memento_init();
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
Memento_event();
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
if (blk == NULL)
|
|
Packit |
3f21c4 |
return;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
memblk = MEMBLK_FROMBLK(blk);
|
|
Packit |
3f21c4 |
VALGRIND_MAKE_MEM_DEFINED(memblk, sizeof(*memblk));
|
|
Packit |
3f21c4 |
if (checkBlock(memblk, "free"))
|
|
Packit |
3f21c4 |
return;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
if (memblk->flags & Memento_Flag_BreakOnFree)
|
|
Packit |
3f21c4 |
Memento_breakpoint();
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
VALGRIND_MAKE_MEM_DEFINED(memblk, sizeof(*memblk));
|
|
Packit |
3f21c4 |
globals.alloc -= memblk->rawsize;
|
|
Packit |
3f21c4 |
globals.numFrees++;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
Memento_removeBlock(&globals.used, memblk);
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
VALGRIND_MAKE_MEM_DEFINED(memblk, sizeof(*memblk));
|
|
Packit |
3f21c4 |
if (Memento_Internal_makeSpace(MEMBLK_SIZE(memblk->rawsize))) {
|
|
Packit |
3f21c4 |
VALGRIND_MAKE_MEM_DEFINED(memblk, sizeof(*memblk));
|
|
Packit |
3f21c4 |
VALGRIND_MAKE_MEM_DEFINED(MEMBLK_TOBLK(memblk), memblk->rawsize + Memento_PostSize);
|
|
Packit |
3f21c4 |
#ifndef MEMENTO_LEAKONLY
|
|
Packit |
3f21c4 |
memset(MEMBLK_TOBLK(memblk), MEMENTO_FREEFILL, memblk->rawsize);
|
|
Packit |
3f21c4 |
#endif
|
|
Packit |
3f21c4 |
Memento_addBlockTail(&globals.free, memblk, 1);
|
|
Packit |
3f21c4 |
} else {
|
|
Packit |
3f21c4 |
MEMENTO_UNDERLYING_FREE(memblk);
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
void *
|
|
Packit |
3f21c4 |
Memento_realloc(void *blk, size_t newsize)
|
|
Packit |
3f21c4 |
{
|
|
Packit |
3f21c4 |
Memento_BlkHeader *memblk, *newmemblk;
|
|
Packit |
3f21c4 |
size_t newsizemem;
|
|
Packit |
3f21c4 |
int flags;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
if (blk == NULL)
|
|
Packit |
3f21c4 |
return Memento_malloc(newsize);
|
|
Packit |
3f21c4 |
if (newsize == 0) {
|
|
Packit |
3f21c4 |
Memento_free(blk);
|
|
Packit |
3f21c4 |
return NULL;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
if (Memento_failThisEvent())
|
|
Packit |
3f21c4 |
return NULL;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
memblk = MEMBLK_FROMBLK(blk);
|
|
Packit |
3f21c4 |
if (checkBlock(memblk, "realloc"))
|
|
Packit |
3f21c4 |
return NULL;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
if (memblk->flags & Memento_Flag_BreakOnRealloc)
|
|
Packit |
3f21c4 |
Memento_breakpoint();
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
if (globals.maxMemory != 0 && globals.alloc - memblk->rawsize + newsize > globals.maxMemory)
|
|
Packit |
3f21c4 |
return NULL;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
newsizemem = MEMBLK_SIZE(newsize);
|
|
Packit |
3f21c4 |
Memento_removeBlock(&globals.used, memblk);
|
|
Packit |
3f21c4 |
flags = memblk->flags;
|
|
Packit |
3f21c4 |
newmemblk = MEMENTO_UNDERLYING_REALLOC(memblk, newsizemem);
|
|
Packit |
3f21c4 |
if (newmemblk == NULL) {
|
|
Packit |
3f21c4 |
Memento_addBlockHead(&globals.used, memblk, 2);
|
|
Packit |
3f21c4 |
return NULL;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
globals.numReallocs++;
|
|
Packit |
3f21c4 |
globals.totalAlloc += newsize;
|
|
Packit |
3f21c4 |
globals.alloc -= newmemblk->rawsize;
|
|
Packit |
3f21c4 |
globals.alloc += newsize;
|
|
Packit |
3f21c4 |
if (globals.peakAlloc < globals.alloc)
|
|
Packit |
3f21c4 |
globals.peakAlloc = globals.alloc;
|
|
Packit |
3f21c4 |
newmemblk->flags = flags;
|
|
Packit |
3f21c4 |
if (newmemblk->rawsize < newsize) {
|
|
Packit |
3f21c4 |
char *newbytes = ((char *)MEMBLK_TOBLK(newmemblk)) + newmemblk->rawsize;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
#ifndef MEMENTO_LEAKONLY
|
|
Packit |
3f21c4 |
memset(newbytes, MEMENTO_ALLOCFILL, newsize - newmemblk->rawsize);
|
|
Packit |
3f21c4 |
#endif
|
|
Packit |
3f21c4 |
VALGRIND_MAKE_MEM_UNDEFINED(newbytes, newsize - newmemblk->rawsize);
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
newmemblk->rawsize = newsize;
|
|
Packit |
3f21c4 |
#ifndef MEMENTO_LEAKONLY
|
|
Packit |
3f21c4 |
memset(newmemblk->preblk, MEMENTO_PREFILL, Memento_PreSize);
|
|
Packit |
3f21c4 |
memset(MEMBLK_POSTPTR(newmemblk), MEMENTO_POSTFILL, Memento_PostSize);
|
|
Packit |
3f21c4 |
#endif
|
|
Packit |
3f21c4 |
Memento_addBlockHead(&globals.used, newmemblk, 2);
|
|
Packit |
3f21c4 |
return MEMBLK_TOBLK(newmemblk);
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
int
|
|
Packit |
3f21c4 |
Memento_checkBlock(void *blk)
|
|
Packit |
3f21c4 |
{
|
|
Packit |
3f21c4 |
Memento_BlkHeader *memblk;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
if (blk == NULL)
|
|
Packit |
3f21c4 |
return 0;
|
|
Packit |
3f21c4 |
memblk = MEMBLK_FROMBLK(blk);
|
|
Packit |
3f21c4 |
return checkBlock(memblk, "check");
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
static int
|
|
Packit |
3f21c4 |
Memento_Internal_checkAllAlloced(Memento_BlkHeader *memblk, void *arg)
|
|
Packit |
3f21c4 |
{
|
|
Packit |
3f21c4 |
BlkCheckData *data = (BlkCheckData *) arg;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
Memento_Internal_checkAllocedBlock(memblk, data);
|
|
Packit |
3f21c4 |
if (data->preCorrupt || data->postCorrupt) {
|
|
Packit |
3f21c4 |
if ((data->found & 2) == 0) {
|
|
Packit |
3f21c4 |
fprintf(stderr, "Allocated blocks:\n");
|
|
Packit |
3f21c4 |
data->found |= 2;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
fprintf(stderr, " Block ");
|
|
Packit |
3f21c4 |
showBlock(memblk, ' ');
|
|
Packit |
3f21c4 |
if (data->preCorrupt) {
|
|
Packit |
3f21c4 |
fprintf(stderr, " Preguard ");
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
if (data->postCorrupt) {
|
|
Packit |
3f21c4 |
fprintf(stderr, "%s Postguard ", (data->preCorrupt ? "&" : ""));
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
fprintf(stderr, "corrupted.\n " "Block last checked OK at allocation %d. Now %d.\n", memblk->lastCheckedOK, globals.sequence);
|
|
Packit |
3f21c4 |
data->preCorrupt = 0;
|
|
Packit |
3f21c4 |
data->postCorrupt = 0;
|
|
Packit |
3f21c4 |
data->freeCorrupt = 0;
|
|
Packit |
3f21c4 |
} else
|
|
Packit |
3f21c4 |
memblk->lastCheckedOK = globals.sequence;
|
|
Packit |
3f21c4 |
return 0;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
static int
|
|
Packit |
3f21c4 |
Memento_Internal_checkAllFreed(Memento_BlkHeader *memblk, void *arg)
|
|
Packit |
3f21c4 |
{
|
|
Packit |
3f21c4 |
BlkCheckData *data = (BlkCheckData *) arg;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
Memento_Internal_checkFreedBlock(memblk, data);
|
|
Packit |
3f21c4 |
if (data->preCorrupt || data->postCorrupt || data->freeCorrupt) {
|
|
Packit |
3f21c4 |
if ((data->found & 4) == 0) {
|
|
Packit |
3f21c4 |
fprintf(stderr, "Freed blocks:\n");
|
|
Packit |
3f21c4 |
data->found |= 4;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
fprintf(stderr, " ");
|
|
Packit |
3f21c4 |
showBlock(memblk, ' ');
|
|
Packit |
3f21c4 |
if (data->freeCorrupt) {
|
|
Packit |
3f21c4 |
fprintf(stderr, " index %d (address 0x%p) onwards", data->index, &((char *)MEMBLK_TOBLK(memblk))[data->index]);
|
|
Packit |
3f21c4 |
if (data->preCorrupt) {
|
|
Packit |
3f21c4 |
fprintf(stderr, "+ preguard");
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
if (data->postCorrupt) {
|
|
Packit |
3f21c4 |
fprintf(stderr, "+ postguard");
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
} else {
|
|
Packit |
3f21c4 |
if (data->preCorrupt) {
|
|
Packit |
3f21c4 |
fprintf(stderr, " preguard");
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
if (data->postCorrupt) {
|
|
Packit |
3f21c4 |
fprintf(stderr, "%s Postguard", (data->preCorrupt ? "+" : ""));
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
fprintf(stderr, " corrupted.\n" " Block last checked OK at allocation %d. Now %d.\n", memblk->lastCheckedOK, globals.sequence);
|
|
Packit |
3f21c4 |
data->preCorrupt = 0;
|
|
Packit |
3f21c4 |
data->postCorrupt = 0;
|
|
Packit |
3f21c4 |
data->freeCorrupt = 0;
|
|
Packit |
3f21c4 |
} else
|
|
Packit |
3f21c4 |
memblk->lastCheckedOK = globals.sequence;
|
|
Packit |
3f21c4 |
return 0;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
int
|
|
Packit |
3f21c4 |
Memento_checkAllMemory(void)
|
|
Packit |
3f21c4 |
{
|
|
Packit |
3f21c4 |
#ifndef MEMENTO_LEAKONLY
|
|
Packit |
3f21c4 |
BlkCheckData data;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
memset(&data, 0, sizeof(data));
|
|
Packit |
3f21c4 |
Memento_appBlocks(&globals.used, Memento_Internal_checkAllAlloced, &data);
|
|
Packit |
3f21c4 |
Memento_appBlocks(&globals.free, Memento_Internal_checkAllFreed, &data);
|
|
Packit |
3f21c4 |
if (data.found & 6) {
|
|
Packit |
3f21c4 |
Memento_breakpoint();
|
|
Packit |
3f21c4 |
return 1;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
#endif
|
|
Packit |
3f21c4 |
return 0;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
int
|
|
Packit |
3f21c4 |
Memento_setParanoia(int i)
|
|
Packit |
3f21c4 |
{
|
|
Packit |
3f21c4 |
globals.paranoia = i;
|
|
Packit |
3f21c4 |
globals.countdown = globals.paranoia;
|
|
Packit |
3f21c4 |
return i;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
int
|
|
Packit |
3f21c4 |
Memento_paranoidAt(int i)
|
|
Packit |
3f21c4 |
{
|
|
Packit |
3f21c4 |
globals.paranoidAt = i;
|
|
Packit |
3f21c4 |
return i;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
int
|
|
Packit |
3f21c4 |
Memento_getBlockNum(void *b)
|
|
Packit |
3f21c4 |
{
|
|
Packit |
3f21c4 |
Memento_BlkHeader *memblk;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
if (b == NULL)
|
|
Packit |
3f21c4 |
return 0;
|
|
Packit |
3f21c4 |
memblk = MEMBLK_FROMBLK(b);
|
|
Packit |
3f21c4 |
return (memblk->sequence);
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
int
|
|
Packit |
3f21c4 |
Memento_check(void)
|
|
Packit |
3f21c4 |
{
|
|
Packit |
3f21c4 |
int result;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
fprintf(stderr, "Checking memory\n");
|
|
Packit |
3f21c4 |
result = Memento_checkAllMemory();
|
|
Packit |
3f21c4 |
fprintf(stderr, "Memory checked!\n");
|
|
Packit |
3f21c4 |
return result;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
typedef struct findBlkData {
|
|
Packit |
3f21c4 |
void *addr;
|
|
Packit |
3f21c4 |
Memento_BlkHeader *blk;
|
|
Packit |
3f21c4 |
int flags;
|
|
Packit |
3f21c4 |
} findBlkData;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
static int
|
|
Packit |
3f21c4 |
Memento_containsAddr(Memento_BlkHeader *b, void *arg)
|
|
Packit |
3f21c4 |
{
|
|
Packit |
3f21c4 |
findBlkData *data = (findBlkData *) arg;
|
|
Packit |
3f21c4 |
char *blkend = &((char *)MEMBLK_TOBLK(b))[b->rawsize];
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
if ((MEMBLK_TOBLK(b) <= data->addr) && ((void *)blkend > data->addr)) {
|
|
Packit |
3f21c4 |
data->blk = b;
|
|
Packit |
3f21c4 |
data->flags = 1;
|
|
Packit |
3f21c4 |
return 1;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
if (((void *)b <= data->addr) && (MEMBLK_TOBLK(b) > data->addr)) {
|
|
Packit |
3f21c4 |
data->blk = b;
|
|
Packit |
3f21c4 |
data->flags = 2;
|
|
Packit |
3f21c4 |
return 1;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
if (((void *)blkend <= data->addr) && ((void *)(blkend + Memento_PostSize) > data->addr)) {
|
|
Packit |
3f21c4 |
data->blk = b;
|
|
Packit |
3f21c4 |
data->flags = 3;
|
|
Packit |
3f21c4 |
return 1;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
return 0;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
int
|
|
Packit |
3f21c4 |
Memento_find(void *a)
|
|
Packit |
3f21c4 |
{
|
|
Packit |
3f21c4 |
findBlkData data;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
data.addr = a;
|
|
Packit |
3f21c4 |
data.blk = NULL;
|
|
Packit |
3f21c4 |
data.flags = 0;
|
|
Packit |
3f21c4 |
Memento_appBlocks(&globals.used, Memento_containsAddr, &data);
|
|
Packit |
3f21c4 |
if (data.blk != NULL) {
|
|
Packit |
3f21c4 |
fprintf(stderr, "Address 0x%p is in %sallocated block ", data.addr, (data.flags == 1 ? "" : (data.flags == 2 ? "preguard of " : "postguard of ")));
|
|
Packit |
3f21c4 |
showBlock(data.blk, ' ');
|
|
Packit |
3f21c4 |
fprintf(stderr, "\n");
|
|
Packit |
3f21c4 |
return data.blk->sequence;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
data.blk = NULL;
|
|
Packit |
3f21c4 |
data.flags = 0;
|
|
Packit |
3f21c4 |
Memento_appBlocks(&globals.free, Memento_containsAddr, &data);
|
|
Packit |
3f21c4 |
if (data.blk != NULL) {
|
|
Packit |
3f21c4 |
fprintf(stderr, "Address 0x%p is in %sfreed block ", data.addr, (data.flags == 1 ? "" : (data.flags == 2 ? "preguard of " : "postguard of ")));
|
|
Packit |
3f21c4 |
showBlock(data.blk, ' ');
|
|
Packit |
3f21c4 |
fprintf(stderr, "\n");
|
|
Packit |
3f21c4 |
return data.blk->sequence;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
return 0;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
void
|
|
Packit |
3f21c4 |
Memento_breakOnFree(void *a)
|
|
Packit |
3f21c4 |
{
|
|
Packit |
3f21c4 |
findBlkData data;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
data.addr = a;
|
|
Packit |
3f21c4 |
data.blk = NULL;
|
|
Packit |
3f21c4 |
data.flags = 0;
|
|
Packit |
3f21c4 |
Memento_appBlocks(&globals.used, Memento_containsAddr, &data);
|
|
Packit |
3f21c4 |
if (data.blk != NULL) {
|
|
Packit |
3f21c4 |
fprintf(stderr, "Will stop when address 0x%p (in %sallocated block ",
|
|
Packit |
3f21c4 |
data.addr, (data.flags == 1 ? "" : (data.flags == 2 ? "preguard of " : "postguard of ")));
|
|
Packit |
3f21c4 |
showBlock(data.blk, ' ');
|
|
Packit |
3f21c4 |
fprintf(stderr, ") is freed\n");
|
|
Packit |
3f21c4 |
data.blk->flags |= Memento_Flag_BreakOnFree;
|
|
Packit |
3f21c4 |
return;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
data.blk = NULL;
|
|
Packit |
3f21c4 |
data.flags = 0;
|
|
Packit |
3f21c4 |
Memento_appBlocks(&globals.free, Memento_containsAddr, &data);
|
|
Packit |
3f21c4 |
if (data.blk != NULL) {
|
|
Packit |
3f21c4 |
fprintf(stderr, "Can't stop on free; address 0x%p is in %sfreed block ",
|
|
Packit |
3f21c4 |
data.addr, (data.flags == 1 ? "" : (data.flags == 2 ? "preguard of " : "postguard of ")));
|
|
Packit |
3f21c4 |
showBlock(data.blk, ' ');
|
|
Packit |
3f21c4 |
fprintf(stderr, "\n");
|
|
Packit |
3f21c4 |
return;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
fprintf(stderr, "Can't stop on free; address 0x%p is not in a known block.\n", a);
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
void
|
|
Packit |
3f21c4 |
Memento_breakOnRealloc(void *a)
|
|
Packit |
3f21c4 |
{
|
|
Packit |
3f21c4 |
findBlkData data;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
data.addr = a;
|
|
Packit |
3f21c4 |
data.blk = NULL;
|
|
Packit |
3f21c4 |
data.flags = 0;
|
|
Packit |
3f21c4 |
Memento_appBlocks(&globals.used, Memento_containsAddr, &data);
|
|
Packit |
3f21c4 |
if (data.blk != NULL) {
|
|
Packit |
3f21c4 |
fprintf(stderr, "Will stop when address 0x%p (in %sallocated block ",
|
|
Packit |
3f21c4 |
data.addr, (data.flags == 1 ? "" : (data.flags == 2 ? "preguard of " : "postguard of ")));
|
|
Packit |
3f21c4 |
showBlock(data.blk, ' ');
|
|
Packit |
3f21c4 |
fprintf(stderr, ") is freed (or realloced)\n");
|
|
Packit |
3f21c4 |
data.blk->flags |= Memento_Flag_BreakOnFree | Memento_Flag_BreakOnRealloc;
|
|
Packit |
3f21c4 |
return;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
data.blk = NULL;
|
|
Packit |
3f21c4 |
data.flags = 0;
|
|
Packit |
3f21c4 |
Memento_appBlocks(&globals.free, Memento_containsAddr, &data);
|
|
Packit |
3f21c4 |
if (data.blk != NULL) {
|
|
Packit |
3f21c4 |
fprintf(stderr, "Can't stop on free/realloc; address 0x%p is in %sfreed block ",
|
|
Packit |
3f21c4 |
data.addr, (data.flags == 1 ? "" : (data.flags == 2 ? "preguard of " : "postguard of ")));
|
|
Packit |
3f21c4 |
showBlock(data.blk, ' ');
|
|
Packit |
3f21c4 |
fprintf(stderr, "\n");
|
|
Packit |
3f21c4 |
return;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
fprintf(stderr, "Can't stop on free/realloc; address 0x%p is not in a known block.\n", a);
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
int
|
|
Packit |
3f21c4 |
Memento_failAt(int i)
|
|
Packit |
3f21c4 |
{
|
|
Packit |
3f21c4 |
globals.failAt = i;
|
|
Packit |
3f21c4 |
if ((globals.sequence > globals.failAt) && (globals.failing != 0))
|
|
Packit |
3f21c4 |
Memento_startFailing();
|
|
Packit |
3f21c4 |
return i;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
size_t
|
|
Packit |
3f21c4 |
Memento_setMax(size_t max)
|
|
Packit |
3f21c4 |
{
|
|
Packit |
3f21c4 |
globals.maxMemory = max;
|
|
Packit |
3f21c4 |
return max;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
#else
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
/* Just in case anyone has left some debugging code in... */
|
|
Packit |
3f21c4 |
void (Memento_breakpoint)(void)
|
|
Packit |
3f21c4 |
{
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
int (Memento_checkBlock)(void *b)
|
|
Packit |
3f21c4 |
{
|
|
Packit |
3f21c4 |
return 0;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
int (Memento_checkAllMemory)(void)
|
|
Packit |
3f21c4 |
{
|
|
Packit |
3f21c4 |
return 0;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
int (Memento_check)(void)
|
|
Packit |
3f21c4 |
{
|
|
Packit |
3f21c4 |
return 0;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
int (Memento_setParanoia)(int i)
|
|
Packit |
3f21c4 |
{
|
|
Packit |
3f21c4 |
return 0;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
int (Memento_paranoidAt)(int i)
|
|
Packit |
3f21c4 |
{
|
|
Packit |
3f21c4 |
return 0;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
int (Memento_breakAt)(int i)
|
|
Packit |
3f21c4 |
{
|
|
Packit |
3f21c4 |
return 0;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
int (Memento_getBlockNum)(void *i)
|
|
Packit |
3f21c4 |
{
|
|
Packit |
3f21c4 |
return 0;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
int (Memento_find)(void *a)
|
|
Packit |
3f21c4 |
{
|
|
Packit |
3f21c4 |
return 0;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
int (Memento_failAt)(int i)
|
|
Packit |
3f21c4 |
{
|
|
Packit |
3f21c4 |
return 0;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
void (Memento_breakOnFree)(void *a)
|
|
Packit |
3f21c4 |
{
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
void (Memento_breakOnRealloc)(void *a)
|
|
Packit |
3f21c4 |
{
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
#undef Memento_malloc
|
|
Packit |
3f21c4 |
#undef Memento_free
|
|
Packit |
3f21c4 |
#undef Memento_realloc
|
|
Packit |
3f21c4 |
#undef Memento_calloc
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
void *
|
|
Packit |
3f21c4 |
Memento_malloc(size_t size)
|
|
Packit |
3f21c4 |
{
|
|
Packit |
3f21c4 |
return MEMENTO_UNDERLYING_MALLOC(size);
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
void
|
|
Packit |
3f21c4 |
Memento_free(void *b)
|
|
Packit |
3f21c4 |
{
|
|
Packit |
3f21c4 |
MEMENTO_UNDERLYING_FREE(b);
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
void *
|
|
Packit |
3f21c4 |
Memento_realloc(void *b, size_t s)
|
|
Packit |
3f21c4 |
{
|
|
Packit |
3f21c4 |
return MEMENTO_UNDERLYING_REALLOC(b, s);
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
void *
|
|
Packit |
3f21c4 |
Memento_calloc(size_t n, size_t s)
|
|
Packit |
3f21c4 |
{
|
|
Packit |
3f21c4 |
return MEMENTO_UNDERLYING_CALLOC(n, s);
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
void (Memento_listBlocks)(void)
|
|
Packit |
3f21c4 |
{
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
void (Memento_listNewBlocks)(void)
|
|
Packit |
3f21c4 |
{
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
size_t(Memento_setMax)(size_t max)
|
|
Packit |
3f21c4 |
{
|
|
Packit |
3f21c4 |
return 0;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
void (Memento_stats)(void)
|
|
Packit |
3f21c4 |
{
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
void *(Memento_label)(void *ptr, const char *label)
|
|
Packit |
3f21c4 |
{
|
|
Packit |
3f21c4 |
return ptr;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
#endif
|