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
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
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 #ifdef DEBUG
00120
00121 #include <stdio.h>
00122 #include <stdlib.h>
00123 #include <string.h>
00124 #include <ctype.h>
00125 #include <stdarg.h>
00126 #include "hprof.h"
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151 static int malloc_watch = 1;
00152
00153
00154 #define FREED_CHAR 'F'
00155
00156
00157 #define ALLOC_CHAR 'A'
00158
00159
00160 #define LEFT_OVER_CHAR 'Z'
00161
00162
00163 #define MAX_FREE_DELAY_COUNT 1
00164 #undef MAX_FREE_DELAY_COUNT
00165
00166
00167 #define WARRANT_NAME_MAX (32-1)
00168
00169
00170 #define user2malloc_(uptr) (((char*)(void*)uptr)-sizeof(Word))
00171
00172
00173 #define malloc2user_(mptr) (((char*)(void*)(mptr))+sizeof(Word))
00174
00175
00176 #define warrant_space ( malloc_watch?sizeof(Warrant_Record):0 )
00177
00178
00179 #define round_up_(n) \
00180 ((n)==0?0:(sizeof(Word)+(((n)-1)/sizeof(Word))*sizeof(Word)))
00181
00182
00183 #define rbytes_(nbytes) \
00184 (size_t)( sizeof(Word) + round_up_(nbytes) + sizeof(Word) + warrant_space )
00185
00186
00187 #define nsize1_(mptr) (((Word*)(void*)(mptr))->nsize1)
00188 #define nsize2_(mptr) (((Word*)(void*)(mptr))->nsize2)
00189
00190
00191
00192 #define tail_nsize1_(mptr) \
00193 nsize1_(((char*)(void*)(mptr))+round_up_(-nsize1_(mptr))+sizeof(Word))
00194 #define tail_nsize2_(mptr) \
00195 nsize2_(((char*)(void*)(mptr))+round_up_(-nsize1_(mptr))+sizeof(Word))
00196
00197
00198 #define user_nsize1_(uptr) nsize1_(user2malloc_(uptr))
00199 #define user_nsize2_(uptr) nsize2_(user2malloc_(uptr))
00200
00201
00202
00203 #define user_tail_nsize1_(uptr) tail_nsize1_(user2malloc_(uptr))
00204 #define user_tail_nsize2_(uptr) tail_nsize2_(user2malloc_(uptr))
00205
00206
00207 #define last_user_word_(mptr) \
00208 ((int*)(((char*)(void*)(mptr))+round_up_(-nsize1_(mptr))))
00209
00210
00211 #define warrant_(mptr) \
00212 (*((Warrant_Record*)(void*)(((char*)(void*)(mptr))+round_up_(-nsize1_(mptr))+sizeof(Word)*2)))
00213
00214
00215
00216 typedef struct {
00217 void *link;
00218 char name[WARRANT_NAME_MAX + 1];
00219 int line;
00220 int id;
00221 } Warrant_Record;
00222 #define warrant_link_(mptr) warrant_(mptr).link
00223 #define warrant_name_(mptr) warrant_(mptr).name
00224 #define warrant_line_(mptr) warrant_(mptr).line
00225 #define warrant_id_(mptr) warrant_(mptr).id
00226 #define MFILE(mptr) (malloc_watch?warrant_name_(mptr):"?")
00227 #define MLINE(mptr) (malloc_watch?warrant_line_(mptr):0)
00228 #define MID(mptr) (malloc_watch?warrant_id_(mptr):0)
00229
00230
00231 typedef struct {
00232 int nsize1;
00233 int nsize2;
00234 } Word;
00235
00236
00237 static void *first_warrant_mptr = NULL;
00238
00239
00240 static int id_counter = 0;
00241 static int largest_size = 0;
00242 static void * largest_addr = NULL;
00243 static void * smallest_addr = NULL;
00244
00245
00246 static char *debug_check;
00247 static void *clobbered_ptr;
00248
00249
00250 #define minimum(a,b) ((a)<(b)?(a):(b))
00251
00252
00253 static void
00254 error_message(const char * format, ...)
00255 {
00256 FILE *error_fp = stderr;
00257 va_list ap;
00258 va_start(ap, format);
00259 (void)fprintf(error_fp, "debug_malloc: ");
00260 (void)vfprintf(error_fp, format, ap);
00261 (void)fprintf(error_fp, "\n");
00262 (void)fflush(error_fp);
00263 va_end(ap);
00264 }
00265
00266
00267
00268
00269
00270 static void
00271 memory_error(void *mptr, const char *name, int mid, const char *mfile, int mline, const char *file, int line)
00272 {
00273 char nice_words[512];
00274 char temp[256];
00275 int len;
00276 void *mptr_walk;
00277
00278 if (name == NULL)
00279 name = "UNKNOWN_NAME";
00280 if (file == NULL)
00281 file = "UNKNOWN_FILE";
00282 md_system_error(temp, (int)sizeof(temp));
00283 (void)strcpy(nice_words, temp);
00284 if ( debug_check!=NULL ) {
00285 (void)md_snprintf(nice_words, sizeof(nice_words),
00286 "%s The %s at %p appears to have been hit.",
00287 temp, debug_check, clobbered_ptr);
00288 }
00289 len = -nsize1_(mptr);
00290 error_message("Error: "
00291 "%s The malloc space #%d is at %p [user size=%d(0x%x)],"
00292 " and was allocated from file \"%s\" at line %d."
00293 " [The debug function %s() detected this error "
00294 "in file \"%s\" at line %d.]",
00295 nice_words, mid, mptr, len, len, mfile, mline,
00296 name, file, line);
00297
00298
00299 {
00300 int i;
00301 void *uptr = malloc2user_(mptr);
00302 char *pmess;
00303 pmess = temp;
00304 for(i=0;i<(int)sizeof(temp);i++) {
00305 int ch = ((unsigned char*)uptr)[i];
00306 if ( isprint(ch) ) {
00307 *pmess++ = ch;
00308 } else {
00309 *pmess++ = '\\';
00310 *pmess++ = 'x';
00311 (void)sprintf(pmess,"%02x",ch);
00312 pmess+=2;
00313 }
00314 }
00315 *pmess = 0;
00316 error_message("Error: %p contains user data: %s", uptr, temp);
00317 }
00318
00319
00320 if (!malloc_watch) {
00321 return;
00322 }
00323 mptr_walk = first_warrant_mptr;
00324 if (mptr_walk != NULL) {
00325 error_message("Active allocations: "
00326 "count=%d, largest_size=%d, address range (%p,%p)",
00327 id_counter, largest_size, smallest_addr, largest_addr);
00328 do {
00329 int size1;
00330 int size2;
00331 char *mfile_walk;
00332
00333 if ( mptr_walk > largest_addr || mptr_walk < smallest_addr ) {
00334 error_message("Terminating list due to pointer corruption");
00335 break;
00336 }
00337 size1 = -nsize1_(mptr_walk);
00338 size2 = -nsize2_(mptr_walk);
00339 mfile_walk = MFILE(mptr_walk);
00340 error_message("#%d: addr=%p size1=%d size2=%d file=\"%.*s\" line=%d",
00341 MID(mptr_walk), mptr_walk, size1, size2,
00342 WARRANT_NAME_MAX, mfile_walk, MLINE(mptr_walk));
00343 if ( size1 != size2 || size1 > largest_size || size1 < 0 ) {
00344 error_message("Terminating list due to size corruption");
00345 break;
00346 }
00347 mptr_walk = warrant_link_(mptr_walk);
00348 } while (mptr_walk != NULL);
00349 }
00350 abort();
00351 }
00352
00353
00354
00355
00356 static void
00357 setup_space_and_issue_warrant(void *mptr, size_t size, const char *file, int line)
00358 {
00359 register int nbytes;
00360
00361
00362 nbytes = (int)size;
00363 if ( nbytes > largest_size || largest_addr == NULL ) largest_size = nbytes;
00364
00365 if ( mptr > largest_addr ) largest_addr = mptr;
00366
00367 if ( mptr < smallest_addr || smallest_addr == NULL ) smallest_addr = mptr;
00368
00369
00370 nsize1_(mptr) = -nbytes;
00371 nsize2_(mptr) = -nbytes;
00372 tail_nsize1_(mptr) = -nbytes;
00373 tail_nsize2_(mptr) = -nbytes;
00374
00375 #ifdef LEFT_OVER_CHAR
00376
00377 {
00378 register int trailing_extra_bytes;
00379
00380 trailing_extra_bytes = (int) (round_up_(nbytes) - nbytes);
00381 if ( trailing_extra_bytes > 0 ) {
00382 register char *p;
00383 register int i;
00384 p = ((char *) mptr) + sizeof(Word) + nbytes;
00385 for (i = 0; i < trailing_extra_bytes; i++)
00386 p[i] = LEFT_OVER_CHAR;
00387 }
00388 }
00389 #endif
00390
00391
00392 if (malloc_watch) {
00393 static Warrant_Record zero_warrant;
00394 register void *p1,
00395 *p2;
00396 size_t len;
00397 int start_pos = 0;
00398 warrant_(mptr) = zero_warrant;
00399 p1 = warrant_name_(mptr);
00400 len = strlen(file);
00401 if ( len > WARRANT_NAME_MAX ) {
00402
00403 start_pos = (int)len - WARRANT_NAME_MAX;
00404 }
00405 p2 = ((char*)file) + start_pos;
00406
00407 (void) memcpy(p1, p2, minimum(((int)len), WARRANT_NAME_MAX));
00408 warrant_line_(mptr) = line;
00409 warrant_id_(mptr) = ++id_counter;
00410 warrant_link_(mptr) = first_warrant_mptr;
00411 first_warrant_mptr = mptr;
00412 }
00413 }
00414
00415
00416
00417
00418 static void
00419 memory_check(void *uptr, int mid, const char *mfile, int mline, const char *file, int line)
00420 {
00421 int neg_nbytes;
00422 int nbytes;
00423
00424 debug_check = "pointer value itself";
00425 clobbered_ptr = uptr;
00426 if (uptr == NULL)
00427 memory_error((void *) NULL, "memory_check", mid, mfile, mline, file, line);
00428
00429
00430
00431 debug_check = "first beginning clobber word";
00432 clobbered_ptr = (char*)&user_nsize1_(uptr);
00433 neg_nbytes = user_nsize1_(uptr);
00434 if (neg_nbytes >= 0)
00435 memory_error(user2malloc_(uptr), "memory_check", mid, mfile, mline, file, line);
00436
00437 debug_check = "second beginning clobber word";
00438 clobbered_ptr = (char*)&user_nsize2_(uptr);
00439 if (neg_nbytes != user_nsize2_(uptr))
00440 memory_error(user2malloc_(uptr), "memory_check", mid, mfile, mline, file, line);
00441
00442 debug_check = "first ending clobber word";
00443 clobbered_ptr = (char*)&user_tail_nsize1_(uptr);
00444 if (neg_nbytes != user_tail_nsize1_(uptr))
00445 memory_error(user2malloc_(uptr), "memory_check", mid, mfile, mline, file, line);
00446
00447 debug_check = "second ending clobber word";
00448 clobbered_ptr = (char*)&user_tail_nsize2_(uptr);
00449 if (neg_nbytes != user_tail_nsize2_(uptr))
00450 memory_error(user2malloc_(uptr), "memory_check", mid, mfile, mline, file, line);
00451
00452
00453 nbytes = -neg_nbytes;
00454
00455 #ifdef LEFT_OVER_CHAR
00456 {
00457
00458 register int trailing_extra_bytes;
00459 register int i;
00460 register char *p;
00461
00462 trailing_extra_bytes = (int) (round_up_(nbytes) - nbytes);
00463 p = ((char *) (uptr)) + nbytes;
00464 debug_check = "trailing left over area";
00465 for (i = 0; i < trailing_extra_bytes; i++) {
00466 clobbered_ptr = p+1;
00467 if (p[i] != LEFT_OVER_CHAR) {
00468 memory_error(user2malloc_(uptr), "memory_check", mid, mfile, mline, file, line);
00469 }
00470 }
00471 }
00472 #endif
00473
00474
00475 debug_check = NULL;
00476 }
00477
00478
00479
00480
00481
00482 static int
00483 remove_warrant(void *mptr)
00484 {
00485 void *mptr1,
00486 *last_mptr1;
00487
00488
00489 if (malloc_watch && mptr != NULL) {
00490 int found;
00491
00492 found = 0;
00493 last_mptr1 = NULL;
00494 mptr1 = first_warrant_mptr;
00495 while (mptr1 != NULL) {
00496 if (mptr1 == mptr) {
00497 if (last_mptr1 == NULL)
00498 first_warrant_mptr = warrant_link_(mptr1);
00499 else
00500 warrant_link_(last_mptr1) = warrant_link_(mptr1);
00501 found = 1;
00502 break;
00503 }
00504 last_mptr1 = mptr1;
00505 mptr1 = warrant_link_(mptr1);
00506 }
00507 return found;
00508 }
00509 return 1;
00510 }
00511
00512 static void
00513 actual_free(void *uptr, const char *file, int line)
00514 {
00515 void *mptr;
00516 const char *mfile;
00517 int mline;
00518 int mid;
00519 if ( uptr == NULL )
00520 return;
00521 mptr = user2malloc_(uptr);
00522 memory_check(uptr, (mid=MID(mptr)), (mfile=MFILE(mptr)), (mline=MLINE(mptr)), file, line);
00523 if (malloc_watch && remove_warrant(mptr)==0 )
00524 memory_check(uptr, mid, mfile, mline, file, line);
00525 #ifdef FREED_CHAR
00526 if ( mptr!=NULL ) {
00527 size_t nbytes = -nsize1_(mptr);
00528
00529 (void)memset(mptr, FREED_CHAR, rbytes_(nbytes));
00530 }
00531 #endif
00532 free(mptr);
00533 }
00534
00535 #ifdef MAX_FREE_DELAY_COUNT
00536
00537 static void *free_delay[MAX_FREE_DELAY_COUNT];
00538 static int free_delay_pos = 0;
00539
00540 static void
00541 delayed_free(void *uptr, const char* file, int line)
00542 {
00543 void *mptr;
00544 void *olduptr = free_delay[free_delay_pos];
00545 size_t nbytes;
00546 if ( uptr==NULL )
00547 return;
00548 mptr = user2malloc_(uptr);
00549 memory_check(uptr, MID(mptr), MFILE(mptr), MLINE(mptr), file, line);
00550 if ( olduptr!=NULL ) {
00551 actual_free(olduptr, file, line);
00552 }
00553 free_delay[free_delay_pos] = uptr;
00554 free_delay_pos++;
00555 free_delay_pos = free_delay_pos % MAX_FREE_DELAY_COUNT;
00556 nbytes = -user_nsize1_(uptr);
00557 #ifdef FREED_CHAR
00558 (void)memset(uptr, FREED_CHAR, (size_t)nbytes);
00559 #endif
00560 }
00561
00562 static void
00563 delayed_free_all(const char *file, int line)
00564 {
00565 int i;
00566 for ( i=0; i< MAX_FREE_DELAY_COUNT; i++) {
00567 void *olduptr = free_delay[i];
00568 free_delay[i] = NULL;
00569 if ( olduptr!=NULL ) {
00570 actual_free(olduptr, file, line);
00571 }
00572 }
00573 }
00574
00575 #endif
00576
00577 void
00578 debug_free(void *uptr, const char *file, int line)
00579 {
00580 int mid = 0;
00581
00582 if (uptr == NULL)
00583 memory_error((void *) NULL, "debug_free", mid, file, line, file, line);
00584 #ifdef MAX_FREE_DELAY_COUNT
00585 delayed_free(uptr, file, line);
00586 #else
00587 actual_free(uptr, file, line);
00588 #endif
00589 }
00590
00591
00592 void *
00593 debug_malloc(size_t nbytes, const char *file, int line)
00594 {
00595 void *mptr;
00596 void *uptr;
00597 int mid = id_counter;
00598
00599
00600 if ((int)nbytes <= 0)
00601 memory_error((void *) NULL, "debug_malloc", mid, file, line, file, line);
00602
00603 mptr = malloc(rbytes_(nbytes));
00604 if (mptr == NULL)
00605 memory_error((void *) NULL, "debug_malloc", mid, file, line, file, line);
00606 setup_space_and_issue_warrant(mptr, nbytes, file, line);
00607 uptr = malloc2user_(mptr);
00608 #ifdef ALLOC_CHAR
00609 (void)memset(uptr, ALLOC_CHAR, (size_t)nbytes);
00610 #endif
00611 return uptr;
00612 }
00613
00614 void *
00615 debug_realloc(void *uptr, size_t nbytes, const char *file, int line)
00616 {
00617 void *mptr;
00618 void *oldmptr;
00619 void *newuptr;
00620 size_t oldnbytes;
00621 int mid = id_counter;
00622
00623 oldmptr = user2malloc_(uptr);
00624 oldnbytes = 0;
00625 if ((int)nbytes <= 0)
00626 memory_error(oldmptr, "debug_realloc", mid, file, line, file, line);
00627 if (uptr != NULL) {
00628 memory_check(uptr, MID(oldmptr), MFILE(oldmptr), MLINE(oldmptr), file, line);
00629 oldnbytes = -user_nsize1_(uptr);
00630 if ( malloc_watch && remove_warrant(oldmptr)==0 )
00631 memory_check(uptr, MID(oldmptr), MFILE(oldmptr), MLINE(oldmptr), file, line);
00632 }
00633 if (uptr == NULL) {
00634
00635 mptr = malloc(rbytes_(nbytes));
00636 } else {
00637
00638 mptr = realloc(oldmptr, rbytes_(nbytes));
00639 }
00640 if (mptr == NULL)
00641 memory_error(oldmptr, "debug_realloc", mid, file, line, file, line);
00642 setup_space_and_issue_warrant(mptr, nbytes, file, line);
00643 newuptr = malloc2user_(mptr);
00644 #ifdef ALLOC_CHAR
00645 if (uptr == NULL)
00646 (void)memset(newuptr, ALLOC_CHAR, (size_t)nbytes);
00647 else if ( nbytes > oldnbytes )
00648 (void)memset(((char*)newuptr)+oldnbytes, ALLOC_CHAR, (size_t)nbytes-oldnbytes);
00649 #endif
00650 return newuptr;
00651 }
00652
00653
00654 void *
00655 debug_calloc(size_t nelem, size_t elsize, const char *file, int line)
00656 {
00657 void *mptr;
00658 size_t nbytes;
00659 int mid = id_counter;
00660
00661 nbytes = nelem*elsize;
00662
00663 if ((int)nbytes <= 0)
00664 memory_error((void *) NULL, "debug_calloc", mid, file, line, file, line);
00665
00666 mptr = calloc(rbytes_(nbytes),1);
00667 if (mptr == NULL)
00668 memory_error((void *) NULL, "debug_calloc", mid, file, line, file, line);
00669 setup_space_and_issue_warrant(mptr, nbytes, file, line);
00670 return malloc2user_(mptr);
00671 }
00672
00673
00674 char *
00675 debug_strdup(const char *s1, const char *file, int line)
00676 {
00677 void *mptr;
00678 void *uptr;
00679 size_t nbytes;
00680 int mid = id_counter;
00681
00682 if (s1 == NULL)
00683 memory_error((void *) NULL, "debug_strdup", mid, file, line, file, line);
00684 nbytes = strlen(s1)+1;
00685
00686 if ((int)nbytes < 0)
00687 memory_error((void *) NULL, "debug_strdup", mid, file, line, file, line);
00688
00689 mptr = malloc(rbytes_(nbytes));
00690 if (mptr == NULL)
00691 memory_error((void *) NULL, "debug_strdup", mid, file, line, file, line);
00692 setup_space_and_issue_warrant(mptr, nbytes, file, line);
00693 uptr = malloc2user_(mptr);
00694 (void)strcpy((char*)uptr, s1);
00695 return (char*)uptr;
00696 }
00697
00698 void
00699 debug_malloc_verify(const char *file, int line)
00700 {
00701 void *mptr;
00702
00703 #ifdef MAX_FREE_DELAY_COUNT
00704 delayed_free_all(file,line);
00705 #endif
00706
00707 if (!malloc_watch) {
00708 return;
00709 }
00710 mptr = first_warrant_mptr;
00711 if (mptr != NULL) {
00712
00713 do {
00714 memory_check(malloc2user_(mptr), MID(mptr), MFILE(mptr), MLINE(mptr), file, line);
00715 mptr = warrant_link_(mptr);
00716 } while (mptr != NULL);
00717 }
00718 }
00719
00720
00721 void
00722 debug_malloc_police(const char *file, int line)
00723 {
00724 void *mptr;
00725
00726 #ifdef MAX_FREE_DELAY_COUNT
00727 delayed_free_all(file,line);
00728 #endif
00729
00730 if (!malloc_watch) {
00731 return;
00732 }
00733
00734 mptr = first_warrant_mptr;
00735 if (mptr != NULL) {
00736 debug_malloc_verify(file, line);
00737
00738 mptr = first_warrant_mptr;
00739 do {
00740 error_message("Outstanding space warrant: %p (%d bytes) allocated by %s at line %d, allocation #%d",
00741 mptr, -nsize1_(mptr), warrant_name_(mptr),
00742 warrant_line_(mptr), warrant_id_(mptr));
00743
00744 mptr = warrant_link_(mptr);
00745 } while (mptr != NULL);
00746 }
00747 }
00748
00749 #else
00750
00751 void
00752 debug_malloc_verify(const char *file, int line)
00753 {
00754 file = file;
00755 line = line;
00756 }
00757
00758 void
00759 debug_malloc_police(const char *file, int line)
00760 {
00761 file = file;
00762 line = line;
00763 }
00764
00765 #endif
00766