mem_dbg.c 22.5 KB
Newer Older
1
/* crypto/mem_dbg.c */
R
Richard Levitte 已提交
2 3
/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
 * All rights reserved.
4
 *
R
Richard Levitte 已提交
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
 * This package is an SSL implementation written
 * by Eric Young (eay@cryptsoft.com).
 * The implementation was written so as to conform with Netscapes SSL.
 * 
 * This library is free for commercial and non-commercial use as long as
 * the following conditions are aheared to.  The following conditions
 * apply to all code found in this distribution, be it the RC4, RSA,
 * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
 * included with this distribution is covered by the same copyright terms
 * except that the holder is Tim Hudson (tjh@cryptsoft.com).
 * 
 * Copyright remains Eric Young's, and as such any Copyright notices in
 * the code are not to be removed.
 * If this package is used in a product, Eric Young should be given attribution
 * as the author of the parts of the library used.
 * This can be in the form of a textual message at program startup or
 * in documentation (online or textual) provided with the package.
 * 
23 24 25
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
R
Richard Levitte 已提交
26 27
 * 1. Redistributions of source code must retain the copyright
 *    notice, this list of conditions and the following disclaimer.
28
 * 2. Redistributions in binary form must reproduce the above copyright
R
Richard Levitte 已提交
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *    "This product includes cryptographic software written by
 *     Eric Young (eay@cryptsoft.com)"
 *    The word 'cryptographic' can be left out if the rouines from the library
 *    being used are not cryptographic related :-).
 * 4. If you include any Windows specific code (or a derivative thereof) from 
 *    the apps directory (application code) you must include an acknowledgement:
 *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
 * 
 * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * 
 * The licence and distribution terms for any publically available version or
 * derivative of this code cannot be changed.  i.e. this code cannot simply be
 * copied and put under another distribution licence
 * [including the GNU Public Licence.]
57
 */
58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
/* ====================================================================
 * Copyright (c) 1998-2006 The OpenSSL Project.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer. 
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. All advertising materials mentioning features or use of this
 *    software must display the following acknowledgment:
 *    "This product includes software developed by the OpenSSL Project
 *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
 *
 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
 *    endorse or promote products derived from this software without
 *    prior written permission. For written permission, please contact
 *    openssl-core@openssl.org.
 *
 * 5. Products derived from this software may not be called "OpenSSL"
 *    nor may "OpenSSL" appear in their names without prior written
 *    permission of the OpenSSL Project.
 *
 * 6. Redistributions of any form whatsoever must retain the following
 *    acknowledgment:
 *    "This product includes software developed by the OpenSSL Project
 *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
 *
 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 * ====================================================================
 *
 * This product includes cryptographic software written by Eric Young
 * (eay@cryptsoft.com).  This product includes software written by Tim
 * Hudson (tjh@cryptsoft.com).
 *
 */
111 112 113 114

#include <stdio.h>
#include <stdlib.h>
#include <time.h>	
115
#include "cryptlib.h"
116 117 118 119 120
#include <openssl/crypto.h>
#include <openssl/buffer.h>
#include <openssl/bio.h>
#include <openssl/lhash.h>

121 122 123 124 125 126
static int mh_mode=CRYPTO_MEM_CHECK_OFF;
/* The state changes to CRYPTO_MEM_CHECK_ON | CRYPTO_MEM_CHECK_ENABLE
 * when the application asks for it (usually after library initialisation
 * for which no book-keeping is desired).
 *
 * State CRYPTO_MEM_CHECK_ON exists only temporarily when the library
127 128 129 130 131 132 133 134 135
 * thinks that certain allocations should not be checked (e.g. the data
 * structures used for memory checking).  It is not suitable as an initial
 * state: the library will unexpectedly enable memory checking when it
 * executes one of those sections that want to disable checking
 * temporarily.
 *
 * State CRYPTO_MEM_CHECK_ENABLE without ..._ON makes no sense whatsoever.
 */

136
static unsigned long order = 0; /* number of memory requests */
137 138
static LHASH *mh=NULL; /* hash-table of memory requests (address as key);
                        * access requires MALLOC2 lock */
139 140 141


