mem_dbg.c revision 1.2
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
86
87typedef struct app_mem_info_st
88/* For application-defined information (static C-string `info')
89 * to be displayed in memory leak list.
90 * Each thread has its own stack.  For applications, there is
91 *   CRYPTO_push_info("...")     to push an entry,
92 *   CRYPTO_pop_info()           to pop an entry,
93 *   CRYPTO_remove_all_info()    to pop all entries.
94 */
95	{
96	unsigned long thread;
97	const char *file;
98	int line;
99	const char *info;
100	struct app_mem_info_st *next; /* tail of thread's stack */
101	int references;
102	} APP_INFO;
103
104static LHASH *amih=NULL; /* hash-table with those app_mem_info_st's
105                          * that are at the top of their thread's stack
106                          * (with `thread' as key) */
107
108typedef struct mem_st
109/* memory-block description */
110	{
111	char *addr;
112	int num;
113	const char *file;
114	int line;
115	unsigned long thread;
116	unsigned long order;
117	time_t time;
118	APP_INFO *app_info;
119	} MEM;
120
121static long options =             /* extra information to be recorded */
122#if defined(CRYPTO_MDEBUG_TIME) || defined(CRYPTO_MDEBUG_ALL)
123	V_CRYPTO_MDEBUG_TIME |
124#endif
125#if defined(CRYPTO_MDEBUG_THREAD) || defined(CRYPTO_MDEBUG_ALL)
126	V_CRYPTO_MDEBUG_THREAD |
127#endif
128	0;
129
130
131static unsigned long disabling_thread = 0;
132
133int CRYPTO_mem_ctrl(int mode)
134	{
135	int ret=mh_mode;
136
137	CRYPTO_w_lock(CRYPTO_LOCK_MALLOC);
138	switch (mode)
139		{
140	/* for applications: */
141	case CRYPTO_MEM_CHECK_ON: /* aka MemCheck_start() */
142		mh_mode = CRYPTO_MEM_CHECK_ON|CRYPTO_MEM_CHECK_ENABLE;
143		disabling_thread = 0;
144		break;
145	case CRYPTO_MEM_CHECK_OFF: /* aka MemCheck_stop() */
146		mh_mode = 0;
147		disabling_thread = 0;
148		break;
149
150	/* switch off temporarily (for library-internal use): */
151	case CRYPTO_MEM_CHECK_DISABLE: /* aka MemCheck_off() */
152		if (mh_mode & CRYPTO_MEM_CHECK_ON)
153			{
154			mh_mode&= ~CRYPTO_MEM_CHECK_ENABLE;
155			if (disabling_thread != CRYPTO_thread_id()) /* otherwise we already have the MALLOC2 lock */
156				{
157				/* Long-time lock CRYPTO_LOCK_MALLOC2 must not be claimed while
158				 * we're holding CRYPTO_LOCK_MALLOC, or we'll deadlock if
159				 * somebody else holds CRYPTO_LOCK_MALLOC2 (and cannot release
160				 * it because we block entry to this function).
161				 * Give them a chance, first, and then claim the locks in
162				 * appropriate order (long-time lock first).
163				 */
164				CRYPTO_w_unlock(CRYPTO_LOCK_MALLOC);
165				/* Note that after we have waited for CRYPTO_LOCK_MALLOC2
166				 * and CRYPTO_LOCK_MALLOC, we'll still be in the right
167				 * "case" and "if" branch because MemCheck_start and
168				 * MemCheck_stop may never be used while there are multiple
169				 * OpenSSL threads. */
170				CRYPTO_w_lock(CRYPTO_LOCK_MALLOC2);
171				CRYPTO_w_lock(CRYPTO_LOCK_MALLOC);
172				disabling_thread=CRYPTO_thread_id();
173				}
174			}
175		break;
176	case CRYPTO_MEM_CHECK_ENABLE: /* aka MemCheck_on() */
177		if (mh_mode & CRYPTO_MEM_CHECK_ON)
178			{
179			mh_mode|=CRYPTO_MEM_CHECK_ENABLE;
180			if (disabling_thread != 0)
181				{
182				disabling_thread=0;
183				CRYPTO_w_unlock(CRYPTO_LOCK_MALLOC2);
184				}
185			}
186		break;
187
188	default:
189		break;
190		}
191	CRYPTO_w_unlock(CRYPTO_LOCK_MALLOC);
192	return(ret);
193	}
194
195int CRYPTO_is_mem_check_on(void)
196	{
197	int ret = 0;
198
199	if (mh_mode & CRYPTO_MEM_CHECK_ON)
200		{
201		CRYPTO_w_lock(CRYPTO_LOCK_MALLOC);
202
203		ret = (mh_mode & CRYPTO_MEM_CHECK_ENABLE)
204			&& disabling_thread != CRYPTO_thread_id();
205
206		CRYPTO_w_unlock(CRYPTO_LOCK_MALLOC);
207		}
208	return(ret);
209	}
210
211
212void CRYPTO_dbg_set_options(long bits)
213	{
214	options = bits;
215	}
216
217long CRYPTO_dbg_get_options(void)
218	{
219	return options;
220	}
221
222static int mem_cmp(MEM *a, MEM *b)
223	{
224	return(a->addr - b->addr);
225	}
226
227static unsigned long mem_hash(MEM *a)
228	{
229	unsigned long ret;
230
231	ret=(unsigned long)a->addr;
232
233	ret=ret*17851+(ret>>14)*7+(ret>>4)*251;
234	return(ret);
235	}
236
237static int app_info_cmp(APP_INFO *a, APP_INFO *b)
238	{
239	return(a->thread != b->thread);
240	}
241
242static unsigned long app_info_hash(APP_INFO *a)
243	{
244	unsigned long ret;
245
246	ret=(unsigned long)a->thread;
247
248	ret=ret*17851+(ret>>14)*7+(ret>>4)*251;
249	return(ret);
250	}
251
252static APP_INFO *pop_info()
253	{
254	APP_INFO tmp;
255	APP_INFO *ret = NULL;
256
257	if (amih != NULL)
258		{
259		tmp.thread=CRYPTO_thread_id();
260		if ((ret=(APP_INFO *)lh_delete(amih,&tmp)) != NULL)
261			{
262			APP_INFO *next=ret->next;
263
264			if (next != NULL)
265				{
266				next->references++;
267				lh_insert(amih,(char *)next);
268				}
269#ifdef LEVITTE_DEBUG
270			if (ret->thread != tmp.thread)
271				{
272				fprintf(stderr, "pop_info(): deleted info has other thread ID (%lu) than the current thread (%lu)!!!!\n",
273					ret->thread, tmp.thread);
274				abort();
275				}
276#endif
277			if (--(ret->references) <= 0)
278				{
279				ret->next = NULL;
280				if (next != NULL)
281					next->references--;
282				Free(ret);
283				}
284			}
285		}
286	return(ret);
287	}
288
289int CRYPTO_push_info_(const char *info, const char *file, int line)
290	{
291	APP_INFO *ami, *amim;
292	int ret=0;
293
294	if (is_MemCheck_on())
295		{
296		MemCheck_off(); /* obtains CRYPTO_LOCK_MALLOC2 */
297
298		if ((ami = (APP_INFO *)Malloc(sizeof(APP_INFO))) == NULL)
299			{
300			ret=0;
301			goto err;
302			}
303		if (amih == NULL)
304			{
305			if ((amih=lh_new(app_info_hash,app_info_cmp)) == NULL)
306				{
307				Free(ami);
308				ret=0;
309				goto err;
310				}
311			}
312
313		ami->thread=CRYPTO_thread_id();
314		ami->file=file;
315		ami->line=line;
316		ami->info=info;
317		ami->references=1;
318		ami->next=NULL;
319
320		if ((amim=(APP_INFO *)lh_insert(amih,(char *)ami)) != NULL)
321			{
322#ifdef LEVITTE_DEBUG
323			if (ami->thread != amim->thread)
324				{
325				fprintf(stderr, "CRYPTO_push_info(): previous info has other thread ID (%lu) than the current thread (%lu)!!!!\n",
326					amim->thread, ami->thread);
327				abort();
328				}
329#endif
330			ami->next=amim;
331			}
332 err:
333		MemCheck_on(); /* releases CRYPTO_LOCK_MALLOC2 */
334		}
335
336	return(ret);
337	}
338
339int CRYPTO_pop_info(void)
340	{
341	int ret=0;
342
343	if (is_MemCheck_on()) /* _must_ be true, or something went severely wrong */
344		{
345		MemCheck_off(); /* obtains CRYPTO_LOCK_MALLOC2 */
346
347		ret=(pop_info() != NULL);
348
349		MemCheck_on(); /* releases CRYPTO_LOCK_MALLOC2 */
350		}
351	return(ret);
352	}
353
354int CRYPTO_remove_all_info(void)
355	{
356	int ret=0;
357
358	if (is_MemCheck_on()) /* _must_ be true */
359		{
360		MemCheck_off(); /* obtains CRYPTO_LOCK_MALLOC2 */
361
362		while(pop_info() != NULL)
363			ret++;
364
365		MemCheck_on(); /* releases CRYPTO_LOCK_MALLOC2 */
366		}
367	return(ret);
368	}
369
370
371static unsigned long break_order_num=0;
372void CRYPTO_dbg_malloc(void *addr, int num, const char *file, int line,
373	int before_p)
374	{
375	MEM *m,*mm;
376	APP_INFO tmp,*amim;
377
378	switch(before_p & 127)
379		{
380	case 0:
381		break;
382	case 1:
383		if (addr == NULL)
384			break;
385
386		if (is_MemCheck_on())
387			{
388			MemCheck_off(); /* obtains CRYPTO_LOCK_MALLOC2 */
389			if ((m=(MEM *)Malloc(sizeof(MEM))) == NULL)
390				{
391				Free(addr);
392				MemCheck_on(); /* releases CRYPTO_LOCK_MALLOC2 */
393				return;
394				}
395			if (mh == NULL)
396				{
397				if ((mh=lh_new(mem_hash,mem_cmp)) == NULL)
398					{
399					Free(addr);
400					Free(m);
401					addr=NULL;
402					goto err;
403					}
404				}
405
406			m->addr=addr;
407			m->file=file;
408			m->line=line;
409			m->num=num;
410			if (options & V_CRYPTO_MDEBUG_THREAD)
411				m->thread=CRYPTO_thread_id();
412			else
413				m->thread=0;
414
415			if (order == break_order_num)
416				{
417				/* BREAK HERE */
418				m->order=order;
419				}
420			m->order=order++;
421#ifdef LEVITTE_DEBUG
422			fprintf(stderr, "LEVITTE_DEBUG: [%5d] %c 0x%p (%d)\n",
423				m->order,
424				(before_p & 128) ? '*' : '+',
425				m->addr, m->num);
426#endif
427			if (options & V_CRYPTO_MDEBUG_TIME)
428				m->time=time(NULL);
429			else
430				m->time=0;
431
432			tmp.thread=CRYPTO_thread_id();
433			m->app_info=NULL;
434			if (amih != NULL
435				&& (amim=(APP_INFO *)lh_retrieve(amih,(char *)&tmp)) != NULL)
436				{
437				m->app_info = amim;
438				amim->references++;
439				}
440
441			if ((mm=(MEM *)lh_insert(mh,(char *)m)) != NULL)
442				{
443				/* Not good, but don't sweat it */
444				if (mm->app_info != NULL)
445					{
446					mm->app_info->references--;
447					}
448				Free(mm);
449				}
450		err:
451			MemCheck_on(); /* releases CRYPTO_LOCK_MALLOC2 */
452			}
453		break;
454		}
455	return;
456	}
457
458void CRYPTO_dbg_free(void *addr, int before_p)
459	{
460	MEM m,*mp;
461
462	switch(before_p)
463		{
464	case 0:
465		if (addr == NULL)
466			break;
467
468		if (is_MemCheck_on() && (mh != NULL))
469			{
470			MemCheck_off();
471
472			m.addr=addr;
473			mp=(MEM *)lh_delete(mh,(char *)&m);
474			if (mp != NULL)
475				{
476#ifdef LEVITTE_DEBUG
477			fprintf(stderr, "LEVITTE_DEBUG: [%5d] - 0x%p (%d)\n",
478				mp->order, mp->addr, mp->num);
479#endif
480				if (mp->app_info != NULL)
481					{
482					mp->app_info->references--;
483					}
484				Free(mp);
485				}
486
487			MemCheck_on(); /* releases CRYPTO_LOCK_MALLOC2 */
488			}
489		break;
490	case 1:
491		break;
492		}
493	}
494
495void CRYPTO_dbg_realloc(void *addr1, void *addr2, int num,
496	const char *file, int line, int before_p)
497	{
498	MEM m,*mp;
499
500#ifdef LEVITTE_DEBUG
501	fprintf(stderr, "LEVITTE_DEBUG: --> CRYPTO_dbg_malloc(addr1 = %p, addr2 = %p, num = %d, file = \"%s\", line = %d, before_p = %d)\n",
502		addr1, addr2, num, file, line, before_p);
503#endif
504
505	switch(before_p)
506		{
507	case 0:
508		break;
509	case 1:
510		if (addr2 == NULL)
511			break;
512
513		if (addr1 == NULL)
514			{
515			CRYPTO_dbg_malloc(addr2, num, file, line, 128 | before_p);
516			break;
517			}
518
519		if (is_MemCheck_on())
520			{
521			MemCheck_off(); /* obtains CRYPTO_LOCK_MALLOC2 */
522
523			m.addr=addr1;
524			mp=(MEM *)lh_delete(mh,(char *)&m);
525			if (mp != NULL)
526				{
527#ifdef LEVITTE_DEBUG
528				fprintf(stderr, "LEVITTE_DEBUG: [%5d] * 0x%p (%d) -> 0x%p (%d)\n",
529					mp->order,
530					mp->addr, mp->num,
531					addr2, num);
532#endif
533				mp->addr=addr2;
534				mp->num=num;
535				lh_insert(mh,(char *)mp);
536				}
537
538			MemCheck_on(); /* releases CRYPTO_LOCK_MALLOC2 */
539			}
540		break;
541		}
542	return;
543	}
544
545
546typedef struct mem_leak_st
547	{
548	BIO *bio;
549	int chunks;
550	long bytes;
551	} MEM_LEAK;
552
553static void print_leak(MEM *m, MEM_LEAK *l)
554	{
555	char buf[1024];
556	char *bufp = buf;
557	APP_INFO *amip;
558	int ami_cnt;
559	struct tm *lcl = NULL;
560	unsigned long ti;
561
562	if(m->addr == (char *)l->bio)
563	    return;
564
565	if (options & V_CRYPTO_MDEBUG_TIME)
566		{
567		lcl = localtime(&m->time);
568
569		sprintf(bufp, "[%02d:%02d:%02d] ",
570			lcl->tm_hour,lcl->tm_min,lcl->tm_sec);
571		bufp += strlen(bufp);
572		}
573
574	sprintf(bufp, "%5lu file=%s, line=%d, ",
575		m->order,m->file,m->line);
576	bufp += strlen(bufp);
577
578	if (options & V_CRYPTO_MDEBUG_THREAD)
579		{
580		sprintf(bufp, "thread=%lu, ", m->thread);
581		bufp += strlen(bufp);
582		}
583
584	sprintf(bufp, "number=%d, address=%08lX\n",
585		m->num,(unsigned long)m->addr);
586	bufp += strlen(bufp);
587
588	BIO_puts(l->bio,buf);
589
590	l->chunks++;
591	l->bytes+=m->num;
592
593	amip=m->app_info;
594	ami_cnt=0;
595	if (!amip)
596		return;
597	ti=amip->thread;
598
599	do
600		{
601		int buf_len;
602		int info_len;
603
604		ami_cnt++;
605		memset(buf,'>',ami_cnt);
606		sprintf(buf + ami_cnt,
607			" thread=%lu, file=%s, line=%d, info=\"",
608			amip->thread, amip->file, amip->line);
609		buf_len=strlen(buf);
610		info_len=strlen(amip->info);
611		if (128 - buf_len - 3 < info_len)
612			{
613			memcpy(buf + buf_len, amip->info, 128 - buf_len - 3);
614			buf_len = 128 - 3;
615			}
616		else
617			{
618			strcpy(buf + buf_len, amip->info);
619			buf_len = strlen(buf);
620			}
621		sprintf(buf + buf_len, "\"\n");
622
623		BIO_puts(l->bio,buf);
624
625		amip = amip->next;
626		}
627	while(amip && amip->thread == ti);
628
629#ifdef LEVITTE_DEBUG
630	if (amip)
631		{
632		fprintf(stderr, "Thread switch detected in backtrace!!!!\n");
633		abort();
634		}
635#endif
636	}
637
638void CRYPTO_mem_leaks(BIO *b)
639	{
640	MEM_LEAK ml;
641	char buf[80];
642
643	if (mh == NULL && amih == NULL)
644		return;
645	ml.bio=b;
646	ml.bytes=0;
647	ml.chunks=0;
648	MemCheck_off(); /* obtains CRYPTO_LOCK_MALLOC2 */
649	if (mh != NULL)
650		lh_doall_arg(mh,(void (*)())print_leak,(char *)&ml);
651	if (ml.chunks != 0)
652		{
653		sprintf(buf,"%ld bytes leaked in %d chunks\n",
654			ml.bytes,ml.chunks);
655		BIO_puts(b,buf);
656		}
657	else
658		{
659		/* Make sure that, if we found no leaks, memory-leak debugging itself
660		 * does not introduce memory leaks (which might irritate
661		 * external debugging tools).
662		 * (When someone enables leak checking, but does not call
663		 * this function, we declare it to be their fault.)
664		 *
665		 * XXX    This should be in CRYPTO_mem_leaks_cb,
666		 * and CRYPTO_mem_leaks should be implemented by
667		 * using CRYPTO_mem_leaks_cb.
668		 * (Also their should be a variant of lh_doall_arg
669		 * that takes a function pointer instead of a void *;
670		 * this would obviate the ugly and illegal
671		 * void_fn_to_char kludge in CRYPTO_mem_leaks_cb.
672		 * Otherwise the code police will come and get us.)
673		 */
674		CRYPTO_w_lock(CRYPTO_LOCK_MALLOC);
675		if (mh != NULL)
676			{
677			lh_free(mh);
678			mh = NULL;
679			}
680		if (amih != NULL)
681			{
682			if (lh_num_items(amih) == 0)
683				{
684				lh_free(amih);
685				amih = NULL;
686				}
687			}
688		CRYPTO_w_unlock(CRYPTO_LOCK_MALLOC);
689		}
690	MemCheck_on(); /* releases CRYPTO_LOCK_MALLOC2 */
691
692#if 0
693	lh_stats_bio(mh,b);
694	lh_node_stats_bio(mh,b);
695	lh_node_usage_stats_bio(mh,b);
696#endif
697	}
698
699union void_fn_to_char_u
700	{
701	char *char_p;
702	void (*fn_p)();
703	};
704
705static void cb_leak(MEM *m, char *cb)
706	{
707	union void_fn_to_char_u mem_callback;
708
709	mem_callback.char_p=cb;
710	mem_callback.fn_p(m->order,m->file,m->line,m->num,m->addr);
711	}
712
713void CRYPTO_mem_leaks_cb(void (*cb)())
714	{
715	union void_fn_to_char_u mem_cb;
716
717	if (mh == NULL) return;
718	CRYPTO_w_lock(CRYPTO_LOCK_MALLOC2);
719	mem_cb.fn_p=cb;
720	lh_doall_arg(mh,(void (*)())cb_leak,mem_cb.char_p);
721	mem_cb.char_p=NULL;
722	CRYPTO_w_unlock(CRYPTO_LOCK_MALLOC2);
723	}
724
725#ifndef NO_FP_API
726void CRYPTO_mem_leaks_fp(FILE *fp)
727	{
728	BIO *b;
729
730	if (mh == NULL) return;
731	if ((b=BIO_new(BIO_s_file())) == NULL)
732		return;
733	BIO_set_fp(b,fp,BIO_NOCLOSE);
734	CRYPTO_mem_leaks(b);
735	BIO_free(b);
736	}
737#endif
738
739