00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
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
00051
00052
00053
00054 #define MEMORY_CREATION_SIZE 1024 * 1024
00055
00056
00057
00058
00059 enum _Mode {
00060 NOT_IN_USE = 0,
00061 FREE,
00062 ALLOCATED,
00063 PROTECTED,
00064 INTERNAL_USE
00065 };
00066 typedef enum _Mode Mode;
00067
00068
00069
00070
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
00083
00084
00085
00086
00087
00088
00089 int EF_ALIGNMENT = -1;
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102 int EF_PROTECT_FREE = -1;
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114 int EF_PROTECT_BELOW = -1;
00115
00116
00117
00118
00119
00120 int EF_ALLOW_MALLOC_0 = -1;
00121
00122
00123
00124
00125
00126 static Slot * allocationList = 0;
00127
00128
00129
00130
00131
00132 static size_t allocationListSize = 0;
00133
00134
00135
00136
00137 static size_t slotCount = 0;
00138
00139
00140
00141
00142
00143
00144 static size_t unUsedSlots = 0;
00145
00146
00147
00148
00149
00150 static size_t slotsPerPage = 0;
00151
00152
00153
00154
00155
00156 static int internalUse = 0;
00157
00158
00159
00160
00161
00162
00163
00164 static int noAllocationListProtection = 0;
00165
00166
00167
00168
00169
00170 static size_t bytesPerPage = 0;
00171
00172
00173
00174
00175
00176 static void
00177 internalError(void)
00178 {
00179 EF_Abort("Internal error in allocator.");
00180 }
00181
00182
00183
00184
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
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
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
00224
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
00235
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
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
00256
00257 bytesPerPage = Page_Size();
00258
00259
00260
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
00273
00274
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
00292
00293
00294 Page_DenyAccess(slot[1].internalAddress, slot[1].internalSize);
00295
00296
00297
00298
00299 unUsedSlots = slotCount - 2;
00300 }
00301
00302
00303
00304
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
00330
00331
00332 noAllocationListProtection = 0;
00333 internalUse = 0;
00334 }
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356
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
00377
00378
00379 if ( !EF_PROTECT_BELOW && alignment > 1 ) {
00380 if ( (slack = userSize % alignment) != 0 )
00381 userSize += alignment - slack;
00382 }
00383
00384
00385
00386
00387
00388
00389 internalSize = userSize + bytesPerPage;
00390 if ( (slack = internalSize % bytesPerPage) != 0 )
00391 internalSize += bytesPerPage - slack;
00392
00393
00394
00395
00396
00397
00398 emptySlots[0] = 0;
00399 emptySlots[1] = 0;
00400
00401
00402
00403
00404
00405
00406
00407 if ( !noAllocationListProtection )
00408 Page_AllowAccess(allocationList, allocationListSize);
00409
00410
00411
00412
00413
00414 if ( !internalUse && unUsedSlots < 7 ) {
00415 allocateMoreSlots();
00416 }
00417
00418
00419
00420
00421
00422
00423
00424
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;
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;
00447 }
00448 slot++;
00449 }
00450 if ( !emptySlots[0] )
00451 internalError();
00452
00453 if ( !fullSlot ) {
00454
00455
00456
00457
00458
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
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
00482
00483
00484
00485 if ( internalUse )
00486 fullSlot->mode = INTERNAL_USE;
00487 else
00488 fullSlot->mode = ALLOCATED;
00489
00490
00491
00492
00493
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
00508
00509
00510
00511 address = (char *)fullSlot->internalAddress;
00512
00513
00514 if ( internalSize - bytesPerPage > 0 )
00515 Page_AllowAccess(
00516 fullSlot->internalAddress
00517 ,internalSize - bytesPerPage);
00518
00519 address += internalSize - bytesPerPage;
00520
00521
00522 if ( EF_PROTECT_FREE )
00523 Page_Delete(address, bytesPerPage);
00524 else
00525 Page_DenyAccess(address, bytesPerPage);
00526
00527
00528 address -= userSize;
00529 }
00530 else {
00531
00532
00533
00534
00535
00536 address = (char *)fullSlot->internalAddress;
00537
00538
00539 if ( EF_PROTECT_FREE )
00540 Page_Delete(address, bytesPerPage);
00541 else
00542 Page_DenyAccess(address, bytesPerPage);
00543
00544 address += bytesPerPage;
00545
00546
00547 if ( internalSize - bytesPerPage > 0 )
00548 Page_AllowAccess(address, internalSize - bytesPerPage);
00549 }
00550
00551 fullSlot->userAddress = address;
00552 fullSlot->userSize = userSize;
00553
00554
00555
00556
00557
00558 if ( !internalUse )
00559 Page_DenyAccess(allocationList, allocationListSize);
00560
00561 return address;
00562 }
00563
00564
00565
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
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
00601
00602
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
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 ;
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
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
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
00688
00689
00690
00691
00692
00693
00694
00695
00696
00697
00698
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
00743 }
00744
00745 return newBuffer;
00746 }
00747
00748 extern C_LINKAGE void *
00749 malloc(size_t size)
00750 {
00751 if ( allocationList == 0 )
00752 initialize();
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
00769
00770
00771 extern C_LINKAGE void *
00772 valloc (size_t size)
00773 {
00774 return memalign(bytesPerPage, size);
00775 }
00776
00777 #ifdef __hpux
00778
00779
00780
00781
00782 char *strcat(char *d, const char *s)
00783 {
00784 strcpy(d+strlen(d), s);
00785 return d;
00786 }
00787 #endif