| lh | 9ed821d | 2023-04-07 01:36:19 -0700 | [diff] [blame] | 1 | /* | 
|  | 2 | * Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved. | 
|  | 3 | * | 
|  | 4 | * Licensed under the OpenSSL license (the "License").  You may not use | 
|  | 5 | * this file except in compliance with the License.  You can obtain a copy | 
|  | 6 | * in the file LICENSE in the source distribution or at | 
|  | 7 | * https://www.openssl.org/source/license.html | 
|  | 8 | */ | 
|  | 9 |  | 
|  | 10 | #include <stdio.h> | 
|  | 11 | #include <stdlib.h> | 
|  | 12 | #include <time.h> | 
|  | 13 | #include "internal/cryptlib.h" | 
|  | 14 | #include "internal/thread_once.h" | 
|  | 15 | #include <openssl/crypto.h> | 
|  | 16 | #include <openssl/buffer.h> | 
|  | 17 | #include "internal/bio.h" | 
|  | 18 | #include <openssl/lhash.h> | 
|  | 19 |  | 
|  | 20 | #ifndef OPENSSL_NO_CRYPTO_MDEBUG_BACKTRACE | 
|  | 21 | # include <execinfo.h> | 
|  | 22 | #endif | 
|  | 23 |  | 
|  | 24 | /* | 
|  | 25 | * The state changes to CRYPTO_MEM_CHECK_ON | CRYPTO_MEM_CHECK_ENABLE when | 
|  | 26 | * the application asks for it (usually after library initialisation for | 
|  | 27 | * which no book-keeping is desired). State CRYPTO_MEM_CHECK_ON exists only | 
|  | 28 | * temporarily when the library thinks that certain allocations should not be | 
|  | 29 | * checked (e.g. the data structures used for memory checking).  It is not | 
|  | 30 | * suitable as an initial state: the library will unexpectedly enable memory | 
|  | 31 | * checking when it executes one of those sections that want to disable | 
|  | 32 | * checking temporarily. State CRYPTO_MEM_CHECK_ENABLE without ..._ON makes | 
|  | 33 | * no sense whatsoever. | 
|  | 34 | */ | 
|  | 35 | #ifndef OPENSSL_NO_CRYPTO_MDEBUG | 
|  | 36 | static int mh_mode = CRYPTO_MEM_CHECK_OFF; | 
|  | 37 | #endif | 
|  | 38 |  | 
|  | 39 | #ifndef OPENSSL_NO_CRYPTO_MDEBUG | 
|  | 40 | static unsigned long order = 0; /* number of memory requests */ | 
|  | 41 |  | 
|  | 42 | /*- | 
|  | 43 | * For application-defined information (static C-string `info') | 
|  | 44 | * to be displayed in memory leak list. | 
|  | 45 | * Each thread has its own stack.  For applications, there is | 
|  | 46 | *   OPENSSL_mem_debug_push("...")     to push an entry, | 
|  | 47 | *   OPENSSL_mem_debug_pop()     to pop an entry, | 
|  | 48 | */ | 
|  | 49 | struct app_mem_info_st { | 
|  | 50 | CRYPTO_THREAD_ID threadid; | 
|  | 51 | const char *file; | 
|  | 52 | int line; | 
|  | 53 | const char *info; | 
|  | 54 | struct app_mem_info_st *next; /* tail of thread's stack */ | 
|  | 55 | int references; | 
|  | 56 | }; | 
|  | 57 |  | 
|  | 58 | static CRYPTO_ONCE memdbg_init = CRYPTO_ONCE_STATIC_INIT; | 
|  | 59 | CRYPTO_RWLOCK *memdbg_lock; | 
|  | 60 | static CRYPTO_RWLOCK *long_memdbg_lock; | 
|  | 61 | static CRYPTO_THREAD_LOCAL appinfokey; | 
|  | 62 |  | 
|  | 63 | /* memory-block description */ | 
|  | 64 | struct mem_st { | 
|  | 65 | void *addr; | 
|  | 66 | int num; | 
|  | 67 | const char *file; | 
|  | 68 | int line; | 
|  | 69 | CRYPTO_THREAD_ID threadid; | 
|  | 70 | unsigned long order; | 
|  | 71 | time_t time; | 
|  | 72 | APP_INFO *app_info; | 
|  | 73 | #ifndef OPENSSL_NO_CRYPTO_MDEBUG_BACKTRACE | 
|  | 74 | void *array[30]; | 
|  | 75 | size_t array_siz; | 
|  | 76 | #endif | 
|  | 77 | }; | 
|  | 78 |  | 
|  | 79 | /* | 
|  | 80 | * hash-table of memory requests (address as * key); access requires | 
|  | 81 | * long_memdbg_lock lock | 
|  | 82 | */ | 
|  | 83 | static LHASH_OF(MEM) *mh = NULL; | 
|  | 84 |  | 
|  | 85 | /* num_disable > 0 iff mh_mode == CRYPTO_MEM_CHECK_ON (w/o ..._ENABLE) */ | 
|  | 86 | static unsigned int num_disable = 0; | 
|  | 87 |  | 
|  | 88 | /* | 
|  | 89 | * Valid iff num_disable > 0.  long_memdbg_lock is locked exactly in this | 
|  | 90 | * case (by the thread named in disabling_thread). | 
|  | 91 | */ | 
|  | 92 | static CRYPTO_THREAD_ID disabling_threadid; | 
|  | 93 |  | 
|  | 94 | DEFINE_RUN_ONCE_STATIC(do_memdbg_init) | 
|  | 95 | { | 
|  | 96 | memdbg_lock = CRYPTO_THREAD_lock_new(); | 
|  | 97 | long_memdbg_lock = CRYPTO_THREAD_lock_new(); | 
|  | 98 | if (memdbg_lock == NULL || long_memdbg_lock == NULL | 
|  | 99 | || !CRYPTO_THREAD_init_local(&appinfokey, NULL)) { | 
|  | 100 | CRYPTO_THREAD_lock_free(memdbg_lock); | 
|  | 101 | memdbg_lock = NULL; | 
|  | 102 | CRYPTO_THREAD_lock_free(long_memdbg_lock); | 
|  | 103 | long_memdbg_lock = NULL; | 
|  | 104 | return 0; | 
|  | 105 | } | 
|  | 106 | return 1; | 
|  | 107 | } | 
|  | 108 |  | 
|  | 109 | static void app_info_free(APP_INFO *inf) | 
|  | 110 | { | 
|  | 111 | if (inf == NULL) | 
|  | 112 | return; | 
|  | 113 | if (--(inf->references) <= 0) { | 
|  | 114 | app_info_free(inf->next); | 
|  | 115 | OPENSSL_free(inf); | 
|  | 116 | } | 
|  | 117 | } | 
|  | 118 | #endif | 
|  | 119 |  | 
|  | 120 | int CRYPTO_mem_ctrl(int mode) | 
|  | 121 | { | 
|  | 122 | #ifdef OPENSSL_NO_CRYPTO_MDEBUG | 
|  | 123 | return mode - mode; | 
|  | 124 | #else | 
|  | 125 | int ret = mh_mode; | 
|  | 126 |  | 
|  | 127 | if (!RUN_ONCE(&memdbg_init, do_memdbg_init)) | 
|  | 128 | return -1; | 
|  | 129 |  | 
|  | 130 | CRYPTO_THREAD_write_lock(memdbg_lock); | 
|  | 131 | switch (mode) { | 
|  | 132 | default: | 
|  | 133 | break; | 
|  | 134 |  | 
|  | 135 | case CRYPTO_MEM_CHECK_ON: | 
|  | 136 | mh_mode = CRYPTO_MEM_CHECK_ON | CRYPTO_MEM_CHECK_ENABLE; | 
|  | 137 | num_disable = 0; | 
|  | 138 | break; | 
|  | 139 |  | 
|  | 140 | case CRYPTO_MEM_CHECK_OFF: | 
|  | 141 | mh_mode = 0; | 
|  | 142 | num_disable = 0; | 
|  | 143 | break; | 
|  | 144 |  | 
|  | 145 | /* switch off temporarily (for library-internal use): */ | 
|  | 146 | case CRYPTO_MEM_CHECK_DISABLE: | 
|  | 147 | if (mh_mode & CRYPTO_MEM_CHECK_ON) { | 
|  | 148 | CRYPTO_THREAD_ID cur = CRYPTO_THREAD_get_current_id(); | 
|  | 149 | /* see if we don't have long_memdbg_lock already */ | 
|  | 150 | if (!num_disable | 
|  | 151 | || !CRYPTO_THREAD_compare_id(disabling_threadid, cur)) { | 
|  | 152 | /* | 
|  | 153 | * Long-time lock long_memdbg_lock must not be claimed | 
|  | 154 | * while we're holding memdbg_lock, or we'll deadlock | 
|  | 155 | * if somebody else holds long_memdbg_lock (and cannot | 
|  | 156 | * release it because we block entry to this function). Give | 
|  | 157 | * them a chance, first, and then claim the locks in | 
|  | 158 | * appropriate order (long-time lock first). | 
|  | 159 | */ | 
|  | 160 | CRYPTO_THREAD_unlock(memdbg_lock); | 
|  | 161 | /* | 
|  | 162 | * Note that after we have waited for long_memdbg_lock and | 
|  | 163 | * memdbg_lock, we'll still be in the right "case" and | 
|  | 164 | * "if" branch because MemCheck_start and MemCheck_stop may | 
|  | 165 | * never be used while there are multiple OpenSSL threads. | 
|  | 166 | */ | 
|  | 167 | CRYPTO_THREAD_write_lock(long_memdbg_lock); | 
|  | 168 | CRYPTO_THREAD_write_lock(memdbg_lock); | 
|  | 169 | mh_mode &= ~CRYPTO_MEM_CHECK_ENABLE; | 
|  | 170 | disabling_threadid = cur; | 
|  | 171 | } | 
|  | 172 | num_disable++; | 
|  | 173 | } | 
|  | 174 | break; | 
|  | 175 |  | 
|  | 176 | case CRYPTO_MEM_CHECK_ENABLE: | 
|  | 177 | if (mh_mode & CRYPTO_MEM_CHECK_ON) { | 
|  | 178 | if (num_disable) {  /* always true, or something is going wrong */ | 
|  | 179 | num_disable--; | 
|  | 180 | if (num_disable == 0) { | 
|  | 181 | mh_mode |= CRYPTO_MEM_CHECK_ENABLE; | 
|  | 182 | CRYPTO_THREAD_unlock(long_memdbg_lock); | 
|  | 183 | } | 
|  | 184 | } | 
|  | 185 | } | 
|  | 186 | break; | 
|  | 187 | } | 
|  | 188 | CRYPTO_THREAD_unlock(memdbg_lock); | 
|  | 189 | return ret; | 
|  | 190 | #endif | 
|  | 191 | } | 
|  | 192 |  | 
|  | 193 | #ifndef OPENSSL_NO_CRYPTO_MDEBUG | 
|  | 194 |  | 
|  | 195 | static int mem_check_on(void) | 
|  | 196 | { | 
|  | 197 | int ret = 0; | 
|  | 198 | CRYPTO_THREAD_ID cur; | 
|  | 199 |  | 
|  | 200 | if (mh_mode & CRYPTO_MEM_CHECK_ON) { | 
|  | 201 | if (!RUN_ONCE(&memdbg_init, do_memdbg_init)) | 
|  | 202 | return 0; | 
|  | 203 |  | 
|  | 204 | cur = CRYPTO_THREAD_get_current_id(); | 
|  | 205 | CRYPTO_THREAD_read_lock(memdbg_lock); | 
|  | 206 |  | 
|  | 207 | ret = (mh_mode & CRYPTO_MEM_CHECK_ENABLE) | 
|  | 208 | || !CRYPTO_THREAD_compare_id(disabling_threadid, cur); | 
|  | 209 |  | 
|  | 210 | CRYPTO_THREAD_unlock(memdbg_lock); | 
|  | 211 | } | 
|  | 212 | return ret; | 
|  | 213 | } | 
|  | 214 |  | 
|  | 215 | static int mem_cmp(const MEM *a, const MEM *b) | 
|  | 216 | { | 
|  | 217 | #ifdef _WIN64 | 
|  | 218 | const char *ap = (const char *)a->addr, *bp = (const char *)b->addr; | 
|  | 219 | if (ap == bp) | 
|  | 220 | return 0; | 
|  | 221 | else if (ap > bp) | 
|  | 222 | return 1; | 
|  | 223 | else | 
|  | 224 | return -1; | 
|  | 225 | #else | 
|  | 226 | return (const char *)a->addr - (const char *)b->addr; | 
|  | 227 | #endif | 
|  | 228 | } | 
|  | 229 |  | 
|  | 230 | static unsigned long mem_hash(const MEM *a) | 
|  | 231 | { | 
|  | 232 | size_t ret; | 
|  | 233 |  | 
|  | 234 | ret = (size_t)a->addr; | 
|  | 235 |  | 
|  | 236 | ret = ret * 17851 + (ret >> 14) * 7 + (ret >> 4) * 251; | 
|  | 237 | return ret; | 
|  | 238 | } | 
|  | 239 |  | 
|  | 240 | /* returns 1 if there was an info to pop, 0 if the stack was empty. */ | 
|  | 241 | static int pop_info(void) | 
|  | 242 | { | 
|  | 243 | APP_INFO *current = NULL; | 
|  | 244 |  | 
|  | 245 | if (!RUN_ONCE(&memdbg_init, do_memdbg_init)) | 
|  | 246 | return 0; | 
|  | 247 |  | 
|  | 248 | current = (APP_INFO *)CRYPTO_THREAD_get_local(&appinfokey); | 
|  | 249 | if (current != NULL) { | 
|  | 250 | APP_INFO *next = current->next; | 
|  | 251 |  | 
|  | 252 | if (next != NULL) { | 
|  | 253 | next->references++; | 
|  | 254 | CRYPTO_THREAD_set_local(&appinfokey, next); | 
|  | 255 | } else { | 
|  | 256 | CRYPTO_THREAD_set_local(&appinfokey, NULL); | 
|  | 257 | } | 
|  | 258 | if (--(current->references) <= 0) { | 
|  | 259 | current->next = NULL; | 
|  | 260 | if (next != NULL) | 
|  | 261 | next->references--; | 
|  | 262 | OPENSSL_free(current); | 
|  | 263 | } | 
|  | 264 | return 1; | 
|  | 265 | } | 
|  | 266 | return 0; | 
|  | 267 | } | 
|  | 268 |  | 
|  | 269 | int CRYPTO_mem_debug_push(const char *info, const char *file, int line) | 
|  | 270 | { | 
|  | 271 | APP_INFO *ami, *amim; | 
|  | 272 | int ret = 0; | 
|  | 273 |  | 
|  | 274 | if (mem_check_on()) { | 
|  | 275 | CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_DISABLE); | 
|  | 276 |  | 
|  | 277 | if (!RUN_ONCE(&memdbg_init, do_memdbg_init) | 
|  | 278 | || (ami = OPENSSL_malloc(sizeof(*ami))) == NULL) | 
|  | 279 | goto err; | 
|  | 280 |  | 
|  | 281 | ami->threadid = CRYPTO_THREAD_get_current_id(); | 
|  | 282 | ami->file = file; | 
|  | 283 | ami->line = line; | 
|  | 284 | ami->info = info; | 
|  | 285 | ami->references = 1; | 
|  | 286 | ami->next = NULL; | 
|  | 287 |  | 
|  | 288 | amim = (APP_INFO *)CRYPTO_THREAD_get_local(&appinfokey); | 
|  | 289 | CRYPTO_THREAD_set_local(&appinfokey, ami); | 
|  | 290 |  | 
|  | 291 | if (amim != NULL) | 
|  | 292 | ami->next = amim; | 
|  | 293 | ret = 1; | 
|  | 294 | err: | 
|  | 295 | CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ENABLE); | 
|  | 296 | } | 
|  | 297 |  | 
|  | 298 | return ret; | 
|  | 299 | } | 
|  | 300 |  | 
|  | 301 | int CRYPTO_mem_debug_pop(void) | 
|  | 302 | { | 
|  | 303 | int ret = 0; | 
|  | 304 |  | 
|  | 305 | if (mem_check_on()) { | 
|  | 306 | CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_DISABLE); | 
|  | 307 | ret = pop_info(); | 
|  | 308 | CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ENABLE); | 
|  | 309 | } | 
|  | 310 | return ret; | 
|  | 311 | } | 
|  | 312 |  | 
|  | 313 | static unsigned long break_order_num = 0; | 
|  | 314 |  | 
|  | 315 | void CRYPTO_mem_debug_malloc(void *addr, size_t num, int before_p, | 
|  | 316 | const char *file, int line) | 
|  | 317 | { | 
|  | 318 | MEM *m, *mm; | 
|  | 319 | APP_INFO *amim; | 
|  | 320 |  | 
|  | 321 | switch (before_p & 127) { | 
|  | 322 | case 0: | 
|  | 323 | break; | 
|  | 324 | case 1: | 
|  | 325 | if (addr == NULL) | 
|  | 326 | break; | 
|  | 327 |  | 
|  | 328 | if (mem_check_on()) { | 
|  | 329 | CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_DISABLE); | 
|  | 330 |  | 
|  | 331 | if (!RUN_ONCE(&memdbg_init, do_memdbg_init) | 
|  | 332 | || (m = OPENSSL_malloc(sizeof(*m))) == NULL) { | 
|  | 333 | OPENSSL_free(addr); | 
|  | 334 | CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ENABLE); | 
|  | 335 | return; | 
|  | 336 | } | 
|  | 337 | if (mh == NULL) { | 
|  | 338 | if ((mh = lh_MEM_new(mem_hash, mem_cmp)) == NULL) { | 
|  | 339 | OPENSSL_free(addr); | 
|  | 340 | OPENSSL_free(m); | 
|  | 341 | addr = NULL; | 
|  | 342 | goto err; | 
|  | 343 | } | 
|  | 344 | } | 
|  | 345 |  | 
|  | 346 | m->addr = addr; | 
|  | 347 | m->file = file; | 
|  | 348 | m->line = line; | 
|  | 349 | m->num = num; | 
|  | 350 | m->threadid = CRYPTO_THREAD_get_current_id(); | 
|  | 351 |  | 
|  | 352 | if (order == break_order_num) { | 
|  | 353 | /* BREAK HERE */ | 
|  | 354 | m->order = order; | 
|  | 355 | } | 
|  | 356 | m->order = order++; | 
|  | 357 | # ifndef OPENSSL_NO_CRYPTO_MDEBUG_BACKTRACE | 
|  | 358 | m->array_siz = backtrace(m->array, OSSL_NELEM(m->array)); | 
|  | 359 | # endif | 
|  | 360 | m->time = time(NULL); | 
|  | 361 |  | 
|  | 362 | amim = (APP_INFO *)CRYPTO_THREAD_get_local(&appinfokey); | 
|  | 363 | m->app_info = amim; | 
|  | 364 | if (amim != NULL) | 
|  | 365 | amim->references++; | 
|  | 366 |  | 
|  | 367 | if ((mm = lh_MEM_insert(mh, m)) != NULL) { | 
|  | 368 | /* Not good, but don't sweat it */ | 
|  | 369 | if (mm->app_info != NULL) { | 
|  | 370 | mm->app_info->references--; | 
|  | 371 | } | 
|  | 372 | OPENSSL_free(mm); | 
|  | 373 | } | 
|  | 374 | err: | 
|  | 375 | CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ENABLE); | 
|  | 376 | } | 
|  | 377 | break; | 
|  | 378 | } | 
|  | 379 | return; | 
|  | 380 | } | 
|  | 381 |  | 
|  | 382 | void CRYPTO_mem_debug_free(void *addr, int before_p, | 
|  | 383 | const char *file, int line) | 
|  | 384 | { | 
|  | 385 | MEM m, *mp; | 
|  | 386 |  | 
|  | 387 | switch (before_p) { | 
|  | 388 | case 0: | 
|  | 389 | if (addr == NULL) | 
|  | 390 | break; | 
|  | 391 |  | 
|  | 392 | if (mem_check_on() && (mh != NULL)) { | 
|  | 393 | CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_DISABLE); | 
|  | 394 |  | 
|  | 395 | m.addr = addr; | 
|  | 396 | mp = lh_MEM_delete(mh, &m); | 
|  | 397 | if (mp != NULL) { | 
|  | 398 | app_info_free(mp->app_info); | 
|  | 399 | OPENSSL_free(mp); | 
|  | 400 | } | 
|  | 401 |  | 
|  | 402 | CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ENABLE); | 
|  | 403 | } | 
|  | 404 | break; | 
|  | 405 | case 1: | 
|  | 406 | break; | 
|  | 407 | } | 
|  | 408 | } | 
|  | 409 |  | 
|  | 410 | void CRYPTO_mem_debug_realloc(void *addr1, void *addr2, size_t num, | 
|  | 411 | int before_p, const char *file, int line) | 
|  | 412 | { | 
|  | 413 | MEM m, *mp; | 
|  | 414 |  | 
|  | 415 | switch (before_p) { | 
|  | 416 | case 0: | 
|  | 417 | break; | 
|  | 418 | case 1: | 
|  | 419 | if (addr2 == NULL) | 
|  | 420 | break; | 
|  | 421 |  | 
|  | 422 | if (addr1 == NULL) { | 
|  | 423 | CRYPTO_mem_debug_malloc(addr2, num, 128 | before_p, file, line); | 
|  | 424 | break; | 
|  | 425 | } | 
|  | 426 |  | 
|  | 427 | if (mem_check_on()) { | 
|  | 428 | CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_DISABLE); | 
|  | 429 |  | 
|  | 430 | m.addr = addr1; | 
|  | 431 | mp = lh_MEM_delete(mh, &m); | 
|  | 432 | if (mp != NULL) { | 
|  | 433 | mp->addr = addr2; | 
|  | 434 | mp->num = num; | 
|  | 435 | #ifndef OPENSSL_NO_CRYPTO_MDEBUG_BACKTRACE | 
|  | 436 | mp->array_siz = backtrace(mp->array, OSSL_NELEM(mp->array)); | 
|  | 437 | #endif | 
|  | 438 | (void)lh_MEM_insert(mh, mp); | 
|  | 439 | } | 
|  | 440 |  | 
|  | 441 | CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ENABLE); | 
|  | 442 | } | 
|  | 443 | break; | 
|  | 444 | } | 
|  | 445 | return; | 
|  | 446 | } | 
|  | 447 |  | 
|  | 448 | typedef struct mem_leak_st { | 
|  | 449 | int (*print_cb) (const char *str, size_t len, void *u); | 
|  | 450 | void *print_cb_arg; | 
|  | 451 | int chunks; | 
|  | 452 | long bytes; | 
|  | 453 | } MEM_LEAK; | 
|  | 454 |  | 
|  | 455 | static void print_leak(const MEM *m, MEM_LEAK *l) | 
|  | 456 | { | 
|  | 457 | char buf[1024]; | 
|  | 458 | char *bufp = buf; | 
|  | 459 | size_t len = sizeof(buf), ami_cnt; | 
|  | 460 | APP_INFO *amip; | 
|  | 461 | int n; | 
|  | 462 | struct tm *lcl = NULL; | 
|  | 463 | /* | 
|  | 464 | * Convert between CRYPTO_THREAD_ID (which could be anything at all) and | 
|  | 465 | * a long. This may not be meaningful depending on what CRYPTO_THREAD_ID is | 
|  | 466 | * but hopefully should give something sensible on most platforms | 
|  | 467 | */ | 
|  | 468 | union { | 
|  | 469 | CRYPTO_THREAD_ID tid; | 
|  | 470 | unsigned long ltid; | 
|  | 471 | } tid; | 
|  | 472 | CRYPTO_THREAD_ID ti; | 
|  | 473 |  | 
|  | 474 | lcl = localtime(&m->time); | 
|  | 475 | n = BIO_snprintf(bufp, len, "[%02d:%02d:%02d] ", | 
|  | 476 | lcl->tm_hour, lcl->tm_min, lcl->tm_sec); | 
|  | 477 | if (n <= 0) { | 
|  | 478 | bufp[0] = '\0'; | 
|  | 479 | return; | 
|  | 480 | } | 
|  | 481 | bufp += n; | 
|  | 482 | len -= n; | 
|  | 483 |  | 
|  | 484 | n = BIO_snprintf(bufp, len, "%5lu file=%s, line=%d, ", | 
|  | 485 | m->order, m->file, m->line); | 
|  | 486 | if (n <= 0) | 
|  | 487 | return; | 
|  | 488 | bufp += n; | 
|  | 489 | len -= n; | 
|  | 490 |  | 
|  | 491 | tid.ltid = 0; | 
|  | 492 | tid.tid = m->threadid; | 
|  | 493 | n = BIO_snprintf(bufp, len, "thread=%lu, ", tid.ltid); | 
|  | 494 | if (n <= 0) | 
|  | 495 | return; | 
|  | 496 | bufp += n; | 
|  | 497 | len -= n; | 
|  | 498 |  | 
|  | 499 | n = BIO_snprintf(bufp, len, "number=%d, address=%p\n", m->num, m->addr); | 
|  | 500 | if (n <= 0) | 
|  | 501 | return; | 
|  | 502 | bufp += n; | 
|  | 503 | len -= n; | 
|  | 504 |  | 
|  | 505 | l->print_cb(buf, (size_t)(bufp - buf), l->print_cb_arg); | 
|  | 506 |  | 
|  | 507 | l->chunks++; | 
|  | 508 | l->bytes += m->num; | 
|  | 509 |  | 
|  | 510 | amip = m->app_info; | 
|  | 511 | ami_cnt = 0; | 
|  | 512 |  | 
|  | 513 | if (amip) { | 
|  | 514 | ti = amip->threadid; | 
|  | 515 |  | 
|  | 516 | do { | 
|  | 517 | int buf_len; | 
|  | 518 | int info_len; | 
|  | 519 |  | 
|  | 520 | ami_cnt++; | 
|  | 521 | if (ami_cnt >= sizeof(buf) - 1) | 
|  | 522 | break; | 
|  | 523 | memset(buf, '>', ami_cnt); | 
|  | 524 | buf[ami_cnt] = '\0'; | 
|  | 525 | tid.ltid = 0; | 
|  | 526 | tid.tid = amip->threadid; | 
|  | 527 | n = BIO_snprintf(buf + ami_cnt, sizeof(buf) - ami_cnt, | 
|  | 528 | " thread=%lu, file=%s, line=%d, info=\"", | 
|  | 529 | tid.ltid, amip->file, amip->line); | 
|  | 530 | if (n <= 0) | 
|  | 531 | break; | 
|  | 532 | buf_len = ami_cnt + n; | 
|  | 533 | info_len = strlen(amip->info); | 
|  | 534 | if (128 - buf_len - 3 < info_len) { | 
|  | 535 | memcpy(buf + buf_len, amip->info, 128 - buf_len - 3); | 
|  | 536 | buf_len = 128 - 3; | 
|  | 537 | } else { | 
|  | 538 | n = BIO_snprintf(buf + buf_len, sizeof(buf) - buf_len, "%s", | 
|  | 539 | amip->info); | 
|  | 540 | if (n < 0) | 
|  | 541 | break; | 
|  | 542 | buf_len += n; | 
|  | 543 | } | 
|  | 544 | n = BIO_snprintf(buf + buf_len, sizeof(buf) - buf_len, "\"\n"); | 
|  | 545 | if (n <= 0) | 
|  | 546 | break; | 
|  | 547 |  | 
|  | 548 | l->print_cb(buf, buf_len + n, l->print_cb_arg); | 
|  | 549 |  | 
|  | 550 | amip = amip->next; | 
|  | 551 | } | 
|  | 552 | while (amip && CRYPTO_THREAD_compare_id(amip->threadid, ti)); | 
|  | 553 | } | 
|  | 554 |  | 
|  | 555 | #ifndef OPENSSL_NO_CRYPTO_MDEBUG_BACKTRACE | 
|  | 556 | { | 
|  | 557 | size_t i; | 
|  | 558 | char **strings = backtrace_symbols(m->array, m->array_siz); | 
|  | 559 |  | 
|  | 560 | for (i = 0; i < m->array_siz; i++) | 
|  | 561 | fprintf(stderr, "##> %s\n", strings[i]); | 
|  | 562 | free(strings); | 
|  | 563 | } | 
|  | 564 | #endif | 
|  | 565 | } | 
|  | 566 |  | 
|  | 567 | IMPLEMENT_LHASH_DOALL_ARG_CONST(MEM, MEM_LEAK); | 
|  | 568 |  | 
|  | 569 | int CRYPTO_mem_leaks_cb(int (*cb) (const char *str, size_t len, void *u), | 
|  | 570 | void *u) | 
|  | 571 | { | 
|  | 572 | MEM_LEAK ml; | 
|  | 573 |  | 
|  | 574 | /* Ensure all resources are released */ | 
|  | 575 | OPENSSL_cleanup(); | 
|  | 576 |  | 
|  | 577 | if (!RUN_ONCE(&memdbg_init, do_memdbg_init)) | 
|  | 578 | return -1; | 
|  | 579 |  | 
|  | 580 | CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_DISABLE); | 
|  | 581 |  | 
|  | 582 | ml.print_cb = cb; | 
|  | 583 | ml.print_cb_arg = u; | 
|  | 584 | ml.bytes = 0; | 
|  | 585 | ml.chunks = 0; | 
|  | 586 | if (mh != NULL) | 
|  | 587 | lh_MEM_doall_MEM_LEAK(mh, print_leak, &ml); | 
|  | 588 |  | 
|  | 589 | if (ml.chunks != 0) { | 
|  | 590 | char buf[256]; | 
|  | 591 |  | 
|  | 592 | BIO_snprintf(buf, sizeof(buf), "%ld bytes leaked in %d chunks\n", | 
|  | 593 | ml.bytes, ml.chunks); | 
|  | 594 | cb(buf, strlen(buf), u); | 
|  | 595 | } else { | 
|  | 596 | /* | 
|  | 597 | * Make sure that, if we found no leaks, memory-leak debugging itself | 
|  | 598 | * does not introduce memory leaks (which might irritate external | 
|  | 599 | * debugging tools). (When someone enables leak checking, but does not | 
|  | 600 | * call this function, we declare it to be their fault.) | 
|  | 601 | */ | 
|  | 602 | int old_mh_mode; | 
|  | 603 |  | 
|  | 604 | CRYPTO_THREAD_write_lock(memdbg_lock); | 
|  | 605 |  | 
|  | 606 | /* | 
|  | 607 | * avoid deadlock when lh_free() uses CRYPTO_mem_debug_free(), which uses | 
|  | 608 | * mem_check_on | 
|  | 609 | */ | 
|  | 610 | old_mh_mode = mh_mode; | 
|  | 611 | mh_mode = CRYPTO_MEM_CHECK_OFF; | 
|  | 612 |  | 
|  | 613 | lh_MEM_free(mh); | 
|  | 614 | mh = NULL; | 
|  | 615 |  | 
|  | 616 | mh_mode = old_mh_mode; | 
|  | 617 | CRYPTO_THREAD_unlock(memdbg_lock); | 
|  | 618 | } | 
|  | 619 | CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_OFF); | 
|  | 620 |  | 
|  | 621 | /* Clean up locks etc */ | 
|  | 622 | CRYPTO_THREAD_cleanup_local(&appinfokey); | 
|  | 623 | CRYPTO_THREAD_lock_free(memdbg_lock); | 
|  | 624 | CRYPTO_THREAD_lock_free(long_memdbg_lock); | 
|  | 625 | memdbg_lock = NULL; | 
|  | 626 | long_memdbg_lock = NULL; | 
|  | 627 |  | 
|  | 628 | return ml.chunks == 0 ? 1 : 0; | 
|  | 629 | } | 
|  | 630 |  | 
|  | 631 | static int print_bio(const char *str, size_t len, void *b) | 
|  | 632 | { | 
|  | 633 | return BIO_write((BIO *)b, str, len); | 
|  | 634 | } | 
|  | 635 |  | 
|  | 636 | int CRYPTO_mem_leaks(BIO *b) | 
|  | 637 | { | 
|  | 638 | /* | 
|  | 639 | * OPENSSL_cleanup() will free the ex_data locks so we can't have any | 
|  | 640 | * ex_data hanging around | 
|  | 641 | */ | 
|  | 642 | bio_free_ex_data(b); | 
|  | 643 |  | 
|  | 644 | return CRYPTO_mem_leaks_cb(print_bio, b); | 
|  | 645 | } | 
|  | 646 |  | 
|  | 647 | # ifndef OPENSSL_NO_STDIO | 
|  | 648 | int CRYPTO_mem_leaks_fp(FILE *fp) | 
|  | 649 | { | 
|  | 650 | BIO *b; | 
|  | 651 | int ret; | 
|  | 652 |  | 
|  | 653 | /* | 
|  | 654 | * Need to turn off memory checking when allocated BIOs ... especially as | 
|  | 655 | * we're creating them at a time when we're trying to check we've not | 
|  | 656 | * left anything un-free()'d!! | 
|  | 657 | */ | 
|  | 658 | CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_DISABLE); | 
|  | 659 | b = BIO_new(BIO_s_file()); | 
|  | 660 | CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ENABLE); | 
|  | 661 | if (b == NULL) | 
|  | 662 | return -1; | 
|  | 663 | BIO_set_fp(b, fp, BIO_NOCLOSE); | 
|  | 664 | ret = CRYPTO_mem_leaks_cb(print_bio, b); | 
|  | 665 | BIO_free(b); | 
|  | 666 | return ret; | 
|  | 667 | } | 
|  | 668 | # endif | 
|  | 669 |  | 
|  | 670 | #endif |