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
00033 #include "efence.h"
00034 #include <stdlib.h>
00035 #include <unistd.h>
00036 #include <memory.h>
00037 #include <string.h>
00038 #include <fcntl.h>
00039 #include <sys/mman.h>
00040 #include <stdio.h>
00041 #include <errno.h>
00042 #include <stdarg.h>
00043 #include <signal.h>
00044
00045 static const char version[] = "\n Electric Fence 2.0.1"
00046 " Copyright (C) 1987-1993 Bruce Perens.\n";
00047
00048
00049
00050
00051
00052
00053 #define MEMORY_CREATION_SIZE 1024 * 1024
00054
00055
00056
00057
00058 enum _Mode {
00059 NOT_IN_USE = 0,
00060 FREE,
00061 ALLOCATED,
00062 PROTECTED,
00063 INTERNAL_USE
00064 };
00065 typedef enum _Mode Mode;
00066
00067
00068
00069
00070
00071 struct _Slot {
00072 void * userAddress;
00073 void * internalAddress;
00074 size_t userSize;
00075 size_t internalSize;
00076 Mode mode;
00077 };
00078 typedef struct _Slot Slot;
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088 int EF_ALIGNMENT = -1;
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101 int EF_PROTECT_FREE = -1;
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113 int EF_PROTECT_BELOW = -1;
00114
00115
00116
00117
00118
00119 int EF_ALLOW_MALLOC_0 = -1;
00120
00121
00122
00123
00124
00125 static Slot * allocationList = 0;
00126
00127
00128
00129
00130
00131 static size_t allocationListSize = 0;
00132
00133
00134
00135
00136 static size_t slotCount = 0;
00137
00138
00139
00140
00141
00142
00143 static size_t unUsedSlots = 0;
00144
00145
00146
00147
00148
00149 static size_t slotsPerPage = 0;
00150
00151
00152
00153
00154
00155 static int internalUse = 0;
00156
00157
00158
00159
00160
00161
00162
00163 static int noAllocationListProtection = 0;
00164
00165
00166
00167
00168
00169 static size_t bytesPerPage = 0;
00170
00171
00172
00173
00174
00175 static void
00176 internalError(void)
00177 {
00178 EF_Abort("Internal error in allocator.");
00179 }
00180
00181
00182
00183
00184
00185 static void
00186 initialize(void)
00187 {
00188 size_t size = MEMORY_CREATION_SIZE;
00189 size_t slack;
00190 char * string;
00191 Slot * slot;
00192
00193 EF_Print(version);
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214 if ( EF_ALIGNMENT == -1 ) {
00215 if ( (string = getenv("EF_ALIGNMENT")) != 0 )
00216 EF_ALIGNMENT = (size_t)atoi(string);
00217 else
00218 EF_ALIGNMENT = sizeof(int);
00219 }
00220
00221
00222
00223
00224
00225 if ( EF_PROTECT_BELOW == -1 ) {
00226 if ( (string = getenv("EF_PROTECT_BELOW")) != 0 )
00227 EF_PROTECT_BELOW = (atoi(string) != 0);
00228 else
00229 EF_PROTECT_BELOW = 0;
00230 }
00231
00232
00233
00234
00235
00236 if ( EF_PROTECT_FREE == -1 ) {
00237 if ( (string = getenv("EF_PROTECT_FREE")) != 0 )
00238 EF_PROTECT_FREE = (atoi(string) != 0);
00239 else
00240 EF_PROTECT_FREE = 0;
00241 }
00242
00243
00244
00245
00246 if ( EF_ALLOW_MALLOC_0 == -1 ) {
00247 if ( (string = getenv("EF_ALLOW_MALLOC_0")) != 0 )
00248 EF_ALLOW_MALLOC_0 = (atoi(string) != 0);
00249 else
00250 EF_ALLOW_MALLOC_0 = 0;
00251 }
00252
00253
00254
00255
00256 bytesPerPage = Page_Size();
00257
00258
00259
00260
00261 slotCount = slotsPerPage = bytesPerPage / sizeof(Slot);
00262 allocationListSize = bytesPerPage;
00263
00264 if ( allocationListSize > size )
00265 size = allocationListSize;
00266
00267 if ( (slack = size % bytesPerPage) != 0 )
00268 size += bytesPerPage - slack;
00269
00270
00271
00272
00273
00274
00275 slot = allocationList = (Slot *)Page_Create(size);
00276 memset((char *)allocationList, 0, allocationListSize);
00277
00278 slot[0].internalSize = slot[0].userSize = allocationListSize;
00279 slot[0].internalAddress = slot[0].userAddress = allocationList;
00280 slot[0].mode = INTERNAL_USE;
00281 if ( size > allocationListSize ) {
00282 slot[1].internalAddress = slot[1].userAddress
00283 = ((char *)slot[0].internalAddress) + slot[0].internalSize;
00284 slot[1].internalSize
00285 = slot[1].userSize = size - slot[0].internalSize;
00286 slot[1].mode = FREE;
00287 }
00288
00289
00290
00291
00292
00293 Page_DenyAccess(slot[1].internalAddress, slot[1].internalSize);
00294
00295
00296
00297
00298 unUsedSlots = slotCount - 2;
00299 }
00300
00301
00302
00303
00304
00305 static void
00306 allocateMoreSlots(void)
00307 {
00308 size_t newSize = allocationListSize + bytesPerPage;
00309 void * newAllocation;
00310 void * oldAllocation = allocationList;
00311
00312 Page_AllowAccess(allocationList, allocationListSize);
00313 noAllocationListProtection = 1;
00314 internalUse = 1;
00315
00316 newAllocation = malloc(newSize);
00317 memcpy(newAllocation, allocationList, allocationListSize);
00318 memset(&(((char *)newAllocation)[allocationListSize]), 0, bytesPerPage);
00319
00320 allocationList = (Slot *)newAllocation;
00321 allocationListSize = newSize;
00322 slotCount += slotsPerPage;
00323 unUsedSlots += slotsPerPage;
00324
00325 free(oldAllocation);
00326
00327
00328
00329
00330
00331 noAllocationListProtection = 0;
00332 internalUse = 0;
00333 }
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357 extern C_LINKAGE void *
00358 memalign(size_t alignment, size_t userSize)
00359 {
00360 register Slot * slot;
00361 register size_t count;
00362 Slot * fullSlot = 0;
00363 Slot * emptySlots[2];
00364 size_t internalSize;
00365 size_t slack;
00366 char * address;
00367
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 Page_AllowAccess(
00515 fullSlot->internalAddress
00516 ,internalSize - bytesPerPage);
00517
00518 address += internalSize - bytesPerPage;
00519
00520
00521 if ( EF_PROTECT_FREE )
00522 Page_Delete(address, bytesPerPage);
00523 else
00524 Page_DenyAccess(address, bytesPerPage);
00525
00526
00527 address -= userSize;
00528 }
00529 else {
00530
00531
00532
00533
00534
00535 address = (char *)fullSlot->internalAddress;
00536
00537
00538 if ( EF_PROTECT_FREE )
00539 Page_Delete(address, bytesPerPage);
00540 else
00541 Page_DenyAccess(address, bytesPerPage);
00542
00543 address += bytesPerPage;
00544
00545
00546 Page_AllowAccess(address, internalSize - bytesPerPage);
00547 }
00548
00549 fullSlot->userAddress = address;
00550 fullSlot->userSize = userSize;
00551
00552
00553
00554
00555
00556 if ( !internalUse )
00557 Page_DenyAccess(allocationList, allocationListSize);
00558
00559 return address;
00560 }
00561
00562
00563
00564
00565 static Slot *
00566 slotForUserAddress(void * address)
00567 {
00568 register Slot * slot = allocationList;
00569 register size_t count = slotCount;
00570
00571 for ( ; count > 0; count-- ) {
00572 if ( slot->userAddress == address )
00573 return slot;
00574 slot++;
00575 }
00576
00577 return 0;
00578 }
00579
00580
00581
00582
00583 static Slot *
00584 slotForInternalAddress(void * address)
00585 {
00586 register Slot * slot = allocationList;
00587 register size_t count = slotCount;
00588
00589 for ( ; count > 0; count-- ) {
00590 if ( slot->internalAddress == address )
00591 return slot;
00592 slot++;
00593 }
00594 return 0;
00595 }
00596
00597
00598
00599
00600
00601
00602 static Slot *
00603 slotForInternalAddressPreviousTo(void * address)
00604 {
00605 register Slot * slot = allocationList;
00606 register size_t count = slotCount;
00607
00608 for ( ; count > 0; count-- ) {
00609 if ( ((char *)slot->internalAddress)
00610 + slot->internalSize == address )
00611 return slot;
00612 slot++;
00613 }
00614 return 0;
00615 }
00616
00617 extern C_LINKAGE void
00618 free(void * address)
00619 {
00620 Slot * slot;
00621 Slot * previousSlot = 0;
00622 Slot * nextSlot = 0;
00623
00624 if ( address == 0 )
00625 EF_Abort("free() called for address zero.");
00626
00627 if ( allocationList == 0 )
00628 EF_Abort("free() called before first malloc().");
00629
00630 if ( !noAllocationListProtection )
00631 Page_AllowAccess(allocationList, allocationListSize);
00632
00633 slot = slotForUserAddress(address);
00634
00635 if ( !slot )
00636 EF_Abort("free(%x): address not from malloc().", address);
00637
00638 if ( slot->mode != ALLOCATED ) {
00639 if ( internalUse && slot->mode == INTERNAL_USE )
00640 ;
00641 else {
00642 EF_Abort(
00643 "free(%x): freeing free memory."
00644 ,address);
00645 }
00646 }
00647
00648 if ( EF_PROTECT_FREE )
00649 slot->mode = PROTECTED;
00650 else
00651 slot->mode = FREE;
00652
00653 previousSlot = slotForInternalAddressPreviousTo(slot->internalAddress);
00654 nextSlot = slotForInternalAddress(
00655 ((char *)slot->internalAddress) + slot->internalSize);
00656
00657 if ( previousSlot
00658 && (previousSlot->mode == FREE || previousSlot->mode == PROTECTED) ) {
00659
00660 previousSlot->internalSize += slot->internalSize;
00661 if ( EF_PROTECT_FREE )
00662 previousSlot->mode = PROTECTED;
00663
00664 slot->internalAddress = slot->userAddress = 0;
00665 slot->internalSize = slot->userSize = 0;
00666 slot->mode = NOT_IN_USE;
00667 slot = previousSlot;
00668 unUsedSlots++;
00669 }
00670 if ( nextSlot
00671 && (nextSlot->mode == FREE || nextSlot->mode == PROTECTED) ) {
00672
00673 slot->internalSize += nextSlot->internalSize;
00674 nextSlot->internalAddress = nextSlot->userAddress = 0;
00675 nextSlot->internalSize = nextSlot->userSize = 0;
00676 nextSlot->mode = NOT_IN_USE;
00677 unUsedSlots++;
00678 }
00679
00680 slot->userAddress = slot->internalAddress;
00681 slot->userSize = slot->internalSize;
00682
00683
00684
00685
00686
00687
00688
00689
00690
00691
00692
00693
00694
00695
00696
00697 if ( EF_PROTECT_FREE )
00698 Page_Delete(slot->internalAddress, slot->internalSize);
00699 else
00700 Page_DenyAccess(slot->internalAddress, slot->internalSize);
00701
00702 if ( !noAllocationListProtection )
00703 Page_DenyAccess(allocationList, allocationListSize);
00704 }
00705
00706 extern C_LINKAGE void *
00707 realloc(void * oldBuffer, size_t newSize)
00708 {
00709 size_t size;
00710 Slot * slot;
00711 void * newBuffer = malloc(newSize);
00712
00713 if ( allocationList == 0 )
00714 EF_Abort("realloc() called before first malloc().");
00715
00716 Page_AllowAccess(allocationList, allocationListSize);
00717 noAllocationListProtection = 1;
00718
00719 slot = slotForUserAddress(oldBuffer);
00720
00721 if ( slot == 0 )
00722 EF_Abort("free(%x): not from malloc().", oldBuffer);
00723
00724 if ( newSize < (size = slot->userSize) )
00725 size = newSize;
00726
00727 if ( size > 0 )
00728 memcpy(newBuffer, oldBuffer, size);
00729
00730 free(oldBuffer);
00731 noAllocationListProtection = 0;
00732 Page_DenyAccess(allocationList, allocationListSize);
00733
00734 if ( size < newSize )
00735 memset(&(((char *)newBuffer)[size]), 0, newSize - size);
00736
00737
00738 return newBuffer;
00739 }
00740
00741 extern C_LINKAGE void *
00742 malloc(size_t size)
00743 {
00744 if ( allocationList == 0 )
00745 initialize();
00746
00747 return memalign(EF_ALIGNMENT, size);
00748 }
00749
00750 extern C_LINKAGE void *
00751 calloc(size_t nelem, size_t elsize)
00752 {
00753 size_t size = nelem * elsize;
00754 void * allocation = malloc(size);
00755
00756 memset(allocation, 0, size);
00757 return allocation;
00758 }
00759
00760
00761
00762
00763
00764 extern C_LINKAGE void *
00765 valloc (size_t size)
00766 {
00767 return memalign(bytesPerPage, size);
00768 }
00769
00770
00771
00772
00773
00774
00775
00776
00777
00778
00779
00780
00781
00782
00783 static caddr_t startAddr = (caddr_t) 0;
00784
00785 #if ( !defined(sgi) && !defined(_AIX) )
00786 extern int sys_nerr;
00787 extern char * sys_errlist[];
00788 #endif
00789
00790 static const char *
00791 stringErrorReport(void)
00792 {
00793 #if ( defined(sgi) )
00794 return strerror(oserror());
00795 #elif ( defined(_AIX) )
00796 return strerror(errno);
00797 #else
00798 if ( errno > 0 && errno < sys_nerr )
00799 return sys_errlist[errno];
00800 else
00801 return "Unknown error.\n";
00802 #endif
00803 }
00804
00805
00806
00807
00808 #if defined(MAP_ANONYMOUS)
00809 void *
00810 Page_Create(size_t size)
00811 {
00812 caddr_t allocation;
00813
00814
00815
00816
00817
00818
00819
00820
00821
00822
00823
00824 allocation = mmap(
00825 startAddr
00826 ,(int)size
00827 ,PROT_READ|PROT_WRITE
00828 ,MAP_PRIVATE|MAP_ANONYMOUS
00829 ,-1
00830 ,0);
00831
00832 startAddr = allocation + size;
00833
00834 if ( allocation == (caddr_t)-1 )
00835 EF_Exit("mmap() failed: %s", stringErrorReport());
00836
00837 return (void *)allocation;
00838 }
00839 #else
00840 void *
00841 Page_Create(size_t size)
00842 {
00843 static int devZeroFd = -1;
00844 caddr_t allocation;
00845
00846 if ( devZeroFd == -1 ) {
00847 devZeroFd = open("/dev/zero", O_RDWR);
00848 if ( devZeroFd < 0 )
00849 EF_Exit(
00850 "open() on /dev/zero failed: %s"
00851 ,stringErrorReport());
00852 }
00853
00854
00855
00856
00857
00858
00859
00860
00861
00862
00863
00864 allocation = mmap(
00865 startAddr
00866 ,(int)size
00867 ,PROT_READ|PROT_WRITE
00868 ,MAP_PRIVATE
00869 ,devZeroFd
00870 ,0);
00871
00872 startAddr = allocation + size;
00873
00874 if ( allocation == (caddr_t)-1 )
00875 EF_Exit("mmap() failed: %s", stringErrorReport());
00876
00877 return (void *)allocation;
00878 }
00879 #endif
00880
00881 static void
00882 mprotectFailed(void)
00883 {
00884 EF_Exit("mprotect() failed: %s", stringErrorReport());
00885 }
00886
00887 void
00888 Page_AllowAccess(void * address, size_t size)
00889 {
00890 if ( mprotect((caddr_t)address, size, PROT_READ|PROT_WRITE) < 0 )
00891 mprotectFailed();
00892 }
00893
00894 void
00895 Page_DenyAccess(void * address, size_t size)
00896 {
00897 if ( mprotect((caddr_t)address, size, PROT_NONE) < 0 )
00898 mprotectFailed();
00899 }
00900
00901 void
00902 Page_Delete(void * address, size_t size)
00903 {
00904
00905
00906
00907
00908
00909
00910 #if ( defined(_AIX) )
00911 if ( munmap((caddr_t)address, size) < 0 )
00912 EF_Exit("munmap() failed: %s", stringErrorReport());
00913 #else
00914 Page_DenyAccess(address, size);
00915 #endif
00916 }
00917
00918 #if defined(_SC_PAGESIZE)
00919 size_t
00920 Page_Size(void)
00921 {
00922 return (size_t)sysconf(_SC_PAGESIZE);
00923 }
00924 #elif defined(_SC_PAGE_SIZE)
00925 size_t
00926 Page_Size(void)
00927 {
00928 return (size_t)sysconf(_SC_PAGE_SIZE);
00929 }
00930 #else
00931 extern int getpagesize();
00932 size_t
00933 Page_Size(void)
00934 {
00935 return getpagesize();
00936 }
00937 #endif
00938
00939
00940
00941
00942
00943
00944
00945
00946
00947
00948
00949
00950
00951
00952
00953
00954 #define NUMBER_BUFFER_SIZE 64
00955
00956 static void
00957 printNumber(unsigned int number, unsigned int base)
00958 {
00959 char buffer[NUMBER_BUFFER_SIZE];
00960 char * s = &buffer[NUMBER_BUFFER_SIZE];
00961 int size;
00962
00963 do {
00964 unsigned int digit;
00965
00966 if ( --s == buffer )
00967 EF_Abort("Internal error printing number.");
00968
00969 digit = number % base;
00970
00971 if ( digit < 10 )
00972 *s = '0' + digit;
00973 else
00974 *s = 'a' + digit - 10;
00975
00976 } while ( (number /= base) > 0 );
00977
00978 size = &buffer[NUMBER_BUFFER_SIZE] - s;
00979
00980 if ( size > 0 )
00981 write(2, s, size);
00982 }
00983
00984 static void
00985 vprint(const char * pattern, va_list args)
00986 {
00987 static const char bad_pattern[] =
00988 "\nBad pattern specifier %%%c in EF_Print().\n";
00989 const char * s = pattern;
00990 char c;
00991
00992 while ( (c = *s++) != '\0' ) {
00993 if ( c == '%' ) {
00994 c = *s++;
00995 switch ( c ) {
00996 case '%':
00997 (void) write(2, &c, 1);
00998 break;
00999 case 's':
01000 {
01001 const char * string;
01002 size_t length;
01003
01004 string = va_arg(args, char *);
01005 length = strlen(string);
01006
01007 (void) write(2, string, length);
01008 }
01009 break;
01010 case 'd':
01011 {
01012 int n = va_arg(args, int);
01013
01014 if ( n < 0 ) {
01015 char c = '-';
01016 write(2, &c, 1);
01017 n = -n;
01018 }
01019 printNumber(n, 10);
01020 }
01021 break;
01022 case 'x':
01023 printNumber(va_arg(args, u_int), 0x10);
01024 break;
01025 case 'c':
01026 {
01027 char c = va_arg(args, char);
01028
01029 (void) write(2, &c, 1);
01030 }
01031 break;
01032 default:
01033 {
01034 EF_Print(bad_pattern, c);
01035 }
01036
01037 }
01038 }
01039 else
01040 (void) write(2, &c, 1);
01041 }
01042 }
01043
01044 void
01045 EF_Abort(const char * pattern, ...)
01046 {
01047 va_list args;
01048
01049 va_start(args, pattern);
01050
01051 EF_Print("\nElectricFence Aborting: ");
01052 vprint(pattern, args);
01053 EF_Print("\n");
01054
01055 va_end(args);
01056
01057
01058
01059
01060
01061
01062 kill(getpid(), SIGILL);
01063
01064 _exit(-1);
01065 }
01066
01067 void
01068 EF_Exit(const char * pattern, ...)
01069 {
01070 va_list args;
01071
01072 va_start(args, pattern);
01073
01074 EF_Print("\nElectricFence Exiting: ");
01075 vprint(pattern, args);
01076 EF_Print("\n");
01077
01078 va_end(args);
01079
01080
01081
01082
01083
01084 _exit(-1);
01085 }
01086
01087 void
01088 EF_Print(const char * pattern, ...)
01089 {
01090 va_list args;
01091
01092 va_start(args, pattern);
01093 vprint(pattern, args);
01094 va_end(args);
01095 }