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.
8280304Sjkim *
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).
15280304Sjkim *
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.
22280304Sjkim *
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 :-).
37280304Sjkim * 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)"
40280304Sjkim *
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.
52280304Sjkim *
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
66280304Sjkim *    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>
114280304Sjkim#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
121280304Sjkimstatic int mh_mode = CRYPTO_MEM_CHECK_OFF;
122280304Sjkim/*
123280304Sjkim * The state changes to CRYPTO_MEM_CHECK_ON | CRYPTO_MEM_CHECK_ENABLE when
124280304Sjkim * the application asks for it (usually after library initialisation for
125280304Sjkim * which no book-keeping is desired). State CRYPTO_MEM_CHECK_ON exists only
126280304Sjkim * temporarily when the library thinks that certain allocations should not be
127280304Sjkim * checked (e.g. the data structures used for memory checking).  It is not
128280304Sjkim * suitable as an initial state: the library will unexpectedly enable memory
129280304Sjkim * checking when it executes one of those sections that want to disable
130280304Sjkim * checking temporarily. State CRYPTO_MEM_CHECK_ENABLE without ..._ON makes
131280304Sjkim * no sense whatsoever.
13259191Skris */
13359191Skris
13459191Skrisstatic unsigned long order = 0; /* number of memory requests */
13559191Skris
136238405SjkimDECLARE_LHASH_OF(MEM);
137280304Sjkimstatic LHASH_OF(MEM) *mh = NULL; /* hash-table of memory requests (address as
138280304Sjkim                                  * key); access requires MALLOC2 lock */
13959191Skris
14059191Skristypedef struct app_mem_info_st
141280304Sjkim/*-
142280304Sjkim * 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 */
149280304Sjkim{
150280304Sjkim    CRYPTO_THREADID threadid;
151280304Sjkim    const char *file;
152280304Sjkim    int line;
153280304Sjkim    const char *info;
154280304Sjkim    struct app_mem_info_st *next; /* tail of thread's stack */
155280304Sjkim    int references;
156280304Sjkim} APP_INFO;
15759191Skris
158109998Smarkmstatic void app_info_free(APP_INFO *);
159109998Smarkm
160238405SjkimDECLARE_LHASH_OF(APP_INFO);
161280304Sjkimstatic LHASH_OF(APP_INFO) *amih = NULL; /* hash-table with those
162280304Sjkim                                         * app_mem_info_st's that are at the
163280304Sjkim                                         * top of their thread's stack (with
164280304Sjkim                                         * `thread' as key); access requires
165280304Sjkim                                         * MALLOC2 lock */
16659191Skris
16759191Skristypedef struct mem_st
16859191Skris/* memory-block description */
169280304Sjkim{
170280304Sjkim    void *addr;
171280304Sjkim    int num;
172280304Sjkim    const char *file;
173280304Sjkim    int line;
174280304Sjkim    CRYPTO_THREADID threadid;
175280304Sjkim    unsigned long order;
176280304Sjkim    time_t time;
177280304Sjkim    APP_INFO *app_info;
178280304Sjkim} MEM;
17959191Skris
180280304Sjkimstatic long options =           /* extra information to be recorded */
18159191Skris#if defined(CRYPTO_MDEBUG_TIME) || defined(CRYPTO_MDEBUG_ALL)
182280304Sjkim    V_CRYPTO_MDEBUG_TIME |
18359191Skris#endif
18459191Skris#if defined(CRYPTO_MDEBUG_THREAD) || defined(CRYPTO_MDEBUG_ALL)
185280304Sjkim    V_CRYPTO_MDEBUG_THREAD |
18659191Skris#endif
187280304Sjkim    0;
18859191Skris
189280304Sjkimstatic unsigned int num_disable = 0; /* num_disable > 0 iff mh_mode ==
190280304Sjkim                                      * CRYPTO_MEM_CHECK_ON (w/o ..._ENABLE) */
19159191Skris
192280304Sjkim/*
193280304Sjkim * 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)
199280304Sjkim{
200280304Sjkim    if (--(inf->references) <= 0) {
201280304Sjkim        if (inf->next != NULL) {
202280304Sjkim            app_info_free(inf->next);
203280304Sjkim        }
204280304Sjkim        OPENSSL_free(inf);
205280304Sjkim    }
206280304Sjkim}
207109998Smarkm
20859191Skrisint CRYPTO_mem_ctrl(int mode)
209280304Sjkim{
210280304Sjkim    int ret = mh_mode;
21159191Skris
212280304Sjkim    CRYPTO_w_lock(CRYPTO_LOCK_MALLOC);
213280304Sjkim    switch (mode) {
214280304Sjkim        /*
215280304Sjkim         * for applications (not to be called while multiple threads use the
216280304Sjkim         * library):
217280304Sjkim         */
218280304Sjkim    case CRYPTO_MEM_CHECK_ON:  /* aka MemCheck_start() */
219280304Sjkim        mh_mode = CRYPTO_MEM_CHECK_ON | CRYPTO_MEM_CHECK_ENABLE;
220280304Sjkim        num_disable = 0;
221280304Sjkim        break;
222280304Sjkim    case CRYPTO_MEM_CHECK_OFF: /* aka MemCheck_stop() */
223280304Sjkim        mh_mode = 0;
224280304Sjkim        num_disable = 0;        /* should be true *before* MemCheck_stop is
225280304Sjkim                                 * used, or there'll be a lot of confusion */
226280304Sjkim        break;
22759191Skris
228280304Sjkim        /* switch off temporarily (for library-internal use): */
229280304Sjkim    case CRYPTO_MEM_CHECK_DISABLE: /* aka MemCheck_off() */
230280304Sjkim        if (mh_mode & CRYPTO_MEM_CHECK_ON) {
231280304Sjkim            CRYPTO_THREADID cur;
232280304Sjkim            CRYPTO_THREADID_current(&cur);
233280304Sjkim            /* see if we don't have the MALLOC2 lock already */
234280304Sjkim            if (!num_disable
235280304Sjkim                || CRYPTO_THREADID_cmp(&disabling_threadid, &cur)) {
236280304Sjkim                /*
237280304Sjkim                 * Long-time lock CRYPTO_LOCK_MALLOC2 must not be claimed
238280304Sjkim                 * while we're holding CRYPTO_LOCK_MALLOC, or we'll deadlock
239280304Sjkim                 * if somebody else holds CRYPTO_LOCK_MALLOC2 (and cannot
240280304Sjkim                 * release it because we block entry to this function). Give
241280304Sjkim                 * them a chance, first, and then claim the locks in
242280304Sjkim                 * appropriate order (long-time lock first).
243280304Sjkim                 */
244280304Sjkim                CRYPTO_w_unlock(CRYPTO_LOCK_MALLOC);
245280304Sjkim                /*
246280304Sjkim                 * Note that after we have waited for CRYPTO_LOCK_MALLOC2 and
247280304Sjkim                 * CRYPTO_LOCK_MALLOC, we'll still be in the right "case" and
248280304Sjkim                 * "if" branch because MemCheck_start and MemCheck_stop may
249280304Sjkim                 * never be used while there are multiple OpenSSL threads.
250280304Sjkim                 */
251280304Sjkim                CRYPTO_w_lock(CRYPTO_LOCK_MALLOC2);
252280304Sjkim                CRYPTO_w_lock(CRYPTO_LOCK_MALLOC);
253280304Sjkim                mh_mode &= ~CRYPTO_MEM_CHECK_ENABLE;
254280304Sjkim                CRYPTO_THREADID_cpy(&disabling_threadid, &cur);
255280304Sjkim            }
256280304Sjkim            num_disable++;
257280304Sjkim        }
258280304Sjkim        break;
259280304Sjkim    case CRYPTO_MEM_CHECK_ENABLE: /* aka MemCheck_on() */
260280304Sjkim        if (mh_mode & CRYPTO_MEM_CHECK_ON) {
261280304Sjkim            if (num_disable) {  /* always true, or something is going wrong */
262280304Sjkim                num_disable--;
263280304Sjkim                if (num_disable == 0) {
264280304Sjkim                    mh_mode |= CRYPTO_MEM_CHECK_ENABLE;
265280304Sjkim                    CRYPTO_w_unlock(CRYPTO_LOCK_MALLOC2);
266280304Sjkim                }
267280304Sjkim            }
268280304Sjkim        }
269280304Sjkim        break;
27059191Skris
271280304Sjkim    default:
272280304Sjkim        break;
273280304Sjkim    }
274280304Sjkim    CRYPTO_w_unlock(CRYPTO_LOCK_MALLOC);
275280304Sjkim    return (ret);
276280304Sjkim}
27759191Skris
27859191Skrisint CRYPTO_is_mem_check_on(void)
279280304Sjkim{
280280304Sjkim    int ret = 0;
28159191Skris
282280304Sjkim    if (mh_mode & CRYPTO_MEM_CHECK_ON) {
283280304Sjkim        CRYPTO_THREADID cur;
284280304Sjkim        CRYPTO_THREADID_current(&cur);
285280304Sjkim        CRYPTO_r_lock(CRYPTO_LOCK_MALLOC);
28659191Skris
287280304Sjkim        ret = (mh_mode & CRYPTO_MEM_CHECK_ENABLE)
288280304Sjkim            || CRYPTO_THREADID_cmp(&disabling_threadid, &cur);
28959191Skris
290280304Sjkim        CRYPTO_r_unlock(CRYPTO_LOCK_MALLOC);
291280304Sjkim    }
292280304Sjkim    return (ret);
293280304Sjkim}
29459191Skris
29559191Skrisvoid CRYPTO_dbg_set_options(long bits)
296280304Sjkim{
297280304Sjkim    options = bits;
298280304Sjkim}
29959191Skris
30059191Skrislong CRYPTO_dbg_get_options(void)
301280304Sjkim{
302280304Sjkim    return options;
303280304Sjkim}
30459191Skris
305238405Sjkimstatic int mem_cmp(const MEM *a, const MEM *b)
306280304Sjkim{
307160814Ssimon#ifdef _WIN64
308280304Sjkim    const char *ap = (const char *)a->addr, *bp = (const char *)b->addr;
309280304Sjkim    if (ap == bp)
310280304Sjkim        return 0;
311280304Sjkim    else if (ap > bp)
312280304Sjkim        return 1;
313280304Sjkim    else
314280304Sjkim        return -1;
315160814Ssimon#else
316280304Sjkim    return (const char *)a->addr - (const char *)b->addr;
317160814Ssimon#endif
318280304Sjkim}
319280304Sjkim
320238405Sjkimstatic IMPLEMENT_LHASH_COMP_FN(mem, MEM)
32159191Skris
322238405Sjkimstatic unsigned long mem_hash(const MEM *a)
323280304Sjkim{
324280304Sjkim    unsigned long ret;
32559191Skris
326280304Sjkim    ret = (unsigned long)a->addr;
32759191Skris
328280304Sjkim    ret = ret * 17851 + (ret >> 14) * 7 + (ret >> 4) * 251;
329280304Sjkim    return (ret);
330280304Sjkim}
331280304Sjkim
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)
336280304Sjkim{
337280304Sjkim    return CRYPTO_THREADID_cmp(&((const APP_INFO *)a_void)->threadid,
338280304Sjkim                               &((const APP_INFO *)b_void)->threadid);
339280304Sjkim}
340280304Sjkim
341238405Sjkimstatic IMPLEMENT_LHASH_COMP_FN(app_info, APP_INFO)
34259191Skris
343238405Sjkimstatic unsigned long app_info_hash(const APP_INFO *a)
344280304Sjkim{
345280304Sjkim    unsigned long ret;
34659191Skris
347280304Sjkim    ret = CRYPTO_THREADID_hash(&a->threadid);
348280304Sjkim    /* This is left in as a "who am I to question legacy?" measure */
349280304Sjkim    ret = ret * 17851 + (ret >> 14) * 7 + (ret >> 4) * 251;
350280304Sjkim    return (ret);
351280304Sjkim}
352280304Sjkim
353238405Sjkimstatic IMPLEMENT_LHASH_HASH_FN(app_info, APP_INFO)
35459191Skris
355109998Smarkmstatic APP_INFO *pop_info(void)
356280304Sjkim{
357280304Sjkim    APP_INFO tmp;
358280304Sjkim    APP_INFO *ret = NULL;
35959191Skris
360280304Sjkim    if (amih != NULL) {
361280304Sjkim        CRYPTO_THREADID_current(&tmp.threadid);
362280304Sjkim        if ((ret = lh_APP_INFO_delete(amih, &tmp)) != NULL) {
363280304Sjkim            APP_INFO *next = ret->next;
36459191Skris
365280304Sjkim            if (next != NULL) {
366280304Sjkim                next->references++;
367280304Sjkim                (void)lh_APP_INFO_insert(amih, next);
368280304Sjkim            }
369109998Smarkm#ifdef LEVITTE_DEBUG_MEM
370280304Sjkim            if (CRYPTO_THREADID_cmp(&ret->threadid, &tmp.threadid)) {
371280304Sjkim                fprintf(stderr,
372280304Sjkim                        "pop_info(): deleted info has other thread ID (%lu) than the current thread (%lu)!!!!\n",
373280304Sjkim                        CRYPTO_THREADID_hash(&ret->threadid),
374280304Sjkim                        CRYPTO_THREADID_hash(&tmp.threadid));
375280304Sjkim                abort();
376280304Sjkim            }
37759191Skris#endif
378280304Sjkim            if (--(ret->references) <= 0) {
379280304Sjkim                ret->next = NULL;
380280304Sjkim                if (next != NULL)
381280304Sjkim                    next->references--;
382280304Sjkim                OPENSSL_free(ret);
383280304Sjkim            }
384280304Sjkim        }
385280304Sjkim    }
386280304Sjkim    return (ret);
387280304Sjkim}
38859191Skris
389238405Sjkimint CRYPTO_push_info_(const char *info, const char *file, int line)
390280304Sjkim{
391280304Sjkim    APP_INFO *ami, *amim;
392280304Sjkim    int ret = 0;
39359191Skris
394280304Sjkim    if (is_MemCheck_on()) {
395280304Sjkim        MemCheck_off();         /* obtain MALLOC2 lock */
39659191Skris
397280304Sjkim        if ((ami = (APP_INFO *)OPENSSL_malloc(sizeof(APP_INFO))) == NULL) {
398280304Sjkim            ret = 0;
399280304Sjkim            goto err;
400280304Sjkim        }
401280304Sjkim        if (amih == NULL) {
402280304Sjkim            if ((amih = lh_APP_INFO_new()) == NULL) {
403280304Sjkim                OPENSSL_free(ami);
404280304Sjkim                ret = 0;
405280304Sjkim                goto err;
406280304Sjkim            }
407280304Sjkim        }
40859191Skris
409280304Sjkim        CRYPTO_THREADID_current(&ami->threadid);
410280304Sjkim        ami->file = file;
411280304Sjkim        ami->line = line;
412280304Sjkim        ami->info = info;
413280304Sjkim        ami->references = 1;
414280304Sjkim        ami->next = NULL;
41559191Skris
416280304Sjkim        if ((amim = lh_APP_INFO_insert(amih, ami)) != NULL) {
417109998Smarkm#ifdef LEVITTE_DEBUG_MEM
418280304Sjkim            if (CRYPTO_THREADID_cmp(&ami->threadid, &amim->threadid)) {
419280304Sjkim                fprintf(stderr,
420280304Sjkim                        "CRYPTO_push_info(): previous info has other thread ID (%lu) than the current thread (%lu)!!!!\n",
421280304Sjkim                        CRYPTO_THREADID_hash(&amim->threadid),
422280304Sjkim                        CRYPTO_THREADID_hash(&ami->threadid));
423280304Sjkim                abort();
424280304Sjkim            }
42559191Skris#endif
426280304Sjkim            ami->next = amim;
427280304Sjkim        }
42859191Skris err:
429280304Sjkim        MemCheck_on();          /* release MALLOC2 lock */
430280304Sjkim    }
43159191Skris
432280304Sjkim    return (ret);
433280304Sjkim}
43459191Skris
435238405Sjkimint CRYPTO_pop_info(void)
436280304Sjkim{
437280304Sjkim    int ret = 0;
43859191Skris
439280304Sjkim    if (is_MemCheck_on()) {     /* _must_ be true, or something went severely
440280304Sjkim                                 * wrong */
441280304Sjkim        MemCheck_off();         /* obtain MALLOC2 lock */
44259191Skris
443280304Sjkim        ret = (pop_info() != NULL);
44459191Skris
445280304Sjkim        MemCheck_on();          /* release MALLOC2 lock */
446280304Sjkim    }
447280304Sjkim    return (ret);
448280304Sjkim}
44959191Skris
450238405Sjkimint CRYPTO_remove_all_info(void)
451280304Sjkim{
452280304Sjkim    int ret = 0;
45359191Skris
454280304Sjkim    if (is_MemCheck_on()) {     /* _must_ be true */
455280304Sjkim        MemCheck_off();         /* obtain MALLOC2 lock */
45659191Skris
457280304Sjkim        while (pop_info() != NULL)
458280304Sjkim            ret++;
45959191Skris
460280304Sjkim        MemCheck_on();          /* release MALLOC2 lock */
461280304Sjkim    }
462280304Sjkim    return (ret);
463280304Sjkim}
46459191Skris
465280304Sjkimstatic unsigned long break_order_num = 0;
46659191Skrisvoid CRYPTO_dbg_malloc(void *addr, int num, const char *file, int line,
467280304Sjkim                       int before_p)
468280304Sjkim{
469280304Sjkim    MEM *m, *mm;
470280304Sjkim    APP_INFO tmp, *amim;
47159191Skris
472280304Sjkim    switch (before_p & 127) {
473280304Sjkim    case 0:
474280304Sjkim        break;
475280304Sjkim    case 1:
476280304Sjkim        if (addr == NULL)
477280304Sjkim            break;
47859191Skris
479280304Sjkim        if (is_MemCheck_on()) {
480280304Sjkim            MemCheck_off();     /* make sure we hold MALLOC2 lock */
481280304Sjkim            if ((m = (MEM *)OPENSSL_malloc(sizeof(MEM))) == NULL) {
482280304Sjkim                OPENSSL_free(addr);
483280304Sjkim                MemCheck_on();  /* release MALLOC2 lock if num_disabled drops
484280304Sjkim                                 * to 0 */
485280304Sjkim                return;
486280304Sjkim            }
487280304Sjkim            if (mh == NULL) {
488280304Sjkim                if ((mh = lh_MEM_new()) == NULL) {
489280304Sjkim                    OPENSSL_free(addr);
490280304Sjkim                    OPENSSL_free(m);
491280304Sjkim                    addr = NULL;
492280304Sjkim                    goto err;
493280304Sjkim                }
494280304Sjkim            }
49559191Skris
496280304Sjkim            m->addr = addr;
497280304Sjkim            m->file = file;
498280304Sjkim            m->line = line;
499280304Sjkim            m->num = num;
500280304Sjkim            if (options & V_CRYPTO_MDEBUG_THREAD)
501280304Sjkim                CRYPTO_THREADID_current(&m->threadid);
502280304Sjkim            else
503280304Sjkim                memset(&m->threadid, 0, sizeof(m->threadid));
50459191Skris
505280304Sjkim            if (order == break_order_num) {
506280304Sjkim                /* BREAK HERE */
507280304Sjkim                m->order = order;
508280304Sjkim            }
509280304Sjkim            m->order = order++;
510109998Smarkm#ifdef LEVITTE_DEBUG_MEM
511280304Sjkim            fprintf(stderr, "LEVITTE_DEBUG_MEM: [%5ld] %c 0x%p (%d)\n",
512280304Sjkim                    m->order, (before_p & 128) ? '*' : '+', m->addr, m->num);
51359191Skris#endif
514280304Sjkim            if (options & V_CRYPTO_MDEBUG_TIME)
515280304Sjkim                m->time = time(NULL);
516280304Sjkim            else
517280304Sjkim                m->time = 0;
51859191Skris
519280304Sjkim            CRYPTO_THREADID_current(&tmp.threadid);
520280304Sjkim            m->app_info = NULL;
521280304Sjkim            if (amih != NULL
522280304Sjkim                && (amim = lh_APP_INFO_retrieve(amih, &tmp)) != NULL) {
523280304Sjkim                m->app_info = amim;
524280304Sjkim                amim->references++;
525280304Sjkim            }
52659191Skris
527280304Sjkim            if ((mm = lh_MEM_insert(mh, m)) != NULL) {
528280304Sjkim                /* Not good, but don't sweat it */
529280304Sjkim                if (mm->app_info != NULL) {
530280304Sjkim                    mm->app_info->references--;
531280304Sjkim                }
532280304Sjkim                OPENSSL_free(mm);
533280304Sjkim            }
534280304Sjkim err:
535280304Sjkim            MemCheck_on();      /* release MALLOC2 lock if num_disabled drops
536280304Sjkim                                 * to 0 */
537280304Sjkim        }
538280304Sjkim        break;
539280304Sjkim    }
540280304Sjkim    return;
541280304Sjkim}
54259191Skris
54359191Skrisvoid CRYPTO_dbg_free(void *addr, int before_p)
544280304Sjkim{
545280304Sjkim    MEM m, *mp;
54659191Skris
547280304Sjkim    switch (before_p) {
548280304Sjkim    case 0:
549280304Sjkim        if (addr == NULL)
550280304Sjkim            break;
55159191Skris
552280304Sjkim        if (is_MemCheck_on() && (mh != NULL)) {
553280304Sjkim            MemCheck_off();     /* make sure we hold MALLOC2 lock */
55459191Skris
555280304Sjkim            m.addr = addr;
556280304Sjkim            mp = lh_MEM_delete(mh, &m);
557280304Sjkim            if (mp != NULL) {
558109998Smarkm#ifdef LEVITTE_DEBUG_MEM
559280304Sjkim                fprintf(stderr, "LEVITTE_DEBUG_MEM: [%5ld] - 0x%p (%d)\n",
560280304Sjkim                        mp->order, mp->addr, mp->num);
56159191Skris#endif
562280304Sjkim                if (mp->app_info != NULL)
563280304Sjkim                    app_info_free(mp->app_info);
564280304Sjkim                OPENSSL_free(mp);
565280304Sjkim            }
56659191Skris
567280304Sjkim            MemCheck_on();      /* release MALLOC2 lock if num_disabled drops
568280304Sjkim                                 * to 0 */
569280304Sjkim        }
570280304Sjkim        break;
571280304Sjkim    case 1:
572280304Sjkim        break;
573280304Sjkim    }
574280304Sjkim}
57559191Skris
57659191Skrisvoid CRYPTO_dbg_realloc(void *addr1, void *addr2, int num,
577280304Sjkim                        const char *file, int line, int before_p)
578280304Sjkim{
579280304Sjkim    MEM m, *mp;
58059191Skris
581109998Smarkm#ifdef LEVITTE_DEBUG_MEM
582280304Sjkim    fprintf(stderr,
583280304Sjkim            "LEVITTE_DEBUG_MEM: --> CRYPTO_dbg_malloc(addr1 = %p, addr2 = %p, num = %d, file = \"%s\", line = %d, before_p = %d)\n",
584280304Sjkim            addr1, addr2, num, file, line, before_p);
58559191Skris#endif
58659191Skris
587280304Sjkim    switch (before_p) {
588280304Sjkim    case 0:
589280304Sjkim        break;
590280304Sjkim    case 1:
591280304Sjkim        if (addr2 == NULL)
592280304Sjkim            break;
59359191Skris
594280304Sjkim        if (addr1 == NULL) {
595280304Sjkim            CRYPTO_dbg_malloc(addr2, num, file, line, 128 | before_p);
596280304Sjkim            break;
597280304Sjkim        }
59859191Skris
599280304Sjkim        if (is_MemCheck_on()) {
600280304Sjkim            MemCheck_off();     /* make sure we hold MALLOC2 lock */
60159191Skris
602280304Sjkim            m.addr = addr1;
603280304Sjkim            mp = lh_MEM_delete(mh, &m);
604280304Sjkim            if (mp != NULL) {
605109998Smarkm#ifdef LEVITTE_DEBUG_MEM
606280304Sjkim                fprintf(stderr,
607280304Sjkim                        "LEVITTE_DEBUG_MEM: [%5ld] * 0x%p (%d) -> 0x%p (%d)\n",
608280304Sjkim                        mp->order, mp->addr, mp->num, addr2, num);
60959191Skris#endif
610280304Sjkim                mp->addr = addr2;
611280304Sjkim                mp->num = num;
612280304Sjkim                (void)lh_MEM_insert(mh, mp);
613280304Sjkim            }
61459191Skris
615280304Sjkim            MemCheck_on();      /* release MALLOC2 lock if num_disabled drops
616280304Sjkim                                 * to 0 */
617280304Sjkim        }
618280304Sjkim        break;
619280304Sjkim    }
620280304Sjkim    return;
621280304Sjkim}
62259191Skris
623280304Sjkimtypedef struct mem_leak_st {
624280304Sjkim    BIO *bio;
625280304Sjkim    int chunks;
626280304Sjkim    long bytes;
627280304Sjkim} MEM_LEAK;
62859191Skris
629238405Sjkimstatic void print_leak_doall_arg(const MEM *m, MEM_LEAK *l)
630280304Sjkim{
631280304Sjkim    char buf[1024];
632280304Sjkim    char *bufp = buf;
633280304Sjkim    APP_INFO *amip;
634280304Sjkim    int ami_cnt;
635280304Sjkim    struct tm *lcl = NULL;
636280304Sjkim    CRYPTO_THREADID ti;
63759191Skris
638127128Snectar#define BUF_REMAIN (sizeof buf - (size_t)(bufp - buf))
639127128Snectar
640280304Sjkim    if (m->addr == (char *)l->bio)
641280304Sjkim        return;
64259191Skris
643280304Sjkim    if (options & V_CRYPTO_MDEBUG_TIME) {
644280304Sjkim        lcl = localtime(&m->time);
64559191Skris
646280304Sjkim        BIO_snprintf(bufp, BUF_REMAIN, "[%02d:%02d:%02d] ",
647280304Sjkim                     lcl->tm_hour, lcl->tm_min, lcl->tm_sec);
648280304Sjkim        bufp += strlen(bufp);
649280304Sjkim    }
65059191Skris
651280304Sjkim    BIO_snprintf(bufp, BUF_REMAIN, "%5lu file=%s, line=%d, ",
652280304Sjkim                 m->order, m->file, m->line);
653280304Sjkim    bufp += strlen(bufp);
65459191Skris
655280304Sjkim    if (options & V_CRYPTO_MDEBUG_THREAD) {
656280304Sjkim        BIO_snprintf(bufp, BUF_REMAIN, "thread=%lu, ",
657280304Sjkim                     CRYPTO_THREADID_hash(&m->threadid));
658280304Sjkim        bufp += strlen(bufp);
659280304Sjkim    }
66059191Skris
661280304Sjkim    BIO_snprintf(bufp, BUF_REMAIN, "number=%d, address=%08lX\n",
662280304Sjkim                 m->num, (unsigned long)m->addr);
663280304Sjkim    bufp += strlen(bufp);
66459191Skris
665280304Sjkim    BIO_puts(l->bio, buf);
666238405Sjkim
667280304Sjkim    l->chunks++;
668280304Sjkim    l->bytes += m->num;
66959191Skris
670280304Sjkim    amip = m->app_info;
671280304Sjkim    ami_cnt = 0;
672280304Sjkim    if (!amip)
673280304Sjkim        return;
674280304Sjkim    CRYPTO_THREADID_cpy(&ti, &amip->threadid);
67559191Skris
676280304Sjkim    do {
677280304Sjkim        int buf_len;
678280304Sjkim        int info_len;
679238405Sjkim
680280304Sjkim        ami_cnt++;
681280304Sjkim        memset(buf, '>', ami_cnt);
682280304Sjkim        BIO_snprintf(buf + ami_cnt, sizeof buf - ami_cnt,
683280304Sjkim                     " thread=%lu, file=%s, line=%d, info=\"",
684280304Sjkim                     CRYPTO_THREADID_hash(&amip->threadid), amip->file,
685280304Sjkim                     amip->line);
686280304Sjkim        buf_len = strlen(buf);
687280304Sjkim        info_len = strlen(amip->info);
688280304Sjkim        if (128 - buf_len - 3 < info_len) {
689280304Sjkim            memcpy(buf + buf_len, amip->info, 128 - buf_len - 3);
690280304Sjkim            buf_len = 128 - 3;
691280304Sjkim        } else {
692280304Sjkim            BUF_strlcpy(buf + buf_len, amip->info, sizeof buf - buf_len);
693280304Sjkim            buf_len = strlen(buf);
694280304Sjkim        }
695280304Sjkim        BIO_snprintf(buf + buf_len, sizeof buf - buf_len, "\"\n");
696280304Sjkim
697280304Sjkim        BIO_puts(l->bio, buf);
698280304Sjkim
699280304Sjkim        amip = amip->next;
700280304Sjkim    }
701280304Sjkim    while (amip && !CRYPTO_THREADID_cmp(&amip->threadid, &ti));
702280304Sjkim
703109998Smarkm#ifdef LEVITTE_DEBUG_MEM
704280304Sjkim    if (amip) {
705280304Sjkim        fprintf(stderr, "Thread switch detected in backtrace!!!!\n");
706280304Sjkim        abort();
707280304Sjkim    }
70859191Skris#endif
709280304Sjkim}
71059191Skris
711238405Sjkimstatic IMPLEMENT_LHASH_DOALL_ARG_FN(print_leak, const MEM, MEM_LEAK)
712109998Smarkm
71359191Skrisvoid CRYPTO_mem_leaks(BIO *b)
714280304Sjkim{
715280304Sjkim    MEM_LEAK ml;
71659191Skris
717280304Sjkim    if (mh == NULL && amih == NULL)
718280304Sjkim        return;
71976866Skris
720280304Sjkim    MemCheck_off();             /* obtain MALLOC2 lock */
72176866Skris
722280304Sjkim    ml.bio = b;
723280304Sjkim    ml.bytes = 0;
724280304Sjkim    ml.chunks = 0;
725280304Sjkim    if (mh != NULL)
726280304Sjkim        lh_MEM_doall_arg(mh, LHASH_DOALL_ARG_FN(print_leak), MEM_LEAK, &ml);
727280304Sjkim    if (ml.chunks != 0) {
728280304Sjkim        BIO_printf(b, "%ld bytes leaked in %d chunks\n", ml.bytes, ml.chunks);
729238405Sjkim#ifdef CRYPTO_MDEBUG_ABORT
730280304Sjkim        abort();
731238405Sjkim#endif
732280304Sjkim    } else {
733280304Sjkim        /*
734280304Sjkim         * Make sure that, if we found no leaks, memory-leak debugging itself
735280304Sjkim         * does not introduce memory leaks (which might irritate external
736280304Sjkim         * debugging tools). (When someone enables leak checking, but does not
737280304Sjkim         * call this function, we declare it to be their fault.) XXX This
738280304Sjkim         * should be in CRYPTO_mem_leaks_cb, and CRYPTO_mem_leaks should be
739280304Sjkim         * implemented by using CRYPTO_mem_leaks_cb. (Also there should be a
740280304Sjkim         * variant of lh_doall_arg that takes a function pointer instead of a
741280304Sjkim         * void *; this would obviate the ugly and illegal void_fn_to_char
742280304Sjkim         * kludge in CRYPTO_mem_leaks_cb. Otherwise the code police will come
743280304Sjkim         * and get us.)
744280304Sjkim         */
745280304Sjkim        int old_mh_mode;
74672613Skris
747280304Sjkim        CRYPTO_w_lock(CRYPTO_LOCK_MALLOC);
74872613Skris
749280304Sjkim        /*
750280304Sjkim         * avoid deadlock when lh_free() uses CRYPTO_dbg_free(), which uses
751280304Sjkim         * CRYPTO_is_mem_check_on
752280304Sjkim         */
753280304Sjkim        old_mh_mode = mh_mode;
754280304Sjkim        mh_mode = CRYPTO_MEM_CHECK_OFF;
75572613Skris
756280304Sjkim        if (mh != NULL) {
757280304Sjkim            lh_MEM_free(mh);
758280304Sjkim            mh = NULL;
759280304Sjkim        }
760280304Sjkim        if (amih != NULL) {
761280304Sjkim            if (lh_APP_INFO_num_items(amih) == 0) {
762280304Sjkim                lh_APP_INFO_free(amih);
763280304Sjkim                amih = NULL;
764280304Sjkim            }
765280304Sjkim        }
76672613Skris
767280304Sjkim        mh_mode = old_mh_mode;
768280304Sjkim        CRYPTO_w_unlock(CRYPTO_LOCK_MALLOC);
769280304Sjkim    }
770280304Sjkim    MemCheck_on();              /* release MALLOC2 lock */
771280304Sjkim}
77259191Skris
773109998Smarkm#ifndef OPENSSL_NO_FP_API
77459191Skrisvoid CRYPTO_mem_leaks_fp(FILE *fp)
775280304Sjkim{
776280304Sjkim    BIO *b;
77759191Skris
778280304Sjkim    if (mh == NULL)
779280304Sjkim        return;
780280304Sjkim    /*
781280304Sjkim     * Need to turn off memory checking when allocated BIOs ... especially as
782280304Sjkim     * we're creating them at a time when we're trying to check we've not
783280304Sjkim     * left anything un-free()'d!!
784280304Sjkim     */
785280304Sjkim    MemCheck_off();
786280304Sjkim    b = BIO_new(BIO_s_file());
787280304Sjkim    MemCheck_on();
788280304Sjkim    if (!b)
789280304Sjkim        return;
790280304Sjkim    BIO_set_fp(b, fp, BIO_NOCLOSE);
791280304Sjkim    CRYPTO_mem_leaks(b);
792280304Sjkim    BIO_free(b);
793280304Sjkim}
79459191Skris#endif
79559191Skris
796280304Sjkim/*
797280304Sjkim * FIXME: We really don't allow much to the callback.  For example, it has no
798280304Sjkim * chance of reaching the info stack for the item it processes.  Should it
799280304Sjkim * really be this way? -- Richard Levitte
800280304Sjkim */
801280304Sjkim/*
802280304Sjkim * NB: The prototypes have been typedef'd to CRYPTO_MEM_LEAK_CB inside
803280304Sjkim * crypto.h If this code is restructured, remove the callback type if it is
804280304Sjkim * no longer needed. -- Geoff Thorpe
805280304Sjkim */
80668651Skris
807280304Sjkim/*
808280304Sjkim * Can't pass CRYPTO_MEM_LEAK_CB directly to lh_MEM_doall_arg because it is a
809280304Sjkim * function pointer and conversion to void * is prohibited. Instead pass its
810280304Sjkim * 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)
816280304Sjkim{
817280304Sjkim    (*cb) (m->order, m->file, m->line, m->num, m->addr);
818280304Sjkim}
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)
823280304Sjkim{
824280304Sjkim    if (mh == NULL)
825280304Sjkim        return;
826280304Sjkim    CRYPTO_w_lock(CRYPTO_LOCK_MALLOC2);
827280304Sjkim    lh_MEM_doall_arg(mh, LHASH_DOALL_ARG_FN(cb_leak), PCRYPTO_MEM_LEAK_CB,
828280304Sjkim                     &cb);
829280304Sjkim    CRYPTO_w_unlock(CRYPTO_LOCK_MALLOC2);
830280304Sjkim}
831