static void vprint(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': { /*Cast used, since char gets promoted to int in ... */ char c = (char)va_arg(args, int); (void)write(2, &c, 1); } break; default: { EF_Print(bad_pattern, c); } } } else
extern C_LINKAGE void _DpsFree(void * address, const char *filename, size_t fileline) { Slot * slot; Slot * previousSlot = 0; Slot * nextSlot = 0; if ( address == 0 ) return; /* fprintf(stderr, "DpsFree: %p at %s:%d\n", address, filename, fileline); */ if ( allocationList == 0 ) EF_Abort("DpsFree() called before first DpsMalloc() at %s:%d.", filename, fileline); lock(); if ( !noAllocationListProtection ) Page_AllowAccess(allocationList, allocationListSize); slot = slotForUserAddress(address); if ( !slot ) { /* EF_Abort("DpsFree(%a): address not from DpsMalloc() at %s:%d.", address, filename, fileline);*/ EF_Print("DpsFree(%a): address not from DpsMalloc() at %s:%d.\n", address, filename, fileline); release(); return; } /* EF_Print("DpsFree(%a): slot=%a\n", address, slot); */ if ( slot->mode != ALLOCATED ) { if ( internalUse && slot->mode == INTERNAL_USE ) /* Do nothing. */; else { if (slot->mode == FREE) EF_Print("DpsFree(%a) FREE\n", address); if (slot->mode == PROTECTED) EF_Print("DpsFree(%a) PROTECTED\n", address); if (slot->mode == INTERNAL_USE) EF_Print("DpsFree(%a) INTERNAL_USE\n", address); if (slot->mode == NOT_IN_USE) EF_Print("DpsFree(%a) NOT_IN_USE\n", address); EF_Abort("DpsFree(%a): freeing free memory at %s:%d.", address, filename, fileline); } } 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(); /* fprintf(stderr, "DpsFree Done\n");*/ }
/* * 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 __linux__ { struct rlimit nolimit = { RLIM_INFINITY, RLIM_INFINITY }; int rc = setrlimit( RLIMIT_AS, &nolimit); } #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; /* if (slotCount > 1) DpsSort(allocationList, slotCount, sizeof(Slot), (qsort_cmp)cmp_Slot);*/ release(); #ifdef HAVE_PTHREAD if (!semEnabled) { semEnabled = 1; #if USE_DPS_MUTEX InitMutex(&ef_mutex); #else if (sem_init(&EF_sem, 0, 1) < 0) { semEnabled = 0; } #endif } #endif }