Annotation of embedaddon/ntp/ElectricFence/efence.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Electric Fence - Red-Zone memory allocator.
! 3: * Bruce Perens, 1988, 1993
! 4: *
! 5: * This is a special version of malloc() and company for debugging software
! 6: * that is suspected of overrunning or underrunning the boundaries of a
! 7: * malloc buffer, or touching free memory.
! 8: *
! 9: * It arranges for each malloc buffer to be followed (or preceded)
! 10: * in the address space by an inaccessable virtual memory page,
! 11: * and for free memory to be inaccessable. If software touches the
! 12: * inaccessable page, it will get an immediate segmentation
! 13: * fault. It is then trivial to uncover the offending code using a debugger.
! 14: *
! 15: * An advantage of this product over most malloc debuggers is that this one
! 16: * detects reading out of bounds as well as writing, and this one stops on
! 17: * the exact instruction that causes the error, rather than waiting until the
! 18: * next boundary check.
! 19: *
! 20: * There is one product that debugs malloc buffer overruns
! 21: * better than Electric Fence: "Purify" from Purify Systems, and that's only
! 22: * a small part of what Purify does. I'm not affiliated with Purify, I just
! 23: * respect a job well done.
! 24: *
! 25: * This version of malloc() should not be linked into production software,
! 26: * since it tremendously increases the time and memory overhead of malloc().
! 27: * Each malloc buffer will consume a minimum of two virtual memory pages,
! 28: * this is 16 kilobytes on many systems. On some systems it will be necessary
! 29: * to increase the amount of swap space in order to debug large programs that
! 30: * perform lots of allocation, because of the per-buffer overhead.
! 31: */
! 32: #include "efence.h"
! 33: #include <stdlib.h>
! 34: #include <unistd.h>
! 35: #include <memory.h>
! 36: #include <string.h>
! 37:
! 38: #ifdef malloc
! 39: #undef malloc
! 40: #endif
! 41:
! 42: #ifdef calloc
! 43: #undef calloc
! 44: #endif
! 45:
! 46: static const char version[] = "\n Electric Fence 2.0.5"
! 47: " Copyright (C) 1987-1995 Bruce Perens.\n";
! 48:
! 49: /*
! 50: * MEMORY_CREATION_SIZE is the amount of memory to get from the operating
! 51: * system at one time. We'll break that memory down into smaller pieces for
! 52: * malloc buffers. One megabyte is probably a good value.
! 53: */
! 54: #define MEMORY_CREATION_SIZE 1024 * 1024
! 55:
! 56: /*
! 57: * Enum Mode indicates the status of a malloc buffer.
! 58: */
! 59: enum _Mode {
! 60: NOT_IN_USE = 0, /* Available to represent a malloc buffer. */
! 61: FREE, /* A free buffer. */
! 62: ALLOCATED, /* A buffer that is in use. */
! 63: PROTECTED, /* A freed buffer that can not be allocated again. */
! 64: INTERNAL_USE /* A buffer used internally by malloc(). */
! 65: };
! 66: typedef enum _Mode Mode;
! 67:
! 68: /*
! 69: * Struct Slot contains all of the information about a malloc buffer except
! 70: * for the contents of its memory.
! 71: */
! 72: struct _Slot {
! 73: void * userAddress;
! 74: void * internalAddress;
! 75: size_t userSize;
! 76: size_t internalSize;
! 77: Mode mode;
! 78: };
! 79: typedef struct _Slot Slot;
! 80:
! 81: /*
! 82: * EF_ALIGNMENT is a global variable used to control the default alignment
! 83: * of buffers returned by malloc(), calloc(), and realloc(). It is all-caps
! 84: * so that its name matches the name of the environment variable that is used
! 85: * to set it. This gives the programmer one less name to remember.
! 86: * If the value is -1, it will be set from the environment or sizeof(int)
! 87: * at run time.
! 88: */
! 89: int EF_ALIGNMENT = -1;
! 90:
! 91: /*
! 92: * EF_PROTECT_FREE is a global variable used to control the disposition of
! 93: * memory that is released using free(). It is all-caps so that its name
! 94: * matches the name of the environment variable that is used to set it.
! 95: * If its value is greater non-zero, memory released by free is made
! 96: * inaccessable and never allocated again. Any software that touches free
! 97: * memory will then get a segmentation fault. If its value is zero, freed
! 98: * memory will be available for reallocation, but will still be inaccessable
! 99: * until it is reallocated.
! 100: * If the value is -1, it will be set from the environment or to 0 at run-time.
! 101: */
! 102: int EF_PROTECT_FREE = -1;
! 103:
! 104: /*
! 105: * EF_PROTECT_BELOW is used to modify the behavior of the allocator. When
! 106: * its value is non-zero, the allocator will place an inaccessable page
! 107: * immediately _before_ the malloc buffer in the address space, instead
! 108: * of _after_ it. Use this to detect malloc buffer under-runs, rather than
! 109: * over-runs. It won't detect both at the same time, so you should test your
! 110: * software twice, once with this value clear, and once with it set.
! 111: * If the value is -1, it will be set from the environment or to zero at
! 112: * run-time
! 113: */
! 114: int EF_PROTECT_BELOW = -1;
! 115:
! 116: /*
! 117: * EF_ALLOW_MALLOC_0 is set if Electric Fence is to allow malloc(0). I
! 118: * trap malloc(0) by default because it is a common source of bugs.
! 119: */
! 120: int EF_ALLOW_MALLOC_0 = -1;
! 121:
! 122: /*
! 123: * allocationList points to the array of slot structures used to manage the
! 124: * malloc arena.
! 125: */
! 126: static Slot * allocationList = 0;
! 127:
! 128: /*
! 129: * allocationListSize is the size of the allocation list. This will always
! 130: * be a multiple of the page size.
! 131: */
! 132: static size_t allocationListSize = 0;
! 133:
! 134: /*
! 135: * slotCount is the number of Slot structures in allocationList.
! 136: */
! 137: static size_t slotCount = 0;
! 138:
! 139: /*
! 140: * unUsedSlots is the number of Slot structures that are currently available
! 141: * to represent new malloc buffers. When this number gets too low, we will
! 142: * create new slots.
! 143: */
! 144: static size_t unUsedSlots = 0;
! 145:
! 146: /*
! 147: * slotsPerPage is the number of slot structures that fit in a virtual
! 148: * memory page.
! 149: */
! 150: static size_t slotsPerPage = 0;
! 151:
! 152: /*
! 153: * internalUse is set when allocating and freeing the allocatior-internal
! 154: * data structures.
! 155: */
! 156: static int internalUse = 0;
! 157:
! 158: /*
! 159: * noAllocationListProtection is set to tell malloc() and free() not to
! 160: * manipulate the protection of the allocation list. This is only set in
! 161: * realloc(), which does it to save on slow system calls, and in
! 162: * allocateMoreSlots(), which does it because it changes the allocation list.
! 163: */
! 164: static int noAllocationListProtection = 0;
! 165:
! 166: /*
! 167: * bytesPerPage is set at run-time to the number of bytes per virtual-memory
! 168: * page, as returned by Page_Size().
! 169: */
! 170: static size_t bytesPerPage = 0;
! 171:
! 172: /*
! 173: * internalError is called for those "shouldn't happen" errors in the
! 174: * allocator.
! 175: */
! 176: static void
! 177: internalError(void)
! 178: {
! 179: EF_Abort("Internal error in allocator.");
! 180: }
! 181:
! 182: /*
! 183: * initialize sets up the memory allocation arena and the run-time
! 184: * configuration information.
! 185: */
! 186: static void
! 187: initialize(void)
! 188: {
! 189: size_t size = MEMORY_CREATION_SIZE;
! 190: size_t slack;
! 191: char * string;
! 192: Slot * slot;
! 193:
! 194: EF_Print(version);
! 195:
! 196: /*
! 197: * Import the user's environment specification of the default
! 198: * alignment for malloc(). We want that alignment to be under
! 199: * user control, since smaller alignment lets us catch more bugs,
! 200: * however some software will break if malloc() returns a buffer
! 201: * that is not word-aligned.
! 202: *
! 203: * I would like
! 204: * alignment to be zero so that we could catch all one-byte
! 205: * overruns, however if malloc() is asked to allocate an odd-size
! 206: * buffer and returns an address that is not word-aligned, or whose
! 207: * size is not a multiple of the word size, software breaks.
! 208: * This was the case with the Sun string-handling routines,
! 209: * which can do word fetches up to three bytes beyond the end of a
! 210: * string. I handle this problem in part by providing
! 211: * byte-reference-only versions of the string library functions, but
! 212: * there are other functions that break, too. Some in X Windows, one
! 213: * in Sam Leffler's TIFF library, and doubtless many others.
! 214: */
! 215: if ( EF_ALIGNMENT == -1 ) {
! 216: if ( (string = getenv("EF_ALIGNMENT")) != 0 )
! 217: EF_ALIGNMENT = (size_t)atoi(string);
! 218: else
! 219: EF_ALIGNMENT = sizeof(int);
! 220: }
! 221:
! 222: /*
! 223: * See if the user wants to protect the address space below a buffer,
! 224: * rather than that above a buffer.
! 225: */
! 226: if ( EF_PROTECT_BELOW == -1 ) {
! 227: if ( (string = getenv("EF_PROTECT_BELOW")) != 0 )
! 228: EF_PROTECT_BELOW = (atoi(string) != 0);
! 229: else
! 230: EF_PROTECT_BELOW = 0;
! 231: }
! 232:
! 233: /*
! 234: * See if the user wants to protect memory that has been freed until
! 235: * the program exits, rather than until it is re-allocated.
! 236: */
! 237: if ( EF_PROTECT_FREE == -1 ) {
! 238: if ( (string = getenv("EF_PROTECT_FREE")) != 0 )
! 239: EF_PROTECT_FREE = (atoi(string) != 0);
! 240: else
! 241: EF_PROTECT_FREE = 0;
! 242: }
! 243:
! 244: /*
! 245: * See if the user wants to allow malloc(0).
! 246: */
! 247: if ( EF_ALLOW_MALLOC_0 == -1 ) {
! 248: if ( (string = getenv("EF_ALLOW_MALLOC_0")) != 0 )
! 249: EF_ALLOW_MALLOC_0 = (atoi(string) != 0);
! 250: else
! 251: EF_ALLOW_MALLOC_0 = 0;
! 252: }
! 253:
! 254: /*
! 255: * Get the run-time configuration of the virtual memory page size.
! 256: */
! 257: bytesPerPage = Page_Size();
! 258:
! 259: /*
! 260: * Figure out how many Slot structures to allocate at one time.
! 261: */
! 262: slotCount = slotsPerPage = bytesPerPage / sizeof(Slot);
! 263: allocationListSize = bytesPerPage;
! 264:
! 265: if ( allocationListSize > size )
! 266: size = allocationListSize;
! 267:
! 268: if ( (slack = size % bytesPerPage) != 0 )
! 269: size += bytesPerPage - slack;
! 270:
! 271: /*
! 272: * Allocate memory, and break it up into two malloc buffers. The
! 273: * first buffer will be used for Slot structures, the second will
! 274: * be marked free.
! 275: */
! 276: slot = allocationList = (Slot *)Page_Create(size);
! 277: memset((char *)allocationList, 0, allocationListSize);
! 278:
! 279: slot[0].internalSize = slot[0].userSize = allocationListSize;
! 280: slot[0].internalAddress = slot[0].userAddress = allocationList;
! 281: slot[0].mode = INTERNAL_USE;
! 282: if ( size > allocationListSize ) {
! 283: slot[1].internalAddress = slot[1].userAddress
! 284: = ((char *)slot[0].internalAddress) + slot[0].internalSize;
! 285: slot[1].internalSize
! 286: = slot[1].userSize = size - slot[0].internalSize;
! 287: slot[1].mode = FREE;
! 288: }
! 289:
! 290: /*
! 291: * Deny access to the free page, so that we will detect any software
! 292: * that treads upon free memory.
! 293: */
! 294: Page_DenyAccess(slot[1].internalAddress, slot[1].internalSize);
! 295:
! 296: /*
! 297: * Account for the two slot structures that we've used.
! 298: */
! 299: unUsedSlots = slotCount - 2;
! 300: }
! 301:
! 302: /*
! 303: * allocateMoreSlots is called when there are only enough slot structures
! 304: * left to support the allocation of a single malloc buffer.
! 305: */
! 306: static void
! 307: allocateMoreSlots(void)
! 308: {
! 309: size_t newSize = allocationListSize + bytesPerPage;
! 310: void * newAllocation;
! 311: void * oldAllocation = allocationList;
! 312:
! 313: Page_AllowAccess(allocationList, allocationListSize);
! 314: noAllocationListProtection = 1;
! 315: internalUse = 1;
! 316:
! 317: newAllocation = malloc(newSize);
! 318: memcpy(newAllocation, allocationList, allocationListSize);
! 319: memset(&(((char *)newAllocation)[allocationListSize]), 0, bytesPerPage);
! 320:
! 321: allocationList = (Slot *)newAllocation;
! 322: allocationListSize = newSize;
! 323: slotCount += slotsPerPage;
! 324: unUsedSlots += slotsPerPage;
! 325:
! 326: free(oldAllocation);
! 327:
! 328: /*
! 329: * Keep access to the allocation list open at this point, because
! 330: * I am returning to memalign(), which needs that access.
! 331: */
! 332: noAllocationListProtection = 0;
! 333: internalUse = 0;
! 334: }
! 335:
! 336: /*
! 337: * This is the memory allocator. When asked to allocate a buffer, allocate
! 338: * it in such a way that the end of the buffer is followed by an inaccessable
! 339: * memory page. If software overruns that buffer, it will touch the bad page
! 340: * and get an immediate segmentation fault. It's then easy to zero in on the
! 341: * offending code with a debugger.
! 342: *
! 343: * There are a few complications. If the user asks for an odd-sized buffer,
! 344: * we would have to have that buffer start on an odd address if the byte after
! 345: * the end of the buffer was to be on the inaccessable page. Unfortunately,
! 346: * there is lots of software that asks for odd-sized buffers and then
! 347: * requires that the returned address be word-aligned, or the size of the
! 348: * buffer be a multiple of the word size. An example are the string-processing
! 349: * functions on Sun systems, which do word references to the string memory
! 350: * and may refer to memory up to three bytes beyond the end of the string.
! 351: * For this reason, I take the alignment requests to memalign() and valloc()
! 352: * seriously, and
! 353: *
! 354: * Electric Fence wastes lots of memory. I do a best-fit allocator here
! 355: * so that it won't waste even more. It's slow, but thrashing because your
! 356: * working set is too big for a system's RAM is even slower.
! 357: */
! 358: extern C_LINKAGE void *
! 359: memalign(size_t alignment, size_t userSize)
! 360: {
! 361: register Slot * slot;
! 362: register size_t count;
! 363: Slot * fullSlot = 0;
! 364: Slot * emptySlots[2];
! 365: size_t internalSize;
! 366: size_t slack;
! 367: char * address;
! 368:
! 369: if ( allocationList == 0 )
! 370: initialize();
! 371:
! 372: if ( userSize == 0 && !EF_ALLOW_MALLOC_0 )
! 373: EF_Abort("Allocating 0 bytes, probably a bug.");
! 374:
! 375: /*
! 376: * If EF_PROTECT_BELOW is set, all addresses returned by malloc()
! 377: * and company will be page-aligned.
! 378: */
! 379: if ( !EF_PROTECT_BELOW && alignment > 1 ) {
! 380: if ( (slack = userSize % alignment) != 0 )
! 381: userSize += alignment - slack;
! 382: }
! 383:
! 384: /*
! 385: * The internal size of the buffer is rounded up to the next page-size
! 386: * boudary, and then we add another page's worth of memory for the
! 387: * dead page.
! 388: */
! 389: internalSize = userSize + bytesPerPage;
! 390: if ( (slack = internalSize % bytesPerPage) != 0 )
! 391: internalSize += bytesPerPage - slack;
! 392:
! 393: /*
! 394: * These will hold the addresses of two empty Slot structures, that
! 395: * can be used to hold information for any memory I create, and any
! 396: * memory that I mark free.
! 397: */
! 398: emptySlots[0] = 0;
! 399: emptySlots[1] = 0;
! 400:
! 401: /*
! 402: * The internal memory used by the allocator is currently
! 403: * inaccessable, so that errant programs won't scrawl on the
! 404: * allocator's arena. I'll un-protect it here so that I can make
! 405: * a new allocation. I'll re-protect it before I return.
! 406: */
! 407: if ( !noAllocationListProtection )
! 408: Page_AllowAccess(allocationList, allocationListSize);
! 409:
! 410: /*
! 411: * If I'm running out of empty slots, create some more before
! 412: * I don't have enough slots left to make an allocation.
! 413: */
! 414: if ( !internalUse && unUsedSlots < 7 ) {
! 415: allocateMoreSlots();
! 416: }
! 417:
! 418: /*
! 419: * Iterate through all of the slot structures. Attempt to find a slot
! 420: * containing free memory of the exact right size. Accept a slot with
! 421: * more memory than we want, if the exact right size is not available.
! 422: * Find two slot structures that are not in use. We will need one if
! 423: * we split a buffer into free and allocated parts, and the second if
! 424: * we have to create new memory and mark it as free.
! 425: *
! 426: */
! 427:
! 428: for ( slot = allocationList, count = slotCount ; count > 0; count-- ) {
! 429: if ( slot->mode == FREE
! 430: && slot->internalSize >= internalSize ) {
! 431: if ( !fullSlot
! 432: ||slot->internalSize < fullSlot->internalSize){
! 433: fullSlot = slot;
! 434: if ( slot->internalSize == internalSize
! 435: && emptySlots[0] )
! 436: break; /* All done, */
! 437: }
! 438: }
! 439: else if ( slot->mode == NOT_IN_USE ) {
! 440: if ( !emptySlots[0] )
! 441: emptySlots[0] = slot;
! 442: else if ( !emptySlots[1] )
! 443: emptySlots[1] = slot;
! 444: else if ( fullSlot
! 445: && fullSlot->internalSize == internalSize )
! 446: break; /* All done. */
! 447: }
! 448: slot++;
! 449: }
! 450: if ( !emptySlots[0] )
! 451: internalError();
! 452:
! 453: if ( !fullSlot ) {
! 454: /*
! 455: * I get here if I haven't been able to find a free buffer
! 456: * with all of the memory I need. I'll have to create more
! 457: * memory. I'll mark it all as free, and then split it into
! 458: * free and allocated portions later.
! 459: */
! 460: size_t chunkSize = MEMORY_CREATION_SIZE;
! 461:
! 462: if ( !emptySlots[1] )
! 463: internalError();
! 464:
! 465: if ( chunkSize < internalSize )
! 466: chunkSize = internalSize;
! 467:
! 468: if ( (slack = chunkSize % bytesPerPage) != 0 )
! 469: chunkSize += bytesPerPage - slack;
! 470:
! 471: /* Use up one of the empty slots to make the full slot. */
! 472: fullSlot = emptySlots[0];
! 473: emptySlots[0] = emptySlots[1];
! 474: fullSlot->internalAddress = Page_Create(chunkSize);
! 475: fullSlot->internalSize = chunkSize;
! 476: fullSlot->mode = FREE;
! 477: unUsedSlots--;
! 478: }
! 479:
! 480: /*
! 481: * If I'm allocating memory for the allocator's own data structures,
! 482: * mark it INTERNAL_USE so that no errant software will be able to
! 483: * free it.
! 484: */
! 485: if ( internalUse )
! 486: fullSlot->mode = INTERNAL_USE;
! 487: else
! 488: fullSlot->mode = ALLOCATED;
! 489:
! 490: /*
! 491: * If the buffer I've found is larger than I need, split it into
! 492: * an allocated buffer with the exact amount of memory I need, and
! 493: * a free buffer containing the surplus memory.
! 494: */
! 495: if ( fullSlot->internalSize > internalSize ) {
! 496: emptySlots[0]->internalSize
! 497: = fullSlot->internalSize - internalSize;
! 498: emptySlots[0]->internalAddress
! 499: = ((char *)fullSlot->internalAddress) + internalSize;
! 500: emptySlots[0]->mode = FREE;
! 501: fullSlot->internalSize = internalSize;
! 502: unUsedSlots--;
! 503: }
! 504:
! 505: if ( !EF_PROTECT_BELOW ) {
! 506: /*
! 507: * Arrange the buffer so that it is followed by an inaccessable
! 508: * memory page. A buffer overrun that touches that page will
! 509: * cause a segmentation fault.
! 510: */
! 511: address = (char *)fullSlot->internalAddress;
! 512:
! 513: /* Set up the "live" page. */
! 514: if ( internalSize - bytesPerPage > 0 )
! 515: Page_AllowAccess(
! 516: fullSlot->internalAddress
! 517: ,internalSize - bytesPerPage);
! 518:
! 519: address += internalSize - bytesPerPage;
! 520:
! 521: /* Set up the "dead" page. */
! 522: if ( EF_PROTECT_FREE )
! 523: Page_Delete(address, bytesPerPage);
! 524: else
! 525: Page_DenyAccess(address, bytesPerPage);
! 526:
! 527: /* Figure out what address to give the user. */
! 528: address -= userSize;
! 529: }
! 530: else { /* EF_PROTECT_BELOW != 0 */
! 531: /*
! 532: * Arrange the buffer so that it is preceded by an inaccessable
! 533: * memory page. A buffer underrun that touches that page will
! 534: * cause a segmentation fault.
! 535: */
! 536: address = (char *)fullSlot->internalAddress;
! 537:
! 538: /* Set up the "dead" page. */
! 539: if ( EF_PROTECT_FREE )
! 540: Page_Delete(address, bytesPerPage);
! 541: else
! 542: Page_DenyAccess(address, bytesPerPage);
! 543:
! 544: address += bytesPerPage;
! 545:
! 546: /* Set up the "live" page. */
! 547: if ( internalSize - bytesPerPage > 0 )
! 548: Page_AllowAccess(address, internalSize - bytesPerPage);
! 549: }
! 550:
! 551: fullSlot->userAddress = address;
! 552: fullSlot->userSize = userSize;
! 553:
! 554: /*
! 555: * Make the pool's internal memory inaccessable, so that the program
! 556: * being debugged can't stomp on it.
! 557: */
! 558: if ( !internalUse )
! 559: Page_DenyAccess(allocationList, allocationListSize);
! 560:
! 561: return address;
! 562: }
! 563:
! 564: /*
! 565: * Find the slot structure for a user address.
! 566: */
! 567: static Slot *
! 568: slotForUserAddress(void * address)
! 569: {
! 570: register Slot * slot = allocationList;
! 571: register size_t count = slotCount;
! 572:
! 573: for ( ; count > 0; count-- ) {
! 574: if ( slot->userAddress == address )
! 575: return slot;
! 576: slot++;
! 577: }
! 578:
! 579: return 0;
! 580: }
! 581:
! 582: /*
! 583: * Find the slot structure for an internal address.
! 584: */
! 585: static Slot *
! 586: slotForInternalAddress(void * address)
! 587: {
! 588: register Slot * slot = allocationList;
! 589: register size_t count = slotCount;
! 590:
! 591: for ( ; count > 0; count-- ) {
! 592: if ( slot->internalAddress == address )
! 593: return slot;
! 594: slot++;
! 595: }
! 596: return 0;
! 597: }
! 598:
! 599: /*
! 600: * Given the internal address of a buffer, find the buffer immediately
! 601: * before that buffer in the address space. This is used by free() to
! 602: * coalesce two free buffers into one.
! 603: */
! 604: static Slot *
! 605: slotForInternalAddressPreviousTo(void * address)
! 606: {
! 607: register Slot * slot = allocationList;
! 608: register size_t count = slotCount;
! 609:
! 610: for ( ; count > 0; count-- ) {
! 611: if ( ((char *)slot->internalAddress)
! 612: + slot->internalSize == address )
! 613: return slot;
! 614: slot++;
! 615: }
! 616: return 0;
! 617: }
! 618:
! 619: extern C_LINKAGE void
! 620: free(void * address)
! 621: {
! 622: Slot * slot;
! 623: Slot * previousSlot = 0;
! 624: Slot * nextSlot = 0;
! 625:
! 626: if ( address == 0 )
! 627: return;
! 628:
! 629: if ( allocationList == 0 )
! 630: EF_Abort("free() called before first malloc().");
! 631:
! 632: if ( !noAllocationListProtection )
! 633: Page_AllowAccess(allocationList, allocationListSize);
! 634:
! 635: slot = slotForUserAddress(address);
! 636:
! 637: if ( !slot )
! 638: EF_Abort("free(%a): address not from malloc().", address);
! 639:
! 640: if ( slot->mode != ALLOCATED ) {
! 641: if ( internalUse && slot->mode == INTERNAL_USE )
! 642: /* Do nothing. */;
! 643: else {
! 644: EF_Abort(
! 645: "free(%a): freeing free memory."
! 646: ,address);
! 647: }
! 648: }
! 649:
! 650: if ( EF_PROTECT_FREE )
! 651: slot->mode = PROTECTED;
! 652: else
! 653: slot->mode = FREE;
! 654:
! 655: previousSlot = slotForInternalAddressPreviousTo(slot->internalAddress);
! 656: nextSlot = slotForInternalAddress(
! 657: ((char *)slot->internalAddress) + slot->internalSize);
! 658:
! 659: if ( previousSlot
! 660: && (previousSlot->mode == FREE || previousSlot->mode == PROTECTED) ) {
! 661: /* Coalesce previous slot with this one. */
! 662: previousSlot->internalSize += slot->internalSize;
! 663: if ( EF_PROTECT_FREE )
! 664: previousSlot->mode = PROTECTED;
! 665:
! 666: slot->internalAddress = slot->userAddress = 0;
! 667: slot->internalSize = slot->userSize = 0;
! 668: slot->mode = NOT_IN_USE;
! 669: slot = previousSlot;
! 670: unUsedSlots++;
! 671: }
! 672: if ( nextSlot
! 673: && (nextSlot->mode == FREE || nextSlot->mode == PROTECTED) ) {
! 674: /* Coalesce next slot with this one. */
! 675: slot->internalSize += nextSlot->internalSize;
! 676: nextSlot->internalAddress = nextSlot->userAddress = 0;
! 677: nextSlot->internalSize = nextSlot->userSize = 0;
! 678: nextSlot->mode = NOT_IN_USE;
! 679: unUsedSlots++;
! 680: }
! 681:
! 682: slot->userAddress = slot->internalAddress;
! 683: slot->userSize = slot->internalSize;
! 684:
! 685: /*
! 686: * Free memory is _always_ set to deny access. When EF_PROTECT_FREE
! 687: * is true, free memory is never reallocated, so it remains access
! 688: * denied for the life of the process. When EF_PROTECT_FREE is false,
! 689: * the memory may be re-allocated, at which time access to it will be
! 690: * allowed again.
! 691: *
! 692: * Some operating systems allow munmap() with single-page resolution,
! 693: * and allow you to un-map portions of a region, rather than the
! 694: * entire region that was mapped with mmap(). On those operating
! 695: * systems, we can release protected free pages with Page_Delete(),
! 696: * in the hope that the swap space attached to those pages will be
! 697: * released as well.
! 698: */
! 699: if ( EF_PROTECT_FREE )
! 700: Page_Delete(slot->internalAddress, slot->internalSize);
! 701: else
! 702: Page_DenyAccess(slot->internalAddress, slot->internalSize);
! 703:
! 704: if ( !noAllocationListProtection )
! 705: Page_DenyAccess(allocationList, allocationListSize);
! 706: }
! 707:
! 708: extern C_LINKAGE void *
! 709: realloc(void * oldBuffer, size_t newSize)
! 710: {
! 711: void * newBuffer = malloc(newSize);
! 712:
! 713: if ( oldBuffer ) {
! 714: size_t size;
! 715: Slot * slot;
! 716:
! 717: Page_AllowAccess(allocationList, allocationListSize);
! 718: noAllocationListProtection = 1;
! 719:
! 720: slot = slotForUserAddress(oldBuffer);
! 721:
! 722: if ( slot == 0 )
! 723: EF_Abort(
! 724: "realloc(%a, %d): address not from malloc()."
! 725: ,oldBuffer
! 726: ,newSize);
! 727:
! 728: if ( newSize < (size = slot->userSize) )
! 729: size = newSize;
! 730:
! 731: if ( size > 0 )
! 732: memcpy(newBuffer, oldBuffer, size);
! 733:
! 734: free(oldBuffer);
! 735: noAllocationListProtection = 0;
! 736: Page_DenyAccess(allocationList, allocationListSize);
! 737:
! 738: if ( size < newSize )
! 739: memset(&(((char *)newBuffer)[size]), 0, newSize - size);
! 740:
! 741: /* Internal memory was re-protected in free() */
! 742: }
! 743:
! 744: return newBuffer;
! 745: }
! 746:
! 747: extern C_LINKAGE void *
! 748: malloc(size_t size)
! 749: {
! 750: if ( allocationList == 0 )
! 751: initialize(); /* This sets EF_ALIGNMENT */
! 752:
! 753: return memalign(EF_ALIGNMENT, size);
! 754: }
! 755:
! 756: extern C_LINKAGE void *
! 757: calloc(size_t nelem, size_t elsize)
! 758: {
! 759: size_t size = nelem * elsize;
! 760: void * allocation = malloc(size);
! 761:
! 762: memset(allocation, 0, size);
! 763: return allocation;
! 764: }
! 765:
! 766: /*
! 767: * This will catch more bugs if you remove the page alignment, but it
! 768: * will break some software.
! 769: */
! 770: extern C_LINKAGE void *
! 771: valloc (size_t size)
! 772: {
! 773: return memalign(bytesPerPage, size);
! 774: }
! 775:
! 776: #ifdef __hpux
! 777: /*
! 778: * HP-UX 8/9.01 strcat reads a word past source when doing unaligned copies!
! 779: * Work around it here. The bug report has been filed with HP.
! 780: */
! 781: char *strcat(char *d, const char *s)
! 782: {
! 783: strcpy(d+strlen(d), s);
! 784: return d;
! 785: }
! 786: #endif
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>