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