00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #if defined(DEBUG) || defined(_DEBUG)
00018
00019 #include <stdio.h>
00020 #include <stdlib.h>
00021
00022 #if defined(_WIN32) || defined(_WIN64)
00023 #include <spl/configwin32.h>
00024 #else
00025 #include <spl/autoconf/config.h>
00026 #endif
00027
00028 #ifdef HAVE_SYS_ERRNO_H
00029 #include <sys/errno.h>
00030 #endif
00031 #ifdef HAVE_ERRNO_H
00032 #include <errno.h>
00033 #endif
00034 #ifdef HAVE_ASSERT_H
00035 #include <assert.h>
00036 #endif
00037 #ifdef HAVE_MEMORY_H
00038 #include <memory.h>
00039 #endif
00040 #include <spl/Debug.h>
00041
00042 #if defined(_WIN32) || defined(_WIN64)
00043 #include <crtdbg.h>
00044 #else
00045 #define _CrtDumpMemoryLeaks() false
00046 #define _CrtCheckMemory() true
00047 #define _CrtIsValidHeapPointer() true
00048 #define _CrtIsValidPointer(a,b,c) true
00049 #endif
00050
00051 #undef malloc
00052 #undef free
00053
00054 #include <string.h>
00055
00056 #if defined(_WIN32) || defined(_WIN64)
00057 #include <crtdbg.h>
00058 #endif
00059
00060 #define DEBUG_MEM_FILL (char)0xCA
00061
00062 static volatile int mallocsize = 0;
00063 static volatile int midnum = 0;
00064 static volatile bool isshutdown = false;
00065 static volatile bool mutexinit = false;
00066 static bool _usemutex = false;
00067
00068 #if defined(_WIN32) || defined(_WIN64)
00069 # define _WINSOCKAPI_
00070 # include <spl/cleanwindows.h>
00071 #endif
00072 #if defined(HAVE_SPTHREAD_H) || defined(_TANDEM)
00073 # define _tal
00074 # define _extensible
00075 # include <spthread.h>
00076 #endif
00077 #if defined(HAVE_PTHREAD_H) && !defined(_TANDEM)
00078 # include <pthread.h>
00079 #endif
00080 #if defined(_WIN32) || defined(_WIN64)
00081 HANDLE mutex;
00082 #else
00083 pthread_mutex_t mutex;
00084 int mutex_recur_hack = 0;
00085 #endif
00086
00087 #include <spl/BigInteger.h>
00088
00089 struct allocblock
00090 {
00091 int16 majic;
00092 int id;
00093 char checkbit;
00094 char checkbit2;
00095 bool isarray;
00096 int size;
00097 const char *filename;
00098 int lineno;
00099 struct allocblock *next;
00100 struct allocblock *prev;
00101 char data[4];
00102 };
00103
00104 struct memcheckpoint
00105 {
00106 int count;
00107 int size;
00108 };
00109
00110 #define ALLOCBLOC_MAJIC 21845
00111
00112 static struct allocblock m_abhead = { ALLOCBLOC_MAJIC, -1, 0, DEBUG_MEM_FILL, 0, 0, NULL, 0, NULL, NULL, DEBUG_MEM_FILL, DEBUG_MEM_FILL, DEBUG_MEM_FILL, DEBUG_MEM_FILL };
00113 static struct allocblock m_abtail = { ALLOCBLOC_MAJIC, -1, 0, DEBUG_MEM_FILL, 0, 0, NULL, 0, NULL, NULL, DEBUG_MEM_FILL, DEBUG_MEM_FILL, DEBUG_MEM_FILL, DEBUG_MEM_FILL };
00114
00115 static struct memcheckpoint m_memcheckpoint;
00116
00117 #define validateBlock(a) (a != NULL && (a->checkbit2 == DEBUG_MEM_FILL && \
00118 a->majic == ALLOCBLOC_MAJIC && \
00119 a->data[a->size] == DEBUG_MEM_FILL && \
00120 a->data[a->size+1] == DEBUG_MEM_FILL && \
00121 a->data[a->size+2] == DEBUG_MEM_FILL && \
00122 a->data[a->size+3] == DEBUG_MEM_FILL && \
00123 (a->checkbit == 0 || a->checkbit == 1)))
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142 void _debugEnableHeapLocking()
00143 {
00144 _usemutex = true;
00145 }
00146
00147 void _debugLockHeap()
00148 {
00149 if ( mutexinit )
00150 {
00151 #ifdef _WINDOWS
00152 WaitForSingleObject(mutex, INFINITE);
00153 #else
00154 int ret = pthread_mutex_lock( &mutex );
00155 if ( ret == EDEADLK )
00156 {
00157
00158 mutex_recur_hack++;
00159 }
00160 else
00161 {
00162 assert(ret == 0);
00163 }
00164 #endif
00165 }
00166 }
00167
00168 void _debugUnlockHeap()
00169 {
00170 if ( mutexinit )
00171 {
00172 #ifdef _WIN32
00173 ReleaseMutex(mutex);
00174 #else
00175 if ( 0 != mutex_recur_hack )
00176 {
00177 assert( mutex_recur_hack > 0 );
00178 mutex_recur_hack--;
00179 }
00180 else
00181 {
00182 assert( 0 == pthread_mutex_unlock( &mutex ) );
00183 }
00184 #endif
00185 }
00186 }
00187
00188 void _debugFreeHeap()
00189 {
00190 BigInteger::DebugClearStatics();
00191
00192 struct allocblock *bp = m_abhead.next;
00193 if ( NULL == bp )
00194 {
00195 return;
00196 }
00197 while ( &m_abtail != bp )
00198 {
00199 assert(bp->next->prev == bp);
00200 validateBlock( bp );
00201 bp = bp->next;
00202 free( bp->prev );
00203 }
00204
00205 assert(m_abhead.next == &m_abtail);
00206 assert(m_abhead.prev == NULL);
00207 assert(m_abtail.prev == &m_abhead);
00208 assert(m_abtail.next == NULL);
00209 }
00210
00211 void _debugTearDown(bool reallyfree)
00212 {
00213 BigInteger::DebugClearStatics();
00214
00215 struct allocblock *bp = m_abhead.next;
00216
00217 while( bp != NULL && &m_abtail != bp )
00218 {
00219 struct allocblock *next;
00220 validateBlock( bp );
00221 next = bp->next;
00222 if ( reallyfree )
00223 {
00224 free( bp );
00225 }
00226 bp = next;
00227 }
00228
00229 if ( mutexinit )
00230 {
00231 #ifdef _WIN32
00232 CloseHandle(mutex);
00233 #else
00234 pthread_mutex_destroy( &mutex );
00235 #endif
00236 mutexinit = false;
00237 }
00238 if ( reallyfree )
00239 {
00240 assert(m_abhead.next == &m_abtail);
00241 assert(m_abhead.prev == NULL);
00242 assert(m_abtail.prev == &m_abhead);
00243 assert(m_abtail.next == NULL);
00244 }
00245 isshutdown = true;
00246 }
00247
00248 void *_debugMalloc( const int len, const char *filename, const int lineno, const bool isarray )
00249 {
00250 struct allocblock *ab;
00251
00252 assert( ! isshutdown );
00253 assert( len > 0 );
00254
00255 if ( NULL == m_abhead.next )
00256 {
00257 m_abhead.next = &m_abtail;
00258 m_abtail.prev = &m_abhead;
00259 if ( _usemutex && !mutexinit )
00260 {
00261 # ifdef _WINDOWS
00262 mutex = CreateMutex(NULL, FALSE, NULL);
00263 # else
00264 assert( 0 == pthread_mutex_init( &mutex, NULL ) );
00265 # endif
00266 mutexinit = true;
00267 }
00268 }
00269 _debugLockHeap( );
00270
00271 mallocsize += sizeof( struct allocblock ) + len;
00272
00273 ab = (struct allocblock *)malloc( sizeof( struct allocblock ) + len );
00274 if( NULL == ab )
00275 {
00276 assert(false);
00277 }
00278
00279 ab->majic = ALLOCBLOC_MAJIC;
00280 ab->id = midnum++;
00281
00282
00283
00284
00285 ab->data[len] = DEBUG_MEM_FILL;
00286 ab->data[len+1] = DEBUG_MEM_FILL;
00287 ab->data[len+2] = DEBUG_MEM_FILL;
00288 ab->data[len+3] = DEBUG_MEM_FILL;
00289 ab->filename = filename;
00290 ab->lineno = lineno;
00291 ab->size = len;
00292 ab->checkbit = 0;
00293 ab->checkbit2 = DEBUG_MEM_FILL;
00294 ab->isarray = isarray;
00295 ab->next = m_abhead.next;
00296 ab->next->prev = ab;
00297 ab->prev = &m_abhead;
00298 m_abhead.next = ab;
00299
00300 validateBlock( ab );
00301
00302 _debugUnlockHeap( );
00303 return ab->data;
00304 }
00305
00306 static struct allocblock *_debugScanForBlock( const void *vp )
00307 {
00308 struct allocblock *bp;
00309 if ( 0 == vp || NULL == vp )
00310 {
00311 return NULL;
00312 }
00313
00314 bp = (struct allocblock *)(((byte *)vp) - (sizeof(struct allocblock)-4));
00315 if ( bp->majic == ALLOCBLOC_MAJIC )
00316 {
00317 if(!validateBlock(bp))
00318 {
00319 assert(false);
00320 }
00321 return bp;
00322 }
00323
00324 bp = m_abhead.next;
00325 while ( bp != &m_abtail )
00326 {
00327 if ( vp == bp->data )
00328 {
00329 return bp;
00330 }
00331 if ( vp > bp->data )
00332 {
00333 if (vp < (void *)(bp->data + bp->size))
00334 {
00335 return bp;
00336 }
00337 }
00338 bp = bp->next;
00339 }
00340 return NULL;
00341 }
00342
00343 struct allocblock *findBlock( const void *vp )
00344 {
00345 struct allocblock *bp = _debugScanForBlock( vp );
00346
00347 if ( bp == NULL )
00348 {
00349 bp = m_abhead.next;
00350 while ( NULL != bp )
00351 {
00352 assert( bp->checkbit2 == DEBUG_MEM_FILL );
00353 if ( vp >= (void *)bp->data && vp < (void *)(bp->data + bp->size) )
00354 {
00355
00356 return bp;
00357 }
00358 bp = bp->next;
00359 }
00360 }
00361 else
00362 {
00363 return bp;
00364 }
00365 return NULL;
00366 }
00367
00368 void _debugFree( void *vp )
00369 {
00370 struct allocblock *bp = NULL;
00371
00372 if ( isshutdown )
00373 {
00374
00375 return;
00376 }
00377
00378 assert(NULL != vp);
00379
00380 DEBUG_VALIDATE();
00381 _debugLockHeap( );
00382
00383 bp = _debugScanForBlock( vp );
00384 if ( NULL == bp )
00385 {
00386 if ( NULL != (bp = _debugScanForBlock( ((byte *)vp)-4 )) )
00387 {
00388
00389 #ifndef WINE
00390 assert( _CrtIsValidPointer( ((byte *)vp)-4, 1, 1 ) );
00391 #endif
00392 }
00393 if ( NULL != (bp = _debugScanForBlock( ((byte *)vp)-8 )) )
00394 {
00395
00396 #ifndef WINE
00397 assert( _CrtIsValidPointer( ((byte *)vp)-8, 1, 1 ) );
00398 #endif
00399 }
00400 }
00401 else
00402 {
00403
00404 #ifndef WINE
00405 assert( _CrtIsValidPointer( vp, 1, 1 ) );
00406 #endif
00407 }
00408 assert( -1 == m_abhead.id && 0 == m_abhead.checkbit );
00409 assert( NULL != bp );
00410
00411 #ifndef WINE
00412 assert( _CrtIsValidPointer( bp, sizeof(struct allocblock), 1 ) );
00413 #endif
00414 assert( bp->prev->next == bp );
00415 bp->next->prev = bp->prev;
00416 bp->prev->next = bp->next;
00417
00418 assert( validateBlock( bp ) );
00419 assert ( bp->prev != NULL );
00420 assert( (&m_abhead == bp->prev)?1:validateBlock( bp->prev ) );
00421 assert( validateBlock( bp->next ) );
00422
00423 assert( validateBlock( bp ) );
00424 assert( &m_abhead != bp );
00425
00426 memset( bp, DEBUG_MEM_FILL, sizeof(struct allocblock) + bp->size );
00427
00428 #ifndef WINE
00429 assert( _CrtIsValidPointer( bp, sizeof(struct allocblock), 1 ) );
00430 #endif
00431 mallocsize -= bp->size;
00432
00433 _debugUnlockHeap( );
00434 DEBUG_VALIDATE();
00435 free( bp );
00436 DEBUG_VALIDATE();
00437 }
00438
00439 void _debugAssert( const int cond, const char *filename, const int lineno )
00440 {
00441 if ( cond == 0 )
00442 {
00443 #ifndef DEBUG
00444 assert( cond );
00445 #else
00446 printf( "assertion failed in %s on line %d.\n", filename, lineno );
00447 exit(20);
00448 #endif
00449 }
00450 }
00451
00452 int _debugCheckPtr( const void *ptr )
00453 {
00454 struct allocblock *bp;
00455 bool ret;
00456 if ( isshutdown )
00457 {
00458 return 1;
00459 }
00460 _debugLockHeap( );
00461
00462 bp = findBlock( ptr );
00463 if ( NULL == bp )
00464 {
00465 if ( NULL != (bp = findBlock( ((byte *)ptr)-4 )) )
00466 {
00467 if ( ! bp->isarray )
00468 {
00469 _debugUnlockHeap( );
00470
00471 return 0;
00472 }
00473 }
00474 if ( NULL != (bp = findBlock( ((byte *)ptr)-8 )) )
00475 {
00476
00477
00478
00479
00480
00481
00482
00483 }
00484 else
00485 {
00486 _debugUnlockHeap( );
00487
00488 return 0;
00489 }
00490
00491 #ifndef WINE
00492 assert( _CrtIsValidPointer( ((byte *)ptr)-4, 1, 1 ) );
00493 #endif
00494 }
00495 else
00496 {
00497
00498 #ifndef WINE
00499 assert( _CrtIsValidPointer( ptr, 1, 1 ) );
00500 #endif
00501 }
00502 assert( NULL != bp );
00503 ret = validateBlock( bp );
00504 _debugUnlockHeap( );
00505 return ret;
00506 }
00507
00508 int _debugCheckBlock( const void *ptr, const int size )
00509 {
00510 struct allocblock *bp;
00511 if ( isshutdown )
00512 {
00513 return 1;
00514 }
00515 assert( NULL != ptr );
00516
00517 _debugLockHeap( );
00518
00519 bp = _debugScanForBlock( ptr );
00520 if( bp == NULL )
00521 {
00522 const int vpsize = sizeof(void *);
00523
00524
00525 if ( NULL == (bp = _debugScanForBlock( ((byte *)ptr)-vpsize ) ) )
00526 {
00527 _debugUnlockHeap( );
00528 return 0;
00529 }
00530
00531
00532
00533
00534
00535
00536
00537
00538 #ifndef WINE
00539 assert( _CrtIsValidPointer( ((byte *)ptr)-vpsize, 1, 1 ) );
00540 #endif
00541 }
00542 else
00543 {
00544
00545 #ifndef WINE
00546 assert( _CrtIsValidPointer( ptr, 1, 1 ) );
00547 #endif
00548 }
00549 if ( NULL == bp )
00550 {
00551 _debugUnlockHeap( );
00552 return 0;
00553 }
00554 if ( bp->size != size )
00555 {
00556 if ( bp->size < size )
00557 {
00558 _debugUnlockHeap( );
00559 return 0;
00560 }
00561 }
00562 assert( validateBlock( bp ));
00563 _debugUnlockHeap( );
00564 return bp->size >= size;
00565 }
00566
00567 void _debugClearMemCheckPoints()
00568 {
00569 struct allocblock *bp;
00570
00571 if ( isshutdown )
00572 {
00573 return;
00574 }
00575
00576 _debugLockHeap( );
00577
00578 bp = m_abhead.next;
00579 while ( NULL != bp )
00580 {
00581 assert( validateBlock( bp ) );
00582 if ( bp != NULL )
00583 {
00584 bp->checkbit = 0;
00585 }
00586 bp = bp->next;
00587 }
00588
00589 BigInteger::CheckMemStatics();
00590
00591 _debugUnlockHeap( );
00592 }
00593
00594 void _debugNoteMemBlock( const void *vp )
00595 {
00596 struct allocblock *bp;
00597
00598 if ( isshutdown )
00599 {
00600 return;
00601 }
00602 _debugLockHeap( );
00603
00604 bp = findBlock( vp );
00605
00606 #ifndef WINE
00607 assert( _CrtIsValidPointer( vp, 1, 1 ) );
00608 #endif
00609 if ( NULL == bp )
00610 {
00611 if ( NULL != (bp = findBlock( ((byte *)vp)-4 )) )
00612 {
00613 assert ( bp->isarray );
00614 }
00615 }
00616 assert( NULL != bp );
00617 assert(validateBlock( bp ));
00618 bp->checkbit = 1;
00619 _debugUnlockHeap( );
00620 }
00621
00622 int _debugCheckMem()
00623 {
00624 struct allocblock *bp;
00625
00626 assert(_CrtCheckMemory());
00627 if ( isshutdown )
00628 {
00629 return 1;
00630 }
00631
00632 _debugLockHeap( );
00633
00634 bp = m_abhead.next;
00635 while ( NULL != bp && &m_abtail != bp )
00636 {
00637 if ( bp != NULL )
00638 {
00639 assert(validateBlock( bp ));
00640 if( bp->checkbit != 1 )
00641 {
00642 return 0;
00643 }
00644 }
00645 bp = bp->next;
00646 }
00647 _debugUnlockHeap( );
00648 return 1;
00649 }
00650
00651 void _debugValidateHeap()
00652 {
00653 struct allocblock *bp = m_abhead.next;
00654
00655 _debugLockHeap( );
00656
00657 while ( NULL != bp && bp != &m_abtail )
00658 {
00659 assert ( validateBlock( bp ) );
00660 assert( bp->next->prev == bp );
00661 assert( bp->prev->next == bp );
00662 bp = bp->next;
00663 }
00664 assert(_CrtCheckMemory());
00665 if ( isshutdown )
00666 {
00667 return;
00668 }
00669 _debugUnlockHeap( );
00670 }
00671
00672 void _debugDumpMemLeaks()
00673 {
00674 struct allocblock *bp = m_abhead.next;
00675 if ( isshutdown || NULL == bp )
00676 {
00677 return;
00678 }
00679 _debugLockHeap( );
00680
00681 while ( bp != &m_abtail )
00682 {
00683 assert(validateBlock( bp ));
00684 if( bp->checkbit != 1 )
00685 {
00686 printf( "Memory leak %d: %d bytes allocated in %s on line %d\n", bp->id, bp->size, bp->filename, bp->lineno );
00687 }
00688 bp = bp->next;
00689 }
00690 _debugUnlockHeap( );
00691 }
00692
00693 int _debugAssertMemFree()
00694 {
00695 return m_abhead.next == &m_abtail;
00696 }
00697
00698 void fillCheckPointData( struct memcheckpoint *mp )
00699 {
00700 struct allocblock *bp;
00701
00702 mp->count = 0;
00703 mp->size = 0;
00704
00705 _debugLockHeap( );
00706 bp = m_abhead.next;
00707
00708 while( NULL != bp && &m_abtail != bp )
00709 {
00710 if( bp != NULL )
00711 {
00712 mp->count++;
00713 mp->size += bp->size;
00714 }
00715 bp = bp->next;
00716 }
00717 _debugUnlockHeap( );
00718 }
00719
00720 void _debugCheckpointHeap()
00721 {
00722 fillCheckPointData( &m_memcheckpoint );
00723 }
00724
00725 int _debugAssertCheckPoint()
00726 {
00727 struct memcheckpoint mp;
00728 fillCheckPointData( &mp );
00729 return mp.size == m_memcheckpoint.size && mp.count == m_memcheckpoint.count;
00730 }
00731
00732 #ifdef DEBUG
00733 void *rpl_malloc( const int size, char *filename, const int lineno, const bool isarray )
00734 {
00735 return _debugMalloc(size, filename, lineno, isarray);
00736 }
00737 #else
00738 void *rpl_malloc( const int size )
00739 {
00740 return malloc( size );
00741 }
00742 #endif
00743
00744 #endif