typedef struct app_mem_info_st
142 143 144
/* For application-defined information (static C-string `info')
 * to be displayed in memory leak list.
 * Each thread has its own stack.  For applications, there is
B
Rename  
Bodo Möller 已提交
145 146 147
 *   CRYPTO_push_info("...")     to push an entry,
 *   CRYPTO_pop_info()           to pop an entry,
 *   CRYPTO_remove_all_info()    to pop all entries.
148
 */
149 150
	{
	CRYPTO_THREADID threadid;
151 152 153
	const char *file;
	int line;
	const char *info;
154
	struct app_mem_info_st *next; /* tail of thread's stack */
155 156 157
	int references;
	} APP_INFO;

158 159
static void app_info_free(APP_INFO *);

160 161
static LHASH *amih=NULL; /* hash-table with those app_mem_info_st's
                          * that are at the top of their thread's stack
162 163
                          * (with `thread' as key);
                          * access requires MALLOC2 lock */
164 165

typedef struct mem_st
166
/* memory-block description */
167
	{
168
	void *addr;
169 170 171
	int num;
	const char *file;
	int line;
172
	CRYPTO_THREADID threadid;
173 174 175 176 177
	unsigned long order;
	time_t time;
	APP_INFO *app_info;
	} MEM;

178 179 180
static long options =             /* extra information to be recorded */
#if defined(CRYPTO_MDEBUG_TIME) || defined(CRYPTO_MDEBUG_ALL)
	V_CRYPTO_MDEBUG_TIME |
181
#endif
182 183
#if defined(CRYPTO_MDEBUG_THREAD) || defined(CRYPTO_MDEBUG_ALL)
	V_CRYPTO_MDEBUG_THREAD |
184
#endif
185
	0;
186

187

188 189 190 191
static unsigned int num_disable = 0; /* num_disable > 0
                                      *     iff
                                      * mh_mode == CRYPTO_MEM_CHECK_ON (w/o ..._ENABLE)
                                      */
192

193 194 195
/* Valid iff num_disable > 0.  CRYPTO_LOCK_MALLOC2 is locked exactly in this
 * case (by the thread named in disabling_threadid). */
static CRYPTO_THREADID disabling_threadid;
196

197 198 199 200 201 202 203 204 205 206 207 208
static void app_info_free(APP_INFO *inf)
	{
	if (--(inf->references) <= 0)
		{
		if (inf->next != NULL)
			{
			app_info_free(inf->next);
			}
		OPENSSL_free(inf);
		}
	}

209 210 211 212 213 214 215
int CRYPTO_mem_ctrl(int mode)
	{
	int ret=mh_mode;

	CRYPTO_w_lock(CRYPTO_LOCK_MALLOC);
	switch (mode)
		{
216 217
	/* for applications (not to be called while multiple threads
	 * use the library): */
218 219
	case CRYPTO_MEM_CHECK_ON: /* aka MemCheck_start() */
		mh_mode = CRYPTO_MEM_CHECK_ON|CRYPTO_MEM_CHECK_ENABLE;
220
		num_disable = 0;
221 222 223
		break;
	case CRYPTO_MEM_CHECK_OFF: /* aka MemCheck_stop() */
		mh_mode = 0;
224 225
		num_disable = 0; /* should be true *before* MemCheck_stop is used,
		                    or there'll be a lot of confusion */
226 227 228 229 230 231
		break;

	/* switch off temporarily (for library-internal use): */
	case CRYPTO_MEM_CHECK_DISABLE: /* aka MemCheck_off() */
		if (mh_mode & CRYPTO_MEM_CHECK_ON)
			{
232 233 234 235
			CRYPTO_THREADID tid;
			CRYPTO_THREADID_set(&tid);
			if (!num_disable || CRYPTO_THREADID_cmp(&tid,
						&disabling_threadid))
236 237 238
				{
				/* Long-time lock CRYPTO_LOCK_MALLOC2 must not be claimed while
				 * we're holding CRYPTO_LOCK_MALLOC, or we'll deadlock if
239 240
				 * somebody else holds CRYPTO_LOCK_MALLOC2 (and cannot release
				 * it because we block entry to this function).
241 242 243 244 245 246 247 248 249 250 251
				 * Give them a chance, first, and then claim the locks in
				 * appropriate order (long-time lock first).
				 */
				CRYPTO_w_unlock(CRYPTO_LOCK_MALLOC);
				/* Note that after we have waited for CRYPTO_LOCK_MALLOC2
				 * and CRYPTO_LOCK_MALLOC, we'll still be in the right
				 * "case" and "if" branch because MemCheck_start and
				 * MemCheck_stop may never be used while there are multiple
				 * OpenSSL threads. */
				CRYPTO_w_lock(CRYPTO_LOCK_MALLOC2);
				CRYPTO_w_lock(CRYPTO_LOCK_MALLOC);
252
				mh_mode &= ~CRYPTO_MEM_CHECK_ENABLE;
253
				CRYPTO_THREADID_set(&disabling_threadid);
254
				}
255
			num_disable++;
256 257 258 259 260
			}
		break;
	case CRYPTO_MEM_CHECK_ENABLE: /* aka MemCheck_on() */
		if (mh_mode & CRYPTO_MEM_CHECK_ON)
			{
261
			if (num_disable) /* always true, or something is going wrong */
262
				{
263 264 265 266 267 268
				num_disable--;
				if (num_disable == 0)
					{
					mh_mode|=CRYPTO_MEM_CHECK_ENABLE;
					CRYPTO_w_unlock(CRYPTO_LOCK_MALLOC2);
					}
269 270 271 272 273 274 275 276 277 278 279
				}
			}
		break;

	default:
		break;
		}
	CRYPTO_w_unlock(CRYPTO_LOCK_MALLOC);
	return(ret);
	}

