159191Skris/* crypto/mem_dbg.c */
259191Skris/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
359191Skris * All rights reserved.
459191Skris *
559191Skris * This package is an SSL implementation written
659191Skris * by Eric Young (eay@cryptsoft.com).
759191Skris * The implementation was written so as to conform with Netscapes SSL.
859191Skris *
959191Skris * This library is free for commercial and non-commercial use as long as
1059191Skris * the following conditions are aheared to.  The following conditions
1159191Skris * apply to all code found in this distribution, be it the RC4, RSA,
1259191Skris * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
1359191Skris * included with this distribution is covered by the same copyright terms
1459191Skris * except that the holder is Tim Hudson (tjh@cryptsoft.com).
1559191Skris *
1659191Skris * Copyright remains Eric Young's, and as such any Copyright notices in
1759191Skris * the code are not to be removed.
1859191Skris * If this package is used in a product, Eric Young should be given attribution
1959191Skris * as the author of the parts of the library used.
2059191Skris * This can be in the form of a textual message at program startup or
2159191Skris * in documentation (online or textual) provided with the package.
2259191Skris *
2359191Skris * Redistribution and use in source and binary forms, with or without
2459191Skris * modification, are permitted provided that the following conditions
2559191Skris * are met:
2659191Skris * 1. Redistributions of source code must retain the copyright
2759191Skris *    notice, this list of conditions and the following disclaimer.
2859191Skris * 2. Redistributions in binary form must reproduce the above copyright
2959191Skris *    notice, this list of conditions and the following disclaimer in the
3059191Skris *    documentation and/or other materials provided with the distribution.
3159191Skris * 3. All advertising materials mentioning features or use of this software
3259191Skris *    must display the following acknowledgement:
3359191Skris *    "This product includes cryptographic software written by
3459191Skris *     Eric Young (eay@cryptsoft.com)"
3559191Skris *    The word 'cryptographic' can be left out if the rouines from the library
3659191Skris *    being used are not cryptographic related :-).
3759191Skris * 4. If you include any Windows specific code (or a derivative thereof) from
3859191Skris *    the apps directory (application code) you must include an acknowledgement:
3959191Skris *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
4059191Skris *
4159191Skris * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
4259191Skris * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
4359191Skris * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
4459191Skris * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
4559191Skris * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
4659191Skris * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
4759191Skris * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
4859191Skris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
4959191Skris * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
5059191Skris * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
5159191Skris * SUCH DAMAGE.
5259191Skris *
5359191Skris * The licence and distribution terms for any publically available version or
5459191Skris * derivative of this code cannot be changed.  i.e. this code cannot simply be
5559191Skris * copied and put under another distribution licence
5659191Skris * [including the GNU Public Licence.]
5759191Skris */
58238405Sjkim/* ====================================================================
59238405Sjkim * Copyright (c) 1998-2006 The OpenSSL Project.  All rights reserved.
60238405Sjkim *
61238405Sjkim * Redistribution and use in source and binary forms, with or without
62238405Sjkim * modification, are permitted provided that the following conditions
63238405Sjkim * are met:
64238405Sjkim *
65238405Sjkim * 1. Redistributions of source code must retain the above copyright
66238405Sjkim *    notice, this list of conditions and the following disclaimer.
67238405Sjkim *
68238405Sjkim * 2. Redistributions in binary form must reproduce the above copyright
69238405Sjkim *    notice, this list of conditions and the following disclaimer in
70238405Sjkim *    the documentation and/or other materials provided with the
71238405Sjkim *    distribution.
72238405Sjkim *
73238405Sjkim * 3. All advertising materials mentioning features or use of this
74238405Sjkim *    software must display the following acknowledgment:
75238405Sjkim *    "This product includes software developed by the OpenSSL Project
76238405Sjkim *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
77238405Sjkim *
78238405Sjkim * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
79238405Sjkim *    endorse or promote products derived from this software without
80238405Sjkim *    prior written permission. For written permission, please contact
81238405Sjkim *    openssl-core@openssl.org.
82238405Sjkim *
83238405Sjkim * 5. Products derived from this software may not be called "OpenSSL"
84238405Sjkim *    nor may "OpenSSL" appear in their names without prior written
85238405Sjkim *    permission of the OpenSSL Project.
86238405Sjkim *
87238405Sjkim * 6. Redistributions of any form whatsoever must retain the following
88238405Sjkim *    acknowledgment:
89238405Sjkim *    "This product includes software developed by the OpenSSL Project
90238405Sjkim *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
91238405Sjkim *
92238405Sjkim * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
93238405Sjkim * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
94238405Sjkim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
95238405Sjkim * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
96238405Sjkim * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
97238405Sjkim * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
98238405Sjkim * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
99238405Sjkim * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
100238405Sjkim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
101238405Sjkim * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
102238405Sjkim * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
103238405Sjkim * OF THE POSSIBILITY OF SUCH DAMAGE.
104238405Sjkim * ====================================================================
105238405Sjkim *
106238405Sjkim * This product includes cryptographic software written by Eric Young
107238405Sjkim * (eay@cryptsoft.com).  This product includes software written by Tim
108238405Sjkim * Hudson (tjh@cryptsoft.com).
109238405Sjkim *
110238405Sjkim */
11159191Skris
11259191Skris#include <stdio.h>
11359191Skris#include <stdlib.h>
11459191Skris#include <time.h>
115160814Ssimon#include "cryptlib.h"
11659191Skris#include <openssl/crypto.h>
11759191Skris#include <openssl/buffer.h>
11859191Skris#include <openssl/bio.h>
11959191Skris#include <openssl/lhash.h>
12059191Skris
12159191Skrisstatic int mh_mode=CRYPTO_MEM_CHECK_OFF;
12259191Skris/* The state changes to CRYPTO_MEM_CHECK_ON | CRYPTO_MEM_CHECK_ENABLE
12359191Skris * when the application asks for it (usually after library initialisation
12459191Skris * for which no book-keeping is desired).
12559191Skris *
12659191Skris * State CRYPTO_MEM_CHECK_ON exists only temporarily when the library
12759191Skris * thinks that certain allocations should not be checked (e.g. the data
12859191Skris * structures used for memory checking).  It is not suitable as an initial
12959191Skris * state: the library will unexpectedly enable memory checking when it
13059191Skris * executes one of those sections that want to disable checking
13159191Skris * temporarily.
13259191Skris *
13359191Skris * State CRYPTO_MEM_CHECK_ENABLE without ..._ON makes no sense whatsoever.
13459191Skris */
13559191Skris
13659191Skrisstatic unsigned long order = 0; /* number of memory requests */
13759191Skris
138238405SjkimDECLARE_LHASH_OF(MEM);
139238405Sjkimstatic LHASH_OF(MEM) *mh=NULL; /* hash-table of memory requests
140238405Sjkim				* (address as key); access requires
141238405Sjkim				* MALLOC2 lock */
14259191Skris
143238405Sjkim
14459191Skristypedef struct app_mem_info_st
14559191Skris/* For application-defined information (static C-string `info')
14659191Skris * to be displayed in memory leak list.
14759191Skris * Each thread has its own stack.  For applications, there is
14859191Skris *   CRYPTO_push_info("...")     to push an entry,
14959191Skris *   CRYPTO_pop_info()           to pop an entry,
15059191Skris *   CRYPTO_remove_all_info()    to pop all entries.
15159191Skris */
152238405Sjkim	{
153238405Sjkim	CRYPTO_THREADID threadid;
15459191Skris	const char *file;
15559191Skris	int line;
15659191Skris	const char *info;
15759191Skris	struct app_mem_info_st *next; /* tail of thread's stack */
15859191Skris	int references;
15959191Skris	} APP_INFO;
16059191Skris
161109998Smarkmstatic void app_info_free(APP_INFO *);
162109998Smarkm
163238405SjkimDECLARE_LHASH_OF(APP_INFO);
164238405Sjkimstatic LHASH_OF(APP_INFO) *amih=NULL; /* hash-table with those
165238405Sjkim				       * app_mem_info_st's that are at
166238405Sjkim				       * the top of their thread's
167238405Sjkim				       * stack (with `thread' as key);
168238405Sjkim				       * access requires MALLOC2
169238405Sjkim				       * lock */
17059191Skris
17159191Skristypedef struct mem_st
17259191Skris/* memory-block description */
17359191Skris	{
17468651Skris	void *addr;
17559191Skris	int num;
17659191Skris	const char *file;
17759191Skris	int line;
178238405Sjkim	CRYPTO_THREADID threadid;
17959191Skris	unsigned long order;
18059191Skris	time_t time;
18159191Skris	APP_INFO *app_info;
18259191Skris	} MEM;
18359191Skris
18459191Skrisstatic long options =             /* extra information to be recorded */
18559191Skris#if defined(CRYPTO_MDEBUG_TIME) || defined(CRYPTO_MDEBUG_ALL)
18659191Skris	V_CRYPTO_MDEBUG_TIME |
18759191Skris#endif
18859191Skris#if defined(CRYPTO_MDEBUG_THREAD) || defined(CRYPTO_MDEBUG_ALL)
18959191Skris	V_CRYPTO_MDEBUG_THREAD |
19059191Skris#endif
19159191Skris	0;
19259191Skris
19359191Skris
19476866Skrisstatic unsigned int num_disable = 0; /* num_disable > 0
19576866Skris                                      *     iff
19676866Skris                                      * mh_mode == CRYPTO_MEM_CHECK_ON (w/o ..._ENABLE)
19776866Skris                                      */
19859191Skris
199238405Sjkim/* Valid iff num_disable > 0.  CRYPTO_LOCK_MALLOC2 is locked exactly in this
200238405Sjkim * case (by the thread named in disabling_thread).
201238405Sjkim */
202238405Sjkimstatic CRYPTO_THREADID disabling_threadid;
203238405Sjkim
204109998Smarkmstatic void app_info_free(APP_INFO *inf)
205109998Smarkm	{
206109998Smarkm	if (--(inf->references) <= 0)
207109998Smarkm		{
208109998Smarkm		if (inf->next != NULL)
209109998Smarkm			{
210109998Smarkm			app_info_free(inf->next);
211109998Smarkm			}
212109998Smarkm		OPENSSL_free(inf);
213109998Smarkm		}
214109998Smarkm	}
215109998Smarkm
21659191Skrisint CRYPTO_mem_ctrl(int mode)
21759191Skris	{
21859191Skris	int ret=mh_mode;
21959191Skris
22059191Skris	CRYPTO_w_lock(CRYPTO_LOCK_MALLOC);
22159191Skris	switch (mode)
22259191Skris		{
22376866Skris	/* for applications (not to be called while multiple threads
22476866Skris	 * use the library): */
22559191Skris	case CRYPTO_MEM_CHECK_ON: /* aka MemCheck_start() */
22659191Skris		mh_mode = CRYPTO_MEM_CHECK_ON|CRYPTO_MEM_CHECK_ENABLE;
22776866Skris		num_disable = 0;
22859191Skris		break;
22959191Skris	case CRYPTO_MEM_CHECK_OFF: /* aka MemCheck_stop() */
23059191Skris		mh_mode = 0;
23176866Skris		num_disable = 0; /* should be true *before* MemCheck_stop is used,
23276866Skris		                    or there'll be a lot of confusion */
23359191Skris		break;
23459191Skris
23559191Skris	/* switch off temporarily (for library-internal use): */
23659191Skris	case CRYPTO_MEM_CHECK_DISABLE: /* aka MemCheck_off() */
23759191Skris		if (mh_mode & CRYPTO_MEM_CHECK_ON)
23859191Skris			{
239238405Sjkim			CRYPTO_THREADID cur;
240238405Sjkim			CRYPTO_THREADID_current(&cur);
241238405Sjkim			if (!num_disable || CRYPTO_THREADID_cmp(&disabling_threadid, &cur)) /* otherwise we already have the MALLOC2 lock */
24259191Skris				{
24359191Skris				/* Long-time lock CRYPTO_LOCK_MALLOC2 must not be claimed while
24459191Skris				 * we're holding CRYPTO_LOCK_MALLOC, or we'll deadlock if
24559191Skris				 * somebody else holds CRYPTO_LOCK_MALLOC2 (and cannot release
24659191Skris				 * it because we block entry to this function).
24759191Skris				 * Give them a chance, first, and then claim the locks in
24859191Skris				 * appropriate order (long-time lock first).
24959191Skris				 */
25059191Skris				CRYPTO_w_unlock(CRYPTO_LOCK_MALLOC);
25159191Skris				/* Note that after we have waited for CRYPTO_LOCK_MALLOC2
25259191Skris				 * and CRYPTO_LOCK_MALLOC, we'll still be in the right
25359191Skris				 * "case" and "if" branch because MemCheck_start and
25459191Skris				 * MemCheck_stop may never be used while there are multiple
25559191Skris				 * OpenSSL threads. */
25659191Skris				CRYPTO_w_lock(CRYPTO_LOCK_MALLOC2);
25759191Skris				CRYPTO_w_lock(CRYPTO_LOCK_MALLOC);
25876866Skris				mh_mode &= ~CRYPTO_MEM_CHECK_ENABLE;
259238405Sjkim				CRYPTO_THREADID_cpy(&disabling_threadid, &cur);
26059191Skris				}
26176866Skris			num_disable++;
26259191Skris			}
26359191Skris		break;
26459191Skris	case CRYPTO_MEM_CHECK_ENABLE: /* aka MemCheck_on() */
26559191Skris		if (mh_mode & CRYPTO_MEM_CHECK_ON)
26659191Skris			{
26776866Skris			if (num_disable) /* always true, or something is going wrong */
26859191Skris				{
26976866Skris				num_disable--;
27076866Skris				if (num_disable == 0)
27176866Skris					{
27276866Skris					mh_mode|=CRYPTO_MEM_CHECK_ENABLE;
27376866Skris					CRYPTO_w_unlock(CRYPTO_LOCK_MALLOC2);
27476866Skris					}
27559191Skris				}
27659191Skris			}
27759191Skris		break;
27859191Skris
27959191Skris	default:
28059191Skris		break;
28159191Skris		}
28259191Skris	CRYPTO_w_unlock(CRYPTO_LOCK_MALLOC);
28359191Skris	return(ret);
28459191Skris	}
28559191Skris
28659191Skrisint CRYPTO_is_mem_check_on(void)
28759191Skris	{
28859191Skris	int ret = 0;
28959191Skris
29059191Skris	if (mh_mode & CRYPTO_MEM_CHECK_ON)
29159191Skris		{
292238405Sjkim		CRYPTO_THREADID cur;
293238405Sjkim		CRYPTO_THREADID_current(&cur);
29476866Skris		CRYPTO_r_lock(CRYPTO_LOCK_MALLOC);
29559191Skris
29659191Skris		ret = (mh_mode & CRYPTO_MEM_CHECK_ENABLE)
297238405Sjkim		        || CRYPTO_THREADID_cmp(&disabling_threadid, &cur);
29859191Skris
29976866Skris		CRYPTO_r_unlock(CRYPTO_LOCK_MALLOC);
30059191Skris		}
30159191Skris	return(ret);
30259191Skris	}
30359191Skris
30459191Skris
30559191Skrisvoid CRYPTO_dbg_set_options(long bits)
30659191Skris	{
30759191Skris	options = bits;
30859191Skris	}
30959191Skris
31059191Skrislong CRYPTO_dbg_get_options(void)
31159191Skris	{
31259191Skris	return options;
31359191Skris	}
31459191Skris
315238405Sjkimstatic int mem_cmp(const MEM *a, const MEM *b)
31659191Skris	{
317160814Ssimon#ifdef _WIN64
318238405Sjkim	const char *ap=(const char *)a->addr,
319238405Sjkim		   *bp=(const char *)b->addr;
320238405Sjkim	if (ap==bp)	return 0;
321238405Sjkim	else if (ap>bp)	return 1;
322160814Ssimon	else		return -1;
323160814Ssimon#else
324238405Sjkim	return (const char *)a->addr - (const char *)b->addr;
325160814Ssimon#endif
32659191Skris	}
327238405Sjkimstatic IMPLEMENT_LHASH_COMP_FN(mem, MEM)
32859191Skris
329238405Sjkimstatic unsigned long mem_hash(const MEM *a)
33059191Skris	{
33159191Skris	unsigned long ret;
33259191Skris
333238405Sjkim	ret=(unsigned long)a->addr;
33459191Skris
33559191Skris	ret=ret*17851+(ret>>14)*7+(ret>>4)*251;
33659191Skris	return(ret);
33759191Skris	}
338238405Sjkimstatic IMPLEMENT_LHASH_HASH_FN(mem, MEM)
33959191Skris
340109998Smarkm/* static int app_info_cmp(APP_INFO *a, APP_INFO *b) */
341109998Smarkmstatic int app_info_cmp(const void *a_void, const void *b_void)
34259191Skris	{
343238405Sjkim	return CRYPTO_THREADID_cmp(&((const APP_INFO *)a_void)->threadid,
344238405Sjkim				&((const APP_INFO *)b_void)->threadid);
34559191Skris	}
346238405Sjkimstatic IMPLEMENT_LHASH_COMP_FN(app_info, APP_INFO)
34759191Skris
348238405Sjkimstatic unsigned long app_info_hash(const APP_INFO *a)
34959191Skris	{
35059191Skris	unsigned long ret;
35159191Skris
352238405Sjkim	ret = CRYPTO_THREADID_hash(&a->threadid);
353238405Sjkim	/* This is left in as a "who am I to question legacy?" measure */
35459191Skris	ret=ret*17851+(ret>>14)*7+(ret>>4)*251;
35559191Skris	return(ret);
35659191Skris	}
357238405Sjkimstatic IMPLEMENT_LHASH_HASH_FN(app_info, APP_INFO)
35859191Skris
359109998Smarkmstatic APP_INFO *pop_info(void)
36059191Skris	{
36159191Skris	APP_INFO tmp;
36259191Skris	APP_INFO *ret = NULL;
36359191Skris
36459191Skris	if (amih != NULL)
36559191Skris		{
366238405Sjkim		CRYPTO_THREADID_current(&tmp.threadid);
367238405Sjkim		if ((ret=lh_APP_INFO_delete(amih,&tmp)) != NULL)
36859191Skris			{
36959191Skris			APP_INFO *next=ret->next;
37059191Skris
37159191Skris			if (next != NULL)
37259191Skris				{
37359191Skris				next->references++;
374238405Sjkim				(void)lh_APP_INFO_insert(amih,next);
37559191Skris				}
376109998Smarkm#ifdef LEVITTE_DEBUG_MEM
377238405Sjkim			if (CRYPTO_THREADID_cmp(&ret->threadid, &tmp.threadid))
37859191Skris				{
37959191Skris				fprintf(stderr, "pop_info(): deleted info has other thread ID (%lu) than the current thread (%lu)!!!!\n",
380238405Sjkim					CRYPTO_THREADID_hash(&ret->threadid),
381238405Sjkim					CRYPTO_THREADID_hash(&tmp.threadid));
38259191Skris				abort();
38359191Skris				}
38459191Skris#endif
38559191Skris			if (--(ret->references) <= 0)
38659191Skris				{
38759191Skris				ret->next = NULL;
38859191Skris				if (next != NULL)
38959191Skris					next->references--;
39068651Skris				OPENSSL_free(ret);
39159191Skris				}
39259191Skris			}
39359191Skris		}
39459191Skris	return(ret);
39559191Skris	}
39659191Skris
397238405Sjkimint CRYPTO_push_info_(const char *info, const char *file, int line)
39859191Skris	{
39959191Skris	APP_INFO *ami, *amim;
40059191Skris	int ret=0;
40159191Skris
40259191Skris	if (is_MemCheck_on())
40359191Skris		{
40476866Skris		MemCheck_off(); /* obtain MALLOC2 lock */
40559191Skris
40668651Skris		if ((ami = (APP_INFO *)OPENSSL_malloc(sizeof(APP_INFO))) == NULL)
40759191Skris			{
40859191Skris			ret=0;
40959191Skris			goto err;
41059191Skris			}
41159191Skris		if (amih == NULL)
41259191Skris			{
413238405Sjkim			if ((amih=lh_APP_INFO_new()) == NULL)
41459191Skris				{
41568651Skris				OPENSSL_free(ami);
41659191Skris				ret=0;
41759191Skris				goto err;
41859191Skris				}
41959191Skris			}
42059191Skris
421238405Sjkim		CRYPTO_THREADID_current(&ami->threadid);
42259191Skris		ami->file=file;
42359191Skris		ami->line=line;
42459191Skris		ami->info=info;
42559191Skris		ami->references=1;
42659191Skris		ami->next=NULL;
42759191Skris
428238405Sjkim		if ((amim=lh_APP_INFO_insert(amih,ami)) != NULL)
42959191Skris			{
430109998Smarkm#ifdef LEVITTE_DEBUG_MEM
431238405Sjkim			if (CRYPTO_THREADID_cmp(&ami->threadid, &amim->threadid))
43259191Skris				{
43359191Skris				fprintf(stderr, "CRYPTO_push_info(): previous info has other thread ID (%lu) than the current thread (%lu)!!!!\n",
434238405Sjkim					CRYPTO_THREADID_hash(&amim->threadid),
435238405Sjkim					CRYPTO_THREADID_hash(&ami->threadid));
43659191Skris				abort();
43759191Skris				}
43859191Skris#endif
43959191Skris			ami->next=amim;
44059191Skris			}
44159191Skris err:
44276866Skris		MemCheck_on(); /* release MALLOC2 lock */
44359191Skris		}
44459191Skris
44559191Skris	return(ret);
44659191Skris	}
44759191Skris
448238405Sjkimint CRYPTO_pop_info(void)
44959191Skris	{
45059191Skris	int ret=0;
45159191Skris
45259191Skris	if (is_MemCheck_on()) /* _must_ be true, or something went severely wrong */
45359191Skris		{
45476866Skris		MemCheck_off(); /* obtain MALLOC2 lock */
45559191Skris
45659191Skris		ret=(pop_info() != NULL);
45759191Skris
45876866Skris		MemCheck_on(); /* release MALLOC2 lock */
45959191Skris		}
46059191Skris	return(ret);
46159191Skris	}
46259191Skris
463238405Sjkimint CRYPTO_remove_all_info(void)
46459191Skris	{
46559191Skris	int ret=0;
46659191Skris
46759191Skris	if (is_MemCheck_on()) /* _must_ be true */
46859191Skris		{
46976866Skris		MemCheck_off(); /* obtain MALLOC2 lock */
47059191Skris
47159191Skris		while(pop_info() != NULL)
47259191Skris			ret++;
47359191Skris
47476866Skris		MemCheck_on(); /* release MALLOC2 lock */
47559191Skris		}
47659191Skris	return(ret);
47759191Skris	}
47859191Skris
47959191Skris
48059191Skrisstatic unsigned long break_order_num=0;
48159191Skrisvoid CRYPTO_dbg_malloc(void *addr, int num, const char *file, int line,
48259191Skris	int before_p)
48359191Skris	{
48459191Skris	MEM *m,*mm;
48559191Skris	APP_INFO tmp,*amim;
48659191Skris
48759191Skris	switch(before_p & 127)
48859191Skris		{
48959191Skris	case 0:
49059191Skris		break;
49159191Skris	case 1:
49259191Skris		if (addr == NULL)
49359191Skris			break;
49459191Skris
49559191Skris		if (is_MemCheck_on())
49659191Skris			{
49776866Skris			MemCheck_off(); /* make sure we hold MALLOC2 lock */
49868651Skris			if ((m=(MEM *)OPENSSL_malloc(sizeof(MEM))) == NULL)
49959191Skris				{
50068651Skris				OPENSSL_free(addr);
50176866Skris				MemCheck_on(); /* release MALLOC2 lock
50276866Skris				                * if num_disabled drops to 0 */
50359191Skris				return;
50459191Skris				}
50559191Skris			if (mh == NULL)
50659191Skris				{
507238405Sjkim				if ((mh=lh_MEM_new()) == NULL)
50859191Skris					{
50968651Skris					OPENSSL_free(addr);
51068651Skris					OPENSSL_free(m);
51159191Skris					addr=NULL;
51259191Skris					goto err;
51359191Skris					}
51459191Skris				}
51559191Skris
51659191Skris			m->addr=addr;
51759191Skris			m->file=file;
51859191Skris			m->line=line;
51959191Skris			m->num=num;
52059191Skris			if (options & V_CRYPTO_MDEBUG_THREAD)
521238405Sjkim				CRYPTO_THREADID_current(&m->threadid);
52259191Skris			else
523238405Sjkim				memset(&m->threadid, 0, sizeof(m->threadid));
52459191Skris
52559191Skris			if (order == break_order_num)
52659191Skris				{
52759191Skris				/* BREAK HERE */
52859191Skris				m->order=order;
52959191Skris				}
53059191Skris			m->order=order++;
531109998Smarkm#ifdef LEVITTE_DEBUG_MEM
532238405Sjkim			fprintf(stderr, "LEVITTE_DEBUG_MEM: [%5ld] %c 0x%p (%d)\n",
53359191Skris				m->order,
53459191Skris				(before_p & 128) ? '*' : '+',
53559191Skris				m->addr, m->num);
53659191Skris#endif
53759191Skris			if (options & V_CRYPTO_MDEBUG_TIME)
53859191Skris				m->time=time(NULL);
53959191Skris			else
54059191Skris				m->time=0;
54159191Skris
542238405Sjkim			CRYPTO_THREADID_current(&tmp.threadid);
54359191Skris			m->app_info=NULL;
54459191Skris			if (amih != NULL
545238405Sjkim			    && (amim=lh_APP_INFO_retrieve(amih,&tmp)) != NULL)
54659191Skris				{
54759191Skris				m->app_info = amim;
54859191Skris				amim->references++;
54959191Skris				}
55059191Skris
551238405Sjkim			if ((mm=lh_MEM_insert(mh, m)) != NULL)
55259191Skris				{
55359191Skris				/* Not good, but don't sweat it */
55459191Skris				if (mm->app_info != NULL)
55559191Skris					{
55659191Skris					mm->app_info->references--;
55759191Skris					}
55868651Skris				OPENSSL_free(mm);
55959191Skris				}
56059191Skris		err:
56176866Skris			MemCheck_on(); /* release MALLOC2 lock
56276866Skris			                * if num_disabled drops to 0 */
56359191Skris			}
56459191Skris		break;
56559191Skris		}
56659191Skris	return;
56759191Skris	}
56859191Skris
56959191Skrisvoid CRYPTO_dbg_free(void *addr, int before_p)
57059191Skris	{
57159191Skris	MEM m,*mp;
57259191Skris
57359191Skris	switch(before_p)
57459191Skris		{
57559191Skris	case 0:
57659191Skris		if (addr == NULL)
57759191Skris			break;
57859191Skris
57959191Skris		if (is_MemCheck_on() && (mh != NULL))
58059191Skris			{
58176866Skris			MemCheck_off(); /* make sure we hold MALLOC2 lock */
58259191Skris
58359191Skris			m.addr=addr;
584238405Sjkim			mp=lh_MEM_delete(mh,&m);
58559191Skris			if (mp != NULL)
58659191Skris				{
587109998Smarkm#ifdef LEVITTE_DEBUG_MEM
588238405Sjkim			fprintf(stderr, "LEVITTE_DEBUG_MEM: [%5ld] - 0x%p (%d)\n",
58959191Skris				mp->order, mp->addr, mp->num);
59059191Skris#endif
59159191Skris				if (mp->app_info != NULL)
592109998Smarkm					app_info_free(mp->app_info);
59368651Skris				OPENSSL_free(mp);
59459191Skris				}
59559191Skris
59676866Skris			MemCheck_on(); /* release MALLOC2 lock
59776866Skris			                * if num_disabled drops to 0 */
59859191Skris			}
59959191Skris		break;
60059191Skris	case 1:
60159191Skris		break;
60259191Skris		}
60359191Skris	}
60459191Skris
60559191Skrisvoid CRYPTO_dbg_realloc(void *addr1, void *addr2, int num,
60659191Skris	const char *file, int line, int before_p)
60759191Skris	{
60859191Skris	MEM m,*mp;
60959191Skris
610109998Smarkm#ifdef LEVITTE_DEBUG_MEM
611109998Smarkm	fprintf(stderr, "LEVITTE_DEBUG_MEM: --> CRYPTO_dbg_malloc(addr1 = %p, addr2 = %p, num = %d, file = \"%s\", line = %d, before_p = %d)\n",
61259191Skris		addr1, addr2, num, file, line, before_p);
61359191Skris#endif
61459191Skris
61559191Skris	switch(before_p)
61659191Skris		{
61759191Skris	case 0:
61859191Skris		break;
61959191Skris	case 1:
62059191Skris		if (addr2 == NULL)
62159191Skris			break;
62259191Skris
62359191Skris		if (addr1 == NULL)
62459191Skris			{
62559191Skris			CRYPTO_dbg_malloc(addr2, num, file, line, 128 | before_p);
62659191Skris			break;
62759191Skris			}
62859191Skris
62959191Skris		if (is_MemCheck_on())
63059191Skris			{
63176866Skris			MemCheck_off(); /* make sure we hold MALLOC2 lock */
63259191Skris
63359191Skris			m.addr=addr1;
634238405Sjkim			mp=lh_MEM_delete(mh,&m);
63559191Skris			if (mp != NULL)
63659191Skris				{
637109998Smarkm#ifdef LEVITTE_DEBUG_MEM
638238405Sjkim				fprintf(stderr, "LEVITTE_DEBUG_MEM: [%5ld] * 0x%p (%d) -> 0x%p (%d)\n",
63959191Skris					mp->order,
64059191Skris					mp->addr, mp->num,
64159191Skris					addr2, num);
64259191Skris#endif
64359191Skris				mp->addr=addr2;
64459191Skris				mp->num=num;
645238405Sjkim				(void)lh_MEM_insert(mh,mp);
64659191Skris				}
64759191Skris
64876866Skris			MemCheck_on(); /* release MALLOC2 lock
64976866Skris			                * if num_disabled drops to 0 */
65059191Skris			}
65159191Skris		break;
65259191Skris		}
65359191Skris	return;
65459191Skris	}
65559191Skris
65659191Skris
65759191Skristypedef struct mem_leak_st
65859191Skris	{
65959191Skris	BIO *bio;
66059191Skris	int chunks;
66159191Skris	long bytes;
66259191Skris	} MEM_LEAK;
66359191Skris
664238405Sjkimstatic void print_leak_doall_arg(const MEM *m, MEM_LEAK *l)
66559191Skris	{
66659191Skris	char buf[1024];
66759191Skris	char *bufp = buf;
66859191Skris	APP_INFO *amip;
66959191Skris	int ami_cnt;
67059191Skris	struct tm *lcl = NULL;
671238405Sjkim	CRYPTO_THREADID ti;
67259191Skris
673127128Snectar#define BUF_REMAIN (sizeof buf - (size_t)(bufp - buf))
674127128Snectar
67559191Skris	if(m->addr == (char *)l->bio)
67659191Skris	    return;
67759191Skris
67859191Skris	if (options & V_CRYPTO_MDEBUG_TIME)
67959191Skris		{
68059191Skris		lcl = localtime(&m->time);
68159191Skris
682127128Snectar		BIO_snprintf(bufp, BUF_REMAIN, "[%02d:%02d:%02d] ",
68359191Skris			lcl->tm_hour,lcl->tm_min,lcl->tm_sec);
68459191Skris		bufp += strlen(bufp);
68559191Skris		}
68659191Skris
687127128Snectar	BIO_snprintf(bufp, BUF_REMAIN, "%5lu file=%s, line=%d, ",
68859191Skris		m->order,m->file,m->line);
68959191Skris	bufp += strlen(bufp);
69059191Skris
69159191Skris	if (options & V_CRYPTO_MDEBUG_THREAD)
69259191Skris		{
693238405Sjkim		BIO_snprintf(bufp, BUF_REMAIN, "thread=%lu, ",
694238405Sjkim			CRYPTO_THREADID_hash(&m->threadid));
69559191Skris		bufp += strlen(bufp);
69659191Skris		}
69759191Skris
698127128Snectar	BIO_snprintf(bufp, BUF_REMAIN, "number=%d, address=%08lX\n",
69959191Skris		m->num,(unsigned long)m->addr);
70059191Skris	bufp += strlen(bufp);
70159191Skris
70259191Skris	BIO_puts(l->bio,buf);
70359191Skris
70459191Skris	l->chunks++;
70559191Skris	l->bytes+=m->num;
70659191Skris
70759191Skris	amip=m->app_info;
70859191Skris	ami_cnt=0;
70959191Skris	if (!amip)
71059191Skris		return;
711238405Sjkim	CRYPTO_THREADID_cpy(&ti, &amip->threadid);
712238405Sjkim
71359191Skris	do
71459191Skris		{
71559191Skris		int buf_len;
71659191Skris		int info_len;
71759191Skris
71859191Skris		ami_cnt++;
71959191Skris		memset(buf,'>',ami_cnt);
720127128Snectar		BIO_snprintf(buf + ami_cnt, sizeof buf - ami_cnt,
72159191Skris			" thread=%lu, file=%s, line=%d, info=\"",
722238405Sjkim			CRYPTO_THREADID_hash(&amip->threadid), amip->file,
723238405Sjkim			amip->line);
72459191Skris		buf_len=strlen(buf);
72559191Skris		info_len=strlen(amip->info);
72659191Skris		if (128 - buf_len - 3 < info_len)
72759191Skris			{
72859191Skris			memcpy(buf + buf_len, amip->info, 128 - buf_len - 3);
72959191Skris			buf_len = 128 - 3;
73059191Skris			}
73159191Skris		else
73259191Skris			{
733127128Snectar			BUF_strlcpy(buf + buf_len, amip->info,
734127128Snectar				    sizeof buf - buf_len);
73559191Skris			buf_len = strlen(buf);
73659191Skris			}
737127128Snectar		BIO_snprintf(buf + buf_len, sizeof buf - buf_len, "\"\n");
73859191Skris
73959191Skris		BIO_puts(l->bio,buf);
74059191Skris
74159191Skris		amip = amip->next;
74259191Skris		}
743238405Sjkim	while(amip && !CRYPTO_THREADID_cmp(&amip->threadid, &ti));
744238405Sjkim
745109998Smarkm#ifdef LEVITTE_DEBUG_MEM
74659191Skris	if (amip)
74759191Skris		{
74859191Skris		fprintf(stderr, "Thread switch detected in backtrace!!!!\n");
74959191Skris		abort();
75059191Skris		}
75159191Skris#endif
75259191Skris	}
75359191Skris
754238405Sjkimstatic IMPLEMENT_LHASH_DOALL_ARG_FN(print_leak, const MEM, MEM_LEAK)
755109998Smarkm
75659191Skrisvoid CRYPTO_mem_leaks(BIO *b)
75759191Skris	{
75859191Skris	MEM_LEAK ml;
75959191Skris
76059191Skris	if (mh == NULL && amih == NULL)
76159191Skris		return;
76276866Skris
76376866Skris	MemCheck_off(); /* obtain MALLOC2 lock */
76476866Skris
76559191Skris	ml.bio=b;
76659191Skris	ml.bytes=0;
76759191Skris	ml.chunks=0;
76859191Skris	if (mh != NULL)
769238405Sjkim		lh_MEM_doall_arg(mh, LHASH_DOALL_ARG_FN(print_leak), MEM_LEAK,
770238405Sjkim				 &ml);
77159191Skris	if (ml.chunks != 0)
77259191Skris		{
773109998Smarkm		BIO_printf(b,"%ld bytes leaked in %d chunks\n",
774109998Smarkm			   ml.bytes,ml.chunks);
775238405Sjkim#ifdef CRYPTO_MDEBUG_ABORT
776238405Sjkim		abort();
777238405Sjkim#endif
77859191Skris		}
77959191Skris	else
78059191Skris		{
78159191Skris		/* Make sure that, if we found no leaks, memory-leak debugging itself
78259191Skris		 * does not introduce memory leaks (which might irritate
78359191Skris		 * external debugging tools).
78459191Skris		 * (When someone enables leak checking, but does not call
78559191Skris		 * this function, we declare it to be their fault.)
78659191Skris		 *
78759191Skris		 * XXX    This should be in CRYPTO_mem_leaks_cb,
78859191Skris		 * and CRYPTO_mem_leaks should be implemented by
78959191Skris		 * using CRYPTO_mem_leaks_cb.
790238405Sjkim		 * (Also there should be a variant of lh_doall_arg
79159191Skris		 * that takes a function pointer instead of a void *;
79259191Skris		 * this would obviate the ugly and illegal
79359191Skris		 * void_fn_to_char kludge in CRYPTO_mem_leaks_cb.
79459191Skris		 * Otherwise the code police will come and get us.)
79559191Skris		 */
79672613Skris		int old_mh_mode;
79772613Skris
79859191Skris		CRYPTO_w_lock(CRYPTO_LOCK_MALLOC);
79972613Skris
80072613Skris		/* avoid deadlock when lh_free() uses CRYPTO_dbg_free(),
80172613Skris		 * which uses CRYPTO_is_mem_check_on */
80272613Skris		old_mh_mode = mh_mode;
80372613Skris		mh_mode = CRYPTO_MEM_CHECK_OFF;
80472613Skris
80559191Skris		if (mh != NULL)
80659191Skris			{
807238405Sjkim			lh_MEM_free(mh);
80859191Skris			mh = NULL;
80959191Skris			}
81059191Skris		if (amih != NULL)
81159191Skris			{
812238405Sjkim			if (lh_APP_INFO_num_items(amih) == 0)
81359191Skris				{
814238405Sjkim				lh_APP_INFO_free(amih);
81559191Skris				amih = NULL;
81659191Skris				}
81759191Skris			}
81872613Skris
81972613Skris		mh_mode = old_mh_mode;
82059191Skris		CRYPTO_w_unlock(CRYPTO_LOCK_MALLOC);
82159191Skris		}
82276866Skris	MemCheck_on(); /* release MALLOC2 lock */
82359191Skris	}
82459191Skris
825109998Smarkm#ifndef OPENSSL_NO_FP_API
82659191Skrisvoid CRYPTO_mem_leaks_fp(FILE *fp)
82759191Skris	{
82859191Skris	BIO *b;
82959191Skris
83059191Skris	if (mh == NULL) return;
831109998Smarkm	/* Need to turn off memory checking when allocated BIOs ... especially
832109998Smarkm	 * as we're creating them at a time when we're trying to check we've not
833109998Smarkm	 * left anything un-free()'d!! */
834109998Smarkm	MemCheck_off();
835109998Smarkm	b = BIO_new(BIO_s_file());
836109998Smarkm	MemCheck_on();
837109998Smarkm	if(!b) return;
83859191Skris	BIO_set_fp(b,fp,BIO_NOCLOSE);
83959191Skris	CRYPTO_mem_leaks(b);
84059191Skris	BIO_free(b);
84159191Skris	}
84259191Skris#endif
84359191Skris
84468651Skris
84568651Skris
84668651Skris/* FIXME: We really don't allow much to the callback.  For example, it has
84768651Skris   no chance of reaching the info stack for the item it processes.  Should
84868651Skris   it really be this way?  -- Richard Levitte */
849109998Smarkm/* NB: The prototypes have been typedef'd to CRYPTO_MEM_LEAK_CB inside crypto.h
850109998Smarkm * If this code is restructured, remove the callback type if it is no longer
851109998Smarkm * needed. -- Geoff Thorpe */
852238405Sjkim
853238405Sjkim/* Can't pass CRYPTO_MEM_LEAK_CB directly to lh_MEM_doall_arg because it
854238405Sjkim * is a function pointer and conversion to void * is prohibited. Instead
855238405Sjkim * pass its address
856238405Sjkim */
857238405Sjkim
858238405Sjkimtypedef CRYPTO_MEM_LEAK_CB *PCRYPTO_MEM_LEAK_CB;
859238405Sjkim
860238405Sjkimstatic void cb_leak_doall_arg(const MEM *m, PCRYPTO_MEM_LEAK_CB *cb)
86168651Skris	{
862238405Sjkim	(*cb)(m->order,m->file,m->line,m->num,m->addr);
86368651Skris	}
86468651Skris
865238405Sjkimstatic IMPLEMENT_LHASH_DOALL_ARG_FN(cb_leak, const MEM, PCRYPTO_MEM_LEAK_CB)
866109998Smarkm
867109998Smarkmvoid CRYPTO_mem_leaks_cb(CRYPTO_MEM_LEAK_CB *cb)
86868651Skris	{
86968651Skris	if (mh == NULL) return;
87068651Skris	CRYPTO_w_lock(CRYPTO_LOCK_MALLOC2);
871238405Sjkim	lh_MEM_doall_arg(mh, LHASH_DOALL_ARG_FN(cb_leak), PCRYPTO_MEM_LEAK_CB,
872238405Sjkim			 &cb);
87368651Skris	CRYPTO_w_unlock(CRYPTO_LOCK_MALLOC2);
87468651Skris	}
875