Blame memento.c

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