280
int CRYPTO_is_mem_check_on(void)
281 282 283 284 285
	{
	int ret = 0;

	if (mh_mode & CRYPTO_MEM_CHECK_ON)
		{
286 287
		CRYPTO_THREADID tid;
		CRYPTO_THREADID_set(&tid);
288
		CRYPTO_r_lock(CRYPTO_LOCK_MALLOC);
289

290 291
		ret = (mh_mode & CRYPTO_MEM_CHECK_ENABLE) ||
			CRYPTO_THREADID_cmp(&tid, &disabling_threadid);
292

293
		CRYPTO_r_unlock(CRYPTO_LOCK_MALLOC);
294 295 296 297 298
		}
	return(ret);
	}	


299
void CRYPTO_dbg_set_options(long bits)
300 301 302 303
	{
	options = bits;
	}

304
long CRYPTO_dbg_get_options(void)
305 306 307 308
	{
	return options;
	}

309
/* static int mem_cmp(MEM *a, MEM *b) */
310
static int mem_cmp(const void *a_void, const void *b_void)
311
	{
312 313 314 315 316 317 318
#ifdef _WIN64
	const char *a=(const char *)((const MEM *)a_void)->addr,
		   *b=(const char *)((const MEM *)b_void)->addr;
	if (a==b)	return 0;
	else if (a>b)	return 1;
	else		return -1;
#else
B
Ben Laurie 已提交
319 320
	return((const char *)((const MEM *)a_void)->addr
		- (const char *)((const MEM *)b_void)->addr);
321
#endif
322 323
	}

324
/* static unsigned long mem_hash(MEM *a) */
325
static unsigned long mem_hash(const void *a_void)
326 327 328
	{
	unsigned long ret;

329
	ret=(unsigned long)((const MEM *)a_void)->addr;
330 331 332 333 334

	ret=ret*17851+(ret>>14)*7+(ret>>4)*251;
	return(ret);
	}

335
/* static int app_info_cmp(APP_INFO *a, APP_INFO *b) */
336
static int app_info_cmp(const void *a_void, const void *b_void)
337
	{
338 339
	return CRYPTO_THREADID_cmp(&((const APP_INFO *)a_void)->threadid,
				&((const APP_INFO *)b_void)->threadid);
340 341
	}

342
/* static unsigned long app_info_hash(APP_INFO *a) */
343
static unsigned long app_info_hash(const void *a_void)
344 345
	{
	unsigned long ret;
346
	ret = CRYPTO_THREADID_hash(&((const APP_INFO *)a_void)->threadid);
347 348 349 350
	ret=ret*17851+(ret>>14)*7+(ret>>4)*251;
	return(ret);
	}

