mem_dbg.c revision 1.7
1/* crypto/mem_dbg.c */ 2/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) 3 * All rights reserved. 4 * 5 * This package is an SSL implementation written 6 * by Eric Young (eay@cryptsoft.com). 7 * The implementation was written so as to conform with Netscapes SSL. 8 * 9 * This library is free for commercial and non-commercial use as long as 10 * the following conditions are aheared to. The following conditions 11 * apply to all code found in this distribution, be it the RC4, RSA, 12 * lhash, DES, etc., code; not just the SSL code. The SSL documentation 13 * included with this distribution is covered by the same copyright terms 14 * except that the holder is Tim Hudson (tjh@cryptsoft.com). 15 * 16 * Copyright remains Eric Young's, and as such any Copyright notices in 17 * the code are not to be removed. 18 * If this package is used in a product, Eric Young should be given attribution 19 * as the author of the parts of the library used. 20 * This can be in the form of a textual message at program startup or 21 * in documentation (online or textual) provided with the package. 22 * 23 * Redistribution and use in source and binary forms, with or without 24 * modification, are permitted provided that the following conditions 25 * are met: 26 * 1. Redistributions of source code must retain the copyright 27 * notice, this list of conditions and the following disclaimer. 28 * 2. Redistributions in binary form must reproduce the above copyright 29 * notice, this list of conditions and the following disclaimer in the 30 * documentation and/or other materials provided with the distribution. 31 * 3. All advertising materials mentioning features or use of this software 32 * must display the following acknowledgement: 33 * "This product includes cryptographic software written by 34 * Eric Young (eay@cryptsoft.com)" 35 * The word 'cryptographic' can be left out if the rouines from the library 36 * being used are not cryptographic related :-). 37 * 4. If you include any Windows specific code (or a derivative thereof) from 38 * the apps directory (application code) you must include an acknowledgement: 39 * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" 40 * 41 * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND 42 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 43 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 44 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 45 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 46 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 47 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 48 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 49 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 50 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 51 * SUCH DAMAGE. 52 * 53 * The licence and distribution terms for any publically available version or 54 * derivative of this code cannot be changed. i.e. this code cannot simply be 55 * copied and put under another distribution licence 56 * [including the GNU Public Licence.] 57 */ 58 59#include <stdio.h> 60#include <stdlib.h> 61#include <time.h> 62#include <openssl/crypto.h> 63#include <openssl/buffer.h> 64#include <openssl/bio.h> 65#include <openssl/lhash.h> 66#include "cryptlib.h" 67 68static int mh_mode=CRYPTO_MEM_CHECK_OFF; 69/* The state changes to CRYPTO_MEM_CHECK_ON | CRYPTO_MEM_CHECK_ENABLE 70 * when the application asks for it (usually after library initialisation 71 * for which no book-keeping is desired). 72 * 73 * State CRYPTO_MEM_CHECK_ON exists only temporarily when the library 74 * thinks that certain allocations should not be checked (e.g. the data 75 * structures used for memory checking). It is not suitable as an initial 76 * state: the library will unexpectedly enable memory checking when it 77 * executes one of those sections that want to disable checking 78 * temporarily. 79 * 80 * State CRYPTO_MEM_CHECK_ENABLE without ..._ON makes no sense whatsoever. 81 */ 82 83static unsigned long order = 0; /* number of memory requests */ 84static LHASH *mh=NULL; /* hash-table of memory requests (address as key); 85 * access requires MALLOC2 lock */ 86 87 88typedef struct app_mem_info_st 89/* For application-defined information (static C-string `info') 90 * to be displayed in memory leak list. 91 * Each thread has its own stack. For applications, there is 92 * CRYPTO_push_info("...") to push an entry, 93 * CRYPTO_pop_info() to pop an entry, 94 * CRYPTO_remove_all_info() to pop all entries. 95 */ 96 { 97 unsigned long thread; 98 const char *file; 99 int line; 100 const char *info; 101 struct app_mem_info_st *next; /* tail of thread's stack */ 102 int references; 103 } APP_INFO; 104 105static LHASH *amih=NULL; /* hash-table with those app_mem_info_st's 106 * that are at the top of their thread's stack 107 * (with `thread' as key); 108 * access requires MALLOC2 lock */ 109 110typedef struct mem_st 111/* memory-block description */ 112 { 113 void *addr; 114 int num; 115 const char *file; 116 int line; 117 unsigned long thread; 118 unsigned long order; 119 time_t time; 120 APP_INFO *app_info; 121 } MEM; 122 123static long options = /* extra information to be recorded */ 124#if defined(CRYPTO_MDEBUG_TIME) || defined(CRYPTO_MDEBUG_ALL) 125 V_CRYPTO_MDEBUG_TIME | 126#endif 127#if defined(CRYPTO_MDEBUG_THREAD) || defined(CRYPTO_MDEBUG_ALL) 128 V_CRYPTO_MDEBUG_THREAD | 129#endif 130 0; 131 132 133static unsigned int num_disable = 0; /* num_disable > 0 134 * iff 135 * mh_mode == CRYPTO_MEM_CHECK_ON (w/o ..._ENABLE) 136 */ 137static unsigned long disabling_thread = 0; /* Valid iff num_disable > 0. 138 * CRYPTO_LOCK_MALLOC2 is locked 139 * exactly in this case (by the 140 * thread named in disabling_thread). 141 */ 142 143int CRYPTO_mem_ctrl(int mode) 144 { 145 int ret=mh_mode; 146 147 CRYPTO_w_lock(CRYPTO_LOCK_MALLOC); 148 switch (mode) 149 { 150 /* for applications (not to be called while multiple threads 151 * use the library): */ 152 case CRYPTO_MEM_CHECK_ON: /* aka MemCheck_start() */ 153 mh_mode = CRYPTO_MEM_CHECK_ON|CRYPTO_MEM_CHECK_ENABLE; 154 num_disable = 0; 155 break; 156 case CRYPTO_MEM_CHECK_OFF: /* aka MemCheck_stop() */ 157 mh_mode = 0; 158 num_disable = 0; /* should be true *before* MemCheck_stop is used, 159 or there'll be a lot of confusion */ 160 break; 161 162 /* switch off temporarily (for library-internal use): */ 163 case CRYPTO_MEM_CHECK_DISABLE: /* aka MemCheck_off() */ 164 if (mh_mode & CRYPTO_MEM_CHECK_ON) 165 { 166 if (!num_disable || (disabling_thread != CRYPTO_thread_id())) /* otherwise we already have the MALLOC2 lock */ 167 { 168 /* Long-time lock CRYPTO_LOCK_MALLOC2 must not be claimed while 169 * we're holding CRYPTO_LOCK_MALLOC, or we'll deadlock if 170 * somebody else holds CRYPTO_LOCK_MALLOC2 (and cannot release 171 * it because we block entry to this function). 172 * Give them a chance, first, and then claim the locks in 173 * appropriate order (long-time lock first). 174 */ 175 CRYPTO_w_unlock(CRYPTO_LOCK_MALLOC); 176 /* Note that after we have waited for CRYPTO_LOCK_MALLOC2 177 * and CRYPTO_LOCK_MALLOC, we'll still be in the right 178 * "case" and "if" branch because MemCheck_start and 179 * MemCheck_stop may never be used while there are multiple 180 * OpenSSL threads. */ 181 CRYPTO_w_lock(CRYPTO_LOCK_MALLOC2); 182 CRYPTO_w_lock(CRYPTO_LOCK_MALLOC); 183 mh_mode &= ~CRYPTO_MEM_CHECK_ENABLE; 184 disabling_thread=CRYPTO_thread_id(); 185 } 186 num_disable++; 187 } 188 break; 189 case CRYPTO_MEM_CHECK_ENABLE: /* aka MemCheck_on() */ 190 if (mh_mode & CRYPTO_MEM_CHECK_ON) 191 { 192 if (num_disable) /* always true, or something is going wrong */ 193 { 194 num_disable--; 195 if (num_disable == 0) 196 { 197 mh_mode|=CRYPTO_MEM_CHECK_ENABLE; 198 CRYPTO_w_unlock(CRYPTO_LOCK_MALLOC2); 199 } 200 } 201 } 202 break; 203 204 default: 205 break; 206 } 207 CRYPTO_w_unlock(CRYPTO_LOCK_MALLOC); 208 return(ret); 209 } 210 211int CRYPTO_is_mem_check_on(void) 212 { 213 int ret = 0; 214 215 if (mh_mode & CRYPTO_MEM_CHECK_ON) 216 { 217 CRYPTO_r_lock(CRYPTO_LOCK_MALLOC); 218 219 ret = (mh_mode & CRYPTO_MEM_CHECK_ENABLE) 220 || (disabling_thread != CRYPTO_thread_id()); 221 222 CRYPTO_r_unlock(CRYPTO_LOCK_MALLOC); 223 } 224 return(ret); 225 } 226 227 228void CRYPTO_dbg_set_options(long bits) 229 { 230 options = bits; 231 } 232 233long CRYPTO_dbg_get_options(void) 234 { 235 return options; 236 } 237 238/* static int mem_cmp(MEM *a, MEM *b) */ 239static int mem_cmp(const void *a_void, const void *b_void) 240 { 241 return((const char *)((const MEM *)a_void)->addr 242 - (const char *)((const MEM *)b_void)->addr); 243 } 244 245/* static unsigned long mem_hash(MEM *a) */ 246static unsigned long mem_hash(const void *a_void) 247 { 248 unsigned long ret; 249 250 ret=(unsigned long)((const MEM *)a_void)->addr; 251 252 ret=ret*17851+(ret>>14)*7+(ret>>4)*251; 253 return(ret); 254 } 255 256/* static int app_info_cmp(APP_INFO *a, APP_INFO *b) */ 257static int app_info_cmp(const void *a_void, const void *b_void) 258 { 259 return(((const APP_INFO *)a_void)->thread 260 != ((const APP_INFO *)b_void)->thread); 261 } 262 263/* static unsigned long app_info_hash(APP_INFO *a) */ 264static unsigned long app_info_hash(const void *a_void) 265 { 266 unsigned long ret; 267 268 ret=(unsigned long)((const APP_INFO *)a_void)->thread; 269 270 ret=ret*17851+(ret>>14)*7+(ret>>4)*251; 271 return(ret); 272 } 273 274static APP_INFO *pop_info(void) 275 { 276 APP_INFO tmp; 277 APP_INFO *ret = NULL; 278 279 if (amih != NULL) 280 { 281 tmp.thread=CRYPTO_thread_id(); 282 if ((ret=(APP_INFO *)lh_delete(amih,&tmp)) != NULL) 283 { 284 APP_INFO *next=ret->next; 285 286 if (next != NULL) 287 { 288 next->references++; 289 lh_insert(amih,(char *)next); 290 } 291#ifdef LEVITTE_DEBUG_MEM 292 if (ret->thread != tmp.thread) 293 { 294 fprintf(stderr, "pop_info(): deleted info has other thread ID (%lu) than the current thread (%lu)!!!!\n", 295 ret->thread, tmp.thread); 296 abort(); 297 } 298#endif 299 if (--(ret->references) <= 0) 300 { 301 ret->next = NULL; 302 if (next != NULL) 303 next->references--; 304 OPENSSL_free(ret); 305 } 306 } 307 } 308 return(ret); 309 } 310 311int CRYPTO_push_info_(const char *info, const char *file, int line) 312 { 313 APP_INFO *ami, *amim; 314 int ret=0; 315 316 if (is_MemCheck_on()) 317 { 318 MemCheck_off(); /* obtain MALLOC2 lock */ 319 320 if ((ami = (APP_INFO *)OPENSSL_malloc(sizeof(APP_INFO))) == NULL) 321 { 322 ret=0; 323 goto err; 324 } 325 if (amih == NULL) 326 { 327 if ((amih=lh_new(app_info_hash, app_info_cmp)) == NULL) 328 { 329 OPENSSL_free(ami); 330 ret=0; 331 goto err; 332 } 333 } 334 335 ami->thread=CRYPTO_thread_id(); 336 ami->file=file; 337 ami->line=line; 338 ami->info=info; 339 ami->references=1; 340 ami->next=NULL; 341 342 if ((amim=(APP_INFO *)lh_insert(amih,(char *)ami)) != NULL) 343 { 344#ifdef LEVITTE_DEBUG_MEM 345 if (ami->thread != amim->thread) 346 { 347 fprintf(stderr, "CRYPTO_push_info(): previous info has other thread ID (%lu) than the current thread (%lu)!!!!\n", 348 amim->thread, ami->thread); 349 abort(); 350 } 351#endif 352 ami->next=amim; 353 } 354 err: 355 MemCheck_on(); /* release MALLOC2 lock */ 356 } 357 358 return(ret); 359 } 360 361int CRYPTO_pop_info(void) 362 { 363 int ret=0; 364 365 if (is_MemCheck_on()) /* _must_ be true, or something went severely wrong */ 366 { 367 MemCheck_off(); /* obtain MALLOC2 lock */ 368 369 ret=(pop_info() != NULL); 370 371 MemCheck_on(); /* release MALLOC2 lock */ 372 } 373 return(ret); 374 } 375 376int CRYPTO_remove_all_info(void) 377 { 378 int ret=0; 379 380 if (is_MemCheck_on()) /* _must_ be true */ 381 { 382 MemCheck_off(); /* obtain MALLOC2 lock */ 383 384 while(pop_info() != NULL) 385 ret++; 386 387 MemCheck_on(); /* release MALLOC2 lock */ 388 } 389 return(ret); 390 } 391 392 393static unsigned long break_order_num=0; 394void CRYPTO_dbg_malloc(void *addr, int num, const char *file, int line, 395 int before_p) 396 { 397 MEM *m,*mm; 398 APP_INFO tmp,*amim; 399 400 switch(before_p & 127) 401 { 402 case 0: 403 break; 404 case 1: 405 if (addr == NULL) 406 break; 407 408 if (is_MemCheck_on()) 409 { 410 MemCheck_off(); /* make sure we hold MALLOC2 lock */ 411 if ((m=(MEM *)OPENSSL_malloc(sizeof(MEM))) == NULL) 412 { 413 OPENSSL_free(addr); 414 MemCheck_on(); /* release MALLOC2 lock 415 * if num_disabled drops to 0 */ 416 return; 417 } 418 if (mh == NULL) 419 { 420 if ((mh=lh_new(mem_hash, mem_cmp)) == NULL) 421 { 422 OPENSSL_free(addr); 423 OPENSSL_free(m); 424 addr=NULL; 425 goto err; 426 } 427 } 428 429 m->addr=addr; 430 m->file=file; 431 m->line=line; 432 m->num=num; 433 if (options & V_CRYPTO_MDEBUG_THREAD) 434 m->thread=CRYPTO_thread_id(); 435 else 436 m->thread=0; 437 438 if (order == break_order_num) 439 { 440 /* BREAK HERE */ 441 m->order=order; 442 } 443 m->order=order++; 444#ifdef LEVITTE_DEBUG_MEM 445 fprintf(stderr, "LEVITTE_DEBUG_MEM: [%5d] %c 0x%p (%d)\n", 446 m->order, 447 (before_p & 128) ? '*' : '+', 448 m->addr, m->num); 449#endif 450 if (options & V_CRYPTO_MDEBUG_TIME) 451 m->time=time(NULL); 452 else 453 m->time=0; 454 455 tmp.thread=CRYPTO_thread_id(); 456 m->app_info=NULL; 457 if (amih != NULL 458 && (amim=(APP_INFO *)lh_retrieve(amih,(char *)&tmp)) != NULL) 459 { 460 m->app_info = amim; 461 amim->references++; 462 } 463 464 if ((mm=(MEM *)lh_insert(mh,(char *)m)) != NULL) 465 { 466 /* Not good, but don't sweat it */ 467 if (mm->app_info != NULL) 468 { 469 mm->app_info->references--; 470 } 471 OPENSSL_free(mm); 472 } 473 err: 474 MemCheck_on(); /* release MALLOC2 lock 475 * if num_disabled drops to 0 */ 476 } 477 break; 478 } 479 return; 480 } 481 482void CRYPTO_dbg_free(void *addr, int before_p) 483 { 484 MEM m,*mp; 485 486 switch(before_p) 487 { 488 case 0: 489 if (addr == NULL) 490 break; 491 492 if (is_MemCheck_on() && (mh != NULL)) 493 { 494 MemCheck_off(); /* make sure we hold MALLOC2 lock */ 495 496 m.addr=addr; 497 mp=(MEM *)lh_delete(mh,(char *)&m); 498 if (mp != NULL) 499 { 500#ifdef LEVITTE_DEBUG_MEM 501 fprintf(stderr, "LEVITTE_DEBUG_MEM: [%5d] - 0x%p (%d)\n", 502 mp->order, mp->addr, mp->num); 503#endif 504 if (mp->app_info != NULL) 505 { 506 mp->app_info->references--; 507 } 508 OPENSSL_free(mp); 509 } 510 511 MemCheck_on(); /* release MALLOC2 lock 512 * if num_disabled drops to 0 */ 513 } 514 break; 515 case 1: 516 break; 517 } 518 } 519 520void CRYPTO_dbg_realloc(void *addr1, void *addr2, int num, 521 const char *file, int line, int before_p) 522 { 523 MEM m,*mp; 524 525#ifdef LEVITTE_DEBUG_MEM 526 fprintf(stderr, "LEVITTE_DEBUG_MEM: --> CRYPTO_dbg_malloc(addr1 = %p, addr2 = %p, num = %d, file = \"%s\", line = %d, before_p = %d)\n", 527 addr1, addr2, num, file, line, before_p); 528#endif 529 530 switch(before_p) 531 { 532 case 0: 533 break; 534 case 1: 535 if (addr2 == NULL) 536 break; 537 538 if (addr1 == NULL) 539 { 540 CRYPTO_dbg_malloc(addr2, num, file, line, 128 | before_p); 541 break; 542 } 543 544 if (is_MemCheck_on()) 545 { 546 MemCheck_off(); /* make sure we hold MALLOC2 lock */ 547 548 m.addr=addr1; 549 mp=(MEM *)lh_delete(mh,(char *)&m); 550 if (mp != NULL) 551 { 552#ifdef LEVITTE_DEBUG_MEM 553 fprintf(stderr, "LEVITTE_DEBUG_MEM: [%5d] * 0x%p (%d) -> 0x%p (%d)\n", 554 mp->order, 555 mp->addr, mp->num, 556 addr2, num); 557#endif 558 mp->addr=addr2; 559 mp->num=num; 560 lh_insert(mh,(char *)mp); 561 } 562 563 MemCheck_on(); /* release MALLOC2 lock 564 * if num_disabled drops to 0 */ 565 } 566 break; 567 } 568 return; 569 } 570 571 572typedef struct mem_leak_st 573 { 574 BIO *bio; 575 int chunks; 576 long bytes; 577 } MEM_LEAK; 578 579static void print_leak(const MEM *m, MEM_LEAK *l) 580 { 581 char buf[1024]; 582 char *bufp = buf; 583 APP_INFO *amip; 584 int ami_cnt; 585 struct tm *lcl = NULL; 586 unsigned long ti; 587 588#define BUF_REMAIN (sizeof buf - (size_t)(bufp - buf)) 589 590 if(m->addr == (char *)l->bio) 591 return; 592 593 if (options & V_CRYPTO_MDEBUG_TIME) 594 { 595 lcl = localtime(&m->time); 596 597 snprintf(bufp, BUF_REMAIN, "[%02d:%02d:%02d] ", 598 lcl->tm_hour,lcl->tm_min,lcl->tm_sec); 599 bufp += strlen(bufp); 600 } 601 602 snprintf(bufp, BUF_REMAIN, "%5lu file=%s, line=%d, ", 603 m->order,m->file,m->line); 604 bufp += strlen(bufp); 605 606 if (options & V_CRYPTO_MDEBUG_THREAD) 607 { 608 snprintf(bufp, BUF_REMAIN, "thread=%lu, ", m->thread); 609 bufp += strlen(bufp); 610 } 611 612 snprintf(bufp, BUF_REMAIN, "number=%d, address=%08lX\n", 613 m->num,(unsigned long)m->addr); 614 bufp += strlen(bufp); 615 616 BIO_puts(l->bio,buf); 617 618 l->chunks++; 619 l->bytes+=m->num; 620 621 amip=m->app_info; 622 ami_cnt=0; 623 if (!amip) 624 return; 625 ti=amip->thread; 626 627 do 628 { 629 int buf_len; 630 int info_len; 631 632 ami_cnt++; 633 memset(buf,'>',ami_cnt); 634 snprintf(buf + ami_cnt, sizeof buf - ami_cnt, 635 " thread=%lu, file=%s, line=%d, info=\"", 636 amip->thread, amip->file, amip->line); 637 buf_len=strlen(buf); 638 info_len=strlen(amip->info); 639 if (128 - buf_len - 3 < info_len) 640 { 641 memcpy(buf + buf_len, amip->info, 128 - buf_len - 3); 642 buf_len = 128 - 3; 643 } 644 else 645 { 646 strlcpy(buf + buf_len, amip->info, 647 sizeof buf - buf_len); 648 buf_len = strlen(buf); 649 } 650 snprintf(buf + buf_len, sizeof buf - buf_len, "\"\n"); 651 652 BIO_puts(l->bio,buf); 653 654 amip = amip->next; 655 } 656 while(amip && amip->thread == ti); 657 658#ifdef LEVITTE_DEBUG_MEM 659 if (amip) 660 { 661 fprintf(stderr, "Thread switch detected in backtrace!!!!\n"); 662 abort(); 663 } 664#endif 665 } 666 667static IMPLEMENT_LHASH_DOALL_ARG_FN(print_leak, const MEM *, MEM_LEAK *) 668 669void CRYPTO_mem_leaks(BIO *b) 670 { 671 MEM_LEAK ml; 672 char buf[80]; 673 674 if (mh == NULL && amih == NULL) 675 return; 676 677 MemCheck_off(); /* obtain MALLOC2 lock */ 678 679 ml.bio=b; 680 ml.bytes=0; 681 ml.chunks=0; 682 if (mh != NULL) 683 lh_doall_arg(mh, LHASH_DOALL_ARG_FN(print_leak), 684 (char *)&ml); 685 if (ml.chunks != 0) 686 { 687 snprintf(buf,sizeof buf,"%ld bytes leaked in %d chunks\n", 688 ml.bytes,ml.chunks); 689 BIO_puts(b,buf); 690 } 691 else 692 { 693 /* Make sure that, if we found no leaks, memory-leak debugging itself 694 * does not introduce memory leaks (which might irritate 695 * external debugging tools). 696 * (When someone enables leak checking, but does not call 697 * this function, we declare it to be their fault.) 698 * 699 * XXX This should be in CRYPTO_mem_leaks_cb, 700 * and CRYPTO_mem_leaks should be implemented by 701 * using CRYPTO_mem_leaks_cb. 702 * (Also their should be a variant of lh_doall_arg 703 * that takes a function pointer instead of a void *; 704 * this would obviate the ugly and illegal 705 * void_fn_to_char kludge in CRYPTO_mem_leaks_cb. 706 * Otherwise the code police will come and get us.) 707 */ 708 int old_mh_mode; 709 710 CRYPTO_w_lock(CRYPTO_LOCK_MALLOC); 711 712 /* avoid deadlock when lh_free() uses CRYPTO_dbg_free(), 713 * which uses CRYPTO_is_mem_check_on */ 714 old_mh_mode = mh_mode; 715 mh_mode = CRYPTO_MEM_CHECK_OFF; 716 717 if (mh != NULL) 718 { 719 lh_free(mh); 720 mh = NULL; 721 } 722 if (amih != NULL) 723 { 724 if (lh_num_items(amih) == 0) 725 { 726 lh_free(amih); 727 amih = NULL; 728 } 729 } 730 731 mh_mode = old_mh_mode; 732 CRYPTO_w_unlock(CRYPTO_LOCK_MALLOC); 733 } 734 MemCheck_on(); /* release MALLOC2 lock */ 735 } 736 737#ifndef OPENSSL_NO_FP_API 738void CRYPTO_mem_leaks_fp(FILE *fp) 739 { 740 BIO *b; 741 742 if (mh == NULL) return; 743 /* Need to turn off memory checking when allocated BIOs ... especially 744 * as we're creating them at a time when we're trying to check we've not 745 * left anything un-free()'d!! */ 746 MemCheck_off(); 747 b = BIO_new(BIO_s_file()); 748 MemCheck_on(); 749 if(!b) return; 750 BIO_set_fp(b,fp,BIO_NOCLOSE); 751 CRYPTO_mem_leaks(b); 752 BIO_free(b); 753 } 754#endif 755 756 757 758/* FIXME: We really don't allow much to the callback. For example, it has 759 no chance of reaching the info stack for the item it processes. Should 760 it really be this way? -- Richard Levitte */ 761/* NB: The prototypes have been typedef'd to CRYPTO_MEM_LEAK_CB inside crypto.h 762 * If this code is restructured, remove the callback type if it is no longer 763 * needed. -- Geoff Thorpe */ 764static void cb_leak(const MEM *m, CRYPTO_MEM_LEAK_CB **cb) 765 { 766 (**cb)(m->order,m->file,m->line,m->num,m->addr); 767 } 768 769static IMPLEMENT_LHASH_DOALL_ARG_FN(cb_leak, const MEM *, CRYPTO_MEM_LEAK_CB **) 770 771void CRYPTO_mem_leaks_cb(CRYPTO_MEM_LEAK_CB *cb) 772 { 773 if (mh == NULL) return; 774 CRYPTO_w_lock(CRYPTO_LOCK_MALLOC2); 775 lh_doall_arg(mh, LHASH_DOALL_ARG_FN(cb_leak), &cb); 776 CRYPTO_w_unlock(CRYPTO_LOCK_MALLOC2); 777 } 778