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 #include <base/MemoryTracer>
00026
00027 #include <string>
00028 #include <iostream>
00029
00030 using std::string;
00031
00032 using base::MemoryTracer;
00033
00034
00035
00036
00037
00038 #define _INTERACTIVE_
00039
00040
00041
00042 #define _THROWEXCEPTION_
00043
00044
00045
00046
00047
00048
00049
00050 base::Byte MemoryTracer::prefill[MemoryTracer::Filling];
00051 base::Byte MemoryTracer::initialized = 0;
00052 bool MemoryTracer::cleanedUp = false;
00053 Int MemoryTracer::entry = 0;
00054 Int MemoryTracer::fullCheckCounter = 0;
00055 base::LInt MemoryTracer::allocCount = 0;
00056 base::LInt MemoryTracer::deallocCount = 0;
00057 base::LInt MemoryTracer::checkCount = 0;
00058 MemoryTracer::AllocList MemoryTracer::mlist;
00059 MemoryTracer::AllocList MemoryTracer::dlist;
00060 base::Byte MemoryTracer::postfill[Filling];
00061
00062 const int MemoryTracer::IsArray = 0xabcd;
00063 const int MemoryTracer::IsNotArray = 0xfcad;
00064
00065 inline void MemoryTracer::Logerr(char* errstr)
00066 {
00067
00068 char str[256];
00069 sprintf(str,"MemoryTracer Log: %s\n",errstr);
00070 fprintf(stderr,str);
00071 }
00072
00073
00074
00075 inline void MemoryTracer::entrylock()
00076 {
00077 if (entry != 0) {
00078 Logerr("Multiple thread entry detected! MemoryTracer is not threadsafe - please restrict use to a single thread at a time.");
00079 handleError();
00080 }
00081 else
00082 entry++;
00083 }
00084
00085 inline void MemoryTracer::exitunlock()
00086 {
00087 entry--;
00088 }
00089
00090
00091
00092
00093
00094
00095
00096
00097 void MemoryTracer::AllocList::push_front(AllocEntry* e)
00098 {
00099 if (head == 0) {
00100 head = tail = e;
00101 e->next = e->prev = 0;
00102 }
00103 else {
00104 AllocEntry* oldhead = head;
00105 head = e;
00106 head->next = oldhead;
00107 head->prev = 0;
00108 oldhead->prev = head;
00109 }
00110 len++;
00111 }
00112
00113
00114 void MemoryTracer::AllocList::push_back(AllocEntry* e)
00115 {
00116 if (head == 0) {
00117 head = tail = e;
00118 e->next = e->prev = 0;
00119 }
00120 else {
00121 AllocEntry* oldtail = tail;
00122 tail = e;
00123 tail->next = 0;
00124 tail->prev = oldtail;
00125 oldtail->next = tail;
00126 }
00127 len++;
00128 }
00129
00130 MemoryTracer::AllocEntry* MemoryTracer::AllocList::pop_front()
00131 {
00132 AllocEntry* oldhead = head;
00133 if (head != 0) {
00134 head = head->next;
00135 if (head)
00136 head->prev = 0;
00137 else
00138 tail = 0;
00139 len--;
00140 }
00141 return oldhead;
00142 }
00143
00144
00145 MemoryTracer::AllocEntry* MemoryTracer::AllocList::pop_back()
00146 {
00147 AllocEntry* oldtail = tail;
00148 if (tail != 0) {
00149 tail = tail->prev;
00150 if (tail)
00151 tail->next = 0;
00152 else
00153 head = 0;
00154 len--;
00155 }
00156 return oldtail;
00157 }
00158
00159
00160 void MemoryTracer::AllocList::remove(AllocEntry* e)
00161 {
00162 if (e == tail) {
00163 pop_back();
00164 }
00165 else if (e == head) {
00166 pop_front();
00167 }
00168 else {
00169 e->next->prev = e->prev;
00170 e->prev->next = e->next;
00171 len--;
00172 }
00173 }
00174
00175
00176 MemoryTracer::AllocEntry* MemoryTracer::AllocList::find(void* address, AllocEntry* from) const
00177 {
00178 Byte* addr = (Byte*)address;
00179 AllocEntry* m = (from==0)?head:from;
00180 while (m) {
00181 if (!m->isExternal()) {
00182 if (addr == m->address+Filling)
00183 return m;
00184 }
00185 else
00186 if (addr == m->address)
00187 return m;
00188
00189 m = m->next;
00190 }
00191 return 0;
00192 }
00193
00194
00195
00196 void MemoryTracer::menu() throw(std::bad_alloc)
00197 {
00198 char ans[32];
00199 bool quit=false;
00200 while (!quit) {
00201 printf("\n");
00202 printf("Choose: (a)llocated memory list (n)amed allocated memory\n");
00203 printf(" (r)eciently deallocated memory (d)ivide by 0 crash (SIGFPE)\n");
00204 printf(" e(x)it (t)hrow bad_alloc (c)continue? ");
00205 scanf("%s",ans);
00206 switch (tolower(ans[0])) {
00207 case 'a': dump(); break;
00208 case 'n': dumpNamed(); break;
00209 case 'r': dumpDeallocated(); break;
00210 case 'd': causefault(); break;
00211 case 'x': exit(-1); break;
00212 case 't': throw std::bad_alloc(); break;
00213 case 'c': quit=true; break;
00214 default: ;
00215 }
00216 }
00217 }
00218
00219
00220 void MemoryTracer::handleError() throw(std::bad_alloc)
00221 {
00222 #ifdef _INTERACTIVE_
00223 menu();
00224 #else
00225 #ifdef _THROWEXCEPTION_
00226 throw std::bad_alloc();
00227 #endif
00228 #endif
00229 }
00230
00231
00232
00233 int MemoryTracer::causefault()
00234 {
00235 int i=5, j=5;
00236
00237 j = i/(j-i);
00238 return j;
00239 }
00240
00241
00242
00243 bool MemoryTracer::checkAllMemory() throw(std::bad_alloc)
00244 {
00245 bool ok = true;
00246 #ifdef _TRACEMEMORY_
00247 checkCount++;
00248 AllocEntry* m = mlist.front();
00249 int size, i,j;
00250 char errstr[256];
00251
00252 while (m) {
00253 if (!m->isOK()) {
00254 Logerr("Memory allocation record has been corrupted (AllocEntry).");
00255 bool prefillOK = true;
00256 for(Int i=0; i<Filling; i++)
00257 if (m->prefill[i] != Filler) prefillOK = false;
00258 bool postfillOK = true;
00259 for(Int i=0; i<Filling; i++)
00260 if (m->postfill[i] != Filler) postfillOK = false;
00261 sprintf(errstr,"Entry: prefill:%s postfill:%s size:%6d isMagic:%s",
00262 prefillOK?"OK":"BAD", postfillOK?"OK":"BAD",m->size,m->isMagic()?"OK":"BAD");
00263 Logerr(errstr);
00264 m=0;
00265 ok=false;
00266 }
00267 else {
00268
00269 if (!m->isExternal()) {
00270 Byte* mem = (Byte*)m->address;
00271 size = m->size;
00272 for(i=0; (i<Filling) && ok; i++) {
00273 if ( *(mem+i) != Filler ) {
00274 sprintf(errstr,"Memory before allocation %x (%s) has been overwritten",(Int)mem+Filling,m->name);
00275 for(j=0; j<Filling; j++) {
00276 sprintf(errstr,"addr(m-%d) = %d (should be %d)",Filling-j,(unsigned int)*(mem+i),Filler);
00277 Logerr(errstr);
00278 }
00279 ok=false;
00280 }
00281 if ( *(mem+Filling+size+i) != Filler ) {
00282 sprintf(errstr,"Memory after allocation %x (%s) has been overwritten",(Int)mem+Filling,m->name);
00283 Logerr(errstr);
00284 for(j=0; j<Filling; j++) {
00285 sprintf(errstr,"addr(m+size+%d) = %d (should be %d)",j,(Int)*(mem+size+Filling+i),Filler);
00286 Logerr(errstr);
00287 }
00288 ok=false;
00289 }
00290
00291 }
00292 }
00293
00294 m = m->next;
00295 }
00296
00297 }
00298
00299 if (!ok) handleError();
00300 #endif
00301 return ok;
00302 }
00303
00304
00305
00306 void* MemoryTracer::allocate(int size, const string& name, bool isArray) throw(std::bad_alloc)
00307 {
00308 entrylock();
00309 if (!isOK()) {
00310 Logerr("memory allocation records have been corrupted (MemoryTracer).");
00311 exitunlock();
00312 return 0;
00313 }
00314
00315 int i;
00316 AllocEntry* ne;
00317 if (size <= 0) {
00318 Logerr("passed size <= 0.");
00319 handleError();
00320 return 0;
00321 }
00322 void* mem = malloc(size + Filling*2);
00323 if (mem == 0) return 0;
00324
00325 #if (_FULLCHECKFREQUENTY_ > 0)
00326 if ((++fullCheckCounter % _FULLCHECKFREQUENTY_) == 0) {
00327 fullCheckCounter=0;
00328 checkAllMemory();
00329 }
00330 #endif
00331
00332 ne = (AllocEntry*)malloc(sizeof(AllocEntry));
00333 if (ne == 0) {
00334 free(mem);
00335 Logerr("no memory available to allocate (for entry).");
00336 return 0;
00337 }
00338 ne->fill();
00339
00340
00341 for(i=0; i< Filling; i++) {
00342 *(((Byte*)mem)+i) = Filler;
00343 *(((Byte*)mem)+size+Filling+i) = Filler;
00344 }
00345
00346 ne->size = size;
00347 ne->name = 0;
00348 ne->setIsArray(isArray);
00349
00350 if (name.size() > 0) {
00351 ne->name = (char*)malloc(name.size()+1);
00352 if (ne->name == 0) {
00353 Logerr("no memory available to allocate name.");
00354 }
00355 else
00356 strcpy(ne->name, name.c_str());
00357 }
00358
00359 ne->setMagic();
00360 ne->address = (Byte*)mem;
00361
00362 mlist.push_front(ne);
00363
00364 allocCount++;
00365 exitunlock();
00366 void* addr = ((Byte*)mem)+Filling;
00367 #ifdef _MEMORYTRACEDEBUG_
00368 char logstr[80];
00369 sprintf(logstr, "allocated(size:%d, name:%s, isArray:%s) = %x", size, (name.size()>0)?name.c_str():"<unnamed>",isArray?"TRUE":"FALSE",Int(addr));
00370 Logerr(logstr);
00371 #endif
00372 return addr;
00373 }
00374
00375
00376
00377
00378 bool MemoryTracer::validate(void* address, int size, const string& name) throw(std::bad_alloc)
00379 {
00380 entrylock();
00381 if (!isOK()) {
00382 Logerr("memory allocation records have been corrupted.");
00383 exitunlock();
00384 return false;
00385 }
00386
00387 AllocEntry* ne;
00388 char errstr[256];
00389
00390 if (size < 0) {
00391 Logerr("passed size < 0.");
00392 exitunlock();
00393 handleError();
00394 return false;
00395 }
00396
00397 #if (_FULLCHECKFREQUENTY_ > 0)
00398 if ((++fullCheckCounter % _FULLCHECKFREQUENTY_) == 0) {
00399 fullCheckCounter=0;
00400 checkAllMemory();
00401 }
00402 #endif
00403
00404
00405
00406 AllocEntry* m = mlist.find(address);
00407 if (m) {
00408 if (!m->isExternal()) {
00409 if (address == m->address + Filling) {
00410 sprintf(errstr,"memory at address %x (%s) was allocated with allocate(), so cannot be validated with validate()\n",
00411 Int(m->address+Filling),(m->name==0)?"<unnamed>":m->name);
00412 Logerr(errstr);
00413 exitunlock();
00414 return false;
00415 }
00416 }
00417 else
00418 if (address == m->address) {
00419 exitunlock();
00420 return true;
00421 }
00422 }
00423
00424 ne = (AllocEntry*)malloc(sizeof(AllocEntry));
00425 if (ne == 0) {
00426 Logerr("no memory available to allocate (for entry).");
00427 exitunlock();
00428 return false;
00429 }
00430
00431 ne->size = size;
00432 ne->name = 0;
00433
00434 if (name.size() > 0) {
00435 ne->name = (char*)malloc(name.size()+1);
00436 if (ne->name == 0) {
00437 Logerr("no memory available to allocate (for name).");
00438 }
00439 else
00440 strcpy(ne->name, name.c_str());
00441
00442 }
00443 ne->setMagic();
00444 ne->setExternal();
00445 ne->setIsArray(false);
00446 ne->address = (Byte*)address;
00447
00448 mlist.push_front(ne);
00449
00450 exitunlock();
00451
00452 #ifdef _MEMORYTRACEDEBUG_
00453 char logstr[80];
00454 sprintf(logstr, "validated(address:%x, size:%d, name:%s)", Int(address), size, (name.size()>0)?name.c_str():"<unnamed>");
00455 Logerr(logstr);
00456 #endif
00457
00458 return true;
00459 }
00460
00461
00462
00463
00464 bool MemoryTracer::release(void* address, bool isArray, int size) throw(std::bad_alloc)
00465 {
00466 entrylock();
00467 if (!isOK()) {
00468 Logerr("memory allocation records have been corrupted.");
00469 exitunlock();
00470 return false;
00471 }
00472
00473 if (cleanedUp) return true;
00474
00475 Byte* addr = (Byte*)address;
00476 char errstr[256];
00477
00478 #if (_FULLCHECKFREQUENTY_ > 0)
00479 if ((++fullCheckCounter % _FULLCHECKFREQUENTY_) == 0) {
00480 fullCheckCounter=0;
00481 checkAllMemory();
00482 }
00483 #endif
00484
00485 AllocEntry* m = mlist.find(address);
00486 bool found = (m!=0);
00487 char name[128];
00488 strcpy(name, "<unknown>");
00489
00490 if (found) {
00491
00492 if (addr == m->address+Filling) {
00493 if ((size!=-1) && (size!=m->size)) {
00494 sprintf(errstr,"size given (%d) for region at %x doesn't match that allocated (%d)",
00495 size,Int(address),m->size);
00496 Logerr(errstr);
00497 }
00498 if (m->isArray() != isArray) {
00499 if (m->isArray()) {
00500 sprintf(errstr,"region at %x was allocated as an array but not free'd as one",
00501 Int(address));
00502 Logerr(errstr);
00503 handleError();
00504 }
00505 else {
00506 sprintf(errstr,"region at %x was free'd as an array but not allocated as one",
00507 Int(address));
00508 Logerr(errstr);
00509 handleError();
00510 }
00511 }
00512
00513 #ifdef _MEMORYTRACEDEBUG_
00514 if (m->name)
00515 strncpy(name, m->name, 127);
00516 #endif
00517
00518
00519 mlist.remove(m);
00520
00521 free(m->address);
00522
00523 dlist.push_front(m);
00524 if (dlist.size() > DList_Max) {
00525 AllocEntry* dm = dlist.pop_back();
00526 if (dm->name!=0)
00527 free(dm->name);
00528 free(dm);
00529 }
00530 }
00531 else {
00532 if ((addr == m->address) && (m->isExternal())) {
00533 sprintf(errstr,"memory at address %x was not allocated with allocate(), but was validated with validate(). (will invalidate without freeing).",(Int)address);
00534 Logerr(errstr);
00535 exitunlock();
00536 invalidate(address,size);
00537 entrylock();
00538 }
00539 }
00540 }
00541 else {
00542 sprintf(errstr,"no memory allocated at address %x.",(Int)address);
00543 Logerr(errstr);
00544
00545
00546 AllocEntry* from = dlist.front();
00547 AllocEntry* dm;
00548 do {
00549 dm = dlist.find(address,from);
00550 if (dm) {
00551 Byte* addr = (dm->isExternal()?dm->address:dm->address+Filling);
00552 sprintf(errstr,"memory was previously allocated at address %x as %s (size %d) - but has since been deallocated.",
00553 Int(addr),((dm->name==0)?"<unnamed>":dm->name),dm->size);
00554 Logerr(errstr);
00555 from = dm->next;
00556 if (from==0) from = dlist.back();
00557 }
00558 } while (dm);
00559
00560
00561 checkAllMemory();
00562 exitunlock();
00563 handleError();
00564 return found;
00565 }
00566
00567 deallocCount++;
00568 exitunlock();
00569
00570 #ifdef _MEMORYTRACEDEBUG_
00571 char logstr[80];
00572 sprintf(logstr, "released(address:%x, isArray:%s, size:%6d, name:%s)", Int(address), isArray?"TRUE":"FALSE", size, name);
00573 Logerr(logstr);
00574 #endif
00575
00576 return found;
00577 }
00578
00579
00580
00581
00582
00583 bool MemoryTracer::invalidate(void* address, int size) throw(std::bad_alloc)
00584 {
00585 entrylock();
00586 if (!isOK()) {
00587 Logerr("memory allocation records have been corrupted.");
00588 exitunlock();
00589 return false;
00590 }
00591
00592 if (cleanedUp) return true;
00593
00594 Byte* addr = (Byte*)address;
00595 char errstr[256];
00596
00597 #if (_FULLCHECKFREQUENTY_ > 0)
00598 if ((++fullCheckCounter % _FULLCHECKFREQUENTY_) == 0) {
00599 fullCheckCounter=0;
00600 checkAllMemory();
00601 }
00602 #endif
00603
00604 AllocEntry* m = mlist.find(address);
00605 bool found = (m!=0);
00606 char name[128];
00607 strcpy(name, "<unknown>");
00608
00609 if (found) {
00610
00611 if (addr == m->address) {
00612 if ((size!=-1) && (size!=m->size)) {
00613 sprintf(errstr,"size given (%d) doesn't match that validated (%d).",size,m->size);
00614 Logerr(errstr);
00615 }
00616
00617
00618 #ifdef _MEMORYTRACEDEBUG_
00619 if (m->name)
00620 strncpy(name, m->name, 127);
00621 #endif
00622 mlist.remove(m);
00623 if (m->name != 0) free(m->name);
00624 free(m);
00625 }
00626 else {
00627 if ((addr == m->address+Filling) && (!m->isExternal())) {
00628 sprintf(errstr,"memory at address %x was allocated with allocate(), not validated with validate().",(Int)address);
00629 Logerr(errstr);
00630 }
00631 }
00632
00633 }
00634 else {
00635 sprintf(errstr,"no memory validated at address %x.",(Int)address);
00636 Logerr(errstr);
00637 exitunlock();
00638 handleError();
00639 return found;
00640 }
00641
00642 exitunlock();
00643
00644 #ifdef _MEMORYTRACEDEBUG_
00645 char logstr[80];
00646 sprintf(logstr, "invalidated(address:%x, size:%6d, name:%s)", Int(address), size, name);
00647 Logerr(logstr);
00648 #endif
00649
00650 return found;
00651 }
00652
00653
00654
00655
00656 void* MemoryTracer::checkAddrRange(void* address, long typesize) throw(std::bad_alloc)
00657 {
00658 checkAddr(address, address, true);
00659 if (typesize>0) checkAddr( ((char*)address)+typesize-1, address, false);
00660 return address;
00661 }
00662
00663
00664
00665 bool MemoryTracer::checkAddr(void* address, void* reportAddr, bool checkAllMemory) throw(std::bad_alloc)
00666 {
00667 bool found=false;
00668 Byte *addr = (Byte*)address;
00669 char errstr[256];
00670 AllocEntry* m = mlist.front();
00671
00672 if (checkAllMemory) MemoryTracer::checkAllMemory();
00673
00674 if (reportAddr == 0) reportAddr = address;
00675
00676 while (m && !found) {
00677 if (!m->isExternal()) {
00678
00679 if ((m->address <= addr) && (addr < m->address+Filling*2+m->size)) {
00680
00681 if ((m->address+Filling <= addr) && (addr < m->address+Filling+m->size))
00682 found=true;
00683 else {
00684 if ((m->address <= addr) && (addr < m->address+Filling)) {
00685 if (address == reportAddr) {
00686 sprintf(errstr,"reference address %x is before memory area at %x (size %d) (%s).",
00687 Int(addr), Int(m->address+Filling), m->size, m->name);
00688 Logerr(errstr);
00689 }
00690 else {
00691 sprintf(errstr,"reference to address %x may allow to access address %x which is before memory area at %x (size %d) (%s).",
00692 Int(reportAddr), Int(addr), Int(m->address+Filling), m->size, m->name);
00693 Logerr(errstr);
00694 }
00695 }
00696 else {
00697 if (address == reportAddr) {
00698 sprintf(errstr,"reference address %x is after memory area at %x (size %d) (%s).",
00699 Int(addr), Int(m->address+Filling), m->size, m->name);
00700 Logerr(errstr);
00701 }
00702 else {
00703 sprintf(errstr,"reference to address %x may allow to access address %x which is after memory area at %x (size %d) (%s)\n",
00704 Int(reportAddr), Int(addr), Int(m->address+Filling), m->size, m->name);
00705 Logerr(errstr);
00706 }
00707 }
00708
00709 }
00710 }
00711 } else {
00712 if ((m->address <= addr) && (addr < m->address+m->size))
00713 found = true;
00714 }
00715
00716 m = m->next;
00717 }
00718 if (!found) {
00719 if (address == reportAddr) {
00720 sprintf(errstr,"reference to invalid memory address %x detected.",Int(addr));
00721 Logerr(errstr);
00722 }
00723 else {
00724 sprintf(errstr,"detected reference to address %x that may allow access to invalid address %x.",Int(reportAddr), Int(addr));
00725 Logerr(errstr);
00726 }
00727 handleError();
00728 return false;
00729 }
00730
00731 return true;
00732 }
00733
00734
00735 char* MemoryTracer::getName(void* addr)
00736 {
00737 AllocEntry* m = mlist.front();
00738 bool found=false;
00739 AllocEntry* entry = 0;
00740 while (m && !found) {
00741 if (!m->isExternal()) {
00742
00743 if ((m->address <= addr) && (addr < m->address+Filling*2+m->size)) {
00744
00745 if ((m->address+Filling <= addr) && (addr < m->address+Filling+m->size)) {
00746 found=true;
00747 entry = m;
00748 }
00749 }
00750 } else {
00751 if ((m->address <= addr) && (addr < m->address+m->size)) {
00752 found = true;
00753 entry=m;
00754 }
00755 }
00756
00757 m = m->next;
00758 }
00759
00760 if (found)
00761 return entry->name;
00762 else
00763 return 0;
00764 }
00765
00766
00767 long MemoryTracer::getOffset(void* addr)
00768 {
00769 AllocEntry* m = mlist.front();
00770 bool found=false;
00771
00772 long offset=-1;
00773 while (m && !found) {
00774 if (!m->isExternal()) {
00775
00776 if ((m->address <= addr) && (addr < m->address+Filling*2+m->size)) {
00777
00778 if ((m->address+Filling <= addr) && (addr < m->address+Filling+m->size)) {
00779 found=true;
00780 offset = (Byte*)addr - (m->address+Filling);
00781 }
00782 }
00783 } else {
00784 if ((m->address <= addr) && (addr < m->address+m->size)) {
00785 found = true;
00786 offset = (Byte*)addr - m->address;
00787 }
00788 }
00789
00790 m = m->next;
00791 }
00792
00793 return offset;
00794 }
00795
00796
00797
00798 bool MemoryTracer::cleanup()
00799 {
00800 #ifdef _TRACEMEMORY_
00801 printf("(Cleanup: %ld allocations, %ld deallocations, %ld integrity checks performed)\n",allocCount,deallocCount,checkCount);
00802
00803 char errstr[256];
00804 if (mlist.size() > 0) {
00805 dump();
00806 sprintf(errstr,"Freeing %d leaked memory allocations",mlist.size());
00807 Logerr(errstr);
00808 while (mlist.size() > 0) {
00809 AllocEntry* m = mlist.pop_front();
00810 if (m->name != 0) free(m->name);
00811 if (!m->isExternal()) free(m->address);
00812 free(m);
00813 }
00814 }
00815
00816 while (dlist.size() > 0) {
00817 AllocEntry* m = dlist.pop_front();
00818 if (m->name != 0) free(m->name);
00819 free(m);
00820 }
00821 #endif
00822 cleanedUp = true;
00823 return true;
00824 }
00825
00826
00827 void MemoryTracer::dump()
00828 {
00829 #ifdef _TRACEMEMORY_
00830 AllocEntry* m = mlist.front();
00831
00832 checkAllMemory();
00833
00834 printf("\nValid memory regions (%d):\n",mlist.size());
00835 printf("(%ld allocations, %ld deallocations, %ld integrity checks performed)\n",allocCount,deallocCount,checkCount);
00836 printf("----------------------------------------------------------------------------------\n");
00837
00838 while(m) {
00839 if (m->isOK()) {
00840 printf("%52s: %10x (%9d) %s %s\n", (m->name==0)?"<unnamed>":m->name, Int(m->address+Filling),
00841 m->size,(m->isArray()?"[]":" "),m->isExternal()?"EXT":"");
00842 m = m->next;
00843 }
00844 else {
00845 Logerr("Memory allocation structure corrupted!");
00846 m=0;
00847 }
00848 }
00849 printf("----------------------------------------------------------------------------------\n\n");
00850 #endif
00851 }
00852
00853
00854
00855 void MemoryTracer::dumpDeallocated()
00856 {
00857 #ifdef _TRACEMEMORY_
00858 AllocEntry* m = dlist.front();
00859
00860 printf("\nReciently deallocated memory regions (%d):\n",dlist.size());
00861 printf("(%ld allocations, %ld deallocations, %ld integrity checks performed)\n",allocCount,deallocCount,checkCount);
00862 printf("----------------------------------------------------------------------------------\n");
00863
00864 while(m) {
00865 if (m->isOK()) {
00866 printf("%52s: %10x (%9d) %s %s\n", (m->name==0)?"<unnamed>":m->name, Int(m->address+Filling),
00867 m->size,(m->isArray()?"[]":" "),m->isExternal()?"EXT":"");
00868 m = m->next;
00869 }
00870 else {
00871 Logerr("Memory allocation structure corrupted!");
00872 m=0;
00873 }
00874 }
00875 printf("----------------------------------------------------------------------------------\n\n");
00876 #endif
00877 }
00878
00879
00880
00881 void MemoryTracer::dumpNamed()
00882 {
00883 #ifdef _TRACEMEMORY_
00884 AllocEntry* m = mlist.front();
00885
00886 checkAllMemory();
00887
00888 printf("\nValid named memory regions (from %d total):\n",mlist.size());
00889 printf("(%ld allocations, %ld deallocations, %ld integrity checks performed)\n",allocCount,deallocCount,checkCount);
00890 printf("----------------------------------------------------------------------------------\n");
00891
00892 int e=0;
00893 while(m) {
00894 if (m->isOK()) {
00895 if (m->name!=0)
00896 printf("%4d %52s: %10x (%9d) %s %s\n",e,m->name, (Int)(m->address+Filling),
00897 m->size,(m->isArray()?"[]":" "),m->isExternal()?"EXT":"");
00898 ++e;
00899 m = m->next;
00900 }
00901 else {
00902 Logerr("Memory allocation structure corrupted!");
00903 m=0;
00904 }
00905 }
00906 printf("----------------------------------------------------------------------------------\n\n");
00907 #endif
00908 }
00909
00910
00911
00912
00913
00914
00915
00916 #include <list>
00917
00918 namespace {
00919
00920 using base::Byte;
00921 using base::Int;
00922
00923 std::list<Byte*> delayedDeletes;
00924 Int count = 0;
00925 Int maxDepth = 0;
00926 static const Int maxCount = 5000;
00927
00928 void stressTestAllocatorRecurse(Int depth)
00929 {
00930 Int size = (rand() & 0xff)+1;
00931 Byte* mem = new Byte[size];
00932 ++count;
00933
00934 if (depth > maxDepth)
00935 maxDepth = depth;
00936
00937 Int r = (rand() & 0xc0) >> 6;
00938 if (r && (count < maxCount))
00939 stressTestAllocatorRecurse(depth+1);
00940
00941 Int d = (rand() & 0x80) >> 7;
00942 if (d)
00943 delete[] mem;
00944 else
00945 delayedDeletes.push_back(mem);
00946 }
00947
00948 }
00949
00950 using std::list;
00951
00952 void base::stressTestAllocator()
00953 {
00954 Logfln("Performing memory allocator test...");
00955 while (count < maxCount) {
00956 stressTestAllocatorRecurse(1);
00957 MemoryTracer::checkAllMemory();
00958
00959
00960 base::Int c = delayedDeletes.size()/2;
00961 std::list<Byte*>::iterator s = delayedDeletes.begin();
00962 std::list<Byte*>::iterator end = delayedDeletes.end();
00963 while (s != end) {
00964 if (--c > 0)
00965 if (*s) delete[] (*s);
00966 (*s) = 0;
00967 ++s;
00968 }
00969 MemoryTracer::checkAllMemory();
00970 }
00971
00972
00973 std::list<Byte*>::const_iterator s = delayedDeletes.begin();
00974 std::list<Byte*>::const_iterator end = delayedDeletes.end();
00975 while (s != end) {
00976 if (*s) delete[] (*s);
00977 ++s;
00978 }
00979 delayedDeletes.clear();
00980 MemoryTracer::checkAllMemory();
00981
00982 Logfln("Done. " << count << " allocations (" << maxDepth << " recursion depth)")
00983 }
00984
00985
00986
00987
00988
00989
00990
00991
00992 #ifdef _TRACEMEMORY_
00993
00994 void* operator new(size_t size) throw (std::bad_alloc)
00995 {
00996 void* p = base::MemoryTracer::allocate(size,"");
00997 #ifdef _TRACEOUTPUT_
00998 #ifndef _NAMEDOUTPUTONLY_
00999 fprintf(stderr, "new(%d) = %x\n",size,Int(p));
01000 #endif
01001 #endif
01002 return p;
01003 }
01004
01005 void* operator new(size_t size, const string& name) throw (std::bad_alloc)
01006 {
01007 void* p = base::MemoryTracer::allocate(size,name);
01008 #ifdef _TRACEOUTPUT_
01009 fprintf(stderr, "new(%d,%s) = %x\n",size,name.c_str(),Int(p));
01010 #endif
01011 return p;
01012 }
01013
01014 void operator delete(void* p) throw()
01015 {
01016 #ifdef _TRACEOUTPUT_
01017 char* name = base::MemoryTracer::getName(p);
01018 if (name)
01019 fprintf(stderr, "delete[](%x,%s)\n", Int(p),name);
01020 #ifndef _NAMEDOUTPUTONLY_
01021 else
01022 fprintf(stderr, "delete[](%x)\n", Int(p));
01023 #endif
01024 #endif
01025 base::MemoryTracer::release(p);
01026 }
01027
01028
01029 void* operator new[](size_t size) throw (std::bad_alloc)
01030 {
01031 void* p = base::MemoryTracer::allocate(size,"",true);
01032 #ifdef _TRACEOUTPUT_
01033 #ifndef _NAMEDOUTPUTONLY_
01034 fprintf(stderr, "new[](%d) = %x\n",size,Int(p));
01035 #endif
01036 #endif
01037 return p;
01038 }
01039
01040 void* operator new[](size_t size, const string& name) throw (std::bad_alloc)
01041 {
01042 void* p = base::MemoryTracer::allocate(size,name,true);
01043 #ifdef _TRACEOUTPUT_
01044 fprintf(stderr, "new[](%d,%s) = %x\n",size,name.c_str(),Int(p));
01045 #endif
01046 return p;
01047 }
01048
01049 void operator delete[](void* p) throw()
01050 {
01051 #ifdef _TRACEOUTPUT_
01052 char* name = base::MemoryTracer::getName(p);
01053 if (name)
01054 fprintf(stderr, "delete[](%x,%s)\n", Int(p),name);
01055 #ifndef _NAMEDOUTPUTONLY_
01056 else
01057 fprintf(stderr, "delete[](%x)\n", Int(p));
01058 #endif
01059 #endif
01060 base::MemoryTracer::release(p,true);
01061 }
01062
01063 #endif