U
Ulf Möller 已提交
351
static APP_INFO *pop_info(void)
352 353 354 355 356 357
	{
	APP_INFO tmp;
	APP_INFO *ret = NULL;

	if (amih != NULL)
		{
358
		CRYPTO_THREADID_set(&tmp.threadid);
359
		if ((ret=(APP_INFO *)lh_delete(amih,&tmp)) != NULL)
360 361 362 363 364 365 366 367
			{
			APP_INFO *next=ret->next;

			if (next != NULL)
				{
				next->references++;
				lh_insert(amih,(char *)next);
				}
368
#ifdef LEVITTE_DEBUG_MEM
369
			if (CRYPTO_THREADID_cmp(&ret->threadid, &tmp.threadid))
370
				{
371 372 373
				fprintf(stderr, "pop_info(): deleted info has other thread ID (%lu) than the current thread (%lu)!!!!\n",
					CRYPTO_THREADID_hash(&ret->threadid),
					CRYPTO_THREADID_hash(&tmp.threadid));
374 375 376 377 378 379 380 381
				abort();
				}
#endif
			if (--(ret->references) <= 0)
				{
				ret->next = NULL;
				if (next != NULL)
					next->references--;
382
				OPENSSL_free(ret);
383 384 385 386 387 388
				}
			}
		}
	return(ret);
	}

B
Rename  
Bodo Möller 已提交
389
int CRYPTO_push_info_(const char *info, const char *file, int line)
390 391 392 393 394 395
	{
	APP_INFO *ami, *amim;
	int ret=0;

	if (is_MemCheck_on())
		{
396
		MemCheck_off(); /* obtain MALLOC2 lock */
397

398
		if ((ami = (APP_INFO *)OPENSSL_malloc(sizeof(APP_INFO))) == NULL)
399 400 401 402 403 404
			{
			ret=0;
			goto err;
			}
		if (amih == NULL)
			{
405
			if ((amih=lh_new(app_info_hash, app_info_cmp)) == NULL)
406
				{
407
				OPENSSL_free(ami);
408 409 410 411 412
				ret=0;
				goto err;
				}
			}

413
		CRYPTO_THREADID_set(&ami->threadid);
414 415 416 417 418 419 420 421
		ami->file=file;
		ami->line=line;
		ami->info=info;
		ami->references=1;
		ami->next=NULL;

		if ((amim=(APP_INFO *)lh_insert(amih,(char *)ami)) != NULL)
			{
422
#ifdef LEVITTE_DEBUG_MEM
423
			if (CRYPTO_THREADID_cmp(&ami->threadid, &amim->threadid))
424
				{
425 426 427
				fprintf(stderr, "CRYPTO_push_info(): previous info has other thread ID (%lu) than the current thread (%lu)!!!!\n",
					CRYPTO_THREADID_hash(&amim->threadid),
					CRYPTO_THREADID_hash(&ami->threadid));
428 429 430 431 432 433
				abort();
				}
#endif
			ami->next=amim;
			}
 err:
434
		MemCheck_on(); /* release MALLOC2 lock */
435 436 437 438 439
		}

	return(ret);
	}

B
Rename  
Bodo Möller 已提交
440
int CRYPTO_pop_info(void)
441 442 443
	{
	int ret=0;

444
	if (is_MemCheck_on()) /* _must_ be true, or something went severely wrong */
445
		{
446
		MemCheck_off(); /* obtain MALLOC2 lock */
447

B
Rename  
Bodo Möller 已提交
448
		ret=(pop_info() != NULL);
449

450
		MemCheck_on(); /* release MALLOC2 lock */
451 452 453 454 455 456 457 458
		}
	return(ret);
	}

int CRYPTO_remove_all_info(void)
	{
	int ret=0;

459
	if (is_MemCheck_on()) /* _must_ be true */
460
		{
461
		MemCheck_off(); /* obtain MALLOC2 lock */
462

B
Rename  
Bodo Möller 已提交
463
		while(pop_info() != NULL)
464 465
			ret++;

466
		MemCheck_on(); /* release MALLOC2 lock */
467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488
		}
	return(ret);
	}


