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.
8296341Sdelphij *
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).
15296341Sdelphij *
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.
22296341Sdelphij *
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 :-).
37296341Sdelphij * 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)"
40296341Sdelphij *
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.
52296341Sdelphij *
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
66296341Sdelphij *    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>
114296341Sdelphij#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
121296341Sdelphijstatic int mh_mode = CRYPTO_MEM_CHECK_OFF;
122296341Sdelphij/*
123296341Sdelphij * The state changes to CRYPTO_MEM_CHECK_ON | CRYPTO_MEM_CHECK_ENABLE when
124296341Sdelphij * the application asks for it (usually after library initialisation for
125296341Sdelphij * which no book-keeping is desired). State CRYPTO_MEM_CHECK_ON exists only
126296341Sdelphij * temporarily when the library thinks that certain allocations should not be
127296341Sdelphij * checked (e.g. the data structures used for memory checking).  It is not
128296341Sdelphij * suitable as an initial state: the library will unexpectedly enable memory
129296341Sdelphij * checking when it executes one of those sections that want to disable
130296341Sdelphij * checking temporarily. State CRYPTO_MEM_CHECK_ENABLE without ..._ON makes
131296341Sdelphij * no sense whatsoever.
13259191Skris */
13359191Skris
13459191Skrisstatic unsigned long order = 0; /* number of memory requests */
13559191Skris
136238405SjkimDECLARE_LHASH_OF(MEM);
137296341Sdelphijstatic LHASH_OF(MEM) *mh = NULL; /* hash-table of memory requests (address as
138296341Sdelphij                                  * key); access requires MALLOC2 lock */
13959191Skris
14059191Skristypedef struct app_mem_info_st
141296341Sdelphij/*-
142296341Sdelphij * For application-defined information (static C-string `info')
14359191Skris * to be displayed in memory leak list.
14459191Skris * Each thread has its own stack.  For applications, there is
14559191Skris *   CRYPTO_push_info("...")     to push an entry,
14659191Skris *   CRYPTO_pop_info()           to pop an entry,
14759191Skris *   CRYPTO_remove_all_info()    to pop all entries.
14859191Skris */
149296341Sdelphij{
150296341Sdelphij    CRYPTO_THREADID threadid;
151296341Sdelphij    const char *file;
152296341Sdelphij    int line;
153296341Sdelphij    const char *info;
154296341Sdelphij    struct app_mem_info_st *next; /* tail of thread's stack */
155296341Sdelphij    int references;
156296341Sdelphij} APP_INFO;
15759191Skris
158109998Smarkmstatic void app_info_free(APP_INFO *);
159109998Smarkm
160238405SjkimDECLARE_LHASH_OF(APP_INFO);
161296341Sdelphijstatic LHASH_OF(APP_INFO) *amih = NULL; /* hash-table with those
162296341Sdelphij                                         * app_mem_info_st's that are at the
163296341Sdelphij                                         * top of their thread's stack (with
164296341Sdelphij                                         * `thread' as key); access requires
165296341Sdelphij                                         * MALLOC2 lock */
16659191Skris
16759191Skristypedef struct mem_st
16859191Skris/* memory-block description */
169296341Sdelphij{
170296341Sdelphij    void *addr;
171296341Sdelphij    int num;
172296341Sdelphij    const char *file;
173296341Sdelphij    int line;
174296341Sdelphij    CRYPTO_THREADID threadid;
175296341Sdelphij    unsigned long order;
176296341Sdelphij    time_t time;
177296341Sdelphij    APP_INFO *app_info;
178296341Sdelphij} MEM;
17959191Skris
180296341Sdelphijstatic long options =           /* extra information to be recorded */
18159191Skris#if defined(CRYPTO_MDEBUG_TIME) || defined(CRYPTO_MDEBUG_ALL)
182296341Sdelphij    V_CRYPTO_MDEBUG_TIME |
18359191Skris#endif
18459191Skris#if defined(CRYPTO_MDEBUG_THREAD) || defined(CRYPTO_MDEBUG_ALL)
185296341Sdelphij    V_CRYPTO_MDEBUG_THREAD |
18659191Skris#endif
187296341Sdelphij    0;
18859191Skris
189296341Sdelphijstatic unsigned int num_disable = 0; /* num_disable > 0 iff mh_mode ==
190296341Sdelphij                                      * CRYPTO_MEM_CHECK_ON (w/o ..._ENABLE) */
19159191Skris
192296341Sdelphij/*
193296341Sdelphij * Valid iff num_disable > 0.  CRYPTO_LOCK_MALLOC2 is locked exactly in this
194238405Sjkim * case (by the thread named in disabling_thread).
195238405Sjkim */
196238405Sjkimstatic CRYPTO_THREADID disabling_threadid;
197238405Sjkim
198109998Smarkmstatic void app_info_free(APP_INFO *inf)
199296341Sdelphij{
200296341Sdelphij    if (--(inf->references) <= 0) {
201296341Sdelphij        if (inf->next != NULL) {
202296341Sdelphij            app_info_free(inf->next);
203296341Sdelphij        }
204296341Sdelphij        OPENSSL_free(inf);
205296341Sdelphij    }
206296341Sdelphij}
207109998Smarkm
20859191Skrisint CRYPTO_mem_ctrl(int mode)
209296341Sdelphij{
210296341Sdelphij    int ret = mh_mode;
21159191Skris
212296341Sdelphij    CRYPTO_w_lock(CRYPTO_LOCK_MALLOC);
213296341Sdelphij    switch (mode) {
214296341Sdelphij        /*
215296341Sdelphij         * for applications (not to be called while multiple threads use the
216296341Sdelphij         * library):
217296341Sdelphij         */
218296341Sdelphij    case CRYPTO_MEM_CHECK_ON:  /* aka MemCheck_start() */
219296341Sdelphij        mh_mode = CRYPTO_MEM_CHECK_ON | CRYPTO_MEM_CHECK_ENABLE;
220296341Sdelphij        num_disable = 0;
221296341Sdelphij        break;
222296341Sdelphij    case CRYPTO_MEM_CHECK_OFF: /* aka MemCheck_stop() */
223296341Sdelphij        mh_mode = 0;
224296341Sdelphij        num_disable = 0;        /* should be true *before* MemCheck_stop is
225296341Sdelphij                                 * used, or there'll be a lot of confusion */
226296341Sdelphij        break;
22759191Skris
228296341Sdelphij        /* switch off temporarily (for library-internal use): */
229296341Sdelphij    case CRYPTO_MEM_CHECK_DISABLE: /* aka MemCheck_off() */
230296341Sdelphij        if (mh_mode & CRYPTO_MEM_CHECK_ON) {
231296341Sdelphij            CRYPTO_THREADID cur;
232296341Sdelphij            CRYPTO_THREADID_current(&cur);
233296341Sdelphij            /* see if we don't have the MALLOC2 lock already */
234296341Sdelphij            if (!num_disable
235296341Sdelphij                || CRYPTO_THREADID_cmp(&disabling_threadid, &cur)) {
236296341Sdelphij                /*
237296341Sdelphij                 * Long-time lock CRYPTO_LOCK_MALLOC2 must not be claimed
238296341Sdelphij                 * while we're holding CRYPTO_LOCK_MALLOC, or we'll deadlock
239296341Sdelphij                 * if somebody else holds CRYPTO_LOCK_MALLOC2 (and cannot
240296341Sdelphij                 * release it because we block entry to this function). Give
241296341Sdelphij                 * them a chance, first, and then claim the locks in
242296341Sdelphij                 * appropriate order (long-time lock first).
243296341Sdelphij                 */
244296341Sdelphij                CRYPTO_w_unlock(CRYPTO_LOCK_MALLOC);
245296341Sdelphij                /*
246296341Sdelphij                 * Note that after we have waited for CRYPTO_LOCK_MALLOC2 and
247296341Sdelphij                 * CRYPTO_LOCK_MALLOC, we'll still be in the right "case" and
248296341Sdelphij                 * "if" branch because MemCheck_start and MemCheck_stop may
249296341Sdelphij                 * never be used while there are multiple OpenSSL threads.
250296341Sdelphij                 */
251296341Sdelphij                CRYPTO_w_lock(CRYPTO_LOCK_MALLOC2);
252296341Sdelphij                CRYPTO_w_lock(CRYPTO_LOCK_MALLOC);
253296341Sdelphij                mh_mode &= ~CRYPTO_MEM_CHECK_ENABLE;
254296341Sdelphij                CRYPTO_THREADID_cpy(&disabling_threadid, &cur);
255296341Sdelphij            }
256296341Sdelphij            num_disable++;
257296341Sdelphij        }
258296341Sdelphij        break;
259296341Sdelphij    case CRYPTO_MEM_CHECK_ENABLE: /* aka MemCheck_on() */
260296341Sdelphij        if (mh_mode & CRYPTO_MEM_CHECK_ON) {
261296341Sdelphij            if (num_disable) {  /* always true, or something is going wrong */
262296341Sdelphij                num_disable--;
263296341Sdelphij                if (num_disable == 0) {
264296341Sdelphij                    mh_mode |= CRYPTO_MEM_CHECK_ENABLE;
265296341Sdelphij                    CRYPTO_w_unlock(CRYPTO_LOCK_MALLOC2);
266296341Sdelphij                }
267296341Sdelphij            }
268296341Sdelphij        }
269296341Sdelphij        break;
27059191Skris
271296341Sdelphij    default:
272296341Sdelphij        break;
273296341Sdelphij    }
274296341Sdelphij    CRYPTO_w_unlock(CRYPTO_LOCK_MALLOC);
275296341Sdelphij    return (ret);
276296341Sdelphij}
27759191Skris
27859191Skrisint CRYPTO_is_mem_check_on(void)
279296341Sdelphij{
280296341Sdelphij    int ret = 0;
28159191Skris
282296341Sdelphij    if (mh_mode & CRYPTO_MEM_CHECK_ON) {
283296341Sdelphij        CRYPTO_THREADID cur;
284296341Sdelphij        CRYPTO_THREADID_current(&cur);
285296341Sdelphij        CRYPTO_r_lock(CRYPTO_LOCK_MALLOC);
28659191Skris
287296341Sdelphij        ret = (mh_mode & CRYPTO_MEM_CHECK_ENABLE)
288296341Sdelphij            || CRYPTO_THREADID_cmp(&disabling_threadid, &cur);
28959191Skris
290296341Sdelphij        CRYPTO_r_unlock(CRYPTO_LOCK_MALLOC);
291296341Sdelphij    }
292296341Sdelphij    return (ret);
293296341Sdelphij}
29459191Skris
29559191Skrisvoid CRYPTO_dbg_set_options(long bits)
296296341Sdelphij{
297296341Sdelphij    options = bits;
298296341Sdelphij}
29959191Skris
30059191Skrislong CRYPTO_dbg_get_options(void)
301296341Sdelphij{
302296341Sdelphij    return options;
303296341Sdelphij}
30459191Skris
305238405Sjkimstatic int mem_cmp(const MEM *a, const MEM *b)
306296341Sdelphij{
307160814Ssimon#ifdef _WIN64
308296341Sdelphij    const char *ap = (const char *)a->addr, *bp = (const char *)b->addr;
309296341Sdelphij    if (ap == bp)
310296341Sdelphij        return 0;
311296341Sdelphij    else if (ap > bp)
312296341Sdelphij        return 1;
313296341Sdelphij    else
314296341Sdelphij        return -1;
315160814Ssimon#else
316296341Sdelphij    return (const char *)a->addr - (const char *)b->addr;
317160814Ssimon#endif
318296341Sdelphij}
319296341Sdelphij
320238405Sjkimstatic IMPLEMENT_LHASH_COMP_FN(mem, MEM)
32159191Skris
322238405Sjkimstatic unsigned long mem_hash(const MEM *a)
323296341Sdelphij{
324296341Sdelphij    unsigned long ret;
32559191Skris
326296341Sdelphij    ret = (unsigned long)a->addr;
32759191Skris
328296341Sdelphij    ret = ret * 17851 + (ret >> 14) * 7 + (ret >> 4) * 251;
329296341Sdelphij    return (ret);
330296341Sdelphij}
331296341Sdelphij
332238405Sjkimstatic IMPLEMENT_LHASH_HASH_FN(mem, MEM)
33359191Skris
334109998Smarkm/* static int app_info_cmp(APP_INFO *a, APP_INFO *b) */
335109998Smarkmstatic int app_info_cmp(const void *a_void, const void *b_void)
336296341Sdelphij{
337296341Sdelphij    return CRYPTO_THREADID_cmp(&((const APP_INFO *)a_void)->threadid,
338296341Sdelphij                               &((const APP_INFO *)b_void)->threadid);
339296341Sdelphij}
340296341Sdelphij
341238405Sjkimstatic IMPLEMENT_LHASH_COMP_FN(app_info, APP_INFO)
34259191Skris
343238405Sjkimstatic unsigned long app_info_hash(const APP_INFO *a)
344296341Sdelphij{
345296341Sdelphij    unsigned long ret;
34659191Skris
347296341Sdelphij    ret = CRYPTO_THREADID_hash(&a->threadid);
348296341Sdelphij    /* This is left in as a "who am I to question legacy?" measure */
349296341Sdelphij    ret = ret * 17851 + (ret >> 14) * 7 + (ret >> 4) * 251;
350296341Sdelphij    return (ret);
351296341Sdelphij}
352296341Sdelphij
353238405Sjkimstatic IMPLEMENT_LHASH_HASH_FN(app_info, APP_INFO)
35459191Skris
355109998Smarkmstatic APP_INFO *pop_info(void)
356296341Sdelphij{
357296341Sdelphij    APP_INFO tmp;
358296341Sdelphij    APP_INFO *ret = NULL;
35959191Skris
360296341Sdelphij    if (amih != NULL) {
361296341Sdelphij        CRYPTO_THREADID_current(&tmp.threadid);
362296341Sdelphij        if ((ret = lh_APP_INFO_delete(amih, &tmp)) != NULL) {
363296341Sdelphij            APP_INFO *next = ret->next;
36459191Skris
365296341Sdelphij            if (next != NULL) {
366296341Sdelphij                next->references++;
367296341Sdelphij                (void)lh_APP_INFO_insert(amih, next);
368296341Sdelphij            }
369109998Smarkm#ifdef LEVITTE_DEBUG_MEM
370296341Sdelphij            if (CRYPTO_THREADID_cmp(&ret->threadid, &tmp.threadid)) {
371296341Sdelphij                fprintf(stderr,
372296341Sdelphij                        "pop_info(): deleted info has other thread ID (%lu) than the current thread (%lu)!!!!\n",
373296341Sdelphij                        CRYPTO_THREADID_hash(&ret->threadid),
374296341Sdelphij                        CRYPTO_THREADID_hash(&tmp.threadid));
375296341Sdelphij                abort();
376296341Sdelphij            }
37759191Skris#endif
378296341Sdelphij            if (--(ret->references) <= 0) {
379296341Sdelphij                ret->next = NULL;
380296341Sdelphij                if (next != NULL)
381296341Sdelphij                    next->references--;
382296341Sdelphij                OPENSSL_free(ret);
383296341Sdelphij            }
384296341Sdelphij        }
385296341Sdelphij    }
386296341Sdelphij    return (ret);
387296341Sdelphij}
38859191Skris
389238405Sjkimint CRYPTO_push_info_(const char *info, const char *file, int line)
390296341Sdelphij{
391296341Sdelphij    APP_INFO *ami, *amim;
392296341Sdelphij    int ret = 0;
39359191Skris
394296341Sdelphij    if (is_MemCheck_on()) {
395296341Sdelphij        MemCheck_off();         /* obtain MALLOC2 lock */
39659191Skris
397296341Sdelphij        if ((ami = (APP_INFO *)OPENSSL_malloc(sizeof(APP_INFO))) == NULL) {
398296341Sdelphij            ret = 0;
399296341Sdelphij            goto err;
400296341Sdelphij        }
401296341Sdelphij        if (amih == NULL) {
402296341Sdelphij            if ((amih = lh_APP_INFO_new()) == NULL) {
403296341Sdelphij                OPENSSL_free(ami);
404296341Sdelphij                ret = 0;
405296341Sdelphij                goto err;
406296341Sdelphij            }
407296341Sdelphij        }
40859191Skris
409296341Sdelphij        CRYPTO_THREADID_current(&ami->threadid);
410296341Sdelphij        ami->file = file;
411296341Sdelphij        ami->line = line;
412296341Sdelphij        ami->info = info;
413296341Sdelphij        ami->references = 1;
414296341Sdelphij        ami->next = NULL;
41559191Skris
416296341Sdelphij        if ((amim = lh_APP_INFO_insert(amih, ami)) != NULL) {
417109998Smarkm#ifdef LEVITTE_DEBUG_MEM
418296341Sdelphij            if (CRYPTO_THREADID_cmp(&ami->threadid, &amim->threadid)) {
419296341Sdelphij                fprintf(stderr,
420296341Sdelphij                        "CRYPTO_push_info(): previous info has other thread ID (%lu) than the current thread (%lu)!!!!\n",
421296341Sdelphij                        CRYPTO_THREADID_hash(&amim->threadid),
422296341Sdelphij                        CRYPTO_THREADID_hash(&ami->threadid));
423296341Sdelphij                abort();
424296341Sdelphij            }
42559191Skris#endif
426296341Sdelphij            ami->next = amim;
427296341Sdelphij        }
42859191Skris err:
429296341Sdelphij        MemCheck_on();          /* release MALLOC2 lock */
430296341Sdelphij    }
43159191Skris
432296341Sdelphij    return (ret);
433296341Sdelphij}
43459191Skris
435238405Sjkimint CRYPTO_pop_info(void)
436296341Sdelphij{
437296341Sdelphij    int ret = 0;
43859191Skris
439296341Sdelphij    if (is_MemCheck_on()) {     /* _must_ be true, or something went severely
440296341Sdelphij                                 * wrong */
441296341Sdelphij        MemCheck_off();         /* obtain MALLOC2 lock */
44259191Skris
443296341Sdelphij        ret = (pop_info() != NULL);
44459191Skris
445296341Sdelphij        MemCheck_on();          /* release MALLOC2 lock */
446296341Sdelphij    }
447296341Sdelphij    return (ret);
448296341Sdelphij}
44959191Skris
450238405Sjkimint CRYPTO_remove_all_info(void)
451296341Sdelphij{
452296341Sdelphij    int ret = 0;
45359191Skris
454296341Sdelphij    if (is_MemCheck_on()) {     /* _must_ be true */
455296341Sdelphij        MemCheck_off();         /* obtain MALLOC2 lock */
45659191Skris
457296341Sdelphij        while (pop_info() != NULL)
458296341Sdelphij            ret++;
45959191Skris
460296341Sdelphij        MemCheck_on();          /* release MALLOC2 lock */
461296341Sdelphij    }
462296341Sdelphij    return (ret);
463296341Sdelphij}
46459191Skris
465296341Sdelphijstatic unsigned long break_order_num = 0;
46659191Skrisvoid CRYPTO_dbg_malloc(void *addr, int num, const char *file, int line,
467296341Sdelphij                       int before_p)
468296341Sdelphij{
469296341Sdelphij    MEM *m, *mm;
470296341Sdelphij    APP_INFO tmp, *amim;
47159191Skris
472296341Sdelphij    switch (before_p & 127) {
473296341Sdelphij    case 0:
474296341Sdelphij        break;
475296341Sdelphij    case 1:
476296341Sdelphij        if (addr == NULL)
477296341Sdelphij            break;
47859191Skris
479296341Sdelphij        if (is_MemCheck_on()) {
480296341Sdelphij            MemCheck_off();     /* make sure we hold MALLOC2 lock */
481296341Sdelphij            if ((m = (MEM *)OPENSSL_malloc(sizeof(MEM))) == NULL) {
482296341Sdelphij                OPENSSL_free(addr);
483296341Sdelphij                MemCheck_on();  /* release MALLOC2 lock if num_disabled drops
484296341Sdelphij                                 * to 0 */
485296341Sdelphij                return;
486296341Sdelphij            }
487296341Sdelphij            if (mh == NULL) {
488296341Sdelphij                if ((mh = lh_MEM_new()) == NULL) {
489296341Sdelphij                    OPENSSL_free(addr);
490296341Sdelphij                    OPENSSL_free(m);
491296341Sdelphij                    addr = NULL;
492296341Sdelphij                    goto err;
493296341Sdelphij                }
494296341Sdelphij            }
49559191Skris
496296341Sdelphij            m->addr = addr;
497296341Sdelphij            m->file = file;
498296341Sdelphij            m->line = line;
499296341Sdelphij            m->num = num;
500296341Sdelphij            if (options & V_CRYPTO_MDEBUG_THREAD)
501296341Sdelphij                CRYPTO_THREADID_current(&m->threadid);
502296341Sdelphij            else
503296341Sdelphij                memset(&m->threadid, 0, sizeof(m->threadid));
50459191Skris
505296341Sdelphij            if (order == break_order_num) {
506296341Sdelphij                /* BREAK HERE */
507296341Sdelphij                m->order = order;
508296341Sdelphij            }
509296341Sdelphij            m->order = order++;
510109998Smarkm#ifdef LEVITTE_DEBUG_MEM
511296341Sdelphij            fprintf(stderr, "LEVITTE_DEBUG_MEM: [%5ld] %c 0x%p (%d)\n",
512296341Sdelphij                    m->order, (before_p & 128) ? '*' : '+', m->addr, m->num);
51359191Skris#endif
514296341Sdelphij            if (options & V_CRYPTO_MDEBUG_TIME)
515296341Sdelphij                m->time = time(NULL);
516296341Sdelphij            else
517296341Sdelphij                m->time = 0;
51859191Skris
519296341Sdelphij            CRYPTO_THREADID_current(&tmp.threadid);
520296341Sdelphij            m->app_info = NULL;
521296341Sdelphij            if (amih != NULL
522296341Sdelphij                && (amim = lh_APP_INFO_retrieve(amih, &tmp)) != NULL) {
523296341Sdelphij                m->app_info = amim;
524296341Sdelphij                amim->references++;
525296341Sdelphij            }
52659191Skris
527296341Sdelphij            if ((mm = lh_MEM_insert(mh, m)) != NULL) {
528296341Sdelphij                /* Not good, but don't sweat it */
529296341Sdelphij                if (mm->app_info != NULL) {
530296341Sdelphij                    mm->app_info->references--;
531296341Sdelphij                }
532296341Sdelphij                OPENSSL_free(mm);
533296341Sdelphij            }
534296341Sdelphij err:
535296341Sdelphij            MemCheck_on();      /* release MALLOC2 lock if num_disabled drops
536296341Sdelphij                                 * to 0 */
537296341Sdelphij        }
538296341Sdelphij        break;
539296341Sdelphij    }
540296341Sdelphij    return;
541296341Sdelphij}
54259191Skris
54359191Skrisvoid CRYPTO_dbg_free(void *addr, int before_p)
544296341Sdelphij{
545296341Sdelphij    MEM m, *mp;
54659191Skris
547296341Sdelphij    switch (before_p) {
548296341Sdelphij    case 0:
549296341Sdelphij        if (addr == NULL)
550296341Sdelphij            break;
55159191Skris
552296341Sdelphij        if (is_MemCheck_on() && (mh != NULL)) {
553296341Sdelphij            MemCheck_off();     /* make sure we hold MALLOC2 lock */
55459191Skris
555296341Sdelphij            m.addr = addr;
556296341Sdelphij            mp = lh_MEM_delete(mh, &m);
557296341Sdelphij            if (mp != NULL) {
558109998Smarkm#ifdef LEVITTE_DEBUG_MEM
559296341Sdelphij                fprintf(stderr, "LEVITTE_DEBUG_MEM: [%5ld] - 0x%p (%d)\n",
560296341Sdelphij                        mp->order, mp->addr, mp->num);
56159191Skris#endif
562296341Sdelphij                if (mp->app_info != NULL)
563296341Sdelphij                    app_info_free(mp->app_info);
564296341Sdelphij                OPENSSL_free(mp);
565296341Sdelphij            }
56659191Skris
567296341Sdelphij            MemCheck_on();      /* release MALLOC2 lock if num_disabled drops
568296341Sdelphij                                 * to 0 */
569296341Sdelphij        }
570296341Sdelphij        break;
571296341Sdelphij    case 1:
572296341Sdelphij        break;
573296341Sdelphij    }
574296341Sdelphij}
57559191Skris
57659191Skrisvoid CRYPTO_dbg_realloc(void *addr1, void *addr2, int num,
577296341Sdelphij                        const char *file, int line, int before_p)
578296341Sdelphij{
579296341Sdelphij    MEM m, *mp;
58059191Skris
581109998Smarkm#ifdef LEVITTE_DEBUG_MEM
582296341Sdelphij    fprintf(stderr,
583296341Sdelphij            "LEVITTE_DEBUG_MEM: --> CRYPTO_dbg_malloc(addr1 = %p, addr2 = %p, num = %d, file = \"%s\", line = %d, before_p = %d)\n",
584296341Sdelphij            addr1, addr2, num, file, line, before_p);
58559191Skris#endif
58659191Skris
587296341Sdelphij    switch (before_p) {
588296341Sdelphij    case 0:
589296341Sdelphij        break;
590296341Sdelphij    case 1:
591296341Sdelphij        if (addr2 == NULL)
592296341Sdelphij            break;
59359191Skris
594296341Sdelphij        if (addr1 == NULL) {
595296341Sdelphij            CRYPTO_dbg_malloc(addr2, num, file, line, 128 | before_p);
596296341Sdelphij            break;
597296341Sdelphij        }
59859191Skris
599296341Sdelphij        if (is_MemCheck_on()) {
600296341Sdelphij            MemCheck_off();     /* make sure we hold MALLOC2 lock */
60159191Skris
602296341Sdelphij            m.addr = addr1;
603296341Sdelphij            mp = lh_MEM_delete(mh, &m);
604296341Sdelphij            if (mp != NULL) {
605109998Smarkm#ifdef LEVITTE_DEBUG_MEM
606296341Sdelphij                fprintf(stderr,
607296341Sdelphij                        "LEVITTE_DEBUG_MEM: [%5ld] * 0x%p (%d) -> 0x%p (%d)\n",
608296341Sdelphij                        mp->order, mp->addr, mp->num, addr2, num);
60959191Skris#endif
610296341Sdelphij                mp->addr = addr2;
611296341Sdelphij                mp->num = num;
612296341Sdelphij                (void)lh_MEM_insert(mh, mp);
613296341Sdelphij            }
61459191Skris
615296341Sdelphij            MemCheck_on();      /* release MALLOC2 lock if num_disabled drops
616296341Sdelphij                                 * to 0 */
617296341Sdelphij        }
618296341Sdelphij        break;
619296341Sdelphij    }
620296341Sdelphij    return;
621296341Sdelphij}
62259191Skris
623296341Sdelphijtypedef struct mem_leak_st {
624296341Sdelphij    BIO *bio;
625296341Sdelphij    int chunks;
626296341Sdelphij    long bytes;
627296341Sdelphij} MEM_LEAK;
62859191Skris
629238405Sjkimstatic void print_leak_doall_arg(const MEM *m, MEM_LEAK *l)
630296341Sdelphij{
631296341Sdelphij    char buf[1024];
632296341Sdelphij    char *bufp = buf;
633296341Sdelphij    APP_INFO *amip;
634296341Sdelphij    int ami_cnt;
635296341Sdelphij    struct tm *lcl = NULL;
636296341Sdelphij    CRYPTO_THREADID ti;
63759191Skris
638127128Snectar#define BUF_REMAIN (sizeof buf - (size_t)(bufp - buf))
639127128Snectar
640296341Sdelphij    if (m->addr == (char *)l->bio)
641296341Sdelphij        return;
64259191Skris
643296341Sdelphij    if (options & V_CRYPTO_MDEBUG_TIME) {
644296341Sdelphij        lcl = localtime(&m->time);
64559191Skris
646296341Sdelphij        BIO_snprintf(bufp, BUF_REMAIN, "[%02d:%02d:%02d] ",
647296341Sdelphij                     lcl->tm_hour, lcl->tm_min, lcl->tm_sec);
648296341Sdelphij        bufp += strlen(bufp);
649296341Sdelphij    }
65059191Skris
651296341Sdelphij    BIO_snprintf(bufp, BUF_REMAIN, "%5lu file=%s, line=%d, ",
652296341Sdelphij                 m->order, m->file, m->line);
653296341Sdelphij    bufp += strlen(bufp);
65459191Skris
655296341Sdelphij    if (options & V_CRYPTO_MDEBUG_THREAD) {
656296341Sdelphij        BIO_snprintf(bufp, BUF_REMAIN, "thread=%lu, ",
657296341Sdelphij                     CRYPTO_THREADID_hash(&m->threadid));
658296341Sdelphij        bufp += strlen(bufp);
659296341Sdelphij    }
66059191Skris
661296341Sdelphij    BIO_snprintf(bufp, BUF_REMAIN, "number=%d, address=%08lX\n",
662296341Sdelphij                 m->num, (unsigned long)m->addr);
663296341Sdelphij    bufp += strlen(bufp);
66459191Skris
665296341Sdelphij    BIO_puts(l->bio, buf);
666238405Sjkim
667296341Sdelphij    l->chunks++;
668296341Sdelphij    l->bytes += m->num;
66959191Skris
670296341Sdelphij    amip = m->app_info;
671296341Sdelphij    ami_cnt = 0;
672296341Sdelphij    if (!amip)
673296341Sdelphij        return;
674296341Sdelphij    CRYPTO_THREADID_cpy(&ti, &amip->threadid);
67559191Skris
676296341Sdelphij    do {
677296341Sdelphij        int buf_len;
678296341Sdelphij        int info_len;
679238405Sjkim
680296341Sdelphij        ami_cnt++;
681296341Sdelphij        memset(buf, '>', ami_cnt);
682296341Sdelphij        BIO_snprintf(buf + ami_cnt, sizeof buf - ami_cnt,
683296341Sdelphij                     " thread=%lu, file=%s, line=%d, info=\"",
684296341Sdelphij                     CRYPTO_THREADID_hash(&amip->threadid), amip->file,
685296341Sdelphij                     amip->line);
686296341Sdelphij        buf_len = strlen(buf);
687296341Sdelphij        info_len = strlen(amip->info);
688296341Sdelphij        if (128 - buf_len - 3 < info_len) {
689296341Sdelphij            memcpy(buf + buf_len, amip->info, 128 - buf_len - 3);
690296341Sdelphij            buf_len = 128 - 3;
691296341Sdelphij        } else {
692296341Sdelphij            BUF_strlcpy(buf + buf_len, amip->info, sizeof buf - buf_len);
693296341Sdelphij            buf_len = strlen(buf);
694296341Sdelphij        }
695296341Sdelphij        BIO_snprintf(buf + buf_len, sizeof buf - buf_len, "\"\n");
696296341Sdelphij
697296341Sdelphij        BIO_puts(l->bio, buf);
698296341Sdelphij
699296341Sdelphij        amip = amip->next;
700296341Sdelphij    }
701296341Sdelphij    while (amip && !CRYPTO_THREADID_cmp(&amip->threadid, &ti));
702296341Sdelphij
703109998Smarkm#ifdef LEVITTE_DEBUG_MEM
704296341Sdelphij    if (amip) {
705296341Sdelphij        fprintf(stderr, "Thread switch detected in backtrace!!!!\n");
706296341Sdelphij        abort();
707296341Sdelphij    }
70859191Skris#endif
709296341Sdelphij}
71059191Skris
711238405Sjkimstatic IMPLEMENT_LHASH_DOALL_ARG_FN(print_leak, const MEM, MEM_LEAK)
712109998Smarkm
71359191Skrisvoid CRYPTO_mem_leaks(BIO *b)
714296341Sdelphij{
715296341Sdelphij    MEM_LEAK ml;
71659191Skris
717296341Sdelphij    if (mh == NULL && amih == NULL)
718296341Sdelphij        return;
71976866Skris
720296341Sdelphij    MemCheck_off();             /* obtain MALLOC2 lock */
72176866Skris
722296341Sdelphij    ml.bio = b;
723296341Sdelphij    ml.bytes = 0;
724296341Sdelphij    ml.chunks = 0;
725296341Sdelphij    if (mh != NULL)
726296341Sdelphij        lh_MEM_doall_arg(mh, LHASH_DOALL_ARG_FN(print_leak), MEM_LEAK, &ml);
727296341Sdelphij    if (ml.chunks != 0) {
728296341Sdelphij        BIO_printf(b, "%ld bytes leaked in %d chunks\n", ml.bytes, ml.chunks);
729238405Sjkim#ifdef CRYPTO_MDEBUG_ABORT
730296341Sdelphij        abort();
731238405Sjkim#endif
732296341Sdelphij    } else {
733296341Sdelphij        /*
734296341Sdelphij         * Make sure that, if we found no leaks, memory-leak debugging itself
735296341Sdelphij         * does not introduce memory leaks (which might irritate external
736296341Sdelphij         * debugging tools). (When someone enables leak checking, but does not
737296341Sdelphij         * call this function, we declare it to be their fault.) XXX This
738296341Sdelphij         * should be in CRYPTO_mem_leaks_cb, and CRYPTO_mem_leaks should be
739296341Sdelphij         * implemented by using CRYPTO_mem_leaks_cb. (Also there should be a
740296341Sdelphij         * variant of lh_doall_arg that takes a function pointer instead of a
741296341Sdelphij         * void *; this would obviate the ugly and illegal void_fn_to_char
742296341Sdelphij         * kludge in CRYPTO_mem_leaks_cb. Otherwise the code police will come
743296341Sdelphij         * and get us.)
744296341Sdelphij         */
745296341Sdelphij        int old_mh_mode;
74672613Skris
747296341Sdelphij        CRYPTO_w_lock(CRYPTO_LOCK_MALLOC);
74872613Skris
749296341Sdelphij        /*
750296341Sdelphij         * avoid deadlock when lh_free() uses CRYPTO_dbg_free(), which uses
751296341Sdelphij         * CRYPTO_is_mem_check_on
752296341Sdelphij         */
753296341Sdelphij        old_mh_mode = mh_mode;
754296341Sdelphij        mh_mode = CRYPTO_MEM_CHECK_OFF;
75572613Skris
756296341Sdelphij        if (mh != NULL) {
757296341Sdelphij            lh_MEM_free(mh);
758296341Sdelphij            mh = NULL;
759296341Sdelphij        }
760296341Sdelphij        if (amih != NULL) {
761296341Sdelphij            if (lh_APP_INFO_num_items(amih) == 0) {
762296341Sdelphij                lh_APP_INFO_free(amih);
763296341Sdelphij                amih = NULL;
764296341Sdelphij            }
765296341Sdelphij        }
76672613Skris
767296341Sdelphij        mh_mode = old_mh_mode;
768296341Sdelphij        CRYPTO_w_unlock(CRYPTO_LOCK_MALLOC);
769296341Sdelphij    }
770296341Sdelphij    MemCheck_on();              /* release MALLOC2 lock */
771296341Sdelphij}
77259191Skris
773109998Smarkm#ifndef OPENSSL_NO_FP_API
77459191Skrisvoid CRYPTO_mem_leaks_fp(FILE *fp)
775296341Sdelphij{
776296341Sdelphij    BIO *b;
77759191Skris
778296341Sdelphij    if (mh == NULL)
779296341Sdelphij        return;
780296341Sdelphij    /*
781296341Sdelphij     * Need to turn off memory checking when allocated BIOs ... especially as
782296341Sdelphij     * we're creating them at a time when we're trying to check we've not
783296341Sdelphij     * left anything un-free()'d!!
784296341Sdelphij     */
785296341Sdelphij    MemCheck_off();
786296341Sdelphij    b = BIO_new(BIO_s_file());
787296341Sdelphij    MemCheck_on();
788296341Sdelphij    if (!b)
789296341Sdelphij        return;
790296341Sdelphij    BIO_set_fp(b, fp, BIO_NOCLOSE);
791296341Sdelphij    CRYPTO_mem_leaks(b);
792296341Sdelphij    BIO_free(b);
793296341Sdelphij}
79459191Skris#endif
79559191Skris
796296341Sdelphij/*
797296341Sdelphij * FIXME: We really don't allow much to the callback.  For example, it has no
798296341Sdelphij * chance of reaching the info stack for the item it processes.  Should it
799296341Sdelphij * really be this way? -- Richard Levitte
800296341Sdelphij */
801296341Sdelphij/*
802296341Sdelphij * NB: The prototypes have been typedef'd to CRYPTO_MEM_LEAK_CB inside
803296341Sdelphij * crypto.h If this code is restructured, remove the callback type if it is
804296341Sdelphij * no longer needed. -- Geoff Thorpe
805296341Sdelphij */
80668651Skris
807296341Sdelphij/*
808296341Sdelphij * Can't pass CRYPTO_MEM_LEAK_CB directly to lh_MEM_doall_arg because it is a
809296341Sdelphij * function pointer and conversion to void * is prohibited. Instead pass its
810296341Sdelphij * address
811238405Sjkim */
812238405Sjkim
813238405Sjkimtypedef CRYPTO_MEM_LEAK_CB *PCRYPTO_MEM_LEAK_CB;
814238405Sjkim
815238405Sjkimstatic void cb_leak_doall_arg(const MEM *m, PCRYPTO_MEM_LEAK_CB *cb)
816296341Sdelphij{
817296341Sdelphij    (*cb) (m->order, m->file, m->line, m->num, m->addr);
818296341Sdelphij}
81968651Skris
820238405Sjkimstatic IMPLEMENT_LHASH_DOALL_ARG_FN(cb_leak, const MEM, PCRYPTO_MEM_LEAK_CB)
821109998Smarkm
822109998Smarkmvoid CRYPTO_mem_leaks_cb(CRYPTO_MEM_LEAK_CB *cb)
823296341Sdelphij{
824296341Sdelphij    if (mh == NULL)
825296341Sdelphij        return;
826296341Sdelphij    CRYPTO_w_lock(CRYPTO_LOCK_MALLOC2);
827296341Sdelphij    lh_MEM_doall_arg(mh, LHASH_DOALL_ARG_FN(cb_leak), PCRYPTO_MEM_LEAK_CB,
828296341Sdelphij                     &cb);
829296341Sdelphij    CRYPTO_w_unlock(CRYPTO_LOCK_MALLOC2);
830296341Sdelphij}
831