Ejemplo n.º 1
0
static void release(void) {
#ifdef	HAVE_PTHREAD
    /* 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 /* HAVE_PTHREAD */
}
Ejemplo n.º 2
0
static void
release()
{
#ifdef	USE_SEMAPHORE
	/* Are we using a semaphore? */
	if (!semEnabled)
		return;
	if (sem_post(&EF_sem) < 0)
	  EF_InternalError("Failed to post the semaphore.");
#endif /* USE_SEMAPHORE */
}
Ejemplo n.º 3
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.
 */
static void * _DpsMemalign(size_t alignment, size_t userSize, const char *filename, size_t fileline) {
    register Slot   *slot, *slot2;
    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 && strcmp(filename, "efence.c"))
        EF_Abort("Allocating 0 bytes, probably a bug at %s:%d.", filename, fileline);

    /*
     * 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.
     *
     */
    slot = allocationList;
    slot2 = &slot[slotCount - 1];
    while (slot <= slot2) {
        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. */
        }

        if ( slot2->mode == FREE
                && slot2->internalSize >= internalSize ) {
            if ( !fullSlot
                    ||slot2->internalSize < fullSlot->internalSize) {
                fullSlot = slot2;
                if ( slot2->internalSize == internalSize
                        && emptySlots[0] )
                    break;	/* All done, */
            }
        }
        else if ( slot2->mode == NOT_IN_USE ) {
            if ( !emptySlots[0] )
                emptySlots[0] = slot2;
            else if ( !emptySlots[1] )
                emptySlots[1] = slot2;
            else if ( fullSlot
                      && fullSlot->internalSize == internalSize )
                break;	/* All done. */
        }
        slot++;
        slot2--;
    }

    /*
    	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;
    fullSlot->fileline = fileline;
    dps_strncpy(fullSlot->filename, filename, DPS_FILENAMELEN);

    /*	if (slotCount > 1) DpsSort(allocationList, slotCount, sizeof(Slot), (qsort_cmp)cmp_Slot);*/

    /*
     * 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();

    /*	if (address == 0x292d3000) {
    	  int r = 1 / 0;
    	  printf("Error r:%d\n");
    	}*/

    /*
    	fprintf(stderr, " -- allocated: %p @ %s:%d\n", address, filename, fileline);
    */
    return address;
}