static unsigned long break_order_num=0;
void CRYPTO_dbg_malloc(void *addr, int num, const char *file, int line,
	int before_p)
	{
	MEM *m,*mm;
	APP_INFO tmp,*amim;

	switch(before_p & 127)
		{
	case 0:
		break;
	case 1:
		if (addr == NULL)
			break;

		if (is_MemCheck_on())
			{
489
			MemCheck_off(); /* make sure we hold MALLOC2 lock */
490
			if ((m=(MEM *)OPENSSL_malloc(sizeof(MEM))) == NULL)
491
				{
492
				OPENSSL_free(addr);
493 494
				MemCheck_on(); /* release MALLOC2 lock
				                * if num_disabled drops to 0 */
495 496 497 498
				return;
				}
			if (mh == NULL)
				{
499
				if ((mh=lh_new(mem_hash, mem_cmp)) == NULL)
500
					{
501 502
					OPENSSL_free(addr);
					OPENSSL_free(m);
503 504 505 506 507 508 509 510 511
					addr=NULL;
					goto err;
					}
				}

			m->addr=addr;
			m->file=file;
			m->line=line;
			m->num=num;
512
			CRYPTO_THREADID_set(&m->threadid);
513 514 515 516 517 518 519

			if (order == break_order_num)
				{
				/* BREAK HERE */
				m->order=order;
				}
			m->order=order++;
520
#ifdef LEVITTE_DEBUG_MEM
521
			fprintf(stderr, "LEVITTE_DEBUG_MEM: [%5ld] %c 0x%p (%d)\n",
522 523 524 525 526 527 528 529 530
				m->order,
				(before_p & 128) ? '*' : '+',
				m->addr, m->num);
#endif
			if (options & V_CRYPTO_MDEBUG_TIME)
				m->time=time(NULL);
			else
				m->time=0;

531
			CRYPTO_THREADID_set(&m->threadid);
532 533 534 535 536 537 538 539 540 541 542 543 544 545 546
			m->app_info=NULL;
			if (amih != NULL
				&& (amim=(APP_INFO *)lh_retrieve(amih,(char *)&tmp)) != NULL)
				{
				m->app_info = amim;
				amim->references++;
				}

			if ((mm=(MEM *)lh_insert(mh,(char *)m)) != NULL)
				{
				/* Not good, but don't sweat it */
				if (mm->app_info != NULL)
					{
					mm->app_info->references--;
					}
547
				OPENSSL_free(mm);
548 549
				}
		err:
550 551
			MemCheck_on(); /* release MALLOC2 lock
			                * if num_disabled drops to 0 */
552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569
			}
		break;
		}
	return;
	}

void CRYPTO_dbg_free(void *addr, int before_p)
	{
	MEM m,*mp;

	switch(before_p)
		{
	case 0:
		if (addr == NULL)
			break;

		if (is_MemCheck_on() && (mh != NULL))
			{
570
			MemCheck_off(); /* make sure we hold MALLOC2 lock */
571 572 573 574 575

			m.addr=addr;
			mp=(MEM *)lh_delete(mh,(char *)&m);
			if (mp != NULL)
				{
576
#ifdef LEVITTE_DEBUG_MEM
577
			fprintf(stderr, "LEVITTE_DEBUG_MEM: [%5ld] - 0x%p (%d)\n",
578 579 580
				mp->order, mp->addr, mp->num);
#endif
				if (mp->app_info != NULL)
581
					app_info_free(mp->app_info);
582
				OPENSSL_free(mp);
583 584
				}

585 586
			MemCheck_on(); /* release MALLOC2 lock
			                * if num_disabled drops to 0 */
587 588 589 590 591 592 593 594 595 596 597 598
			}
		break;
	case 1:
		break;
		}
	}

void CRYPTO_dbg_realloc(void *addr1, void *addr2, int num,
	const char *file, int line, int before_p)
	{
	MEM m,*mp;

599 600
#ifdef LEVITTE_DEBUG_MEM
	fprintf(stderr, "LEVITTE_DEBUG_MEM: --> CRYPTO_dbg_malloc(addr1 = %p, addr2 = %p, num = %d, file = \"%s\", line = %d, before_p = %d)\n",
601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619
		addr1, addr2, num, file, line, before_p);
#endif

	switch(before_p)
		{
	case 0:
		break;
	case 1:
		if (addr2 == NULL)
			break;

		if (addr1 == NULL)
			{
			CRYPTO_dbg_malloc(addr2, num, file, line, 128 | before_p);
			break;
			}

		if (is_MemCheck_on())
			{
620
			MemCheck_off(); /* make sure we hold MALLOC2 lock */
621 622 623 624 625

			m.addr=addr1;
			mp=(MEM *)lh_delete(mh,(char *)&m);
			if (mp != NULL)
				{
626
#ifdef LEVITTE_DEBUG_MEM
627
				fprintf(stderr, "LEVITTE_DEBUG_MEM: [%5ld] * 0x%p (%d) -> 0x%p (%d)\n",
628 629 630 631 632 633 634 635 636
					mp->order,
					mp->addr, mp->num,
					addr2, num);
#endif
				mp->addr=addr2;
				mp->num=num;
				lh_insert(mh,(char *)mp);
				}

637 638
			MemCheck_on(); /* release MALLOC2 lock
			                * if num_disabled drops to 0 */
639 640 641 642 643 644 645 646 647 648 649 650 651 652
			}
		break;
		}
	return;
	}


