pkg://ElectricFence-2.2.2-19.src.rpm:38696/ElectricFence-2.2.2.tar.gz
info downloads
ElectricFence-2.2.2/ 40755 764 764 0 6704702357 12600 5 ustar bruce bruce ElectricFence-2.2.2/README 100644 764 764 1612 6704253163 13551 0 ustar bruce bruce This is Electric Fence 2.2
Electric Fence is a different kind of malloc() debugger. It uses the virtual
memory hardware of your system to detect when software overruns the boundaries
of a malloc() buffer. It will also detect any accesses of memory that has
been released by free(). Because it uses the VM hardware for detection,
Electric Fence stops your program on the first instruction that causes
a bounds violation. It's then trivial to use a debugger to display the
offending statement.
This version should run on all systems that support POSIX mmap() and
mprotect(). This includes Linux, Unix, and I think even BeOS.
Complete information on the use of Electric Fence is in the manual page
efence.3 .
There is a mailing list to support Electric Fence. You can subscribe to it
using the web form at http://lists.perens.com/mailman/listinfo/electric-fence.
Thanks
Bruce Perens
bruce@perens.com
ElectricFence-2.2.2/Makefile 100644 764 764 3455 6704676551 14352 0 ustar bruce bruce PIC= -fPIC
CFLAGS= -g -DUSE_SEMAPHORE $(PIC)
LIBS= -lpthread
prefix=/usr
BIN_INSTALL_DIR= $(prefix)/bin
LIB_INSTALL_DIR= $(prefix)/lib
MAN_INSTALL_DIR= $(prefix)/man/man3
CC= cc
AR= ar
INSTALL= install
PACKAGE_SOURCE= README efence.3 Makefile efence.h \
efence.c page.c print.c eftest.c tstheap.c CHANGES
OBJECTS= efence.o page.o print.o
all: libefence.a libefence.so.0.0 tstheap eftest
@ echo
@ echo "Testing Electric Fence."
@ echo "After the last test, it should print that the test has PASSED."
./eftest
./tstheap 3072
@ echo
@ echo "Electric Fence confidence test PASSED."
@ echo
install: libefence.a efence.3 libefence.so.0.0
$(INSTALL) -m 755 ef.sh $(BIN_INSTALL_DIR)/ef
$(INSTALL) -m 644 libefence.a $(LIB_INSTALL_DIR)
$(INSTALL) -m 755 libefence.so.0.0 $(LIB_INSTALL_DIR)
- rm -f $(LIB_INSTALL_DIR)/libefence.so.0
ln -s libefence.so.0.0 $(LIB_INSTALL_DIR)/libefence.so.0
- rm -f $(LIB_INSTALL_DIR)/libefence.so
ln -s libefence.so.0.0 $(LIB_INSTALL_DIR)/libefence.so
$(INSTALL) -m 644 efence.3 $(MAN_INSTALL_DIR)/efence.3
clean:
- rm -f $(OBJECTS) tstheap.o eftest.o tstheap eftest \
libefence.a libefence.so.0.0 libefence.cat ElectricFence.shar
roff:
nroff -man < efence.3 > efence.cat
ElectricFence.shar: $(PACKAGE_SOURCE)
shar $(PACKAGE_SOURCE) > ElectricFence.shar
shar: ElectricFence.shar
libefence.a: $(OBJECTS)
- rm -f libefence.a
$(AR) crv libefence.a $(OBJECTS)
libefence.so.0.0: $(OBJECTS)
gcc -g -shared -Wl,-soname,libefence.so.0 -o libefence.so.0.0 \
$(OBJECTS) -lpthread -lc
tstheap: libefence.a tstheap.o
- rm -f tstheap
$(CC) $(CFLAGS) tstheap.o libefence.a -o tstheap $(LIBS)
eftest: libefence.a eftest.o
- rm -f eftest
$(CC) $(CFLAGS) eftest.o libefence.a -o eftest $(LIBS)
$(OBJECTS) tstheap.o eftest.o: efence.h
.c.o:
$(CC) $(CFLAGS) $(CPPFLAGS) -c $< -o $@
ElectricFence-2.2.2/efence.h 100644 764 764 2234 6704226031 14262 0 ustar bruce bruce #include <sys/types.h>
#include <sys/param.h>
#include <stdarg.h>
/*
* ef_number is the largest unsigned integer we'll need. On systems that
* support 64-bit pointers, this may be "unsigned long long".
*/
#if defined(USE_LONG_LONG)
typedef unsigned long long ef_number;
#else
typedef unsigned long ef_number;
#endif
/*
* NBBY is the number of bits per byte. Some systems define it in
* <sys/param.h> .
*/
#ifndef NBBY
#define NBBY 8
#endif
/*
* This is used to declare functions with "C" linkage if we are compiling
* with C++ .
*/
#ifdef __cplusplus
#define C_LINKAGE "C"
#else
#define C_LINKAGE
#endif
void Page_AllowAccess(void * address, size_t size);
void * Page_Create(size_t size);
void Page_Delete(void * address, size_t size);
void Page_DenyAccess(void * address, size_t size);
size_t Page_Size(void);
void EF_Abort(const char * message, ...);
void EF_Abortv(const char * message, va_list args);
void EF_Exit(const char * message, ...);
void EF_Exitv(const char * message, va_list args);
void EF_Print(const char * message, ...);
void EF_Printv(const char * message, va_list args);
void EF_InternalError(const char * message, ...);
ElectricFence-2.2.2/efence.c 100644 764 764 61554 6704513501 14310 0 ustar bruce bruce /*
* Electric Fence - Red-Zone memory allocator.
* Bruce Perens, 1988, 1993
*
* This is a special version of malloc() and company for debugging software
* that is suspected of overrunning or underrunning the boundaries of a
* malloc buffer, or touching free memory.
*
* It arranges for each malloc buffer to be followed (or preceded)
* in the address space by an inaccessable virtual memory page,
* and for free memory to be inaccessable. If software touches the
* inaccessable page, it will get an immediate segmentation
* fault. It is then trivial to uncover the offending code using a debugger.
*
* An advantage of this product over most malloc debuggers is that this one
* detects reading out of bounds as well as writing, and this one stops on
* the exact instruction that causes the error, rather than waiting until the
* next boundary check.
*
* There is one product that debugs malloc buffer overruns
* better than Electric Fence: "Purify" from Purify Systems, and that's only
* a small part of what Purify does. I'm not affiliated with Purify, I just
* respect a job well done.
*
* This version of malloc() should not be linked into production software,
* since it tremendously increases the time and memory overhead of malloc().
* Each malloc buffer will consume a minimum of two virtual memory pages,
* this is 16 kilobytes on many systems. On some systems it will be necessary
* to increase the amount of swap space in order to debug large programs that
* perform lots of allocation, because of the per-buffer overhead.
*/
#include "efence.h"
#include <stdlib.h>
#include <unistd.h>
#include <memory.h>
#include <string.h>
#ifdef USE_SEMAPHORE
# include <pthread.h>
# include <semaphore.h>
#endif
#ifdef malloc
#undef malloc
#endif
#ifdef calloc
#undef calloc
#endif
static const char version[] = "\n Electric Fence 2.2.0"
" Copyright (C) 1987-1999 Bruce Perens <bruce@perens.com>\n";
/*
* MEMORY_CREATION_SIZE is the amount of memory to get from the operating
* system at one time. We'll break that memory down into smaller pieces for
* malloc buffers. One megabyte is probably a good value.
*/
#define MEMORY_CREATION_SIZE 1024 * 1024
/*
* Enum Mode indicates the status of a malloc buffer.
*/
enum _Mode {
NOT_IN_USE = 0, /* Available to represent a malloc buffer. */
FREE, /* A free buffer. */
ALLOCATED, /* A buffer that is in use. */
PROTECTED, /* A freed buffer that can not be allocated again. */
INTERNAL_USE /* A buffer used internally by malloc(). */
};
typedef enum _Mode Mode;
/*
* Struct Slot contains all of the information about a malloc buffer except
* for the contents of its memory.
*/
struct _Slot {
void * userAddress;
void * internalAddress;
size_t userSize;
size_t internalSize;
Mode mode;
};
typedef struct _Slot Slot;
/*
* EF_ALIGNMENT is a global variable used to control the default alignment
* of buffers returned by malloc(), calloc(), and realloc(). It is all-caps
* so that its name matches the name of the environment variable that is used
* to set it. This gives the programmer one less name to remember.
* If the value is -1, it will be set from the environment or sizeof(int)
* at run time.
*/
int EF_ALIGNMENT = -1;
/*
* EF_PROTECT_FREE is a global variable used to control the disposition of
* memory that is released using free(). It is all-caps so that its name
* matches the name of the environment variable that is used to set it.
* If its value is greater non-zero, memory released by free is made
* inaccessable and never allocated again. Any software that touches free
* memory will then get a segmentation fault. If its value is zero, freed
* memory will be available for reallocation, but will still be inaccessable
* until it is reallocated.
* If the value is -1, it will be set from the environment or to 0 at run-time.
*/
int EF_PROTECT_FREE = -1;
/*
* EF_PROTECT_BELOW is used to modify the behavior of the allocator. When
* its value is non-zero, the allocator will place an inaccessable page
* immediately _before_ the malloc buffer in the address space, instead
* of _after_ it. Use this to detect malloc buffer under-runs, rather than
* over-runs. It won't detect both at the same time, so you should test your
* software twice, once with this value clear, and once with it set.
* If the value is -1, it will be set from the environment or to zero at
* run-time
*/
int EF_PROTECT_BELOW = -1;
/*
* EF_ALLOW_MALLOC_0 is set if Electric Fence is to allow malloc(0). I
* trap malloc(0) by default because it is a common source of bugs.
*/
int EF_ALLOW_MALLOC_0 = -1;
/*
* EF_FILL is set to 0-255 if Electric Fence should fill all new allocated
* memory with the specified value.
*/
int EF_FILL = -1;
/*
* allocationList points to the array of slot structures used to manage the
* malloc arena.
*/
static Slot * allocationList = 0;
/*
* allocationListSize is the size of the allocation list. This will always
* be a multiple of the page size.
*/
static size_t allocationListSize = 0;
/*
* slotCount is the number of Slot structures in allocationList.
*/
static size_t slotCount = 0;
/*
* unUsedSlots is the number of Slot structures that are currently available
* to represent new malloc buffers. When this number gets too low, we will
* create new slots.
*/
static size_t unUsedSlots = 0;
/*
* slotsPerPage is the number of slot structures that fit in a virtual
* memory page.
*/
static size_t slotsPerPage = 0;
/*
* internalUse is set when allocating and freeing the allocatior-internal
* data structures.
*/
static int internalUse = 0;
/*
* noAllocationListProtection is set to tell malloc() and free() not to
* manipulate the protection of the allocation list. This is only set in
* realloc(), which does it to save on slow system calls, and in
* allocateMoreSlots(), which does it because it changes the allocation list.
*/
static int noAllocationListProtection = 0;
#ifdef USE_SEMAPHORE
/*
* EF_sem is a semaphore used to allow one thread at a time into
* these routines.
* Also, we use semEnabled as a boolean to see if we should be
* using the semaphore.
* semThread is set to the thread id of the thread that currently
* has the semaphore so that when/if it tries to get the semaphore
* again (realloc calling malloc/free) - nothing will happen to the
* semaphore.
* semDepth is used to keep track of how many times the same thread
* gets the semaphore - so we know when it is actually freed.
*/
static sem_t EF_sem = { 0 };
static int semEnabled = 0;
static pthread_t semThread = (pthread_t) 0;
static int semDepth = 0;
#endif
/*
* bytesPerPage is set at run-time to the number of bytes per virtual-memory
* page, as returned by Page_Size().
*/
static size_t bytesPerPage = 0;
static void
lock()
{
#ifdef USE_SEMAPHORE
/* Are we using a semaphore? */
if (!semEnabled)
return;
/* Do we already have the semaphore? */
if (semThread == pthread_self()) {
/* Increment semDepth - push one stack level */
semDepth++;
return;
}
/* Wait for the semaphore. */
while (sem_wait(&EF_sem) < 0)
/* try again */;
/* Let everyone know who has the semaphore. */
semThread = pthread_self();
semDepth++;
#endif /* USE_SEMAPHORE */
}
static void
release()
{
#ifdef USE_SEMAPHORE
/* Are we using a semaphore? */
if (!semEnabled)
return;
/* Do we have the semaphore? Cannot free it if we don't. */
if (semThread != pthread_self()) {
if ( semThread == 0 )
EF_InternalError(
"Releasing semaphore that wasn't locked.");
else
EF_InternalError(
"Semaphore doesn't belong to thread.");
}
/* Make sure this is positive as well. */
if (semDepth <= 0)
EF_InternalError("Semaphore depth");
/* Decrement semDepth - popping one stack level */
semDepth--;
/* Only actually free the semaphore when we've reached the top */
/* of our call stack. */
if (semDepth == 0) {
/* Zero this before actually free'ing the semaphore. */
semThread = (pthread_t) 0;
if (sem_post(&EF_sem) < 0)
EF_InternalError("Failed to post the semaphore.");
}
#endif /* USE_SEMAPHORE */
}
/*
* initialize sets up the memory allocation arena and the run-time
* configuration information.
*/
static void
initialize(void)
{
size_t size = MEMORY_CREATION_SIZE;
size_t slack;
char * string;
Slot * slot;
EF_Print(version);
#ifdef USE_SEMAPHORE
if (sem_init(&EF_sem, 0, 1) >= 0) {
semEnabled = 1;
}
#endif
lock();
/*
* Import the user's environment specification of the default
* alignment for malloc(). We want that alignment to be under
* user control, since smaller alignment lets us catch more bugs,
* however some software will break if malloc() returns a buffer
* that is not word-aligned.
*
* I would like
* alignment to be zero so that we could catch all one-byte
* overruns, however if malloc() is asked to allocate an odd-size
* buffer and returns an address that is not word-aligned, or whose
* size is not a multiple of the word size, software breaks.
* This was the case with the Sun string-handling routines,
* which can do word fetches up to three bytes beyond the end of a
* string. I handle this problem in part by providing
* byte-reference-only versions of the string library functions, but
* there are other functions that break, too. Some in X Windows, one
* in Sam Leffler's TIFF library, and doubtless many others.
*/
if ( EF_ALIGNMENT == -1 ) {
if ( (string = getenv("EF_ALIGNMENT")) != 0 )
EF_ALIGNMENT = (size_t)atoi(string);
else
EF_ALIGNMENT = sizeof(int);
}
/*
* See if the user wants to protect the address space below a buffer,
* rather than that above a buffer.
*/
if ( EF_PROTECT_BELOW == -1 ) {
if ( (string = getenv("EF_PROTECT_BELOW")) != 0 )
EF_PROTECT_BELOW = (atoi(string) != 0);
else
EF_PROTECT_BELOW = 0;
}
/*
* See if the user wants to protect memory that has been freed until
* the program exits, rather than until it is re-allocated.
*/
if ( EF_PROTECT_FREE == -1 ) {
if ( (string = getenv("EF_PROTECT_FREE")) != 0 )
EF_PROTECT_FREE = (atoi(string) != 0);
else
EF_PROTECT_FREE = 0;
}
/*
* See if the user wants to allow malloc(0).
*/
if ( EF_ALLOW_MALLOC_0 == -1 ) {
if ( (string = getenv("EF_ALLOW_MALLOC_0")) != 0 )
EF_ALLOW_MALLOC_0 = (atoi(string) != 0);
else
EF_ALLOW_MALLOC_0 = 0;
}
/*
* Check if we should be filling new memory with a value.
*/
if ( EF_FILL == -1 ) {
if ( (string = getenv("EF_FILL")) != 0)
EF_FILL = (unsigned char) atoi(string);
}
/*
* Get the run-time configuration of the virtual memory page size.
*/
bytesPerPage = Page_Size();
/*
* Figure out how many Slot structures to allocate at one time.
*/
slotCount = slotsPerPage = bytesPerPage / sizeof(Slot);
allocationListSize = bytesPerPage;
if ( allocationListSize > size )
size = allocationListSize;
if ( (slack = size % bytesPerPage) != 0 )
size += bytesPerPage - slack;
/*
* Allocate memory, and break it up into two malloc buffers. The
* first buffer will be used for Slot structures, the second will
* be marked free.
*/
slot = allocationList = (Slot *)Page_Create(size);
memset((char *)allocationList, 0, allocationListSize);
slot[0].internalSize = slot[0].userSize = allocationListSize;
slot[0].internalAddress = slot[0].userAddress = allocationList;
slot[0].mode = INTERNAL_USE;
if ( size > allocationListSize ) {
slot[1].internalAddress = slot[1].userAddress
= ((char *)slot[0].internalAddress) + slot[0].internalSize;
slot[1].internalSize
= slot[1].userSize = size - slot[0].internalSize;
slot[1].mode = FREE;
}
/*
* Deny access to the free page, so that we will detect any software
* that treads upon free memory.
*/
Page_DenyAccess(slot[1].internalAddress, slot[1].internalSize);
/*
* Account for the two slot structures that we've used.
*/
unUsedSlots = slotCount - 2;
release();
}
/*
* allocateMoreSlots is called when there are only enough slot structures
* left to support the allocation of a single malloc buffer.
*/
static void
allocateMoreSlots(void)
{
size_t newSize = allocationListSize + bytesPerPage;
void * newAllocation;
void * oldAllocation = allocationList;
Page_AllowAccess(allocationList, allocationListSize);
noAllocationListProtection = 1;
internalUse = 1;
newAllocation = malloc(newSize);
memcpy(newAllocation, allocationList, allocationListSize);
memset(&(((char *)newAllocation)[allocationListSize]), 0, bytesPerPage);
allocationList = (Slot *)newAllocation;
allocationListSize = newSize;
slotCount += slotsPerPage;
unUsedSlots += slotsPerPage;
free(oldAllocation);
/*
* Keep access to the allocation list open at this point, because
* I am returning to memalign(), which needs that access.
*/
noAllocationListProtection = 0;
internalUse = 0;
}
/*
* This is the memory allocator. When asked to allocate a buffer, allocate
* it in such a way that the end of the buffer is followed by an inaccessable
* memory page. If software overruns that buffer, it will touch the bad page
* and get an immediate segmentation fault. It's then easy to zero in on the
* offending code with a debugger.
*
* There are a few complications. If the user asks for an odd-sized buffer,
* we would have to have that buffer start on an odd address if the byte after
* the end of the buffer was to be on the inaccessable page. Unfortunately,
* there is lots of software that asks for odd-sized buffers and then
* requires that the returned address be word-aligned, or the size of the
* buffer be a multiple of the word size. An example are the string-processing
* functions on Sun systems, which do word references to the string memory
* and may refer to memory up to three bytes beyond the end of the string.
* For this reason, I take the alignment requests to memalign() and valloc()
* seriously, and
*
* Electric Fence wastes lots of memory. I do a best-fit allocator here
* so that it won't waste even more. It's slow, but thrashing because your
* working set is too big for a system's RAM is even slower.
*/
extern C_LINKAGE void *
memalign(size_t alignment, size_t userSize)
{
register Slot * slot;
register size_t count;
Slot * fullSlot = 0;
Slot * emptySlots[2];
size_t internalSize;
size_t slack;
char * address;
if ( allocationList == 0 )
initialize();
lock();
if ( userSize == 0 && !EF_ALLOW_MALLOC_0 )
EF_Abort("Allocating 0 bytes, probably a bug.");
/*
* If EF_PROTECT_BELOW is set, all addresses returned by malloc()
* and company will be page-aligned.
*/
if ( !EF_PROTECT_BELOW && alignment > 1 ) {
if ( (slack = userSize % alignment) != 0 )
userSize += alignment - slack;
}
/*
* The internal size of the buffer is rounded up to the next page-size
* boudary, and then we add another page's worth of memory for the
* dead page.
*/
internalSize = userSize + bytesPerPage;
if ( (slack = internalSize % bytesPerPage) != 0 )
internalSize += bytesPerPage - slack;
/*
* These will hold the addresses of two empty Slot structures, that
* can be used to hold information for any memory I create, and any
* memory that I mark free.
*/
emptySlots[0] = 0;
emptySlots[1] = 0;
/*
* The internal memory used by the allocator is currently
* inaccessable, so that errant programs won't scrawl on the
* allocator's arena. I'll un-protect it here so that I can make
* a new allocation. I'll re-protect it before I return.
*/
if ( !noAllocationListProtection )
Page_AllowAccess(allocationList, allocationListSize);
/*
* If I'm running out of empty slots, create some more before
* I don't have enough slots left to make an allocation.
*/
if ( !internalUse && unUsedSlots < 7 ) {
allocateMoreSlots();
}
/*
* Iterate through all of the slot structures. Attempt to find a slot
* containing free memory of the exact right size. Accept a slot with
* more memory than we want, if the exact right size is not available.
* Find two slot structures that are not in use. We will need one if
* we split a buffer into free and allocated parts, and the second if
* we have to create new memory and mark it as free.
*
*/
for ( slot = allocationList, count = slotCount ; count > 0; count-- ) {
if ( slot->mode == FREE
&& slot->internalSize >= internalSize ) {
if ( !fullSlot
||slot->internalSize < fullSlot->internalSize){
fullSlot = slot;
if ( slot->internalSize == internalSize
&& emptySlots[0] )
break; /* All done, */
}
}
else if ( slot->mode == NOT_IN_USE ) {
if ( !emptySlots[0] )
emptySlots[0] = slot;
else if ( !emptySlots[1] )
emptySlots[1] = slot;
else if ( fullSlot
&& fullSlot->internalSize == internalSize )
break; /* All done. */
}
slot++;
}
if ( !emptySlots[0] )
EF_InternalError("No empty slot 0.");
if ( !fullSlot ) {
/*
* I get here if I haven't been able to find a free buffer
* with all of the memory I need. I'll have to create more
* memory. I'll mark it all as free, and then split it into
* free and allocated portions later.
*/
size_t chunkSize = MEMORY_CREATION_SIZE;
if ( !emptySlots[1] )
EF_InternalError("No empty slot 1.");
if ( chunkSize < internalSize )
chunkSize = internalSize;
if ( (slack = chunkSize % bytesPerPage) != 0 )
chunkSize += bytesPerPage - slack;
/* Use up one of the empty slots to make the full slot. */
fullSlot = emptySlots[0];
emptySlots[0] = emptySlots[1];
fullSlot->internalAddress = Page_Create(chunkSize);
fullSlot->internalSize = chunkSize;
fullSlot->mode = FREE;
unUsedSlots--;
/* Fill the slot if it was specified to do so. */
if ( EF_FILL != -1 )
memset(
(char *)fullSlot->internalAddress
,EF_FILL
,chunkSize);
}
/*
* If I'm allocating memory for the allocator's own data structures,
* mark it INTERNAL_USE so that no errant software will be able to
* free it.
*/
if ( internalUse )
fullSlot->mode = INTERNAL_USE;
else
fullSlot->mode = ALLOCATED;
/*
* If the buffer I've found is larger than I need, split it into
* an allocated buffer with the exact amount of memory I need, and
* a free buffer containing the surplus memory.
*/
if ( fullSlot->internalSize > internalSize ) {
emptySlots[0]->internalSize
= fullSlot->internalSize - internalSize;
emptySlots[0]->internalAddress
= ((char *)fullSlot->internalAddress) + internalSize;
emptySlots[0]->mode = FREE;
fullSlot->internalSize = internalSize;
unUsedSlots--;
}
if ( !EF_PROTECT_BELOW ) {
/*
* Arrange the buffer so that it is followed by an inaccessable
* memory page. A buffer overrun that touches that page will
* cause a segmentation fault.
*/
address = (char *)fullSlot->internalAddress;
/* Set up the "live" page. */
if ( internalSize - bytesPerPage > 0 )
Page_AllowAccess(
fullSlot->internalAddress
,internalSize - bytesPerPage);
address += internalSize - bytesPerPage;
/* Set up the "dead" page. */
if ( EF_PROTECT_FREE )
Page_Delete(address, bytesPerPage);
else
Page_DenyAccess(address, bytesPerPage);
/* Figure out what address to give the user. */
address -= userSize;
}
else { /* EF_PROTECT_BELOW != 0 */
/*
* Arrange the buffer so that it is preceded by an inaccessable
* memory page. A buffer underrun that touches that page will
* cause a segmentation fault.
*/
address = (char *)fullSlot->internalAddress;
/* Set up the "dead" page. */
if ( EF_PROTECT_FREE )
Page_Delete(address, bytesPerPage);
else
Page_DenyAccess(address, bytesPerPage);
address += bytesPerPage;
/* Set up the "live" page. */
if ( internalSize - bytesPerPage > 0 )
Page_AllowAccess(address, internalSize - bytesPerPage);
}
fullSlot->userAddress = address;
fullSlot->userSize = userSize;
/*
* Make the pool's internal memory inaccessable, so that the program
* being debugged can't stomp on it.
*/
if ( !internalUse )
Page_DenyAccess(allocationList, allocationListSize);
release();
return address;
}
/*
* Find the slot structure for a user address.
*/
static Slot *
slotForUserAddress(void * address)
{
register Slot * slot = allocationList;
register size_t count = slotCount;
for ( ; count > 0; count-- ) {
if ( slot->userAddress == address )
return slot;
slot++;
}
return 0;
}
/*
* Find the slot structure for an internal address.
*/
static Slot *
slotForInternalAddress(void * address)
{
register Slot * slot = allocationList;
register size_t count = slotCount;
for ( ; count > 0; count-- ) {
if ( slot->internalAddress == address )
return slot;
slot++;
}
return 0;
}
/*
* Given the internal address of a buffer, find the buffer immediately
* before that buffer in the address space. This is used by free() to
* coalesce two free buffers into one.
*/
static Slot *
slotForInternalAddressPreviousTo(void * address)
{
register Slot * slot = allocationList;
register size_t count = slotCount;
for ( ; count > 0; count-- ) {
if ( ((char *)slot->internalAddress)
+ slot->internalSize == address )
return slot;
slot++;
}
return 0;
}
extern C_LINKAGE void
free(void * address)
{
Slot * slot;
Slot * previousSlot = 0;
Slot * nextSlot = 0;
if ( address == 0 )
return;
if ( allocationList == 0 )
EF_Abort("free() called before first malloc().");
lock();
if ( !noAllocationListProtection )
Page_AllowAccess(allocationList, allocationListSize);
slot = slotForUserAddress(address);
if ( !slot )
EF_Abort("free(%a): address not from malloc().", address);
if ( slot->mode != ALLOCATED ) {
if ( internalUse && slot->mode == INTERNAL_USE )
/* Do nothing. */;
else {
EF_Abort(
"free(%a): freeing free memory."
,address);
}
}
if ( EF_PROTECT_FREE )
slot->mode = PROTECTED;
else
slot->mode = FREE;
/*
* Free memory is _always_ set to deny access. When EF_PROTECT_FREE
* is true, free memory is never reallocated, so it remains access
* denied for the life of the process. When EF_PROTECT_FREE is false,
* the memory may be re-allocated, at which time access to it will be
* allowed again.
*
* Some operating systems allow munmap() with single-page resolution,
* and allow you to un-map portions of a region, rather than the
* entire region that was mapped with mmap(). On those operating
* systems, we can release protected free pages with Page_Delete(),
* in the hope that the swap space attached to those pages will be
* released as well.
*/
if ( EF_PROTECT_FREE )
Page_Delete(slot->internalAddress, slot->internalSize);
else
Page_DenyAccess(slot->internalAddress, slot->internalSize);
previousSlot = slotForInternalAddressPreviousTo(slot->internalAddress);
nextSlot = slotForInternalAddress(
((char *)slot->internalAddress) + slot->internalSize);
if ( previousSlot && previousSlot->mode == slot->mode ) {
/* Coalesce previous slot with this one. */
previousSlot->internalSize += slot->internalSize;
slot->internalAddress = slot->userAddress = 0;
slot->internalSize = slot->userSize = 0;
slot->mode = NOT_IN_USE;
slot = previousSlot;
unUsedSlots++;
}
if ( nextSlot && nextSlot->mode == slot->mode ) {
/* Coalesce next slot with this one. */
slot->internalSize += nextSlot->internalSize;
nextSlot->internalAddress = nextSlot->userAddress = 0;
nextSlot->internalSize = nextSlot->userSize = 0;
nextSlot->mode = NOT_IN_USE;
unUsedSlots++;
}
slot->userAddress = slot->internalAddress;
slot->userSize = slot->internalSize;
if ( !noAllocationListProtection )
Page_DenyAccess(allocationList, allocationListSize);
release();
}
extern C_LINKAGE void *
realloc(void * oldBuffer, size_t newSize)
{
void * newBuffer = 0;
if ( allocationList == 0 )
initialize(); /* This sets EF_ALIGNMENT */
lock();
newBuffer = malloc(newSize);
if ( oldBuffer ) {
size_t size;
Slot * slot;
Page_AllowAccess(allocationList, allocationListSize);
noAllocationListProtection = 1;
slot = slotForUserAddress(oldBuffer);
if ( slot == 0 )
EF_Abort(
"realloc(%a, %d): address not from malloc()."
,oldBuffer
,newSize);
if ( newSize < (size = slot->userSize) )
size = newSize;
if ( size > 0 )
memcpy(newBuffer, oldBuffer, size);
free(oldBuffer);
noAllocationListProtection = 0;
Page_DenyAccess(allocationList, allocationListSize);
if ( size < newSize )
memset(&(((char *)newBuffer)[size]), 0, newSize - size);
/* Internal memory was re-protected in free() */
}
release();
return newBuffer;
}
extern C_LINKAGE void *
malloc(size_t size)
{
if ( allocationList == 0 )
initialize(); /* This sets EF_ALIGNMENT */
return memalign(EF_ALIGNMENT, size);
}
extern C_LINKAGE void *
calloc(size_t nelem, size_t elsize)
{
size_t size = nelem * elsize;
void * allocation = malloc(size);
memset(allocation, 0, size);
return allocation;
}
/*
* This will catch more bugs if you remove the page alignment, but it
* will break some software.
*/
extern C_LINKAGE void *
valloc (size_t size)
{
return memalign(bytesPerPage, size);
}
#ifdef __hpux
/*
* HP-UX 8/9.01 strcat reads a word past source when doing unaligned copies!
* Work around it here. The bug report has been filed with HP.
*/
char *strcat(char *d, const char *s)
{
strcpy(d+strlen(d), s);
return d;
}
#endif
ElectricFence-2.2.2/page.c 100644 764 764 10047 6704213766 14000 0 ustar bruce bruce #include "efence.h"
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
/*
* Lots of systems are missing the definition of PROT_NONE.
*/
#ifndef PROT_NONE
#define PROT_NONE 0
#endif
/*
* 386 BSD has MAP_ANON instead of MAP_ANONYMOUS.
*/
#if ( !defined(MAP_ANONYMOUS) && defined(MAP_ANON) )
#define MAP_ANONYMOUS MAP_ANON
#endif
/*
* For some reason, I can't find mprotect() in any of the headers on
* IRIX or SunOS 4.1.2
*/
/* extern C_LINKAGE int mprotect(void * addr, size_t len, int prot); */
static caddr_t startAddr = (caddr_t) 0;
#if ( !defined(sgi) && !defined(_AIX) &&!defined(__USE_BSD))
extern int sys_nerr;
extern char * sys_errlist[];
#endif
static const char *
stringErrorReport(void)
{
#if ( defined(sgi) )
return strerror(oserror());
#elif ( defined(_AIX) )
return strerror(errno);
#else
if ( errno > 0 && errno < sys_nerr )
return sys_errlist[errno];
else
return "Unknown error.\n";
#endif
}
/*
* Create memory.
*/
#if defined(MAP_ANONYMOUS)
void *
Page_Create(size_t size)
{
caddr_t allocation;
/*
* In this version, "startAddr" is a _hint_, not a demand.
* When the memory I map here is contiguous with other
* mappings, the allocator can coalesce the memory from two
* or more mappings into one large contiguous chunk, and thus
* might be able to find a fit that would not otherwise have
* been possible. I could _force_ it to be contiguous by using
* the MMAP_FIXED flag, but I don't want to stomp on memory mappings
* generated by other software, etc.
*/
allocation = (caddr_t) mmap(
startAddr
,(int)size
,PROT_READ|PROT_WRITE
,MAP_PRIVATE|MAP_ANONYMOUS
,-1
,0);
#ifndef __hpux
/*
* Set the "address hint" for the next mmap() so that it will abut
* the mapping we just created.
*
* HP/UX 9.01 has a kernel bug that makes mmap() fail sometimes
* when given a non-zero address hint, so we'll leave the hint set
* to zero on that system. HP recently told me this is now fixed.
* Someone please tell me when it is probable to assume that most
* of those systems that were running 9.01 have been upgraded.
*/
startAddr = allocation + size;
#endif
if ( allocation == (caddr_t)-1 )
EF_Exit("mmap() failed: %s", stringErrorReport());
return (void *)allocation;
}
#else
void *
Page_Create(size_t size)
{
static int devZeroFd = -1;
caddr_t allocation;
if ( devZeroFd == -1 ) {
devZeroFd = open("/dev/zero", O_RDWR);
if ( devZeroFd < 0 )
EF_Exit(
"open() on /dev/zero failed: %s"
,stringErrorReport());
}
/*
* In this version, "startAddr" is a _hint_, not a demand.
* When the memory I map here is contiguous with other
* mappings, the allocator can coalesce the memory from two
* or more mappings into one large contiguous chunk, and thus
* might be able to find a fit that would not otherwise have
* been possible. I could _force_ it to be contiguous by using
* the MMAP_FIXED flag, but I don't want to stomp on memory mappings
* generated by other software, etc.
*/
allocation = (caddr_t) mmap(
startAddr
,(int)size
,PROT_READ|PROT_WRITE
,MAP_PRIVATE
,devZeroFd
,0);
startAddr = allocation + size;
if ( allocation == (caddr_t)-1 )
EF_Exit("mmap() failed: %s", stringErrorReport());
return (void *)allocation;
}
#endif
static void
mprotectFailed(void)
{
EF_Exit("mprotect() failed: %s", stringErrorReport());
}
void
Page_AllowAccess(void * address, size_t size)
{
if ( mprotect((caddr_t)address, size, PROT_READ|PROT_WRITE) < 0 )
mprotectFailed();
}
void
Page_DenyAccess(void * address, size_t size)
{
if ( mprotect((caddr_t)address, size, PROT_NONE) < 0 )
mprotectFailed();
}
void
Page_Delete(void * address, size_t size)
{
if ( munmap((caddr_t)address, size) < 0 )
Page_DenyAccess(address, size);
}
#if defined(_SC_PAGESIZE)
size_t
Page_Size(void)
{
return (size_t)sysconf(_SC_PAGESIZE);
}
#elif defined(_SC_PAGE_SIZE)
size_t
Page_Size(void)
{
return (size_t)sysconf(_SC_PAGE_SIZE);
}
#else
/* extern int getpagesize(); */
size_t
Page_Size(void)
{
return getpagesize();
}
#endif
ElectricFence-2.2.2/print.c 100644 764 764 7034 6704230121 14162 0 ustar bruce bruce #include "efence.h"
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
/*
* These routines do their printing without using stdio. Stdio can't
* be used because it calls malloc(). Internal routines of a malloc()
* debugger should not re-enter malloc(), so stdio is out.
*/
/*
* NUMBER_BUFFER_SIZE is the longest character string that could be needed
* to represent an unsigned integer, assuming we might print in base 2.
*/
#define NUMBER_BUFFER_SIZE (sizeof(ef_number) * NBBY)
static void
do_abort()
{
/*
* I use kill(getpid(), SIGILL) instead of abort() because some
* mis-guided implementations of abort() flush stdio, which can
* cause malloc() or free() to be called.
*/
kill(getpid(), SIGILL);
/* Just in case something handles SIGILL and returns, exit here. */
_exit(-1);
}
static void
printNumber(ef_number number, ef_number base)
{
char buffer[NUMBER_BUFFER_SIZE];
char * s = &buffer[NUMBER_BUFFER_SIZE];
int size;
do {
ef_number digit;
if ( --s == buffer )
EF_Abort("Internal error printing number.");
digit = number % base;
if ( digit < 10 )
*s = '0' + digit;
else
*s = 'a' + digit - 10;
} while ( (number /= base) > 0 );
size = &buffer[NUMBER_BUFFER_SIZE] - s;
if ( size > 0 )
write(2, s, size);
}
void
EF_Printv(const char * pattern, va_list args)
{
static const char bad_pattern[] =
"\nBad pattern specifier %%%c in EF_Print().\n";
const char * s = pattern;
char c;
while ( (c = *s++) != '\0' ) {
if ( c == '%' ) {
c = *s++;
switch ( c ) {
case '%':
(void) write(2, &c, 1);
break;
case 'a':
/*
* Print an address passed as a void pointer.
* The type of ef_number must be set so that
* it is large enough to contain all of the
* bits of a void pointer.
*/
printNumber(
(ef_number)va_arg(args, void *)
,0x10);
break;
case 's':
{
const char * string;
size_t length;
string = va_arg(args, char *);
length = strlen(string);
(void) write(2, string, length);
}
break;
case 'd':
{
int n = va_arg(args, int);
if ( n < 0 ) {
char c = '-';
write(2, &c, 1);
n = -n;
}
printNumber(n, 10);
}
break;
case 'x':
printNumber(va_arg(args, u_int), 0x10);
break;
case 'c':
{
char c = va_arg(args, char);
(void) write(2, &c, 1);
}
break;
default:
{
EF_Print(bad_pattern, c);
}
}
}
else
(void) write(2, &c, 1);
}
}
void
EF_Abortv(const char * pattern, va_list args)
{
EF_Print("\nElectricFence Aborting: ");
EF_Printv(pattern, args);
EF_Print("\n");
do_abort();
}
void
EF_Abort(const char * pattern, ...)
{
va_list args;
va_start(args, pattern);
EF_Abortv(pattern, args);
/* Not reached: va_end(args); */
}
void
EF_Exitv(const char * pattern, va_list args)
{
EF_Print("\nElectricFence Exiting: ");
EF_Printv(pattern, args);
EF_Print("\n");
/*
* I use _exit() because the regular exit() flushes stdio,
* which may cause malloc() or free() to be called.
*/
_exit(-1);
}
void
EF_Exit(const char * pattern, ...)
{
va_list args;
va_start(args, pattern);
EF_Exitv(pattern, args);
/* Not reached: va_end(args); */
}
void
EF_Print(const char * pattern, ...)
{
va_list args;
va_start(args, pattern);
EF_Printv(pattern, args);
va_end(args);
}
void
EF_InternalError(const char * pattern, ...)
{
va_list args;
EF_Print("\nInternal error in allocator: ");
va_start(args, pattern);
EF_Printv(pattern, args);
EF_Print("\n");
va_end(args);
do_abort();
}
ElectricFence-2.2.2/eftest.c 100644 764 764 7443 5707641006 14336 0 ustar bruce bruce #include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <setjmp.h>
#include <signal.h>
#include "efence.h"
/*
* Electric Fence confidence tests.
* Make sure all of the various functions of Electric Fence work correctly.
*/
#ifndef PAGE_PROTECTION_VIOLATED_SIGNAL
#define PAGE_PROTECTION_VIOLATED_SIGNAL SIGSEGV
#endif
struct diagnostic {
int (*test)(void);
int expectedStatus;
const char * explanation;
};
extern int EF_PROTECT_BELOW;
extern int EF_ALIGNMENT;
static jmp_buf env;
/*
* There is still too little standardization of the arguments and return
* type of signal handler functions.
*/
static
void
segmentationFaultHandler(
int signalNumber
#if ( defined(_AIX) )
, ...
#endif
)
{
signal(PAGE_PROTECTION_VIOLATED_SIGNAL, SIG_DFL);
longjmp(env, 1);
}
static int
gotSegmentationFault(int (*test)(void))
{
if ( setjmp(env) == 0 ) {
int status;
signal(PAGE_PROTECTION_VIOLATED_SIGNAL
,segmentationFaultHandler);
status = (*test)();
signal(PAGE_PROTECTION_VIOLATED_SIGNAL, SIG_DFL);
return status;
}
else
return 1;
}
static char * allocation;
/* c is global so that assignments to it won't be optimized out. */
char c;
static int
testSizes(void)
{
/*
* If ef_number can't hold all of the bits of a void *, have the user
* add -DUSE_ LONG_LONG to the compiler flags so that ef_number will be
* declared as "unsigned long long" instead of "unsigned long".
*/
return ( sizeof(ef_number) < sizeof(void *) );
}
static int
allocateMemory(void)
{
allocation = (char *)malloc(1);
if ( allocation != 0 )
return 0;
else
return 1;
}
static int
freeMemory(void)
{
free(allocation);
return 0;
}
static int
protectBelow(void)
{
EF_PROTECT_BELOW = 1;
return 0;
}
static int
read0(void)
{
c = *allocation;
return 0;
}
static int
write0(void)
{
*allocation = 1;
return 0;
}
static int
read1(void)
{
c = allocation[1];
return 0;
}
static int
readMinus1(void)
{
c = allocation[-1];
return 0;
}
static struct diagnostic diagnostics[] = {
{
testSizes, 0,
"Please add -DLONG_LONG to the compiler flags and recompile."
},
{
allocateMemory, 0,
"Allocation 1: This test allocates a single byte of memory."
},
{
read0, 0,
"Read valid memory 1: This test reads the allocated memory."
},
{
write0, 0,
"Write valid memory 1: This test writes the allocated memory."
},
{
read1, 1,
"Read overrun: This test reads beyond the end of the buffer."
},
{
freeMemory, 0,
"Free memory: This test frees the allocated memory."
},
{
protectBelow, 0,
"Protect below: This sets Electric Fence to protect\n"
"the lower boundary of a malloc buffer, rather than the\n"
"upper boundary."
},
{
allocateMemory, 0,
"Allocation 2: This allocates memory with the lower boundary"
" protected."
},
{
read0, 0,
"Read valid memory 2: This test reads the allocated memory."
},
{
write0, 0,
"Write valid memory 2: This test writes the allocated memory."
},
{
readMinus1, 1,
"Read underrun: This test reads before the beginning of the"
" buffer."
},
{
0, 0, 0
}
};
static const char failedTest[]
= "Electric Fence confidence test failed.\n";
static const char newline = '\n';
int
main(int argc, char * * argv)
{
static const struct diagnostic * diag = diagnostics;
EF_PROTECT_BELOW = 0;
EF_ALIGNMENT = 0;
while ( diag->explanation != 0 ) {
int status = gotSegmentationFault(diag->test);
if ( status != diag->expectedStatus ) {
/*
* Don't use stdio to print here, because stdio
* uses malloc() and we've just proven that malloc()
* is broken. Also, use _exit() instead of exit(),
* because _exit() doesn't flush stdio.
*/
write(2, failedTest, sizeof(failedTest) - 1);
write(2, diag->explanation, strlen(diag->explanation));
write(2, &newline, 1);
_exit(-1);
}
diag++;
}
return 0;
}
ElectricFence-2.2.2/tstheap.c 100644 764 764 2330 5707641010 14475 0 ustar bruce bruce #include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <limits.h>
#include "efence.h"
/*
* This is a simple program to exercise the allocator. It allocates and frees
* memory in a pseudo-random fashion. It should run silently, using up time
* and resources on your system until you stop it or until it has gone
* through TEST_DURATION (or the argument) iterations of the loop.
*/
extern C_LINKAGE double drand48(void); /* For pre-ANSI C systems */
#define POOL_SIZE 1024
#define LARGEST_BUFFER 30000
#define TEST_DURATION 1000000
void * pool[POOL_SIZE];
#ifdef FAKE_DRAND48
/*
* Add -DFAKE_DRAND48 to your compile flags if your system doesn't
* provide drand48().
*/
#ifndef ULONG_MAX
#define ULONG_MAX ~(1L)
#endif
double
drand48(void)
{
return (random() / (double)ULONG_MAX);
}
#endif
int
main(int argc, char * * argv)
{
int count = 0;
int duration = TEST_DURATION;
if ( argc >= 2 )
duration = atoi(argv[1]);
for ( ; count < duration; count++ ) {
void * * element = &pool[(int)(drand48() * POOL_SIZE)];
size_t size = (size_t)(drand48() * (LARGEST_BUFFER + 1));
if ( *element ) {
free( *element );
*element = 0;
}
else if ( size > 0 ) {
*element = malloc(size);
}
}
return 0;
}
ElectricFence-2.2.2/CHANGES 100644 764 764 2025 6704677201 13666 0 ustar bruce bruce 2.2.2 Oops. Shared library must be position-independent code.
2.2.0
Merge in bug-fixes, multi-thread patch, shared library patch,
debian/ subdirectory used for building the Debian package
2.0.1
Add work-arounds for kernel and library bugs under HP-UX.
HP has been notified and will repair these soon.
2.0.2
Add support for DEC Alpha. Add %a pattern for printing addresses, which
assumes they are passed in a void *.
2.0.3 30-Sep-1993
When realloc is passed a zero address, it should work the same
way as malloc(). Fix forward declaration of mprotect() in page.c to
use void *, not caddr_t, for addresses. IRIX 5.0.1 complained about that.
2.0.4 29-May-1994
Don't attempt to allow access to a zero-sized page when
EF_ALLOW_MALLOC_0 is set. Attempt to un-map memory from
Page_Delete(). If that doesn't work, fall back by protecting the
page from all references. Un-mapping small segments of a mapping
used to crash my SGI IRIX 5.0 system. I assume that nobody is running
5.0 any longer.
2.0.5 20-January-1995
Port to Linux.
ElectricFence-2.2.2/COPYING 100644 764 764 43076 5707644137 13765 0 ustar bruce bruce GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
675 Mass Ave, Cambridge, MA 02139, USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
Appendix: How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) 19yy <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) 19yy name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.
ElectricFence-2.2.2/debian/ 40755 764 764 0 6704221021 14002 5 ustar bruce bruce ElectricFence-2.2.2/debian/README.debian 100644 764 764 1356 6704221021 16205 0 ustar bruce bruce electric-fence for DEBIAN
-------------------------
The official maintainer of this package is Siggy Brentrup <bsb@debian.org>.
But he apparently lost his net.access, so this version was made
by joost witteveen, <joostje@debian.org>.
This package now also contains a shared library of electric fence.
Thus, you don't need to recompile any programmes any more, all
you need to do is
LD_PRELOAD=libefence.so.0.0 your-buggy-programme
and efence's malloc will be used.
Oh, and note that if you're using c++, you and want to statically link
your c++ programmes, you shouldn't use g++ to link libefence.a, but
rather
gcc -o myprog myprog.o -lstdc++ -lg++ -lefence
(if you use g++, the order is different, and efence's malloc doesn't get used)
ElectricFence-2.2.2/debian/changelog 100644 764 764 2431 6704213033 15755 0 ustar bruce bruce electric-fence (2.0.5-4.1) unstable; urgency=low
* Orphaned the package:
(Siggy Brentrup has left the project a long while ago)
* Now point to the correct manpage (Fix #8122).
* upstream changelog file named correctly (Fix #9618).
* Now point to the upstream location (Fix #17354, #28059).
* Don't install libefence.so.0 executable (Fix #25993).
-- Vincent Renardias <vincent@waw.com> Wed, 13 Jan 1999 01:41:31 +0100
electric-fence (2.0.5-4) unstable; urgency=low
* recompiled for libc6; added an extra condition around the sys_errlist
declaration.
* added a libefence.so.0.0 shared library.
* non-maintainer release.
-- joost witteveen <joostje@debian.org> Fri, 19 Sep 1997 15:11:31 +0200
electric-fence (2.0.5-3) unstable; urgency=low
* Changed to new package format (Bug #7118)
* Added extended description (Bug #3582)
* Multi-architecture support (hopefully) (Bug #4045)
-- Siggy Brentrup <bsb@debian.org> Wed, 5 Feb 1997 17:17:17 +0100
electric-fence (2.0.5-2) unstable; urgency=low
* converted to ELF directory structure
* cleaned up debian.control
* minor changes to debian.rules
-- Siggy Brentrup <bsb@uni-muenster.de> Wed, 20 Jan 1996 00:00:00 +0100
Local variables:
mode: debian-changelog
add-log-mailing-address: "bsb@debian.org"
End:
ElectricFence-2.2.2/debian/control 100644 764 764 430 6704213033 15463 0 ustar bruce bruce Source: electric-fence
Section: devel
Priority: extra
Maintainer: Debian QA Group <debian-qa@lists.debian.org>
Standards-Version: 2.1.2.2
Package: electric-fence
Architecture: any
Description: A malloc(3) debugger
Use virtual memory hardware to detect illegal memory accesses.
ElectricFence-2.2.2/debian/control.multi 100644 764 764 436 6276102332 16625 0 ustar bruce bruce Source: efence
Section: unknown
Priority: extra
Maintainer: Siggy Brentrup <bsb@debian.org>
Standards-Version: 2.1.1.0
Package: efence
Architecture: any
Depends: ${shlibs:Depends}
Description: Missing
Missing
Package: efence-doc
Architecture: all
Description: Documentation
Missing
ElectricFence-2.2.2/debian/copyright 100644 764 764 555 6704220646 16033 0 ustar bruce bruce This package was debianized by Siggy Brentrup bsb@debian.org on
Wed, 5 Feb 1997 15:53:23 +0100.
The canonical version of the source code is available at
http://perens.com/FreeSoftware/ElectricFence .
Copyright:
(c) 1987-1999 Bruce Perens <bruce@perens.com>
The program is distributed under the GNU General Public License which
can be found in the file COPYING.
ElectricFence-2.2.2/debian/diversions.ex 100644 764 764 43 6276102332 16566 0 ustar bruce bruce <FILE> <Diverted to> <Packagename>
ElectricFence-2.2.2/debian/info.ex 100644 764 764 1014 6276102332 15373 0 ustar bruce bruce # This is a configuration files for installing a .info menu
# The Description to be placed into the directory
DESCR="Description"
# The section this info file should be placed in (Regexp) folllowed by
# the new section name to be created if the Regexp does not match
# (Optional. If not given the .info will be appended to the directory)
#SECTION_MATCH="Regexp"
#SECTION_NAME="New Section Name"
# The file referred to from the Info directory
FILE=efence.info
# Optional. The files to be copied to /usr/info
#FILES=*.info
ElectricFence-2.2.2/debian/rules 100755 764 764 3476 6704213033 15175 0 ustar bruce bruce #!/usr/bin/make -f
# Sample debian.rules file - for GNU Hello (1.3).
# Copyright 1994,1995 by Ian Jackson.
# I hereby give you perpetual unlimited permission to copy,
# modify and relicense this file, provided that you do not remove
# my name from the file itself. (I assert my moral right of
# paternity under the Copyright, Designs and Patents Act 1988.)
# This file may have to be extensively modified
#
# Modified to be a prototype for debmake by Christoph Lameter <clameter@debian.org>
package=electric-fence
build:
$(checkdir)
if [ -x configure ]; then ./configure --prefix=/usr; fi
make CFLAGS="-O2 -g -Wall"
rm *.o
make CFLAGS="-O2 -g -Wall -fPIC" libefence.so.0.0
touch build
clean:
$(checkdir)
rm -f build
rm -f libefence.so.0.0
-make clean
-rm -f `find . -name "*~"`
-rm -rf debian/tmp debian/files* core debian/substvars
binary-indep: checkroot build
$(checkdir)
# There are no architecture-independent files to be uploaded
# generated by this package. If there were any they would be
# made here.
binary-arch: checkroot build
$(checkdir)
-rm -rf debian/tmp
install -d debian/tmp
cd debian/tmp;install -d `cat ../dirs`
make install prefix=`pwd`/debian/tmp/usr
install -m 644 -o root -g root libefence.so.0.0 debian/tmp/usr/lib
# Must have debmake installed for this to work. Otherwise please copy
# /usr/bin/debstd into the debian directory and change debstd to debian/debstd
debstd CHANGES README
dpkg-gencontrol
chown -R root.root debian/tmp
chmod -R go=rX debian/tmp
dpkg --build debian/tmp ..
define checkdir
test -f debian/rules
endef
# Below here is fairly generic really
binary: binary-indep binary-arch
source diff:
@echo >&2 'source and diff are obsolete - use dpkg-source -b'; false
checkroot:
$(checkdir)
test root = "`whoami`"
.PHONY: binary binary-arch binary-indep clean checkroot
ElectricFence-2.2.2/debian/rules.multi 100644 764 764 2674 6276102333 16326 0 ustar bruce bruce #!/usr/bin/make -f
# Sample debian.rules file - for GNU Hello (1.3).
# Copyright 1994,1995 by Ian Jackson.
# I hereby give you perpetual unlimited permission to copy,
# modify and relicense this file, provided that you do not remove
# my name from the file itself. (I assert my moral right of
# paternity under the Copyright, Designs and Patents Act 1988.)
# This file may have to be extensively modified
#
# Modified to be a prototype for debmake by Christoph Lameter <clameter@debian.org>
package=efence
build:
$(checkdir)
make
touch build
clean:
$(checkdir)
-rm -f build
-make clean
-rm `find . -name "*~"`
-rm -rf debian/tmp debian/*/tmp debian/files* core
binary-indep: checkroot build
$(checkdir)
# There are no architecture-independent files to be uploaded
# generated by this package. If there were any they would be
# made here.
binary-arch: checkroot build
$(checkdir)
-rm -rf debian/tmp debian/*/tmp
install -d debian/tmp/usr/{bin,sbin}
make install DESTDIR=`pwd`/debian/tmp
debmstd $(package) CHANGES INSTALL README* TODO
dpkg-gencontrol
chown -R root.root debian/tmp
chmod -R go=rX debian/tmp
dpkg --build debian/tmp ..
define checkdir
test -f debian/rules
endef
# Below here is fairly generic really
binary: binary-indep binary-arch
source diff:
@echo >&2 'source and diff are obsolete - use dpkg-source -b'; false
checkroot:
$(checkdir)
test root = "`whoami`"
.PHONY: binary binary-arch binary-indep clean checkroot
ElectricFence-2.2.2/debian/dirs 100664 764 764 54 6704213033 14730 0 ustar bruce bruce usr/lib
usr/doc/electric-fence
usr/man/man3
ElectricFence-2.2.2/efence.3 100644 764 764 33376 6704253663 14243 0 ustar bruce bruce .TH efence 3 27-April-1993
.SH NAME
efence \- Electric Fence Malloc Debugger
.SH SYNOPSIS
.nf
.ft B
#include <stdlib.h>
.ft
.fi
.LP
.nf
.ft B
void * malloc (size_t size);
.ft
.fi
.LP
.nf
.ft B
void free (void *ptr);
.ft
.fi
.LP
.nf
.ft B
void * realloc (void *ptr, size_t size);
.ft
.fi
.LP
.nf
.ft B
void * calloc (size_t nelem, size_t elsize);
.ft
.fi
.LP
.nf
.ft B
void * memalign (size_t alignment, size_t size);
.ft
.fi
.LP
.nf
.ft B
void * valloc (size_t size);
.ft
.fi
.LP
.nf
.ft B
extern int EF_ALIGNMENT;
.ft
.fi
.LP
.nf
.ft B
extern int EF_PROTECT_BELOW;
.ft
.fi
.LP
.nf
.ft B
extern int EF_PROTECT_FREE;
.ft
.fi
.LP
.nf
.ft B
extern int EF_ALLOW_MALLOC_0;
.ft
.fi
.LP
.nf
.ft B
extern int EF_FILL;
.ft
.fi
.SH DESCRIPTION
.I Electric Fence
helps you detect two common programming bugs:
software that overruns the boundaries of a malloc() memory
allocation, and software that touches a memory allocation that has been
released by free(). Unlike other malloc() debuggers, Electric Fence will
detect
.I read
accesses as well as writes, and it will pinpoint the exact instruction that
causes an error. It has been in use at Pixar since 1987, and at many other
sites for years.
.LP
Electric Fence uses the virtual memory hardware of your computer to place an
inaccessible memory page immediately after (or before, at the user's option)
each memory allocation. When software reads or writes this inaccessible page,
the
hardware issues a segmentation fault, stopping the program at the offending
instruction. It is then trivial to find the erroneous statement using your
favorite debugger. In a similar manner, memory that has been released by
free() is made inaccessible, and any code that touches it will get a
segmentation fault.
.LP
Simply linking your application with libefence.a will allow you to detect
most, but not all, malloc buffer overruns and accesses of free memory.
If you want to be reasonably sure that you've found
.I all
bugs of this type, you'll have to read and understand the rest of this
man page.
.SH USAGE
Link your program with the library
.B libefence.a .
Make sure you are
.I not
linking with
.B -lmalloc,
.B -lmallocdebug,
or with other malloc-debugger or malloc-enhancer libraries.
You can only use one at a time.
If your system administrator
has installed Electric Fence for public use, you'll be able to use the
.B -lefence
argument to the linker, otherwise you'll have to put the path-name for
.B libefence.a
in the linker's command line.
You can also use dynamic linking. If you're using a Bourne shell, the
statement
.B export LD_PRELOAD=libefence.so.0.0
will cause Electric Fence to be loaded to run all dynamic executables.
The command
.B ef
.I command
runs a single command under Electric Fence.
.LP
Some systems will require special arguments to the linker to assure that
you are using the Electric Fence malloc() and not the one from your C library.
.LP
Run your program
.I using a debugger.
It's easier to work this way than to create a
.B core
file and post-mortem debug it. Electric Fence can create
.I huge
core files, and some operating systems will thus take minutes simply to dump
core! Some operating systems will not create usable core files from programs
that are linked with Electric Fence.
If your program has one of the errors detected by Electric Fence, it will
get a segmentation fault (SIGSEGV) at the offending instruction. Use the
debugger to locate the erroneous statement, and repair it.
.SH GLOBAL AND ENVIRONMENT VARIABLES
Electric Fence has four configuration switches that can be enabled via
the shell environment, or by setting the value of global integer variables
using a debugger. These switches change what bugs Electric Fence will detect,
so it's important that you know how to use them.
.TP
EF_ALIGNMENT
This is an integer that specifies the alignment for any memory allocations
that will be returned by malloc(), calloc(), and realloc().
The value is specified in
bytes, thus a value of 4 will cause memory to be aligned to 32-bit boundaries
unless your system doesn't have a 8-bit characters. EF_ALIGNMENT is set to
sizeof(int) by default, since that is generally the word-size of your CPU.
If your program requires that allocations be aligned to 64-bit
boundaries and you have a 32-bit
.B int
you'll have to set this value to 8. This is the case when compiling with the
.B -mips2
flag on MIPS-based systems such as those from SGI.
The memory allocation that is returned by Electric Fence malloc() is aligned
using the value in EF_ALIGNMENT, and
.I its size the multiple of
.I that value
that is greater than or equal to the requested size.
For this reason, you will sometimes want to set EF_ALIGNMENT to 0 (no
alignment), so that
you can detect overruns of less than your CPU's word size. Be sure to read
the section
.I WORD-ALIGNMENT AND OVERRUN DETECTION
in this manual page before you try this.
To change this value, set EF_ALIGNMENT in the shell environment to an
integer value, or assign
to the global integer variable EF_ALIGNMENT using a debugger.
.TP
EF_PROTECT_BELOW
Electric Fence usually places an inaccessible page immediately after each
memory allocation, so that software that runs past the end of the allocation
will be detected. Setting EF_PROTECT_BELOW to 1 causes Electric Fence
to place the inaccessible page
.I before
the allocation in the address space, so that under-runs will be detected
instead of over-runs.
When EF_PROTECT_BELOW is set, the EF_ALIGNMENT parameter is ignored.
All allocations will be aligned to virtual-memory-page boundaries, and
their size will be the exact size that was requested.
To change this value, set EF_PROTECT_BELOW in the shell environment to an
integer value, or assign to the global integer variable EF_PROTECT_BELOW using
a debugger.
.TP
EF_PROTECT_FREE
Electric Fence usually returns free memory to a pool from which it may be
re-allocated. If you suspect that a program may be touching free memory,
set EF_PROTECT_FREE to 1. This will cause Electric Fence to never re-allocate
memory once it has been freed, so that any access to free memory will be
detected. Some programs will use tremendous amounts of memory when this
parameter is set.
To change this value, set EF_PROTECT_FREE in the shell environment to an
integer value, or assign to the global integer variable EF_PROTECT_FREE using
a debugger.
.TP
EF_ALLOW_MALLOC_0
By default, Electric Fence traps calls to malloc() with a size of zero, because
they are often the result of a software bug. If EF_ALLOW_MALLOC_0 is non-zero,
the software will not trap calls to malloc() with a size of zero.
To change this value, set EF_ALLOC_MALLOC_0 in the shell environment to an
integer value, or assign to the global integer variable EF_ALLOC_MALLOC_0 using
a debugger.
.TP
EF_FILL
When set to a value between 0 and 255, every byte of allocated memory is
initialized to that value. This can help detect reads of uninitialized memory.
When set to -1, some memory is filled with zeroes
(the operating system default on most systems) and some memory will retain
the values written to it during its last use.
.SH WORD-ALIGNMENT AND OVERRUN DETECTION
There is a conflict between the alignment restrictions that malloc() operates
under and the debugging strategy used by Electric Fence. When detecting
overruns, Electric Fence malloc() allocates two or more virtual memory
pages for each allocation. The last page is made inaccessible in such a way
that any read, write, or execute access will cause a segmentation fault.
Then, Electric Fence malloc() will return an address such that the first
byte after
the end of the allocation is on the inaccessible page.
Thus, any overrun
of the allocation will cause a segmentation fault.
.LP
It follows that the
address returned by malloc() is the address of the inaccessible page minus
the size of the memory allocation.
Unfortunately, malloc() is required to return
.I word-aligned
allocations, since many CPUs can only access a word when its address is aligned.
The conflict happens when software makes a memory allocation using a size that
is not a multiple of the word size, and expects to do word accesses to that
allocation. The location of the inaccessible page is fixed by hardware at
a word-aligned address. If Electric Fence malloc() is to return an aligned
address, it must increase the size of the allocation to a multiple of the
word size.
In addition, the functions memalign() and valloc() must honor explicit
specifications on the alignment of the memory allocation, and this, as well
can only be implemented by increasing the size of the allocation.
Thus, there will be situations in which the end of a memory allocation
contains some padding space, and accesses of that padding space will not
be detected, even if they are overruns.
.LP
Electric Fence provides the variable EF_ALIGNMENT so that the user can
control the default alignment used by malloc(), calloc(), and realloc().
To debug overruns as small as a single byte, you can set EF_ALIGNMENT to
zero. This will result in Electric Fence malloc() returning unaligned
addresses for allocations with sizes that are not a multiple of the word
size. This is not a problem in most cases, because compilers must pad the
size of objects so that alignment restrictions are honored when storing
those objects in arrays. The problem surfaces when software allocates
odd-sized buffers for objects that must be word-aligned. One case of this
is software that allocates a buffer to contain a structure and a
string, and the string has an odd size (this example was in a popular TIFF
library). If word references are made to un-aligned buffers, you will see
a bus error (SIGBUS) instead of a segmentation fault. The only way to fix
this is to re-write the offending code to make byte references or not make
odd-sized allocations, or to set EF_ALIGNMENT to the word size.
.LP
Another example of software incompatible with
EF_ALIGNMENT < word-size
is the strcmp() function and other string functions on SunOS (and probably
Solaris), which make word-sized accesses to character strings, and may
attempt to access up to three bytes beyond the end of a string. These
result in a segmentation fault (SIGSEGV). The only way around this is to
use versions of the string functions that perform byte references instead
of word references.
.SH INSTRUCTIONS FOR DEBUGGING YOUR PROGRAM
.TP
1.
Link with libefence.a as explained above.
.TP
2.
Run your program in a debugger and fix any overruns or accesses to free memory.
.TP
3.
Quit the debugger.
.TP
4.
Set EF_PROTECT_BELOW = 1 in the shell environment.
.TP
5.
Repeat step 2, this time repairing underruns if they occur.
.TP
6.
Quit the debugger.
.TP
7.
Read the restrictions in the section on
.I WORD-ALIGNMENT AND OVERRUN DETECTION.
See if you can
set EF_ALIGNMENT to 0 and repeat step 2. Sometimes this will be too much work,
or there will be problems with library routines for which you don't have the
source, that will prevent you from doing this.
.SH MEMORY USAGE AND EXECUTION SPEED
Since Electric Fence uses at least two virtual memory pages for each of its
allocations, it's a terrible memory hog. I've sometimes found it necessary to
add a swap file using swapon(8) so that the system would have enough virtual
memory to debug my program. Also, the way we manipulate memory results in
various cache and translation buffer entries being flushed with each call
to malloc or free. The end result is that your program will be much slower
and use more resources while you are debugging it with Electric Fence.
.LP
Don't leave libefence.a linked into production software! Use it only
for debugging.
.SH MAILING LIST
There is a mailing list to support Electric Fence. You can subscribe using the
mail form at
http://lists.perens.com/mailman/listinfo/electric-fence .
.SH AUTHOR
Bruce Perens
.SH WARNINGS
I have tried to do as good a job as I can on this software, but I doubt
that it is even theoretically possible to make it bug-free.
This software has no warranty. It will not detect some bugs that you might
expect it to detect, and will indicate that some non-bugs are bugs.
.SH LICENSE
Copyright 1987-1999 Bruce Perens. All rights reserved.
.br
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License, Version 2,
as published by the Free Software Foundation. A copy of this license is
distributed with this software in the file "COPYING".
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Read the
file "COPYING" for more details.
.SH CONTACTING THE AUTHOR
.nf
Bruce Perens
1563 Solano Ave. #349
Berkeley, CA 94707
Telephone: 510-526-1165
Internet: bruce@perens.com
.fi
.ft
.SH FILES
/dev/zero: Source of memory pages (via mmap(2)).
.SH SEE ALSO
malloc(3), mmap(2), mprotect(2), swapon(8)
.SH DIAGNOSTICS
Segmentation Fault: Examine the offending statement for violation of the
boundaries of a memory allocation.
.br
Bus Error: See the section on
.I WORD-ALIGNMENT AND OVERRUN DETECTION.
in this manual page.
.SH BUGS
My explanation of the alignment issue could be improved.
.LP
Some Sun systems running SunOS 4.1 were reported to signal an access to a
protected page with
.B SIGBUS
rather than
.B SIGSEGV,
I suspect this is an undocumented feature of a particular Sun hardware
version, not just the operating system.
On these systems, eftest will fail with a bus error until you modify the
Makefile to define
.B PAGE_PROTECTION_VIOLATED_SIGNAL
as
.B SIGBUS.
.LP
There are, without doubt, other bugs and porting issues. Please contact me via
e-mail if you have any bug reports, ideas, etc.
.SH WHAT'S BETTER
.I Purify
does a much more thorough job than Electric Fence, and does not have
the huge memory overhead.
.I Checkergcc,
a modified version of the GNU C Compiler that instruments all memory
references,
is available on Linux systems and where GCC is used. It performs some of the
same tasks as Purify, but only on code that it has compiled.
ElectricFence-2.2.2/ef.sh 100664 764 764 623 6704233532 13600 0 ustar bruce bruce #!/bin/bash
#
# Simple script to run electric fence on stuff. (needs libefence.so).
#
# $Id: ef,v 1.1 1999/03/31 21:31:23 kefka Exp $
#
# Usage check.
if [ "$1" = "" ]; then
echo "$0: Usage: ef [executable] [arguments]."
echo " Runs the executable under the Electric Fence malloc debugger."
exit
fi
# Set the environment to load eletric fence.
(\
export LD_PRELOAD=libefence.so.0.0;\
exec $*;\
)