]>
Commit | Line | Data |
---|---|---|
aa6bb135 | 1 | /* |
6738bf14 | 2 | * Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved. |
48fc582f | 3 | * |
0e9725bc | 4 | * Licensed under the Apache License 2.0 (the "License"). You may not use |
aa6bb135 RS |
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 | |
48fc582f | 8 | */ |
9ac42ed8 RL |
9 | |
10 | #include <stdio.h> | |
11 | #include <stdlib.h> | |
0f113f3e | 12 | #include <time.h> |
b39fc560 | 13 | #include "internal/cryptlib.h" |
23dd0c9f | 14 | #include "internal/thread_once.h" |
9ac42ed8 RL |
15 | #include <openssl/crypto.h> |
16 | #include <openssl/buffer.h> | |
1ee7b8b9 | 17 | #include "internal/bio.h" |
9ac42ed8 | 18 | #include <openssl/lhash.h> |
ef8ca6bd RL |
19 | |
20 | #ifndef OPENSSL_NO_CRYPTO_MDEBUG_BACKTRACE | |
012c5408 RL |
21 | # include <execinfo.h> |
22 | #endif | |
9ac42ed8 | 23 | |
0f113f3e MC |
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. | |
9ac42ed8 | 34 | */ |
c2e27310 | 35 | #ifndef OPENSSL_NO_CRYPTO_MDEBUG |
bbd86bf5 | 36 | static int mh_mode = CRYPTO_MEM_CHECK_OFF; |
c2e27310 | 37 | #endif |
9ac42ed8 | 38 | |
6ac11bd0 | 39 | #ifndef OPENSSL_NO_CRYPTO_MDEBUG |
0cd08cce | 40 | static unsigned long order = 0; /* number of memory requests */ |
3c1d6bbc | 41 | |
c80fd6b2 MC |
42 | /*- |
43 | * For application-defined information (static C-string `info') | |
0cd08cce BM |
44 | * to be displayed in memory leak list. |
45 | * Each thread has its own stack. For applications, there is | |
4fae386c RS |
46 | * OPENSSL_mem_debug_push("...") to push an entry, |
47 | * OPENSSL_mem_debug_pop() to pop an entry, | |
0cd08cce | 48 | */ |
e6b5c341 | 49 | struct app_mem_info_st { |
9471f776 | 50 | CRYPTO_THREAD_ID threadid; |
0f113f3e MC |
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; | |
e6b5c341 | 56 | }; |
9ac42ed8 | 57 | |
9471f776 | 58 | static CRYPTO_ONCE memdbg_init = CRYPTO_ONCE_STATIC_INIT; |
0e598a3d RS |
59 | CRYPTO_RWLOCK *memdbg_lock; |
60 | static CRYPTO_RWLOCK *long_memdbg_lock; | |
9471f776 | 61 | static CRYPTO_THREAD_LOCAL appinfokey; |
9ac42ed8 | 62 | |
0cd08cce | 63 | /* memory-block description */ |
e6b5c341 | 64 | struct mem_st { |
0f113f3e MC |
65 | void *addr; |
66 | int num; | |
67 | const char *file; | |
68 | int line; | |
9471f776 | 69 | CRYPTO_THREAD_ID threadid; |
0f113f3e MC |
70 | unsigned long order; |
71 | time_t time; | |
72 | APP_INFO *app_info; | |
ef8ca6bd | 73 | #ifndef OPENSSL_NO_CRYPTO_MDEBUG_BACKTRACE |
012c5408 RL |
74 | void *array[30]; |
75 | size_t array_siz; | |
76 | #endif | |
e6b5c341 DSH |
77 | }; |
78 | ||
0e598a3d RS |
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; | |
0f113f3e | 84 | |
bbd86bf5 RS |
85 | /* num_disable > 0 iff mh_mode == CRYPTO_MEM_CHECK_ON (w/o ..._ENABLE) */ |
86 | static unsigned int num_disable = 0; | |
48fc582f | 87 | |
0f113f3e | 88 | /* |
0e598a3d | 89 | * Valid iff num_disable > 0. long_memdbg_lock is locked exactly in this |
4c329696 | 90 | * case (by the thread named in disabling_thread). |
5f834ab1 | 91 | */ |
9471f776 MC |
92 | static CRYPTO_THREAD_ID disabling_threadid; |
93 | ||
23dd0c9f | 94 | DEFINE_RUN_ONCE_STATIC(do_memdbg_init) |
9471f776 | 95 | { |
63ab5ea1 BK |
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)) { | |
0e598a3d RS |
100 | CRYPTO_THREAD_lock_free(memdbg_lock); |
101 | memdbg_lock = NULL; | |
102 | CRYPTO_THREAD_lock_free(long_memdbg_lock); | |
103 | long_memdbg_lock = NULL; | |
23dd0c9f DSH |
104 | return 0; |
105 | } | |
106 | return 1; | |
9471f776 | 107 | } |
9ac42ed8 | 108 | |
9dc61049 | 109 | static void app_info_free(APP_INFO *inf) |
0f113f3e | 110 | { |
0e598a3d | 111 | if (inf == NULL) |
25aaa98a | 112 | return; |
0f113f3e | 113 | if (--(inf->references) <= 0) { |
25aaa98a | 114 | app_info_free(inf->next); |
0f113f3e MC |
115 | OPENSSL_free(inf); |
116 | } | |
117 | } | |
bbd86bf5 | 118 | #endif |
9dc61049 | 119 | |
9ac42ed8 | 120 | int CRYPTO_mem_ctrl(int mode) |
0f113f3e | 121 | { |
c2e27310 | 122 | #ifdef OPENSSL_NO_CRYPTO_MDEBUG |
bbd86bf5 RS |
123 | return mode - mode; |
124 | #else | |
0f113f3e MC |
125 | int ret = mh_mode; |
126 | ||
c2e4e5d2 RL |
127 | if (!RUN_ONCE(&memdbg_init, do_memdbg_init)) |
128 | return -1; | |
9471f776 | 129 | |
0e598a3d | 130 | CRYPTO_THREAD_write_lock(memdbg_lock); |
0f113f3e | 131 | switch (mode) { |
bbd86bf5 RS |
132 | default: |
133 | break; | |
134 | ||
135 | case CRYPTO_MEM_CHECK_ON: | |
0f113f3e MC |
136 | mh_mode = CRYPTO_MEM_CHECK_ON | CRYPTO_MEM_CHECK_ENABLE; |
137 | num_disable = 0; | |
138 | break; | |
bbd86bf5 RS |
139 | |
140 | case CRYPTO_MEM_CHECK_OFF: | |
0f113f3e | 141 | mh_mode = 0; |
bbd86bf5 | 142 | num_disable = 0; |
0f113f3e MC |
143 | break; |
144 | ||
bbd86bf5 RS |
145 | /* switch off temporarily (for library-internal use): */ |
146 | case CRYPTO_MEM_CHECK_DISABLE: | |
0f113f3e | 147 | if (mh_mode & CRYPTO_MEM_CHECK_ON) { |
9471f776 | 148 | CRYPTO_THREAD_ID cur = CRYPTO_THREAD_get_current_id(); |
0e598a3d | 149 | /* see if we don't have long_memdbg_lock already */ |
0f113f3e | 150 | if (!num_disable |
9471f776 | 151 | || !CRYPTO_THREAD_compare_id(disabling_threadid, cur)) { |
0f113f3e | 152 | /* |
0e598a3d RS |
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 | |
0f113f3e MC |
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 | */ | |
0e598a3d | 160 | CRYPTO_THREAD_unlock(memdbg_lock); |
0f113f3e | 161 | /* |
0e598a3d RS |
162 | * Note that after we have waited for long_memdbg_lock and |
163 | * memdbg_lock, we'll still be in the right "case" and | |
0f113f3e MC |
164 | * "if" branch because MemCheck_start and MemCheck_stop may |
165 | * never be used while there are multiple OpenSSL threads. | |
166 | */ | |
0e598a3d RS |
167 | CRYPTO_THREAD_write_lock(long_memdbg_lock); |
168 | CRYPTO_THREAD_write_lock(memdbg_lock); | |
0f113f3e | 169 | mh_mode &= ~CRYPTO_MEM_CHECK_ENABLE; |
9471f776 | 170 | disabling_threadid = cur; |
0f113f3e MC |
171 | } |
172 | num_disable++; | |
173 | } | |
174 | break; | |
bbd86bf5 RS |
175 | |
176 | case CRYPTO_MEM_CHECK_ENABLE: | |
0f113f3e MC |
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; | |
0e598a3d | 182 | CRYPTO_THREAD_unlock(long_memdbg_lock); |
0f113f3e MC |
183 | } |
184 | } | |
185 | } | |
186 | break; | |
0f113f3e | 187 | } |
0e598a3d | 188 | CRYPTO_THREAD_unlock(memdbg_lock); |
b4df712a | 189 | return ret; |
bbd86bf5 | 190 | #endif |
0f113f3e | 191 | } |
9ac42ed8 | 192 | |
6ac11bd0 | 193 | #ifndef OPENSSL_NO_CRYPTO_MDEBUG |
bbd86bf5 RS |
194 | |
195 | static int mem_check_on(void) | |
0f113f3e MC |
196 | { |
197 | int ret = 0; | |
a0605744 | 198 | CRYPTO_THREAD_ID cur; |
9ac42ed8 | 199 | |
0f113f3e | 200 | if (mh_mode & CRYPTO_MEM_CHECK_ON) { |
c2e4e5d2 RL |
201 | if (!RUN_ONCE(&memdbg_init, do_memdbg_init)) |
202 | return 0; | |
9471f776 | 203 | |
a0605744 | 204 | cur = CRYPTO_THREAD_get_current_id(); |
0e598a3d | 205 | CRYPTO_THREAD_read_lock(memdbg_lock); |
9ac42ed8 | 206 | |
0f113f3e | 207 | ret = (mh_mode & CRYPTO_MEM_CHECK_ENABLE) |
9471f776 | 208 | || !CRYPTO_THREAD_compare_id(disabling_threadid, cur); |
9ac42ed8 | 209 | |
0e598a3d | 210 | CRYPTO_THREAD_unlock(memdbg_lock); |
0f113f3e | 211 | } |
b4df712a | 212 | return ret; |
0f113f3e | 213 | } |
9ac42ed8 | 214 | |
3c1d6bbc | 215 | static int mem_cmp(const MEM *a, const MEM *b) |
0f113f3e | 216 | { |
1875e6db | 217 | #ifdef _WIN64 |
0f113f3e MC |
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; | |
1875e6db | 225 | #else |
0f113f3e | 226 | return (const char *)a->addr - (const char *)b->addr; |
1875e6db | 227 | #endif |
0f113f3e MC |
228 | } |
229 | ||
3c1d6bbc | 230 | static unsigned long mem_hash(const MEM *a) |
0f113f3e | 231 | { |
5f0580cc | 232 | size_t ret; |
9ac42ed8 | 233 | |
5f0580cc | 234 | ret = (size_t)a->addr; |
0f113f3e MC |
235 | |
236 | ret = ret * 17851 + (ret >> 14) * 7 + (ret >> 4) * 251; | |
b4df712a | 237 | return ret; |
0f113f3e | 238 | } |
9ac42ed8 | 239 | |
96e25c49 PC |
240 | /* returns 1 if there was an info to pop, 0 if the stack was empty. */ |
241 | static int pop_info(void) | |
0f113f3e | 242 | { |
96e25c49 | 243 | APP_INFO *current = NULL; |
0f113f3e | 244 | |
c2e4e5d2 RL |
245 | if (!RUN_ONCE(&memdbg_init, do_memdbg_init)) |
246 | return 0; | |
247 | ||
9471f776 MC |
248 | current = (APP_INFO *)CRYPTO_THREAD_get_local(&appinfokey); |
249 | if (current != NULL) { | |
250 | APP_INFO *next = current->next; | |
0f113f3e | 251 | |
9471f776 MC |
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); | |
0f113f3e | 263 | } |
9471f776 | 264 | return 1; |
0f113f3e | 265 | } |
96e25c49 | 266 | return 0; |
0f113f3e | 267 | } |
9ac42ed8 | 268 | |
4fae386c | 269 | int CRYPTO_mem_debug_push(const char *info, const char *file, int line) |
0f113f3e MC |
270 | { |
271 | APP_INFO *ami, *amim; | |
272 | int ret = 0; | |
273 | ||
bbd86bf5 RS |
274 | if (mem_check_on()) { |
275 | CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_DISABLE); | |
0f113f3e | 276 | |
c2e4e5d2 RL |
277 | if (!RUN_ONCE(&memdbg_init, do_memdbg_init) |
278 | || (ami = OPENSSL_malloc(sizeof(*ami))) == NULL) | |
0f113f3e | 279 | goto err; |
0f113f3e | 280 | |
9471f776 | 281 | ami->threadid = CRYPTO_THREAD_get_current_id(); |
0f113f3e MC |
282 | ami->file = file; |
283 | ami->line = line; | |
284 | ami->info = info; | |
285 | ami->references = 1; | |
286 | ami->next = NULL; | |
287 | ||
9471f776 MC |
288 | amim = (APP_INFO *)CRYPTO_THREAD_get_local(&appinfokey); |
289 | CRYPTO_THREAD_set_local(&appinfokey, ami); | |
290 | ||
291 | if (amim != NULL) | |
0f113f3e | 292 | ami->next = amim; |
bbd86bf5 | 293 | ret = 1; |
9ac42ed8 | 294 | err: |
bbd86bf5 | 295 | CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ENABLE); |
0f113f3e | 296 | } |
9ac42ed8 | 297 | |
b4df712a | 298 | return ret; |
0f113f3e | 299 | } |
9ac42ed8 | 300 | |
4fae386c | 301 | int CRYPTO_mem_debug_pop(void) |
0f113f3e MC |
302 | { |
303 | int ret = 0; | |
9ac42ed8 | 304 | |
bbd86bf5 RS |
305 | if (mem_check_on()) { |
306 | CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_DISABLE); | |
96e25c49 | 307 | ret = pop_info(); |
bbd86bf5 | 308 | CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ENABLE); |
0f113f3e | 309 | } |
b4df712a | 310 | return ret; |
0f113f3e | 311 | } |
9ac42ed8 | 312 | |
0f113f3e | 313 | static unsigned long break_order_num = 0; |
bbd86bf5 RS |
314 | |
315 | void CRYPTO_mem_debug_malloc(void *addr, size_t num, int before_p, | |
316 | const char *file, int line) | |
0f113f3e MC |
317 | { |
318 | MEM *m, *mm; | |
9471f776 | 319 | APP_INFO *amim; |
0f113f3e MC |
320 | |
321 | switch (before_p & 127) { | |
322 | case 0: | |
323 | break; | |
324 | case 1: | |
325 | if (addr == NULL) | |
326 | break; | |
327 | ||
bbd86bf5 RS |
328 | if (mem_check_on()) { |
329 | CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_DISABLE); | |
9471f776 | 330 | |
c2e4e5d2 RL |
331 | if (!RUN_ONCE(&memdbg_init, do_memdbg_init) |
332 | || (m = OPENSSL_malloc(sizeof(*m))) == NULL) { | |
0f113f3e | 333 | OPENSSL_free(addr); |
bbd86bf5 | 334 | CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ENABLE); |
0f113f3e MC |
335 | return; |
336 | } | |
337 | if (mh == NULL) { | |
62d0577e | 338 | if ((mh = lh_MEM_new(mem_hash, mem_cmp)) == NULL) { |
0f113f3e MC |
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; | |
9471f776 | 350 | m->threadid = CRYPTO_THREAD_get_current_id(); |
0f113f3e MC |
351 | |
352 | if (order == break_order_num) { | |
353 | /* BREAK HERE */ | |
354 | m->order = order; | |
355 | } | |
356 | m->order = order++; | |
ef8ca6bd | 357 | # ifndef OPENSSL_NO_CRYPTO_MDEBUG_BACKTRACE |
012c5408 | 358 | m->array_siz = backtrace(m->array, OSSL_NELEM(m->array)); |
bbd86bf5 RS |
359 | # endif |
360 | m->time = time(NULL); | |
0f113f3e | 361 | |
9471f776 MC |
362 | amim = (APP_INFO *)CRYPTO_THREAD_get_local(&appinfokey); |
363 | m->app_info = amim; | |
364 | if (amim != NULL) | |
0f113f3e | 365 | amim->references++; |
0f113f3e MC |
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: | |
bbd86bf5 | 375 | CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ENABLE); |
0f113f3e MC |
376 | } |
377 | break; | |
378 | } | |
379 | return; | |
380 | } | |
9ac42ed8 | 381 | |
05c7b163 RL |
382 | void CRYPTO_mem_debug_free(void *addr, int before_p, |
383 | const char *file, int line) | |
0f113f3e MC |
384 | { |
385 | MEM m, *mp; | |
386 | ||
387 | switch (before_p) { | |
388 | case 0: | |
389 | if (addr == NULL) | |
390 | break; | |
391 | ||
bbd86bf5 RS |
392 | if (mem_check_on() && (mh != NULL)) { |
393 | CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_DISABLE); | |
0f113f3e MC |
394 | |
395 | m.addr = addr; | |
396 | mp = lh_MEM_delete(mh, &m); | |
397 | if (mp != NULL) { | |
25aaa98a | 398 | app_info_free(mp->app_info); |
0f113f3e MC |
399 | OPENSSL_free(mp); |
400 | } | |
401 | ||
bbd86bf5 | 402 | CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ENABLE); |
0f113f3e MC |
403 | } |
404 | break; | |
405 | case 1: | |
406 | break; | |
407 | } | |
408 | } | |
9ac42ed8 | 409 | |
bbd86bf5 RS |
410 | void CRYPTO_mem_debug_realloc(void *addr1, void *addr2, size_t num, |
411 | int before_p, const char *file, int line) | |
0f113f3e MC |
412 | { |
413 | MEM m, *mp; | |
9ac42ed8 | 414 | |
0f113f3e MC |
415 | switch (before_p) { |
416 | case 0: | |
417 | break; | |
418 | case 1: | |
419 | if (addr2 == NULL) | |
420 | break; | |
421 | ||
422 | if (addr1 == NULL) { | |
bbd86bf5 | 423 | CRYPTO_mem_debug_malloc(addr2, num, 128 | before_p, file, line); |
0f113f3e MC |
424 | break; |
425 | } | |
426 | ||
bbd86bf5 RS |
427 | if (mem_check_on()) { |
428 | CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_DISABLE); | |
0f113f3e MC |
429 | |
430 | m.addr = addr1; | |
431 | mp = lh_MEM_delete(mh, &m); | |
432 | if (mp != NULL) { | |
0f113f3e MC |
433 | mp->addr = addr2; |
434 | mp->num = num; | |
ef8ca6bd | 435 | #ifndef OPENSSL_NO_CRYPTO_MDEBUG_BACKTRACE |
012c5408 RL |
436 | mp->array_siz = backtrace(mp->array, OSSL_NELEM(mp->array)); |
437 | #endif | |
0f113f3e MC |
438 | (void)lh_MEM_insert(mh, mp); |
439 | } | |
440 | ||
bbd86bf5 | 441 | CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ENABLE); |
0f113f3e MC |
442 | } |
443 | break; | |
444 | } | |
445 | return; | |
446 | } | |
447 | ||
448 | typedef struct mem_leak_st { | |
20626cfd RL |
449 | int (*print_cb) (const char *str, size_t len, void *u); |
450 | void *print_cb_arg; | |
0f113f3e MC |
451 | int chunks; |
452 | long bytes; | |
453 | } MEM_LEAK; | |
9ac42ed8 | 454 | |
2a056de8 | 455 | static void print_leak(const MEM *m, MEM_LEAK *l) |
0f113f3e MC |
456 | { |
457 | char buf[1024]; | |
458 | char *bufp = buf; | |
86ba26c8 | 459 | size_t len = sizeof(buf), ami_cnt; |
0f113f3e | 460 | APP_INFO *amip; |
86ba26c8 | 461 | int n; |
0f113f3e | 462 | struct tm *lcl = NULL; |
9471f776 MC |
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; | |
9ac42ed8 | 473 | |
bbd86bf5 | 474 | lcl = localtime(&m->time); |
86ba26c8 P |
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; | |
0f113f3e | 483 | |
86ba26c8 P |
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; | |
0f113f3e | 490 | |
9471f776 MC |
491 | tid.ltid = 0; |
492 | tid.tid = m->threadid; | |
86ba26c8 P |
493 | n = BIO_snprintf(bufp, len, "thread=%lu, ", tid.ltid); |
494 | if (n <= 0) | |
495 | return; | |
496 | bufp += n; | |
497 | len -= n; | |
0f113f3e | 498 | |
86ba26c8 P |
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; | |
0f113f3e | 504 | |
86ba26c8 | 505 | l->print_cb(buf, (size_t)(bufp - buf), l->print_cb_arg); |
0f113f3e MC |
506 | |
507 | l->chunks++; | |
508 | l->bytes += m->num; | |
509 | ||
510 | amip = m->app_info; | |
511 | ami_cnt = 0; | |
bbd86bf5 | 512 | |
012c5408 | 513 | if (amip) { |
9471f776 | 514 | ti = amip->threadid; |
012c5408 RL |
515 | |
516 | do { | |
517 | int buf_len; | |
518 | int info_len; | |
519 | ||
520 | ami_cnt++; | |
86ba26c8 P |
521 | if (ami_cnt >= sizeof(buf) - 1) |
522 | break; | |
012c5408 | 523 | memset(buf, '>', ami_cnt); |
86ba26c8 | 524 | buf[ami_cnt] = '\0'; |
9471f776 MC |
525 | tid.ltid = 0; |
526 | tid.tid = amip->threadid; | |
86ba26c8 P |
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; | |
012c5408 RL |
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 { | |
86ba26c8 P |
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; | |
012c5408 | 543 | } |
86ba26c8 P |
544 | n = BIO_snprintf(buf + buf_len, sizeof(buf) - buf_len, "\"\n"); |
545 | if (n <= 0) | |
546 | break; | |
0f113f3e | 547 | |
86ba26c8 | 548 | l->print_cb(buf, buf_len + n, l->print_cb_arg); |
0f113f3e | 549 | |
012c5408 RL |
550 | amip = amip->next; |
551 | } | |
9471f776 | 552 | while (amip && CRYPTO_THREAD_compare_id(amip->threadid, ti)); |
0f113f3e | 553 | } |
f7ccba3e | 554 | |
ef8ca6bd | 555 | #ifndef OPENSSL_NO_CRYPTO_MDEBUG_BACKTRACE |
012c5408 RL |
556 | { |
557 | size_t i; | |
558 | char **strings = backtrace_symbols(m->array, m->array_siz); | |
bbd86bf5 | 559 | |
012c5408 RL |
560 | for (i = 0; i < m->array_siz; i++) |
561 | fprintf(stderr, "##> %s\n", strings[i]); | |
012c5408 RL |
562 | free(strings); |
563 | } | |
564 | #endif | |
0f113f3e | 565 | } |
9ac42ed8 | 566 | |
2a056de8 | 567 | IMPLEMENT_LHASH_DOALL_ARG_CONST(MEM, MEM_LEAK); |
98d517c5 | 568 | |
20626cfd RL |
569 | int CRYPTO_mem_leaks_cb(int (*cb) (const char *str, size_t len, void *u), |
570 | void *u) | |
0f113f3e MC |
571 | { |
572 | MEM_LEAK ml; | |
573 | ||
38a6d7f8 | 574 | /* Ensure all resources are released */ |
f672aee4 | 575 | OPENSSL_cleanup(); |
38a6d7f8 | 576 | |
c2e4e5d2 RL |
577 | if (!RUN_ONCE(&memdbg_init, do_memdbg_init)) |
578 | return -1; | |
9471f776 | 579 | |
bbd86bf5 | 580 | CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_DISABLE); |
0f113f3e | 581 | |
20626cfd RL |
582 | ml.print_cb = cb; |
583 | ml.print_cb_arg = u; | |
0f113f3e MC |
584 | ml.bytes = 0; |
585 | ml.chunks = 0; | |
586 | if (mh != NULL) | |
2a056de8 | 587 | lh_MEM_doall_MEM_LEAK(mh, print_leak, &ml); |
b3895f42 | 588 | |
0f113f3e | 589 | if (ml.chunks != 0) { |
20626cfd RL |
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); | |
0f113f3e MC |
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 | |
bbd86bf5 | 600 | * call this function, we declare it to be their fault.) |
0f113f3e MC |
601 | */ |
602 | int old_mh_mode; | |
603 | ||
0e598a3d | 604 | CRYPTO_THREAD_write_lock(memdbg_lock); |
0f113f3e MC |
605 | |
606 | /* | |
bbd86bf5 RS |
607 | * avoid deadlock when lh_free() uses CRYPTO_mem_debug_free(), which uses |
608 | * mem_check_on | |
0f113f3e MC |
609 | */ |
610 | old_mh_mode = mh_mode; | |
611 | mh_mode = CRYPTO_MEM_CHECK_OFF; | |
612 | ||
25aaa98a RS |
613 | lh_MEM_free(mh); |
614 | mh = NULL; | |
0f113f3e MC |
615 | |
616 | mh_mode = old_mh_mode; | |
0e598a3d | 617 | CRYPTO_THREAD_unlock(memdbg_lock); |
0f113f3e | 618 | } |
9471f776 MC |
619 | CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_OFF); |
620 | ||
621 | /* Clean up locks etc */ | |
622 | CRYPTO_THREAD_cleanup_local(&appinfokey); | |
0e598a3d RS |
623 | CRYPTO_THREAD_lock_free(memdbg_lock); |
624 | CRYPTO_THREAD_lock_free(long_memdbg_lock); | |
625 | memdbg_lock = NULL; | |
626 | long_memdbg_lock = NULL; | |
9471f776 | 627 | |
4e482ae6 | 628 | return ml.chunks == 0 ? 1 : 0; |
0f113f3e | 629 | } |
9ac42ed8 | 630 | |
20626cfd RL |
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 | ||
bbd86bf5 | 647 | # ifndef OPENSSL_NO_STDIO |
4e482ae6 | 648 | int CRYPTO_mem_leaks_fp(FILE *fp) |
0f113f3e MC |
649 | { |
650 | BIO *b; | |
4e482ae6 | 651 | int ret; |
0f113f3e | 652 | |
0f113f3e MC |
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 | */ | |
bbd86bf5 | 658 | CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_DISABLE); |
0f113f3e | 659 | b = BIO_new(BIO_s_file()); |
bbd86bf5 | 660 | CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ENABLE); |
90945fa3 | 661 | if (b == NULL) |
4e482ae6 | 662 | return -1; |
0f113f3e | 663 | BIO_set_fp(b, fp, BIO_NOCLOSE); |
20626cfd | 664 | ret = CRYPTO_mem_leaks_cb(print_bio, b); |
0f113f3e | 665 | BIO_free(b); |
4e482ae6 | 666 | return ret; |
0f113f3e | 667 | } |
bbd86bf5 | 668 | # endif |
65962686 | 669 | |
bbd86bf5 | 670 | #endif |