typedef struct mem_leak_st
	{
	BIO *bio;
	int chunks;
	long bytes;
	} MEM_LEAK;

B
Ben Laurie 已提交
653
static void print_leak(const MEM *m, MEM_LEAK *l)
654 655 656 657 658 659
	{
	char buf[1024];
	char *bufp = buf;
	APP_INFO *amip;
	int ami_cnt;
	struct tm *lcl = NULL;
660
	CRYPTO_THREADID tid;
661

662 663
#define BUF_REMAIN (sizeof buf - (size_t)(bufp - buf))

664 665 666 667 668 669 670
	if(m->addr == (char *)l->bio)
	    return;

	if (options & V_CRYPTO_MDEBUG_TIME)
		{
		lcl = localtime(&m->time);
	
671
		BIO_snprintf(bufp, BUF_REMAIN, "[%02d:%02d:%02d] ",
672 673 674 675
			lcl->tm_hour,lcl->tm_min,lcl->tm_sec);
		bufp += strlen(bufp);
		}

676
	BIO_snprintf(bufp, BUF_REMAIN, "%5lu file=%s, line=%d, ",
677 678 679 680 681
		m->order,m->file,m->line);
	bufp += strlen(bufp);

	if (options & V_CRYPTO_MDEBUG_THREAD)
		{
682 683
		BIO_snprintf(bufp, BUF_REMAIN, "thread=%lu, ",
			CRYPTO_THREADID_hash(&m->threadid));
684 685 686
		bufp += strlen(bufp);
		}

687
	BIO_snprintf(bufp, BUF_REMAIN, "number=%d, address=%08lX\n",
688 689 690 691 692 693 694 695 696 697
		m->num,(unsigned long)m->addr);
	bufp += strlen(bufp);

	BIO_puts(l->bio,buf);
	
	l->chunks++;
	l->bytes+=m->num;

	amip=m->app_info;
	ami_cnt=0;
698 699
	if (!amip)
		return;
700
	CRYPTO_THREADID_set(&tid);
701 702
	
	do
703 704 705 706 707 708
		{
		int buf_len;
		int info_len;

		ami_cnt++;
		memset(buf,'>',ami_cnt);
709
		BIO_snprintf(buf + ami_cnt, sizeof buf - ami_cnt,
710 711
			" thread=%lu, file=%s, line=%d, info=\"",
			CRYPTO_THREADID_hash(&amip->threadid), amip->file, amip->line);
712 713 714 715 716 717 718 719 720
		buf_len=strlen(buf);
		info_len=strlen(amip->info);
		if (128 - buf_len - 3 < info_len)
			{
			memcpy(buf + buf_len, amip->info, 128 - buf_len - 3);
			buf_len = 128 - 3;
			}
		else
			{
721 722
			BUF_strlcpy(buf + buf_len, amip->info,
				    sizeof buf - buf_len);
723 724
			buf_len = strlen(buf);
			}
725
		BIO_snprintf(buf + buf_len, sizeof buf - buf_len, "\"\n");
726 727 728 729 730
		
		BIO_puts(l->bio,buf);

		amip = amip->next;
		}
731 732
	while(amip && !CRYPTO_THREADID_cmp(&amip->threadid, &tid));

733
#ifdef LEVITTE_DEBUG_MEM
734 735
	if (amip)
		{
R
Typo...  
Richard Levitte 已提交
736
		fprintf(stderr, "Thread switch detected in backtrace!!!!\n");
737 738 739 740 741
		abort();
		}
#endif
	}

B
Ben Laurie 已提交
742
static IMPLEMENT_LHASH_DOALL_ARG_FN(print_leak, const MEM *, MEM_LEAK *)
743

