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