Ejemplo n.º 1
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;
}
Ejemplo n.º 2
0
// load in an image from the filename, and store it in IPAGE. 
// if there were any errors, return a NULL
IPAGE *
iff_file_load_page(
	char * filename
)
{
    int x,y;
    int plane;
    int handle_x = 0;
    int handle_y = 1;
    BLOCKHEADER bh;
    IFF_BMHD bmhd;
    FILE * fp;
    COLEL * palette = NULL;
    IPAGE * iff_page = NULL;

    fp = fopen(filename, "r");

    // skip the container header...
    (void)endian_little_read_32(fp);
    (void)endian_little_read_32(fp);
    (void)endian_little_read_32(fp);

    bmhd.width=0;
    bmhd.height=0;
    // parse the file...
    iff_read_header(fp, &bh);
    while (bh.size)
    {
	/*
	printf( "%c%c%c%c\n",
		(bh.name>>24)&0xff,
		(bh.name>>16)&0xff,
		(bh.name>>8)&0xff,
		(bh.name)&0xff );
	*/
	switch (bh.name)
	{
	case(IFF_BLOCK_BMHD):
	    //printf("Bitmap header\n");

	    bmhd.width   = endian_little_read_16(fp) & 0x00ffff;
	    bmhd.height  = endian_little_read_16(fp) & 0x00ffff;
	    bmhd.x       = endian_little_read_16(fp) & 0x00ffff;
	    bmhd.y       = endian_little_read_16(fp) & 0x00ffff;
	    bmhd.planes  = endian_little_read_8(fp)  & 0x0000ff;
	    bmhd.masking = endian_little_read_8(fp)  & 0x0000ff;
	    bmhd.comp    = endian_little_read_8(fp)  & 0x0000ff;
	    (void)endian_little_read_8(fp);  // pad.  not used.  -- store 0
	    bmhd.xparent = endian_little_read_16(fp) & 0x00ffff;
	    bmhd.xaspect = endian_little_read_8(fp)  & 0x0000ff;
	    bmhd.yaspect = endian_little_read_8(fp)  & 0x0000ff;
	    bmhd.pwidth  = endian_little_read_16(fp) & 0x00ffff;
	    bmhd.pheight = endian_little_read_16(fp) & 0x00ffff;

	    /*
	    printf("image is %d by %d  (%d %d)  (%d %d)\n",
			bmhd.width, bmhd.height,
			bmhd.pwidth, bmhd.pheight,
			bmhd.xaspect, bmhd.yaspect);
	    printf("%d planes %d %s\n",
			bmhd.planes, bmhd.masking, 
			(bmhd.comp==1)?"RLE":"?");
	    */
	    break;

	case(IFF_BLOCK_GRAB):
	    handle_x = endian_little_read_16(fp);
	    handle_y = endian_little_read_16(fp);
	    break;

	case(IFF_BLOCK_CMAP):
	    palette = (COLEL *) malloc(bh.size*sizeof(COLEL));
	    for (x=0 ; x<bh.size/3 ; x++)
	    {
		palette[x].r = endian_little_read_8(fp)&0x00ff;
		palette[x].g = endian_little_read_8(fp)&0x00ff;
		palette[x].b = endian_little_read_8(fp)&0x00ff;
	    }
	    break;

	case(IFF_BLOCK_CRNG):
	    // Electronic Arts Deluxe Paint color range
	    (void)endian_little_read_16(fp); // pad -- store 0
	    (void)endian_little_read_16(fp); // rate
	    (void)endian_little_read_16(fp); // active -- 1 means cycle them
	    (void)endian_little_read_8(fp);  // start range
	    (void)endian_little_read_8(fp);  // end range
	    break;

	case(IFF_BLOCK_CCRT):
	    // Commodore Graphicraft color range
	    (void)endian_little_read_16(fp); // direction  0=stop 1=forw -1=back
	    (void)endian_little_read_8(fp);  // start range
	    (void)endian_little_read_8(fp);  // end range
	    (void)endian_little_read_32(fp); // seconds
	    (void)endian_little_read_32(fp); // microseconds
	    (void)endian_little_read_16(fp); // pad -- store 0
	    break;

	case(IFF_BLOCK_BODY):
	    //printf("Image Body %d (%d colors)\n", bh.size, 1<<bmhd.planes);

	    iff_page = Page_Create(bmhd.width, bmhd.height, 1<<bmhd.planes);

	    iff_page->handle_x = handle_x;
	    iff_page->handle_y = handle_y;

	    // at this point, we should have a palette, but just in case,
	    // we'll put an if around this anyway...
	    if (palette)
	    {
		free(iff_page->palette);
		iff_page->palette = palette;
	    }

	    // now load in the bitmap data...

	    for (y=0 ; y < iff_page->h ; y++)
	    {
		// decode image data

		for ( plane = 0 ; plane < bmhd.planes ; plane++)
		{
		    if (1) //bmhd.comp==1)
		    {
			iff_decode_plane(fp, iff_page->pimage, y, 
						iff_page->w, plane);
		    } else {
			iff_load_in_plane(fp, iff_page->pimage, y, 
						iff_page->w, plane);
		    }
		}

		// and the mask...
		if (bmhd.masking == 1)
		{
		    iff_decode_plane(fp, iff_page->alpha, y, iff_page->w, 1);
		}
	    }

	    return iff_page;
	    break;

	default:
	    iff_skip_block(fp, &bh);
	}


	iff_read_header(fp, &bh);
    }

    fclose(fp);
    return iff_page;
}
Ejemplo n.º 3
0
/*
 * 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
}