• Main Page
  • Related Pages
  • Modules
  • Namespaces
  • Data Structures
  • Files
  • File List
  • Globals

contrib/maloc/src/efence/efence.c

00001 /*
00002  * Electric Fence - Red-Zone memory allocator.
00003  * Bruce Perens, 1988, 1993
00004  * 
00005  * This is a special version of malloc() and company for debugging software
00006  * that is suspected of overrunning or underrunning the boundaries of a
00007  * malloc buffer, or touching free memory.
00008  *
00009  * It arranges for each malloc buffer to be followed (or preceded)
00010  * in the address space by an inaccessable virtual memory page,
00011  * and for free memory to be inaccessable. If software touches the
00012  * inaccessable page, it will get an immediate segmentation
00013  * fault. It is then trivial to uncover the offending code using a debugger.
00014  *
00015  * An advantage of this product over most malloc debuggers is that this one
00016  * detects reading out of bounds as well as writing, and this one stops on
00017  * the exact instruction that causes the error, rather than waiting until the
00018  * next boundary check.
00019  *
00020  * There is one product that debugs malloc buffer overruns
00021  * better than Electric Fence: "Purify" from Purify Systems, and that's only
00022  * a small part of what Purify does. I'm not affiliated with Purify, I just
00023  * respect a job well done.
00024  *
00025  * This version of malloc() should not be linked into production software,
00026  * since it tremendously increases the time and memory overhead of malloc().
00027  * Each malloc buffer will consume a minimum of two virtual memory pages,
00028  * this is 16 kilobytes on many systems. On some systems it will be necessary
00029  * to increase the amount of swap space in order to debug large programs that
00030  * perform lots of allocation, because of the per-buffer overhead.
00031  */
00032 #include "efence.h"
00033 #include <stdlib.h>
00034 #include <unistd.h>
00035 #include <memory.h>
00036 #include <string.h>
00037 
00038 #ifdef     malloc
00039 #undef     malloc
00040 #endif
00041 
00042 #ifdef     calloc
00043 #undef     calloc
00044 #endif
00045 
00046 static const char     version[] = "\n  Electric Fence 2.0.5"
00047  " Copyright (C) 1987-1995 Bruce Perens.\n";
00048 
00049 /*
00050  * MEMORY_CREATION_SIZE is the amount of memory to get from the operating
00051  * system at one time. We'll break that memory down into smaller pieces for
00052  * malloc buffers. One megabyte is probably a good value.
00053  */
00054 #define                          MEMORY_CREATION_SIZE  1024 * 1024
00055 
00056 /*
00057  * Enum Mode indicates the status of a malloc buffer.
00058  */
00059 enum _Mode {
00060            NOT_IN_USE = 0,       /* Available to represent a malloc buffer. */
00061            FREE,                 /* A free buffer. */
00062            ALLOCATED, /* A buffer that is in use. */
00063            PROTECTED, /* A freed buffer that can not be allocated again. */
00064            INTERNAL_USE          /* A buffer used internally by malloc(). */
00065 };
00066 typedef enum _Mode    Mode;
00067 
00068 /*
00069  * Struct Slot contains all of the information about a malloc buffer except
00070  * for the contents of its memory.
00071  */
00072 struct _Slot {
00073            void *                userAddress;
00074            void *                internalAddress;
00075            size_t                userSize;
00076            size_t                internalSize;
00077            Mode                  mode;
00078 };
00079 typedef struct _Slot  Slot;
00080 
00081 /*
00082  * EF_ALIGNMENT is a global variable used to control the default alignment
00083  * of buffers returned by malloc(), calloc(), and realloc(). It is all-caps
00084  * so that its name matches the name of the environment variable that is used
00085  * to set it. This gives the programmer one less name to remember.
00086  * If the value is -1, it will be set from the environment or sizeof(int)
00087  * at run time.
00088  */
00089 int                   EF_ALIGNMENT = -1;
00090 
00091 /*
00092  * EF_PROTECT_FREE is a global variable used to control the disposition of
00093  * memory that is released using free(). It is all-caps so that its name
00094  * matches the name of the environment variable that is used to set it.
00095  * If its value is greater non-zero, memory released by free is made
00096  * inaccessable and never allocated again. Any software that touches free
00097  * memory will then get a segmentation fault. If its value is zero, freed
00098  * memory will be available for reallocation, but will still be inaccessable
00099  * until it is reallocated.
00100  * If the value is -1, it will be set from the environment or to 0 at run-time.
00101  */
00102 int                   EF_PROTECT_FREE = -1;
00103 
00104 /*
00105  * EF_PROTECT_BELOW is used to modify the behavior of the allocator. When
00106  * its value is non-zero, the allocator will place an inaccessable page
00107  * immediately _before_ the malloc buffer in the address space, instead
00108  * of _after_ it. Use this to detect malloc buffer under-runs, rather than
00109  * over-runs. It won't detect both at the same time, so you should test your
00110  * software twice, once with this value clear, and once with it set.
00111  * If the value is -1, it will be set from the environment or to zero at
00112  * run-time
00113  */
00114 int                   EF_PROTECT_BELOW = -1;
00115 
00116 /*
00117  * EF_ALLOW_MALLOC_0 is set if Electric Fence is to allow malloc(0). I
00118  * trap malloc(0) by default because it is a common source of bugs.
00119  */
00120 int                   EF_ALLOW_MALLOC_0 = -1;
00121 
00122 /*
00123  * allocationList points to the array of slot structures used to manage the
00124  * malloc arena.
00125  */
00126 static Slot *                    allocationList = 0;
00127 
00128 /*
00129  * allocationListSize is the size of the allocation list. This will always
00130  * be a multiple of the page size.
00131  */
00132 static size_t                    allocationListSize = 0;
00133 
00134 /*
00135  * slotCount is the number of Slot structures in allocationList.
00136  */
00137 static size_t                    slotCount = 0;
00138 
00139 /*
00140  * unUsedSlots is the number of Slot structures that are currently available
00141  * to represent new malloc buffers. When this number gets too low, we will
00142  * create new slots.
00143  */
00144 static size_t                    unUsedSlots = 0;
00145 
00146 /*
00147  * slotsPerPage is the number of slot structures that fit in a virtual
00148  * memory page.
00149  */
00150 static size_t                    slotsPerPage = 0;
00151 
00152 /*
00153  * internalUse is set when allocating and freeing the allocatior-internal
00154  * data structures.
00155  */
00156 static int            internalUse = 0;
00157 
00158 /*
00159  * noAllocationListProtection is set to tell malloc() and free() not to
00160  * manipulate the protection of the allocation list. This is only set in
00161  * realloc(), which does it to save on slow system calls, and in
00162  * allocateMoreSlots(), which does it because it changes the allocation list.
00163  */
00164 static int            noAllocationListProtection = 0;
00165 
00166 /*
00167  * bytesPerPage is set at run-time to the number of bytes per virtual-memory
00168  * page, as returned by Page_Size().
00169  */
00170 static size_t                    bytesPerPage = 0;
00171 
00172 /*
00173  * internalError is called for those "shouldn't happen" errors in the
00174  * allocator.
00175  */
00176 static void
00177 internalError(void)
00178 {
00179            EF_Abort("Internal error in allocator.");
00180 }
00181 
00182 /*
00183  * initialize sets up the memory allocation arena and the run-time
00184  * configuration information.
00185  */
00186 static void
00187 initialize(void)
00188 {
00189            size_t     size = MEMORY_CREATION_SIZE;
00190            size_t     slack;
00191            char *     string;
00192            Slot *     slot;
00193 
00194            EF_Print(version);
00195 
00196            /*
00197             * Import the user's environment specification of the default
00198             * alignment for malloc(). We want that alignment to be under
00199             * user control, since smaller alignment lets us catch more bugs,
00200             * however some software will break if malloc() returns a buffer
00201             * that is not word-aligned.
00202             *
00203             * I would like
00204             * alignment to be zero so that we could catch all one-byte
00205             * overruns, however if malloc() is asked to allocate an odd-size
00206             * buffer and returns an address that is not word-aligned, or whose
00207             * size is not a multiple of the word size, software breaks.
00208             * This was the case with the Sun string-handling routines,
00209             * which can do word fetches up to three bytes beyond the end of a
00210             * string. I handle this problem in part by providing
00211             * byte-reference-only versions of the string library functions, but
00212             * there are other functions that break, too. Some in X Windows, one
00213             * in Sam Leffler's TIFF library, and doubtless many others.
00214             */
00215            if ( EF_ALIGNMENT == -1 ) {
00216                       if ( (string = getenv("EF_ALIGNMENT")) != 0 )
00217                                  EF_ALIGNMENT = (size_t)atoi(string);
00218                       else
00219                                  EF_ALIGNMENT = sizeof(int);
00220            }
00221 
00222            /*
00223             * See if the user wants to protect the address space below a buffer,
00224             * rather than that above a buffer.
00225             */
00226            if ( EF_PROTECT_BELOW == -1 ) {
00227                       if ( (string = getenv("EF_PROTECT_BELOW")) != 0 )
00228                                  EF_PROTECT_BELOW = (atoi(string) != 0);
00229                       else
00230                                  EF_PROTECT_BELOW = 0;
00231            }
00232 
00233            /*
00234             * See if the user wants to protect memory that has been freed until
00235             * the program exits, rather than until it is re-allocated.
00236             */
00237            if ( EF_PROTECT_FREE == -1 ) {
00238                       if ( (string = getenv("EF_PROTECT_FREE")) != 0 )
00239                                  EF_PROTECT_FREE = (atoi(string) != 0);
00240                       else
00241                                  EF_PROTECT_FREE = 0;
00242            }
00243 
00244            /*
00245             * See if the user wants to allow malloc(0).
00246             */
00247            if ( EF_ALLOW_MALLOC_0 == -1 ) {
00248                       if ( (string = getenv("EF_ALLOW_MALLOC_0")) != 0 )
00249                                  EF_ALLOW_MALLOC_0 = (atoi(string) != 0);
00250                       else
00251                                  EF_ALLOW_MALLOC_0 = 0;
00252            }
00253 
00254            /*
00255             * Get the run-time configuration of the virtual memory page size.
00256             */
00257            bytesPerPage = Page_Size();
00258 
00259            /*
00260             * Figure out how many Slot structures to allocate at one time.
00261             */
00262            slotCount = slotsPerPage = bytesPerPage / sizeof(Slot);
00263            allocationListSize = bytesPerPage;
00264 
00265            if ( allocationListSize > size )
00266                       size = allocationListSize;
00267 
00268            if ( (slack = size % bytesPerPage) != 0 )
00269                       size += bytesPerPage - slack;
00270 
00271            /*
00272             * Allocate memory, and break it up into two malloc buffers. The
00273             * first buffer will be used for Slot structures, the second will
00274             * be marked free.
00275             */
00276            slot = allocationList = (Slot *)Page_Create(size);
00277            memset((char *)allocationList, 0, allocationListSize);
00278 
00279            slot[0].internalSize = slot[0].userSize = allocationListSize;
00280            slot[0].internalAddress = slot[0].userAddress = allocationList;
00281            slot[0].mode = INTERNAL_USE;
00282            if ( size > allocationListSize ) {
00283                       slot[1].internalAddress = slot[1].userAddress
00284                        = ((char *)slot[0].internalAddress) + slot[0].internalSize;
00285                       slot[1].internalSize
00286                        = slot[1].userSize = size - slot[0].internalSize;
00287                       slot[1].mode = FREE;
00288            }
00289 
00290            /*
00291             * Deny access to the free page, so that we will detect any software
00292             * that treads upon free memory.
00293             */
00294            Page_DenyAccess(slot[1].internalAddress, slot[1].internalSize);
00295 
00296            /*
00297             * Account for the two slot structures that we've used.
00298             */
00299            unUsedSlots = slotCount - 2;
00300 }
00301 
00302 /*
00303  * allocateMoreSlots is called when there are only enough slot structures
00304  * left to support the allocation of a single malloc buffer.
00305  */
00306 static void
00307 allocateMoreSlots(void)
00308 {
00309            size_t     newSize = allocationListSize + bytesPerPage;
00310            void *     newAllocation;
00311            void *     oldAllocation = allocationList;
00312 
00313            Page_AllowAccess(allocationList, allocationListSize);
00314            noAllocationListProtection = 1;
00315            internalUse = 1;
00316 
00317            newAllocation = malloc(newSize);
00318            memcpy(newAllocation, allocationList, allocationListSize);
00319            memset(&(((char *)newAllocation)[allocationListSize]), 0, bytesPerPage);
00320 
00321            allocationList = (Slot *)newAllocation;
00322            allocationListSize = newSize;
00323            slotCount += slotsPerPage;
00324            unUsedSlots += slotsPerPage;
00325 
00326            free(oldAllocation);
00327 
00328            /*
00329             * Keep access to the allocation list open at this point, because
00330             * I am returning to memalign(), which needs that access.
00331             */
00332            noAllocationListProtection = 0;
00333            internalUse = 0;
00334 }
00335 
00336 /*
00337  * This is the memory allocator. When asked to allocate a buffer, allocate
00338  * it in such a way that the end of the buffer is followed by an inaccessable
00339  * memory page. If software overruns that buffer, it will touch the bad page
00340  * and get an immediate segmentation fault. It's then easy to zero in on the
00341  * offending code with a debugger.
00342  *
00343  * There are a few complications. If the user asks for an odd-sized buffer,
00344  * we would have to have that buffer start on an odd address if the byte after
00345  * the end of the buffer was to be on the inaccessable page. Unfortunately,
00346  * there is lots of software that asks for odd-sized buffers and then
00347  * requires that the returned address be word-aligned, or the size of the
00348  * buffer be a multiple of the word size. An example are the string-processing
00349  * functions on Sun systems, which do word references to the string memory
00350  * and may refer to memory up to three bytes beyond the end of the string.
00351  * For this reason, I take the alignment requests to memalign() and valloc()
00352  * seriously, and 
00353  * 
00354  * Electric Fence wastes lots of memory. I do a best-fit allocator here
00355  * so that it won't waste even more. It's slow, but thrashing because your
00356  * working set is too big for a system's RAM is even slower. 
00357  */
00358 extern C_LINKAGE void *
00359 memalign(size_t alignment, size_t userSize)
00360 {
00361            register Slot *       slot;
00362            register size_t       count;
00363            Slot *                fullSlot = 0;
00364            Slot *                emptySlots[2];
00365            size_t                internalSize;
00366            size_t                slack;
00367            char *                address;
00368 
00369            if ( allocationList == 0 )
00370                       initialize();
00371 
00372            if ( userSize == 0 && !EF_ALLOW_MALLOC_0 )
00373                       EF_Abort("Allocating 0 bytes, probably a bug.");
00374 
00375            /*
00376             * If EF_PROTECT_BELOW is set, all addresses returned by malloc()
00377             * and company will be page-aligned.
00378             */
00379            if ( !EF_PROTECT_BELOW && alignment > 1 ) {
00380                       if ( (slack = userSize % alignment) != 0 )
00381                                  userSize += alignment - slack;
00382            }
00383 
00384            /*
00385             * The internal size of the buffer is rounded up to the next page-size
00386             * boudary, and then we add another page's worth of memory for the
00387             * dead page.
00388             */
00389            internalSize = userSize + bytesPerPage;
00390            if ( (slack = internalSize % bytesPerPage) != 0 )
00391                       internalSize += bytesPerPage - slack;
00392 
00393            /*
00394             * These will hold the addresses of two empty Slot structures, that
00395             * can be used to hold information for any memory I create, and any
00396             * memory that I mark free.
00397             */
00398            emptySlots[0] = 0;
00399            emptySlots[1] = 0;
00400 
00401            /*
00402             * The internal memory used by the allocator is currently
00403             * inaccessable, so that errant programs won't scrawl on the
00404             * allocator's arena. I'll un-protect it here so that I can make
00405             * a new allocation. I'll re-protect it before I return.
00406             */
00407            if ( !noAllocationListProtection )
00408                       Page_AllowAccess(allocationList, allocationListSize);
00409 
00410            /*
00411             * If I'm running out of empty slots, create some more before
00412             * I don't have enough slots left to make an allocation.
00413             */
00414            if ( !internalUse && unUsedSlots < 7 ) {
00415                       allocateMoreSlots();
00416            }
00417            
00418            /*
00419             * Iterate through all of the slot structures. Attempt to find a slot
00420             * containing free memory of the exact right size. Accept a slot with
00421             * more memory than we want, if the exact right size is not available.
00422             * Find two slot structures that are not in use. We will need one if
00423             * we split a buffer into free and allocated parts, and the second if
00424             * we have to create new memory and mark it as free.
00425             *
00426             */
00427            
00428            for ( slot = allocationList, count = slotCount ; count > 0; count-- ) {
00429                       if ( slot->mode == FREE
00430                        && slot->internalSize >= internalSize ) {
00431                                  if ( !fullSlot
00432                                   ||slot->internalSize < fullSlot->internalSize){
00433                                             fullSlot = slot;
00434                                             if ( slot->internalSize == internalSize
00435                                              && emptySlots[0] )
00436                                                        break;     /* All done, */
00437                                  }
00438                       }
00439                       else if ( slot->mode == NOT_IN_USE ) {
00440                                  if ( !emptySlots[0] )
00441                                             emptySlots[0] = slot;
00442                                  else if ( !emptySlots[1] )
00443                                             emptySlots[1] = slot;
00444                                  else if ( fullSlot
00445                                   && fullSlot->internalSize == internalSize )
00446                                             break;     /* All done. */
00447                       }
00448                       slot++;
00449            }
00450            if ( !emptySlots[0] )
00451                       internalError();
00452 
00453            if ( !fullSlot ) {
00454                       /*
00455                        * I get here if I haven't been able to find a free buffer
00456                        * with all of the memory I need. I'll have to create more
00457                        * memory. I'll mark it all as free, and then split it into
00458                        * free and allocated portions later.
00459                        */
00460                       size_t     chunkSize = MEMORY_CREATION_SIZE;
00461 
00462                       if ( !emptySlots[1] )
00463                                  internalError();
00464 
00465                       if ( chunkSize < internalSize )
00466                                  chunkSize = internalSize;
00467 
00468                       if ( (slack = chunkSize % bytesPerPage) != 0 )
00469                                  chunkSize += bytesPerPage - slack;
00470 
00471                       /* Use up one of the empty slots to make the full slot. */
00472                       fullSlot = emptySlots[0];
00473                       emptySlots[0] = emptySlots[1];
00474                       fullSlot->internalAddress = Page_Create(chunkSize);
00475                       fullSlot->internalSize = chunkSize;
00476                       fullSlot->mode = FREE;
00477                       unUsedSlots--;
00478            }
00479 
00480            /*
00481             * If I'm allocating memory for the allocator's own data structures,
00482             * mark it INTERNAL_USE so that no errant software will be able to
00483             * free it.
00484             */
00485            if ( internalUse )
00486                       fullSlot->mode = INTERNAL_USE;
00487            else
00488                       fullSlot->mode = ALLOCATED;
00489 
00490            /*
00491             * If the buffer I've found is larger than I need, split it into
00492             * an allocated buffer with the exact amount of memory I need, and
00493             * a free buffer containing the surplus memory.
00494             */
00495            if ( fullSlot->internalSize > internalSize ) {
00496                       emptySlots[0]->internalSize
00497                        = fullSlot->internalSize - internalSize;
00498                       emptySlots[0]->internalAddress
00499                        = ((char *)fullSlot->internalAddress) + internalSize;
00500                       emptySlots[0]->mode = FREE;
00501                       fullSlot->internalSize = internalSize;
00502                       unUsedSlots--;
00503            }
00504 
00505            if ( !EF_PROTECT_BELOW ) {
00506                       /*
00507                        * Arrange the buffer so that it is followed by an inaccessable
00508                        * memory page. A buffer overrun that touches that page will
00509                        * cause a segmentation fault.
00510                        */
00511                       address = (char *)fullSlot->internalAddress;
00512 
00513                       /* Set up the "live" page. */
00514                       if ( internalSize - bytesPerPage > 0 )
00515                                             Page_AllowAccess(
00516                                              fullSlot->internalAddress
00517                                             ,internalSize - bytesPerPage);
00518                                  
00519                       address += internalSize - bytesPerPage;
00520 
00521                       /* Set up the "dead" page. */
00522                       if ( EF_PROTECT_FREE )
00523                                  Page_Delete(address, bytesPerPage);
00524                       else
00525                                  Page_DenyAccess(address, bytesPerPage);
00526 
00527                       /* Figure out what address to give the user. */
00528                       address -= userSize;
00529            }
00530            else {     /* EF_PROTECT_BELOW != 0 */
00531                       /*
00532                        * Arrange the buffer so that it is preceded by an inaccessable
00533                        * memory page. A buffer underrun that touches that page will
00534                        * cause a segmentation fault.
00535                        */
00536                       address = (char *)fullSlot->internalAddress;
00537 
00538                       /* Set up the "dead" page. */
00539                       if ( EF_PROTECT_FREE )
00540                                  Page_Delete(address, bytesPerPage);
00541                       else
00542                                  Page_DenyAccess(address, bytesPerPage);
00543                                  
00544                       address += bytesPerPage;
00545 
00546                       /* Set up the "live" page. */
00547                       if ( internalSize - bytesPerPage > 0 )
00548                                  Page_AllowAccess(address, internalSize - bytesPerPage);
00549            }
00550 
00551            fullSlot->userAddress = address;
00552            fullSlot->userSize = userSize;
00553 
00554            /*
00555             * Make the pool's internal memory inaccessable, so that the program
00556             * being debugged can't stomp on it.
00557             */
00558            if ( !internalUse )
00559                       Page_DenyAccess(allocationList, allocationListSize);
00560 
00561            return address;
00562 }
00563 
00564 /*
00565  * Find the slot structure for a user address.
00566  */
00567 static Slot *
00568 slotForUserAddress(void * address)
00569 {
00570            register Slot *       slot = allocationList;
00571            register size_t       count = slotCount;
00572            
00573            for ( ; count > 0; count-- ) {
00574                       if ( slot->userAddress == address )
00575                                  return slot;
00576                       slot++;
00577            }
00578 
00579            return 0;
00580 }
00581 
00582 /*
00583  * Find the slot structure for an internal address.
00584  */
00585 static Slot *
00586 slotForInternalAddress(void * address)
00587 {
00588            register Slot *       slot = allocationList;
00589            register size_t       count = slotCount;
00590            
00591            for ( ; count > 0; count-- ) {
00592                       if ( slot->internalAddress == address )
00593                                  return slot;
00594                       slot++;
00595            }
00596            return 0;
00597 }
00598 
00599 /*
00600  * Given the internal address of a buffer, find the buffer immediately
00601  * before that buffer in the address space. This is used by free() to
00602  * coalesce two free buffers into one.
00603  */
00604 static Slot *
00605 slotForInternalAddressPreviousTo(void * address)
00606 {
00607            register Slot *       slot = allocationList;
00608            register size_t       count = slotCount;
00609            
00610            for ( ; count > 0; count-- ) {
00611                       if ( ((char *)slot->internalAddress)
00612                        + slot->internalSize == (char*)address ) 
00613                 /* M. HOLST: added 2nd (char*) cast above... */
00614                                  return slot;
00615                       slot++;
00616            }
00617            return 0;
00618 }
00619 
00620 extern C_LINKAGE void
00621 free(void * address)
00622 {
00623            Slot *     slot;
00624            Slot *     previousSlot = 0;
00625            Slot *     nextSlot = 0;
00626 
00627            if ( address == 0 )
00628                       return;
00629 
00630            if ( allocationList == 0 )
00631                       EF_Abort("free() called before first malloc().");
00632 
00633            if ( !noAllocationListProtection )
00634                       Page_AllowAccess(allocationList, allocationListSize);
00635 
00636            slot = slotForUserAddress(address);
00637 
00638            if ( !slot )
00639                       EF_Abort("free(%a): address not from malloc().", address);
00640 
00641            if ( slot->mode != ALLOCATED ) {
00642                       if ( internalUse && slot->mode == INTERNAL_USE )
00643                                  /* Do nothing. */;
00644                       else {
00645                                  EF_Abort(
00646                                   "free(%a): freeing free memory."
00647                                  ,address);
00648                       }
00649            }
00650 
00651            if ( EF_PROTECT_FREE )
00652                       slot->mode = PROTECTED;
00653            else
00654                       slot->mode = FREE;
00655 
00656            previousSlot = slotForInternalAddressPreviousTo(slot->internalAddress);
00657            nextSlot = slotForInternalAddress(
00658             ((char *)slot->internalAddress) + slot->internalSize);
00659 
00660            if ( previousSlot
00661             && (previousSlot->mode == FREE || previousSlot->mode == PROTECTED) ) {
00662                       /* Coalesce previous slot with this one. */
00663                       previousSlot->internalSize += slot->internalSize;
00664                       if ( EF_PROTECT_FREE )
00665                                  previousSlot->mode = PROTECTED;
00666 
00667                       slot->internalAddress = slot->userAddress = 0;
00668                       slot->internalSize = slot->userSize = 0;
00669                       slot->mode = NOT_IN_USE;
00670                       slot = previousSlot;
00671                       unUsedSlots++;
00672            }
00673            if ( nextSlot
00674             && (nextSlot->mode == FREE || nextSlot->mode == PROTECTED) ) {
00675                       /* Coalesce next slot with this one. */
00676                       slot->internalSize += nextSlot->internalSize;
00677                       nextSlot->internalAddress = nextSlot->userAddress = 0;
00678                       nextSlot->internalSize = nextSlot->userSize = 0;
00679                       nextSlot->mode = NOT_IN_USE;
00680                       unUsedSlots++;
00681            }
00682 
00683            slot->userAddress = slot->internalAddress;
00684            slot->userSize = slot->internalSize;
00685 
00686            /*
00687             * Free memory is _always_ set to deny access. When EF_PROTECT_FREE
00688             * is true, free memory is never reallocated, so it remains access
00689             * denied for the life of the process. When EF_PROTECT_FREE is false, 
00690             * the memory may be re-allocated, at which time access to it will be
00691             * allowed again.
00692             *
00693             * Some operating systems allow munmap() with single-page resolution,
00694             * and allow you to un-map portions of a region, rather than the
00695             * entire region that was mapped with mmap(). On those operating
00696             * systems, we can release protected free pages with Page_Delete(),
00697             * in the hope that the swap space attached to those pages will be
00698             * released as well.
00699             */
00700            if ( EF_PROTECT_FREE )
00701                Page_Delete(slot->internalAddress, slot->internalSize);
00702            else
00703                Page_DenyAccess(slot->internalAddress, slot->internalSize);
00704 
00705            if ( !noAllocationListProtection )
00706                       Page_DenyAccess(allocationList, allocationListSize);
00707 }
00708 
00709 extern C_LINKAGE void *
00710 realloc(void * oldBuffer, size_t newSize)
00711 {
00712            void *     newBuffer = malloc(newSize);
00713 
00714            if ( oldBuffer ) {
00715                       size_t     size;
00716                       Slot *     slot;
00717 
00718                       Page_AllowAccess(allocationList, allocationListSize);
00719                       noAllocationListProtection = 1;
00720                       
00721                       slot = slotForUserAddress(oldBuffer);
00722 
00723                       if ( slot == 0 )
00724                                  EF_Abort(
00725                                   "realloc(%a, %d): address not from malloc()."
00726                                  ,oldBuffer
00727                                  ,newSize);
00728 
00729                       if ( newSize < (size = slot->userSize) )
00730                                  size = newSize;
00731 
00732                       if ( size > 0 )
00733                                  memcpy(newBuffer, oldBuffer, size);
00734 
00735                       free(oldBuffer);
00736                       noAllocationListProtection = 0;
00737                       Page_DenyAccess(allocationList, allocationListSize);
00738 
00739                       if ( size < newSize )
00740                                  memset(&(((char *)newBuffer)[size]), 0, newSize - size);
00741                       
00742                       /* Internal memory was re-protected in free() */
00743            }
00744 
00745            return newBuffer;
00746 }
00747 
00748 extern C_LINKAGE void *
00749 malloc(size_t size)
00750 {
00751            if ( allocationList == 0 )
00752                       initialize();         /* This sets EF_ALIGNMENT */
00753 
00754            return memalign(EF_ALIGNMENT, size);
00755 }
00756 
00757 extern C_LINKAGE void *
00758 calloc(size_t nelem, size_t elsize)
00759 {
00760            size_t     size = nelem * elsize;
00761            void *     allocation = malloc(size);
00762 
00763            memset(allocation, 0, size);
00764            return allocation;
00765 }
00766 
00767 /*
00768  * This will catch more bugs if you remove the page alignment, but it
00769  * will break some software.
00770  */
00771 extern C_LINKAGE void *
00772 valloc (size_t size)
00773 {
00774            return memalign(bytesPerPage, size);
00775 }
00776 
00777 #ifdef __hpux
00778 /*
00779  * HP-UX 8/9.01 strcat reads a word past source when doing unaligned copies!
00780  * Work around it here. The bug report has been filed with HP.
00781  */
00782 char *strcat(char *d, const char *s)
00783 {
00784            strcpy(d+strlen(d), s);
00785            return d;
00786 }
00787 #endif

Generated on Wed Oct 20 2010 11:12:14 for APBS by  doxygen 1.7.2