744 745 746 747
void CRYPTO_mem_leaks(BIO *b)
	{
	MEM_LEAK ml;

748 749
	if (mh == NULL && amih == NULL)
		return;
750 751 752

	MemCheck_off(); /* obtain MALLOC2 lock */

753 754 755
	ml.bio=b;
	ml.bytes=0;
	ml.chunks=0;
756
	if (mh != NULL)
757
		lh_doall_arg(mh, LHASH_DOALL_ARG_FN(print_leak),
758
				(char *)&ml);
759 760
	if (ml.chunks != 0)
		{
761 762
		BIO_printf(b,"%ld bytes leaked in %d chunks\n",
			   ml.bytes,ml.chunks);
763
		}
764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780
	else
		{
		/* Make sure that, if we found no leaks, memory-leak debugging itself
		 * does not introduce memory leaks (which might irritate
		 * external debugging tools).
		 * (When someone enables leak checking, but does not call
		 * this function, we declare it to be their fault.)
		 *
		 * XXX    This should be in CRYPTO_mem_leaks_cb,
		 * and CRYPTO_mem_leaks should be implemented by
		 * using CRYPTO_mem_leaks_cb.
		 * (Also their should be a variant of lh_doall_arg
		 * that takes a function pointer instead of a void *;
		 * this would obviate the ugly and illegal
		 * void_fn_to_char kludge in CRYPTO_mem_leaks_cb.
		 * Otherwise the code police will come and get us.)
		 */
B
Bodo Möller 已提交
781 782
		int old_mh_mode;

783
		CRYPTO_w_lock(CRYPTO_LOCK_MALLOC);
B
Bodo Möller 已提交
784 785 786 787 788 789

		/* avoid deadlock when lh_free() uses CRYPTO_dbg_free(),
		 * which uses CRYPTO_is_mem_check_on */
		old_mh_mode = mh_mode;
		mh_mode = CRYPTO_MEM_CHECK_OFF;

790 791 792 793 794 795 796 797 798 799 800 801 802
		if (mh != NULL)
			{
			lh_free(mh);
			mh = NULL;
			}
		if (amih != NULL)
			{
			if (lh_num_items(amih) == 0) 
				{
				lh_free(amih);
				amih = NULL;
				}
			}
B
Bodo Möller 已提交
803 804

		mh_mode = old_mh_mode;
805 806
		CRYPTO_w_unlock(CRYPTO_LOCK_MALLOC);
		}
807
	MemCheck_on(); /* release MALLOC2 lock */
808 809
	}

810
#ifndef OPENSSL_NO_FP_API
811 812 813 814 815
void CRYPTO_mem_leaks_fp(FILE *fp)
	{
	BIO *b;

	if (mh == NULL) return;
816 817 818 819
	/* Need to turn off memory checking when allocated BIOs ... especially
	 * as we're creating them at a time when we're trying to check we've not
	 * left anything un-free()'d!! */
	MemCheck_off();
820
	b = BIO_new(BIO_s_file());
821
	MemCheck_on();
822
	if(!b) return;
823 824 825 826 827 828
	BIO_set_fp(b,fp,BIO_NOCLOSE);
	CRYPTO_mem_leaks(b);
	BIO_free(b);
	}
#endif

829 830 831 832 833


/* FIXME: We really don't allow much to the callback.  For example, it has
   no chance of reaching the info stack for the item it processes.  Should
   it really be this way?  -- Richard Levitte */
834 835 836
/* NB: The prototypes have been typedef'd to CRYPTO_MEM_LEAK_CB inside crypto.h
 * If this code is restructured, remove the callback type if it is no longer
 * needed. -- Geoff Thorpe */
B
Ben Laurie 已提交
837
static void cb_leak(const MEM *m, CRYPTO_MEM_LEAK_CB **cb)
838 839 840 841
	{
	(**cb)(m->order,m->file,m->line,m->num,m->addr);
	}

B
Ben Laurie 已提交
842
static IMPLEMENT_LHASH_DOALL_ARG_FN(cb_leak, const MEM *, CRYPTO_MEM_LEAK_CB **)
843

844
void CRYPTO_mem_leaks_cb(CRYPTO_MEM_LEAK_CB *cb)
845 846 847
	{
	if (mh == NULL) return;
	CRYPTO_w_lock(CRYPTO_LOCK_MALLOC2);
848
	lh_doall_arg(mh, LHASH_DOALL_ARG_FN(cb_leak), &cb);
849 850
	CRYPTO_w_unlock(CRYPTO_LOCK_MALLOC2);
	}