D:/Programming/GUI Editor (Source)/mmgr.cpp
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
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077 #include "stdafx.h"
00078 #include <iostream>
00079 #include <stdio.h>
00080 #include <stdlib.h>
00081 #include <assert.h>
00082 #include <string.h>
00083 #include <time.h>
00084 #include <stdarg.h>
00085 #include <new>
00086
00087 #ifndef WIN32
00088 #include <unistd.h>
00089 #endif
00090
00091 #include "mmgr.h"
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150 #ifdef STRESS_TEST
00151 static const unsigned int hashBits = 12;
00152 static bool randomWipe = true;
00153 static bool alwaysValidateAll = true;
00154 static bool alwaysLogAll = true;
00155 static bool alwaysWipeAll = true;
00156 static bool cleanupLogOnFirstRun = true;
00157 static const unsigned int paddingSize = 1024;
00158 #else
00159 static const unsigned int hashBits = 12;
00160 static bool randomWipe = false;
00161 static bool alwaysValidateAll = false;
00162 static bool alwaysLogAll = false;
00163 static bool alwaysWipeAll = true;
00164 static bool cleanupLogOnFirstRun = true;
00165 static const unsigned int paddingSize = 4;
00166 #endif
00167
00168
00169
00170
00171
00172
00173
00174
00175 #ifdef WIN32
00176 #ifdef _DEBUG
00177 #define m_assert(x) if ((x) == false) __asm { int 3 }
00178 #else
00179 #define m_assert(x) {}
00180 #endif
00181 #elif defined(__BEOS__)
00182 #ifdef DEBUG
00183 extern void debugger(const char *message);
00184 #define m_assert(x) if ((x) == false) debugger("mmgr: assert failed")
00185 #else
00186 #define m_assert(x) {}
00187 #endif
00188 #else // Linux uses assert, which we can use safely, since it doesn't bring up a dialog within the program.
00189 #define m_assert(cond) assert(cond)
00190 #endif
00191
00192
00193
00194
00195
00196
00197 #undef new
00198 #undef delete
00199 #undef malloc
00200 #undef calloc
00201 #undef realloc
00202 #undef free
00203
00204
00205
00206
00207
00208 const unsigned int m_alloc_unknown = 0;
00209 const unsigned int m_alloc_new = 1;
00210 const unsigned int m_alloc_new_array = 2;
00211 const unsigned int m_alloc_malloc = 3;
00212 const unsigned int m_alloc_calloc = 4;
00213 const unsigned int m_alloc_realloc = 5;
00214 const unsigned int m_alloc_delete = 6;
00215 const unsigned int m_alloc_delete_array = 7;
00216 const unsigned int m_alloc_free = 8;
00217
00218
00219
00220
00221
00222 static unsigned int prefixPattern = 0xbaadf00d;
00223 static unsigned int postfixPattern = 0xdeadc0de;
00224 static unsigned int unusedPattern = 0xfeedface;
00225 static unsigned int releasedPattern = 0xdeadbeef;
00226
00227
00228
00229
00230
00231 static const unsigned int hashSize = 1 << hashBits;
00232 static const char *allocationTypes[] = {"Unknown",
00233 "new", "new[]", "malloc", "calloc",
00234 "realloc", "delete", "delete[]", "free"};
00235 static sAllocUnit *hashTable[hashSize];
00236 static sAllocUnit *reservoir;
00237 static unsigned int currentAllocationCount = 0;
00238 static unsigned int breakOnAllocationCount = 0;
00239 static sMStats stats;
00240 static const char *sourceFile = "??";
00241 static const char *sourceFunc = "??";
00242 static unsigned int sourceLine = 0;
00243 static bool staticDeinitTime = false;
00244 static sAllocUnit **reservoirBuffer = NULL;
00245 static unsigned int reservoirBufferSize = 0;
00246 static const char *memoryLogFile = "memory.log";
00247 static const char *memoryLeakLogFile = "memleaks.log";
00248 static void doCleanupLogOnFirstRun();
00249
00250
00251
00252
00253
00254 static void log(const char *format, ...)
00255 {
00256
00257
00258 if (cleanupLogOnFirstRun) doCleanupLogOnFirstRun();
00259
00260
00261
00262 static char buffer[2048];
00263 va_list ap;
00264 va_start(ap, format);
00265 vsprintf(buffer, format, ap);
00266 va_end(ap);
00267
00268
00269
00270 FILE *fp = fopen(memoryLogFile, "ab");
00271
00272
00273
00274 m_assert(fp);
00275
00276 if (!fp) return;
00277
00278
00279
00280 fprintf(fp, "%s\r\n", buffer);
00281 fclose(fp);
00282 }
00283
00284
00285
00286 static void doCleanupLogOnFirstRun()
00287 {
00288 if (cleanupLogOnFirstRun)
00289 {
00290 unlink(memoryLogFile);
00291 cleanupLogOnFirstRun = false;
00292
00293
00294
00295 time_t t = time(NULL);
00296 log("--------------------------------------------------------------------------------");
00297 log("");
00298 log(" %s - Memory logging file created on %s", memoryLogFile, asctime(localtime(&t)));
00299 log("--------------------------------------------------------------------------------");
00300 log("");
00301 log("This file contains a log of all memory operations performed during the last run.");
00302 log("");
00303 log("Interrogate this file to track errors or to help track down memory-related");
00304 log("issues. You can do this by tracing the allocations performed by a specific owner");
00305 log("or by tracking a specific address through a series of allocations and");
00306 log("reallocations.");
00307 log("");
00308 log("There is a lot of useful information here which, when used creatively, can be");
00309 log("extremely helpful.");
00310 log("");
00311 log("Note that the following guides are used throughout this file:");
00312 log("");
00313 log(" [!] - Error");
00314 log(" [+] - Allocation");
00315 log(" [~] - Reallocation");
00316 log(" [-] - Deallocation");
00317 log(" [I] - Generic information");
00318 log(" [F] - Failure induced for the purpose of stress-testing your application");
00319 log(" [D] - Information used for debugging this memory manager");
00320 log("");
00321 log("...so, to find all errors in the file, search for \"[!]\"");
00322 log("");
00323 log("--------------------------------------------------------------------------------");
00324 }
00325 }
00326
00327
00328
00329 static const char *sourceFileStripper(const char *sourceFile)
00330 {
00331 char *ptr = strrchr(sourceFile, '\\');
00332 if (ptr) return ptr + 1;
00333 ptr = strrchr(sourceFile, '/');
00334 if (ptr) return ptr + 1;
00335 return sourceFile;
00336 }
00337
00338
00339
00340 static const char *ownerString(const char *sourceFile, const unsigned int sourceLine, const char *sourceFunc)
00341 {
00342 static char str[90];
00343 memset(str, 0, sizeof(str));
00344 sprintf(str, "%s(%05d)::%s", sourceFileStripper(sourceFile), sourceLine, sourceFunc);
00345 return str;
00346 }
00347
00348
00349
00350 static const char *insertCommas(unsigned int value)
00351 {
00352 static char str[30];
00353 memset(str, 0, sizeof(str));
00354
00355 sprintf(str, "%u", value);
00356 if (strlen(str) > 3)
00357 {
00358 memmove(&str[strlen(str)-3], &str[strlen(str)-4], 4);
00359 str[strlen(str) - 4] = ',';
00360 }
00361 if (strlen(str) > 7)
00362 {
00363 memmove(&str[strlen(str)-7], &str[strlen(str)-8], 8);
00364 str[strlen(str) - 8] = ',';
00365 }
00366 if (strlen(str) > 11)
00367 {
00368 memmove(&str[strlen(str)-11], &str[strlen(str)-12], 12);
00369 str[strlen(str) - 12] = ',';
00370 }
00371
00372 return str;
00373 }
00374
00375
00376
00377 static const char *memorySizeString(unsigned long size)
00378 {
00379 static char str[90];
00380 if (size > (1024*1024)) sprintf(str, "%10s (%7.2fM)", insertCommas(size), static_cast<float>(size) / (1024.0f * 1024.0f));
00381 else if (size > 1024) sprintf(str, "%10s (%7.2fK)", insertCommas(size), static_cast<float>(size) / 1024.0f);
00382 else sprintf(str, "%10s bytes ", insertCommas(size));
00383 return str;
00384 }
00385
00386
00387
00388 static sAllocUnit *findAllocUnit(const void *reportedAddress)
00389 {
00390
00391 m_assert(reportedAddress != NULL);
00392
00393
00394
00395
00396
00397 unsigned int hashIndex = (reinterpret_cast<unsigned int>(const_cast<void *>(reportedAddress)) >> 4) & (hashSize - 1);
00398 sAllocUnit *ptr = hashTable[hashIndex];
00399 while(ptr)
00400 {
00401 if (ptr->reportedAddress == reportedAddress) return ptr;
00402 ptr = ptr->next;
00403 }
00404
00405 return NULL;
00406 }
00407
00408
00409
00410 static size_t calculateActualSize(const size_t reportedSize)
00411 {
00412
00413
00414
00415
00416 return reportedSize + paddingSize * sizeof(long) * 2;
00417 }
00418
00419
00420
00421 static size_t calculateReportedSize(const size_t actualSize)
00422 {
00423
00424
00425
00426
00427 return actualSize - paddingSize * sizeof(long) * 2;
00428 }
00429
00430
00431
00432 static void *calculateReportedAddress(const void *actualAddress)
00433 {
00434
00435
00436 if (!actualAddress) return NULL;
00437
00438
00439
00440 return reinterpret_cast<void *>(const_cast<char *>(reinterpret_cast<const char *>(actualAddress) + sizeof(long) * paddingSize));
00441 }
00442
00443
00444
00445 static void wipeWithPattern(sAllocUnit *allocUnit, unsigned long pattern, const unsigned int originalReportedSize = 0)
00446 {
00447
00448
00449
00450
00451
00452 if (randomWipe)
00453 {
00454 pattern = ((rand() & 0xff) << 24) | ((rand() & 0xff) << 16) | ((rand() & 0xff) << 8) | (rand() & 0xff);
00455 }
00456
00457
00458
00459
00460
00461
00462
00463
00464
00465
00466 if (alwaysWipeAll && allocUnit->reportedSize > originalReportedSize)
00467 {
00468
00469
00470 long *lptr = reinterpret_cast<long *>(reinterpret_cast<char *>(allocUnit->reportedAddress) + originalReportedSize);
00471 int length = static_cast<int>(allocUnit->reportedSize - originalReportedSize);
00472 int i;
00473 for (i = 0; i < (length >> 2); i++, lptr++)
00474 {
00475 *lptr = pattern;
00476 }
00477
00478
00479
00480 unsigned int shiftCount = 0;
00481 char *cptr = reinterpret_cast<char *>(lptr);
00482 for (i = 0; i < (length & 0x3); i++, cptr++, shiftCount += 8)
00483 {
00484 *cptr = static_cast<char>((pattern & (0xff << shiftCount)) >> shiftCount);
00485 }
00486 }
00487
00488
00489
00490 long *pre = reinterpret_cast<long *>(allocUnit->actualAddress);
00491 long *post = reinterpret_cast<long *>(reinterpret_cast<char *>(allocUnit->actualAddress) + allocUnit->actualSize - paddingSize * sizeof(long));
00492 for (unsigned int i = 0; i < paddingSize; i++, pre++, post++)
00493 {
00494 *pre = prefixPattern;
00495 *post = postfixPattern;
00496 }
00497 }
00498
00499
00500
00501 static void dumpAllocations(FILE *fp)
00502 {
00503 fprintf(fp, "Alloc. Addr Size Addr Size BreakOn BreakOn \r\n");
00504 fprintf(fp, "Number Reported Reported Actual Actual Unused Method Dealloc Realloc Allocated by \r\n");
00505 fprintf(fp, "------ ---------- ---------- ---------- ---------- ---------- -------- ------- ------- --------------------------------------------------- \r\n");
00506
00507
00508 for (unsigned int i = 0; i < hashSize; i++)
00509 {
00510 sAllocUnit *ptr = hashTable[i];
00511 while(ptr)
00512 {
00513 fprintf(fp, "%06d 0x%08X 0x%08X 0x%08X 0x%08X 0x%08X %-8s %c %c %s\r\n",
00514 ptr->allocationNumber,
00515 reinterpret_cast<unsigned int>(ptr->reportedAddress), ptr->reportedSize,
00516 reinterpret_cast<unsigned int>(ptr->actualAddress), ptr->actualSize,
00517 m_calcUnused(ptr),
00518 allocationTypes[ptr->allocationType],
00519 ptr->breakOnDealloc ? 'Y':'N',
00520 ptr->breakOnRealloc ? 'Y':'N',
00521 ownerString(ptr->sourceFile, ptr->sourceLine, ptr->sourceFunc));
00522 ptr = ptr->next;
00523 }
00524 }
00525 }
00526
00527
00528
00529 static void dumpLeakReport()
00530 {
00531
00532
00533 FILE *fp = fopen(memoryLeakLogFile, "w+b");
00534
00535
00536
00537 m_assert(fp);
00538 if (!fp) return;
00539
00540
00541
00542
00543
00544 static char timeString[25];
00545 memset(timeString, 0, sizeof(timeString));
00546 time_t t = time(NULL);
00547 struct tm *tme = localtime(&t);
00548 fprintf(fp, " ---------------------------------------------------------------------------------------------------------------------------------- \r\n");
00549 fprintf(fp, "| Memory leak report for: %02d/%02d/%04d %02d:%02d:%02d |\r\n", tme->tm_mon + 1, tme->tm_mday, tme->tm_year + 1900, tme->tm_hour, tme->tm_min, tme->tm_sec);
00550 fprintf(fp, " ---------------------------------------------------------------------------------------------------------------------------------- \r\n");
00551 fprintf(fp, "\r\n");
00552 fprintf(fp, "\r\n");
00553 if (stats.totalAllocUnitCount)
00554 {
00555 fprintf(fp, "%d memory leak%s found:\r\n", stats.totalAllocUnitCount, stats.totalAllocUnitCount == 1 ? "":"s");
00556 }
00557 else
00558 {
00559 fprintf(fp, "Congratulations! No memory leaks found!\r\n");
00560
00561
00562
00563 if (reservoirBuffer)
00564 {
00565 for (unsigned int i = 0; i < reservoirBufferSize; i++)
00566 {
00567 free(reservoirBuffer[i]);
00568 }
00569 free(reservoirBuffer);
00570 reservoirBuffer = 0;
00571 reservoirBufferSize = 0;
00572 reservoir = NULL;
00573 }
00574 }
00575 fprintf(fp, "\r\n");
00576
00577 if (stats.totalAllocUnitCount)
00578 {
00579 dumpAllocations(fp);
00580 }
00581
00582 fclose(fp);
00583 }
00584
00585
00586
00587
00588
00589 class MemStaticTimeTracker
00590 {
00591 public:
00592 MemStaticTimeTracker() {doCleanupLogOnFirstRun();}
00593 ~MemStaticTimeTracker() {staticDeinitTime = true; dumpLeakReport();}
00594 };
00595 static MemStaticTimeTracker mstt;
00596
00597
00598
00599
00600
00601 bool &m_alwaysValidateAll()
00602 {
00603
00604 return alwaysValidateAll;
00605 }
00606
00607
00608
00609 bool &m_alwaysLogAll()
00610 {
00611
00612 return alwaysLogAll;
00613 }
00614
00615
00616
00617 bool &m_alwaysWipeAll()
00618 {
00619
00620 return alwaysWipeAll;
00621 }
00622
00623
00624
00625 bool &m_randomeWipe()
00626 {
00627
00628 return randomWipe;
00629 }
00630
00631
00632
00633
00634
00635
00636 bool &m_breakOnRealloc(void *reportedAddress)
00637 {
00638
00639
00640 sAllocUnit *au = findAllocUnit(reportedAddress);
00641
00642
00643
00644 m_assert(au != NULL);
00645
00646
00647
00648 m_assert(au->allocationType == m_alloc_malloc ||
00649 au->allocationType == m_alloc_calloc ||
00650 au->allocationType == m_alloc_realloc);
00651
00652 return au->breakOnRealloc;
00653 }
00654
00655
00656
00657
00658
00659
00660 bool &m_breakOnDealloc(void *reportedAddress)
00661 {
00662
00663
00664 sAllocUnit *au = findAllocUnit(reportedAddress);
00665
00666
00667
00668 m_assert(au != NULL);
00669
00670 return au->breakOnDealloc;
00671 }
00672
00673
00674
00675
00676
00677 void m_breakOnAllocation(unsigned int count)
00678 {
00679 breakOnAllocationCount = count;
00680 }
00681
00682
00683
00684
00685
00686 void m_setOwner(const char *file, const unsigned int line, const char *func)
00687 {
00688
00689
00690
00691
00692
00693
00694
00695
00696
00697
00698
00699
00700
00701
00702
00703
00704
00705
00706
00707
00708
00709
00710
00711
00712
00713
00714
00715
00716
00717
00718
00719
00720
00721
00722
00723
00724
00725
00726
00727
00728
00729
00730 if (sourceLine && alwaysLogAll)
00731 {
00732 log("[I] NOTE! Possible destructor chain: previous owner is %s", ownerString(sourceFile, sourceLine, sourceFunc));
00733 }
00734
00735
00736
00737 sourceFile = file;
00738 sourceLine = line;
00739 sourceFunc = func;
00740 }
00741
00742
00743
00744 static void resetGlobals()
00745 {
00746 sourceFile = "??";
00747 sourceLine = 0;
00748 sourceFunc = "??";
00749 }
00750
00751
00752
00753
00754
00755
00756
00757
00758 void *operator new(size_t reportedSize)
00759 {
00760 #ifdef TEST_MEMORY_MANAGER
00761 log("[D] ENTER: new");
00762 #endif
00763
00764
00765
00766 const char *file = sourceFile;
00767 const unsigned int line = sourceLine;
00768 const char *func = sourceFunc;
00769
00770
00771
00772 if (reportedSize == 0) reportedSize = 1;
00773
00774
00775
00776 for(;;)
00777 {
00778
00779
00780 void *ptr = m_allocator(file, line, func, m_alloc_new, reportedSize);
00781 if (ptr)
00782 {
00783 #ifdef TEST_MEMORY_MANAGER
00784 log("[D] EXIT : new");
00785 #endif
00786 return ptr;
00787 }
00788
00789
00790
00791
00792 new_handler nh = std::set_new_handler(0);
00793 std::set_new_handler(nh);
00794
00795
00796
00797 if (nh)
00798 {
00799 (*nh)();
00800 }
00801
00802
00803
00804 else
00805 {
00806 #ifdef TEST_MEMORY_MANAGER
00807 log("[D] EXIT : new");
00808 #endif
00809 throw std::bad_alloc();
00810 }
00811 }
00812 }
00813
00814
00815
00816 void *operator new[](size_t reportedSize)
00817 {
00818 #ifdef TEST_MEMORY_MANAGER
00819 log("[D] ENTER: new[]");
00820 #endif
00821
00822
00823
00824 const char *file = sourceFile;
00825 const unsigned int line = sourceLine;
00826 const char *func = sourceFunc;
00827
00828
00829
00830 if (reportedSize == 0) reportedSize = 1;
00831
00832
00833
00834 for(;;)
00835 {
00836
00837
00838 void *ptr = m_allocator(file, line, func, m_alloc_new_array, reportedSize);
00839 if (ptr)
00840 {
00841 #ifdef TEST_MEMORY_MANAGER
00842 log("[D] EXIT : new[]");
00843 #endif
00844 return ptr;
00845 }
00846
00847
00848
00849
00850 new_handler nh = std::set_new_handler(0);
00851 std::set_new_handler(nh);
00852
00853
00854
00855 if (nh)
00856 {
00857 (*nh)();
00858 }
00859
00860
00861
00862 else
00863 {
00864 #ifdef TEST_MEMORY_MANAGER
00865 log("[D] EXIT : new[]");
00866 #endif
00867 throw std::bad_alloc();
00868 }
00869 }
00870 }
00871
00872
00873
00874
00875
00876
00877
00878
00879
00880 void *operator new(size_t reportedSize, const char *sourceFile, int sourceLine)
00881 {
00882 #ifdef TEST_MEMORY_MANAGER
00883 log("[D] ENTER: new");
00884 #endif
00885
00886
00887
00888 if (reportedSize == 0) reportedSize = 1;
00889
00890
00891
00892 for(;;)
00893 {
00894
00895
00896 void *ptr = m_allocator(sourceFile, sourceLine, "??", m_alloc_new, reportedSize);
00897 if (ptr)
00898 {
00899 #ifdef TEST_MEMORY_MANAGER
00900 log("[D] EXIT : new");
00901 #endif
00902 return ptr;
00903 }
00904
00905
00906
00907
00908 new_handler nh = std::set_new_handler(0);
00909 std::set_new_handler(nh);
00910
00911
00912
00913 if (nh)
00914 {
00915 (*nh)();
00916 }
00917
00918
00919
00920 else
00921 {
00922 #ifdef TEST_MEMORY_MANAGER
00923 log("[D] EXIT : new");
00924 #endif
00925 throw std::bad_alloc();
00926 }
00927 }
00928 }
00929
00930
00931
00932 void *operator new[](size_t reportedSize, const char *sourceFile, int sourceLine)
00933 {
00934 #ifdef TEST_MEMORY_MANAGER
00935 log("[D] ENTER: new[]");
00936 #endif
00937
00938
00939
00940 if (reportedSize == 0) reportedSize = 1;
00941
00942
00943
00944 for(;;)
00945 {
00946
00947
00948 void *ptr = m_allocator(sourceFile, sourceLine, "??", m_alloc_new_array, reportedSize);
00949 if (ptr)
00950 {
00951 #ifdef TEST_MEMORY_MANAGER
00952 log("[D] EXIT : new[]");
00953 #endif
00954 return ptr;
00955 }
00956
00957
00958
00959
00960 new_handler nh = std::set_new_handler(0);
00961 std::set_new_handler(nh);
00962
00963
00964
00965 if (nh)
00966 {
00967 (*nh)();
00968 }
00969
00970
00971
00972 else
00973 {
00974 #ifdef TEST_MEMORY_MANAGER
00975 log("[D] EXIT : new[]");
00976 #endif
00977 throw std::bad_alloc();
00978 }
00979 }
00980 }
00981
00982
00983
00984
00985
00986
00987
00988
00989 void operator delete(void *reportedAddress)
00990 {
00991 #ifdef TEST_MEMORY_MANAGER
00992 log("[D] ENTER: delete");
00993 #endif
00994
00995
00996
00997 if (reportedAddress) m_deallocator(sourceFile, sourceLine, sourceFunc, m_alloc_delete, reportedAddress);
00998 else if (alwaysLogAll) log("[-] ----- %8s of NULL by %s", allocationTypes[m_alloc_delete], ownerString(sourceFile, sourceLine, sourceFunc));
00999
01000
01001
01002
01003 resetGlobals();
01004
01005 #ifdef TEST_MEMORY_MANAGER
01006 log("[D] EXIT : delete");
01007 #endif
01008 }
01009
01010
01011
01012 void operator delete[](void *reportedAddress)
01013 {
01014 #ifdef TEST_MEMORY_MANAGER
01015 log("[D] ENTER: delete[]");
01016 #endif
01017
01018
01019
01020 if (reportedAddress) m_deallocator(sourceFile, sourceLine, sourceFunc, m_alloc_delete_array, reportedAddress);
01021 else if (alwaysLogAll)
01022 log("[-] ----- %8s of NULL by %s", allocationTypes[m_alloc_delete_array], ownerString(sourceFile, sourceLine, sourceFunc));
01023
01024
01025
01026
01027 resetGlobals();
01028
01029 #ifdef TEST_MEMORY_MANAGER
01030 log("[D] EXIT : delete[]");
01031 #endif
01032 }
01033
01034
01035
01036
01037
01038 void *m_allocator(const char *sourceFile, const unsigned int sourceLine, const char *sourceFunc, const unsigned int allocationType, const size_t reportedSize)
01039 {
01040 try
01041 {
01042 #ifdef TEST_MEMORY_MANAGER
01043 log("[D] ENTER: m_allocator()");
01044 #endif
01045
01046
01047
01048 currentAllocationCount++;
01049
01050
01051
01052 if (alwaysLogAll) log("[+] %05d %8s of size 0x%08X(%08d) by %s", currentAllocationCount, allocationTypes[allocationType], reportedSize, reportedSize, ownerString(sourceFile, sourceLine, sourceFunc));
01053
01054
01055 m_assert(currentAllocationCount != breakOnAllocationCount);
01056
01057
01058
01059 if (!reservoir)
01060 {
01061
01062
01063 reservoir = (sAllocUnit *) malloc(sizeof(sAllocUnit) * 256);
01064
01065
01066
01067 m_assert(reservoir != NULL);
01068
01069
01070
01071 if (reservoir == NULL) throw "Unable to allocate RAM for internal memory tracking data";
01072
01073
01074
01075 memset(reservoir, 0, sizeof(sAllocUnit) * 256);
01076 for (unsigned int i = 0; i < 256 - 1; i++)
01077 {
01078 reservoir[i].next = &reservoir[i+1];
01079 }
01080
01081
01082
01083 sAllocUnit **temp = (sAllocUnit **) realloc(reservoirBuffer, (reservoirBufferSize + 1) * sizeof(sAllocUnit *));
01084 m_assert(temp);
01085 if (temp)
01086 {
01087 reservoirBuffer = temp;
01088 reservoirBuffer[reservoirBufferSize++] = reservoir;
01089 }
01090 }
01091
01092
01093 m_assert(reservoir != NULL);
01094
01095
01096
01097 sAllocUnit *au = reservoir;
01098 reservoir = au->next;
01099
01100
01101
01102 memset(au, 0, sizeof(sAllocUnit));
01103 au->actualSize = calculateActualSize(reportedSize);
01104 #ifdef RANDOM_FAILURE
01105 double a = rand();
01106 double b = RAND_MAX / 100.0 * RANDOM_FAILURE;
01107 if (a > b)
01108 {
01109 au->actualAddress = malloc(au->actualSize);
01110 }
01111 else
01112 {
01113 log("[F] Random faiure");
01114 au->actualAddress = NULL;
01115 }
01116 #else
01117 au->actualAddress = malloc(au->actualSize);
01118 #endif
01119 au->reportedSize = reportedSize;
01120 au->reportedAddress = calculateReportedAddress(au->actualAddress);
01121 au->allocationType = allocationType;
01122 au->sourceLine = sourceLine;
01123 au->allocationNumber = currentAllocationCount;
01124 if (sourceFile) strncpy(au->sourceFile, sourceFileStripper(sourceFile), sizeof(au->sourceFile) - 1);
01125 else strcpy (au->sourceFile, "??");
01126 if (sourceFunc) strncpy(au->sourceFunc, sourceFunc, sizeof(au->sourceFunc) - 1);
01127 else strcpy (au->sourceFunc, "??");
01128
01129
01130
01131 #ifndef RANDOM_FAILURE
01132
01133
01134 m_assert(au->actualAddress != NULL);
01135 #endif
01136
01137 if (au->actualAddress == NULL)
01138 {
01139 throw "Request for allocation failed. Out of memory.";
01140 }
01141
01142
01143
01144 m_assert(allocationType != m_alloc_unknown);
01145
01146
01147
01148 unsigned int hashIndex = (reinterpret_cast<unsigned int>(au->reportedAddress) >> 4) & (hashSize - 1);
01149 if (hashTable[hashIndex]) hashTable[hashIndex]->prev = au;
01150 au->next = hashTable[hashIndex];
01151 au->prev = NULL;
01152 hashTable[hashIndex] = au;
01153
01154
01155
01156 stats.totalReportedMemory += static_cast<unsigned int>(au->reportedSize);
01157 stats.totalActualMemory += static_cast<unsigned int>(au->actualSize);
01158 stats.totalAllocUnitCount++;
01159 if (stats.totalReportedMemory > stats.peakReportedMemory) stats.peakReportedMemory = stats.totalReportedMemory;
01160 if (stats.totalActualMemory > stats.peakActualMemory) stats.peakActualMemory = stats.totalActualMemory;
01161 if (stats.totalAllocUnitCount > stats.peakAllocUnitCount) stats.peakAllocUnitCount = stats.totalAllocUnitCount;
01162 stats.accumulatedReportedMemory += static_cast<unsigned int>(au->reportedSize);
01163 stats.accumulatedActualMemory += static_cast<unsigned int>(au->actualSize);
01164 stats.accumulatedAllocUnitCount++;
01165
01166
01167
01168 wipeWithPattern(au, unusedPattern);
01169
01170
01171
01172 if (allocationType == m_alloc_calloc)
01173 {
01174 memset(au->reportedAddress, 0, au->reportedSize);
01175 }
01176
01177
01178
01179 if (alwaysValidateAll) m_validateAllAllocUnits();
01180
01181
01182
01183 if (alwaysLogAll) log("[+] ----> addr 0x%08X", reinterpret_cast<unsigned int>(au->reportedAddress));
01184
01185
01186
01187
01188 resetGlobals();
01189
01190
01191
01192 #ifdef TEST_MEMORY_MANAGER
01193 log("[D] EXIT : m_allocator()");
01194 #endif
01195
01196 return au->reportedAddress;
01197 }
01198 catch(const char *err)
01199 {
01200
01201
01202 log("[!] %s", err);
01203 resetGlobals();
01204
01205 #ifdef TEST_MEMORY_MANAGER
01206 log("[D] EXIT : m_allocator()");
01207 #endif
01208
01209 return NULL;
01210 }
01211 }
01212
01213
01214
01215
01216
01217 void *m_reallocator(const char *sourceFile, const unsigned int sourceLine, const char *sourceFunc, const unsigned int reallocationType, const size_t reportedSize, void *reportedAddress)
01218 {
01219 try
01220 {
01221 #ifdef TEST_MEMORY_MANAGER
01222 log("[D] ENTER: m_reallocator()");
01223 #endif
01224
01225
01226
01227 if (!reportedAddress)
01228 {
01229 return m_allocator(sourceFile, sourceLine, sourceFunc, reallocationType, reportedSize);
01230 }
01231
01232
01233
01234 currentAllocationCount++;
01235
01236
01237 m_assert(currentAllocationCount != breakOnAllocationCount);
01238
01239
01240
01241 if (alwaysLogAll) log("[~] %05d %8s of size 0x%08X(%08d) by %s", currentAllocationCount, allocationTypes[reallocationType], reportedSize, reportedSize, ownerString(sourceFile, sourceLine, sourceFunc));
01242
01243
01244
01245 sAllocUnit *au = findAllocUnit(reportedAddress);
01246
01247
01248 m_assert(au != NULL);
01249 if (au == NULL) throw "Request to reallocate RAM that was never allocated";
01250
01251
01252
01253 m_assert(m_validateAllocUnit(au));
01254
01255
01256
01257 m_assert(reallocationType != m_alloc_unknown);
01258
01259
01260
01261 m_assert(au->allocationType == m_alloc_malloc ||
01262 au->allocationType == m_alloc_calloc ||
01263 au->allocationType == m_alloc_realloc);
01264
01265
01266
01267
01268 m_assert(au->breakOnRealloc == false);
01269
01270
01271
01272 unsigned int originalReportedSize = static_cast<unsigned int>(au->reportedSize);
01273
01274 if (alwaysLogAll) log("[~] ----> from 0x%08X(%08d)", originalReportedSize, originalReportedSize);
01275
01276
01277
01278 void *oldReportedAddress = reportedAddress;
01279 size_t newActualSize = calculateActualSize(reportedSize);
01280 void *newActualAddress = NULL;
01281 #ifdef RANDOM_FAILURE
01282 double a = rand();
01283 double b = RAND_MAX / 100.0 * RANDOM_FAILURE;
01284 if (a > b)
01285 {
01286 newActualAddress = realloc(au->actualAddress, newActualSize);
01287 }
01288 else
01289 {
01290 log("[F] Random faiure");
01291 }
01292 #else
01293 newActualAddress = realloc(au->actualAddress, newActualSize);
01294 #endif
01295
01296
01297
01298 #ifndef RANDOM_FAILURE
01299
01300
01301
01302 m_assert(newActualAddress);
01303 #endif
01304
01305 if (!newActualAddress) throw "Request for reallocation failed. Out of memory.";
01306
01307
01308
01309 stats.totalReportedMemory -= static_cast<unsigned int>(au->reportedSize);
01310 stats.totalActualMemory -= static_cast<unsigned int>(au->actualSize);
01311
01312
01313
01314 au->actualSize = newActualSize;
01315 au->actualAddress = newActualAddress;
01316 au->reportedSize = calculateReportedSize(newActualSize);
01317 au->reportedAddress = calculateReportedAddress(newActualAddress);
01318 au->allocationType = reallocationType;
01319 au->sourceLine = sourceLine;
01320 au->allocationNumber = currentAllocationCount;
01321 if (sourceFile) strncpy(au->sourceFile, sourceFileStripper(sourceFile), sizeof(au->sourceFile) - 1);
01322 else strcpy (au->sourceFile, "??");
01323 if (sourceFunc) strncpy(au->sourceFunc, sourceFunc, sizeof(au->sourceFunc) - 1);
01324 else strcpy (au->sourceFunc, "??");
01325
01326
01327
01328 unsigned int hashIndex = static_cast<unsigned int>(-1);
01329 if (oldReportedAddress != au->reportedAddress)
01330 {
01331
01332
01333 {
01334 unsigned int hashIndex = (reinterpret_cast<unsigned int>(oldReportedAddress) >> 4) & (hashSize - 1);
01335 if (hashTable[hashIndex] == au)
01336 {
01337 hashTable[hashIndex] = hashTable[hashIndex]->next;
01338 }
01339 else
01340 {
01341 if (au->prev) au->prev->next = au->next;
01342 if (au->next) au->next->prev = au->prev;
01343 }
01344 }
01345
01346
01347
01348 hashIndex = (reinterpret_cast<unsigned int>(au->reportedAddress) >> 4) & (hashSize - 1);
01349 if (hashTable[hashIndex]) hashTable[hashIndex]->prev = au;
01350 au->next = hashTable[hashIndex];
01351 au->prev = NULL;
01352 hashTable[hashIndex] = au;
01353 }
01354
01355
01356
01357 stats.totalReportedMemory += static_cast<unsigned int>(au->reportedSize);
01358 stats.totalActualMemory += static_cast<unsigned int>(au->actualSize);
01359 if (stats.totalReportedMemory > stats.peakReportedMemory) stats.peakReportedMemory = stats.totalReportedMemory;
01360 if (stats.totalActualMemory > stats.peakActualMemory) stats.peakActualMemory = stats.totalActualMemory;
01361 int deltaReportedSize = static_cast<int>(reportedSize - originalReportedSize);
01362 if (deltaReportedSize > 0)
01363 {
01364 stats.accumulatedReportedMemory += deltaReportedSize;
01365 stats.accumulatedActualMemory += deltaReportedSize;
01366 }
01367
01368
01369
01370 wipeWithPattern(au, unusedPattern, originalReportedSize);
01371
01372
01373
01374 m_assert(m_validateAllocUnit(au));
01375
01376
01377
01378 if (alwaysValidateAll) m_validateAllAllocUnits();
01379
01380
01381
01382 if (alwaysLogAll) log("[~] ----> addr 0x%08X", reinterpret_cast<unsigned int>(au->reportedAddress));
01383
01384
01385
01386
01387 resetGlobals();
01388
01389
01390
01391 #ifdef TEST_MEMORY_MANAGER
01392 log("[D] EXIT : m_reallocator()");
01393 #endif
01394
01395 return au->reportedAddress;
01396 }
01397 catch(const char *err)
01398 {
01399
01400
01401 log("[!] %s", err);
01402 resetGlobals();
01403
01404 #ifdef TEST_MEMORY_MANAGER
01405 log("[D] EXIT : m_reallocator()");
01406 #endif
01407
01408 return NULL;
01409 }
01410 }
01411
01412
01413
01414
01415
01416 void m_deallocator(const char *sourceFile, const unsigned int sourceLine, const char *sourceFunc, const unsigned int deallocationType, const void *reportedAddress)
01417 {
01418 try
01419 {
01420 #ifdef TEST_MEMORY_MANAGER
01421 log("[D] ENTER: m_deallocator()");
01422 #endif
01423
01424
01425
01426 if (alwaysLogAll) log("[-] ----- %8s of addr 0x%08X by %s", allocationTypes[deallocationType], reinterpret_cast<unsigned int>(const_cast<void *>(reportedAddress)), ownerString(sourceFile, sourceLine, sourceFunc));
01427
01428
01429
01430
01431
01432 if (reportedAddress)
01433 {
01434
01435
01436 sAllocUnit *au = findAllocUnit(reportedAddress);
01437
01438
01439 m_assert(au != NULL);
01440 if (au == NULL) throw "Request to deallocate RAM that was never allocated";
01441
01442
01443
01444 m_assert(m_validateAllocUnit(au));
01445
01446
01447
01448 m_assert(deallocationType != m_alloc_unknown);
01449
01450
01451
01452 m_assert((deallocationType == m_alloc_delete && au->allocationType == m_alloc_new ) ||
01453 (deallocationType == m_alloc_delete_array && au->allocationType == m_alloc_new_array) ||
01454 (deallocationType == m_alloc_free && au->allocationType == m_alloc_malloc ) ||
01455 (deallocationType == m_alloc_free && au->allocationType == m_alloc_calloc ) ||
01456 (deallocationType == m_alloc_free && au->allocationType == m_alloc_realloc ) ||
01457 (deallocationType == m_alloc_unknown ) );
01458
01459
01460
01461 m_assert(au->breakOnDealloc == false);
01462
01463
01464
01465
01466 wipeWithPattern(au, releasedPattern);
01467
01468
01469
01470 free(au->actualAddress);
01471
01472
01473
01474 unsigned int hashIndex = (reinterpret_cast<unsigned int>(au->reportedAddress) >> 4) & (hashSize - 1);
01475 if (hashTable[hashIndex] == au)
01476 {
01477 hashTable[hashIndex] = au->next;
01478 }
01479 else
01480 {
01481 if (au->prev) au->prev->next = au->next;
01482 if (au->next) au->next->prev = au->prev;
01483 }
01484
01485
01486
01487 stats.totalReportedMemory -= static_cast<unsigned int>(au->reportedSize);
01488 stats.totalActualMemory -= static_cast<unsigned int>(au->actualSize);
01489 stats.totalAllocUnitCount--;
01490
01491
01492
01493 memset(au, 0, sizeof(sAllocUnit));
01494 au->next = reservoir;
01495 reservoir = au;
01496 }
01497
01498
01499
01500
01501 resetGlobals();
01502
01503
01504
01505 if (alwaysValidateAll) m_validateAllAllocUnits();
01506
01507
01508
01509 if (staticDeinitTime) dumpLeakReport();
01510 }
01511 catch(const char *err)
01512 {
01513
01514
01515 log("[!] %s", err);
01516 resetGlobals();
01517 }
01518
01519 #ifdef TEST_MEMORY_MANAGER
01520 log("[D] EXIT : m_deallocator()");
01521 #endif
01522 }
01523
01524
01525
01526
01527
01528
01529 bool m_validateAddress(const void *reportedAddress)
01530 {
01531
01532
01533 return findAllocUnit(reportedAddress) != NULL;
01534 }
01535
01536
01537
01538 bool m_validateAllocUnit(const sAllocUnit *allocUnit)
01539 {
01540
01541
01542 long *pre = reinterpret_cast<long *>(allocUnit->actualAddress);
01543 long *post = reinterpret_cast<long *>((char *)allocUnit->actualAddress + allocUnit->actualSize - paddingSize * sizeof(long));
01544 bool errorFlag = false;
01545 for (unsigned int i = 0; i < paddingSize; i++, pre++, post++)
01546 {
01547 if (*pre != (long) prefixPattern)
01548 {
01549 log("[!] A memory allocation unit was corrupt because of an underrun:");
01550 m_dumpAllocUnit(allocUnit, " ");
01551 errorFlag = true;
01552 }
01553
01554
01555
01556
01557 m_assert(*pre == static_cast<long>(prefixPattern));
01558
01559 if (*post != static_cast<long>(postfixPattern))
01560 {
01561 log("[!] A memory allocation unit was corrupt because of an overrun:");
01562 m_dumpAllocUnit(allocUnit, " ");
01563 errorFlag = true;
01564 }
01565
01566
01567
01568
01569 m_assert(*post == static_cast<long>(postfixPattern));
01570 }
01571
01572
01573
01574 return !errorFlag;
01575 }
01576
01577
01578
01579 bool m_validateAllAllocUnits()
01580 {
01581
01582
01583 unsigned int errors = 0;
01584 unsigned int allocCount = 0;
01585 for (unsigned int i = 0; i < hashSize; i++)
01586 {
01587 sAllocUnit *ptr = hashTable[i];
01588 while(ptr)
01589 {
01590 allocCount++;
01591 if (!m_validateAllocUnit(ptr)) errors++;
01592 ptr = ptr->next;
01593 }
01594 }
01595
01596
01597
01598 if (allocCount != stats.totalAllocUnitCount)
01599 {
01600 log("[!] Memory tracking hash table corrupt!");
01601 errors++;
01602 }
01603
01604
01605
01606
01607
01608
01609 m_assert(allocCount == stats.totalAllocUnitCount);
01610
01611
01612
01613 m_assert(errors == 0);
01614
01615
01616
01617 if (errors) log("[!] While validting all allocation units, %d allocation unit(s) were found to have problems", errors);
01618
01619
01620
01621 return errors != 0;
01622 }
01623
01624
01625
01626
01627
01628 unsigned int m_calcUnused(const sAllocUnit *allocUnit)
01629 {
01630 const unsigned long *ptr = reinterpret_cast<const unsigned long *>(allocUnit->reportedAddress);
01631 unsigned int count = 0;
01632
01633 for (unsigned int i = 0; i < allocUnit->reportedSize; i += sizeof(long), ptr++)
01634 {
01635 if (*ptr == unusedPattern) count += sizeof(long);
01636 }
01637
01638 return count;
01639 }
01640
01641
01642
01643 unsigned int m_calcAllUnused()
01644 {
01645
01646
01647 unsigned int total = 0;
01648 for (unsigned int i = 0; i < hashSize; i++)
01649 {
01650 sAllocUnit *ptr = hashTable[i];
01651 while(ptr)
01652 {
01653 total += m_calcUnused(ptr);
01654 ptr = ptr->next;
01655 }
01656 }
01657
01658 return total;
01659 }
01660
01661
01662
01663
01664
01665 void m_dumpAllocUnit(const sAllocUnit *allocUnit, const char *prefix)
01666 {
01667 log("[I] %sAddress (reported): %010p", prefix, allocUnit->reportedAddress);
01668 log("[I] %sAddress (actual) : %010p", prefix, allocUnit->actualAddress);
01669 log("[I] %sSize (reported) : 0x%08X (%s)", prefix, static_cast<unsigned int>(allocUnit->reportedSize), memorySizeString(static_cast<unsigned int>(allocUnit->reportedSize)));
01670 log("[I] %sSize (actual) : 0x%08X (%s)", prefix, static_cast<unsigned int>(allocUnit->actualSize), memorySizeString(static_cast<unsigned int>(allocUnit->actualSize)));
01671 log("[I] %sOwner : %s(%d)::%s", prefix, allocUnit->sourceFile, allocUnit->sourceLine, allocUnit->sourceFunc);
01672 log("[I] %sAllocation type : %s", prefix, allocationTypes[allocUnit->allocationType]);
01673 log("[I] %sAllocation number : %d", prefix, allocUnit->allocationNumber);
01674 }
01675
01676
01677
01678 void m_dumpMemoryReport(const char *filename, const bool overwrite)
01679 {
01680
01681
01682 FILE *fp = NULL;
01683
01684 if (overwrite) fp = fopen(filename, "w+b");
01685 else fp = fopen(filename, "ab");
01686
01687
01688
01689 m_assert(fp);
01690 if (!fp) return;
01691
01692
01693
01694 static char timeString[25];
01695 memset(timeString, 0, sizeof(timeString));
01696 time_t t = time(NULL);
01697 struct tm *tme = localtime(&t);
01698 fprintf(fp, " ---------------------------------------------------------------------------------------------------------------------------------- \r\n");
01699 fprintf(fp, "| Memory report for: %02d/%02d/%04d %02d:%02d:%02d |\r\n", tme->tm_mon + 1, tme->tm_mday, tme->tm_year + 1900, tme->tm_hour, tme->tm_min, tme->tm_sec);
01700 fprintf(fp, " ---------------------------------------------------------------------------------------------------------------------------------- \r\n");
01701 fprintf(fp, "\r\n");
01702 fprintf(fp, "\r\n");
01703
01704
01705
01706 fprintf(fp, " ---------------------------------------------------------------------------------------------------------------------------------- \r\n");
01707 fprintf(fp, "| T O T A L S |\r\n");
01708 fprintf(fp, " ---------------------------------------------------------------------------------------------------------------------------------- \r\n");
01709 fprintf(fp, " Allocation unit count: %10s\r\n", insertCommas(stats.totalAllocUnitCount));
01710 fprintf(fp, " Reported to application: %s\r\n", memorySizeString(stats.totalReportedMemory));
01711 fprintf(fp, " Actual total memory in use: %s\r\n", memorySizeString(stats.totalActualMemory));
01712 fprintf(fp, " Memory tracking overhead: %s\r\n", memorySizeString(stats.totalActualMemory - stats.totalReportedMemory));
01713 fprintf(fp, "\r\n");
01714
01715 fprintf(fp, " ---------------------------------------------------------------------------------------------------------------------------------- \r\n");
01716 fprintf(fp, "| P E A K S |\r\n");
01717 fprintf(fp, " ---------------------------------------------------------------------------------------------------------------------------------- \r\n");
01718 fprintf(fp, " Allocation unit count: %10s\r\n", insertCommas(stats.peakAllocUnitCount));
01719 fprintf(fp, " Reported to application: %s\r\n", memorySizeString(stats.peakReportedMemory));
01720 fprintf(fp, " Actual: %s\r\n", memorySizeString(stats.peakActualMemory));
01721 fprintf(fp, " Memory tracking overhead: %s\r\n", memorySizeString(stats.peakActualMemory - stats.peakReportedMemory));
01722 fprintf(fp, "\r\n");
01723
01724 fprintf(fp, " ---------------------------------------------------------------------------------------------------------------------------------- \r\n");
01725 fprintf(fp, "| A C C U M U L A T E D |\r\n");
01726 fprintf(fp, " ---------------------------------------------------------------------------------------------------------------------------------- \r\n");
01727 fprintf(fp, " Allocation unit count: %s\r\n", memorySizeString(stats.accumulatedAllocUnitCount));
01728 fprintf(fp, " Reported to application: %s\r\n", memorySizeString(stats.accumulatedReportedMemory));
01729 fprintf(fp, " Actual: %s\r\n", memorySizeString(stats.accumulatedActualMemory));
01730 fprintf(fp, "\r\n");
01731
01732 fprintf(fp, " ---------------------------------------------------------------------------------------------------------------------------------- \r\n");
01733 fprintf(fp, "| U N U S E D |\r\n");
01734 fprintf(fp, " ---------------------------------------------------------------------------------------------------------------------------------- \r\n");
01735 fprintf(fp, " Memory allocated but not in use: %s\r\n", memorySizeString(m_calcAllUnused()));
01736 fprintf(fp, "\r\n");
01737
01738 dumpAllocations(fp);
01739
01740 fclose(fp);
01741 }
01742
01743
01744
01745 sMStats m_getMemoryStatistics()
01746 {
01747 return stats;
01748 }
01749
01750
01751
01752
Generated on Sun Jul 17 21:34:28 2005 for OpenGL GUI by
1.3.8