]>
Commit | Line | Data |
---|---|---|
aa6bb135 | 1 | /* |
2d905f67 | 2 | * Copyright 1995-2019 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 | |
9471f776 | 42 | static CRYPTO_ONCE memdbg_init = CRYPTO_ONCE_STATIC_INIT; |
0e598a3d RS |
43 | CRYPTO_RWLOCK *memdbg_lock; |
44 | static CRYPTO_RWLOCK *long_memdbg_lock; | |
9ac42ed8 | 45 | |
0cd08cce | 46 | /* memory-block description */ |
e6b5c341 | 47 | struct mem_st { |
0f113f3e MC |
48 | void *addr; |
49 | int num; | |
50 | const char *file; | |
51 | int line; | |
9471f776 | 52 | CRYPTO_THREAD_ID threadid; |
0f113f3e MC |
53 | unsigned long order; |
54 | time_t time; | |
ef8ca6bd | 55 | #ifndef OPENSSL_NO_CRYPTO_MDEBUG_BACKTRACE |
012c5408 RL |
56 | void *array[30]; |
57 | size_t array_siz; | |
58 | #endif | |
e6b5c341 DSH |
59 | }; |
60 | ||
0e598a3d RS |
61 | /* |
62 | * hash-table of memory requests (address as * key); access requires | |
63 | * long_memdbg_lock lock | |
64 | */ | |
65 | static LHASH_OF(MEM) *mh = NULL; | |
0f113f3e | 66 | |
bbd86bf5 RS |
67 | /* num_disable > 0 iff mh_mode == CRYPTO_MEM_CHECK_ON (w/o ..._ENABLE) */ |
68 | static unsigned int num_disable = 0; | |
48fc582f | 69 | |
0f113f3e | 70 | /* |
0e598a3d | 71 | * Valid iff num_disable > 0. long_memdbg_lock is locked exactly in this |
4c329696 | 72 | * case (by the thread named in disabling_thread). |
5f834ab1 | 73 | */ |
9471f776 MC |
74 | static CRYPTO_THREAD_ID disabling_threadid; |
75 | ||
23dd0c9f | 76 | DEFINE_RUN_ONCE_STATIC(do_memdbg_init) |
9471f776 | 77 | { |
63ab5ea1 BK |
78 | memdbg_lock = CRYPTO_THREAD_lock_new(); |
79 | long_memdbg_lock = CRYPTO_THREAD_lock_new(); | |
e7aa7c11 | 80 | if (memdbg_lock == NULL || long_memdbg_lock == NULL) { |
0e598a3d RS |
81 | CRYPTO_THREAD_lock_free(memdbg_lock); |
82 | memdbg_lock = NULL; | |
83 | CRYPTO_THREAD_lock_free(long_memdbg_lock); | |
84 | long_memdbg_lock = NULL; | |
23dd0c9f DSH |
85 | return 0; |
86 | } | |
87 | return 1; | |
9471f776 | 88 | } |
9ac42ed8 | 89 | |
bbd86bf5 | 90 | #endif |
9dc61049 | 91 | |
9ac42ed8 | 92 | int CRYPTO_mem_ctrl(int mode) |
0f113f3e | 93 | { |
c2e27310 | 94 | #ifdef OPENSSL_NO_CRYPTO_MDEBUG |
bbd86bf5 RS |
95 | return mode - mode; |
96 | #else | |
0f113f3e MC |
97 | int ret = mh_mode; |
98 | ||
c2e4e5d2 RL |
99 | if (!RUN_ONCE(&memdbg_init, do_memdbg_init)) |
100 | return -1; | |
9471f776 | 101 | |
0e598a3d | 102 | CRYPTO_THREAD_write_lock(memdbg_lock); |
0f113f3e | 103 | switch (mode) { |
bbd86bf5 RS |
104 | default: |
105 | break; | |
106 | ||
107 | case CRYPTO_MEM_CHECK_ON: | |
0f113f3e MC |
108 | mh_mode = CRYPTO_MEM_CHECK_ON | CRYPTO_MEM_CHECK_ENABLE; |
109 | num_disable = 0; | |
110 | break; | |
bbd86bf5 RS |
111 | |
112 | case CRYPTO_MEM_CHECK_OFF: | |
0f113f3e | 113 | mh_mode = 0; |
bbd86bf5 | 114 | num_disable = 0; |
0f113f3e MC |
115 | break; |
116 | ||
bbd86bf5 RS |
117 | /* switch off temporarily (for library-internal use): */ |
118 | case CRYPTO_MEM_CHECK_DISABLE: | |
0f113f3e | 119 | if (mh_mode & CRYPTO_MEM_CHECK_ON) { |
9471f776 | 120 | CRYPTO_THREAD_ID cur = CRYPTO_THREAD_get_current_id(); |
0e598a3d | 121 | /* see if we don't have long_memdbg_lock already */ |
0f113f3e | 122 | if (!num_disable |
9471f776 | 123 | || !CRYPTO_THREAD_compare_id(disabling_threadid, cur)) { |
0f113f3e | 124 | /* |
0e598a3d RS |
125 | * Long-time lock long_memdbg_lock must not be claimed |
126 | * while we're holding memdbg_lock, or we'll deadlock | |
127 | * if somebody else holds long_memdbg_lock (and cannot | |
0f113f3e MC |
128 | * release it because we block entry to this function). Give |
129 | * them a chance, first, and then claim the locks in | |
130 | * appropriate order (long-time lock first). | |
131 | */ | |
0e598a3d | 132 | CRYPTO_THREAD_unlock(memdbg_lock); |
0f113f3e | 133 | /* |
0e598a3d RS |
134 | * Note that after we have waited for long_memdbg_lock and |
135 | * memdbg_lock, we'll still be in the right "case" and | |
0f113f3e MC |
136 | * "if" branch because MemCheck_start and MemCheck_stop may |
137 | * never be used while there are multiple OpenSSL threads. | |
138 | */ | |
0e598a3d RS |
139 | CRYPTO_THREAD_write_lock(long_memdbg_lock); |
140 | CRYPTO_THREAD_write_lock(memdbg_lock); | |
0f113f3e | 141 | mh_mode &= ~CRYPTO_MEM_CHECK_ENABLE; |
9471f776 | 142 | disabling_threadid = cur; |
0f113f3e MC |
143 | } |
144 | num_disable++; | |
145 | } | |
146 | break; | |
bbd86bf5 RS |
147 | |
148 | case CRYPTO_MEM_CHECK_ENABLE: | |
0f113f3e MC |
149 | if (mh_mode & CRYPTO_MEM_CHECK_ON) { |
150 | if (num_disable) { /* always true, or something is going wrong */ | |
151 | num_disable--; | |
152 | if (num_disable == 0) { | |
153 | mh_mode |= CRYPTO_MEM_CHECK_ENABLE; | |
0e598a3d | 154 | CRYPTO_THREAD_unlock(long_memdbg_lock); |
0f113f3e MC |
155 | } |
156 | } | |
157 | } | |
158 | break; | |
0f113f3e | 159 | } |
0e598a3d | 160 | CRYPTO_THREAD_unlock(memdbg_lock); |
b4df712a | 161 | return ret; |
bbd86bf5 | 162 | #endif |
0f113f3e | 163 | } |
9ac42ed8 | 164 | |
6ac11bd0 | 165 | #ifndef OPENSSL_NO_CRYPTO_MDEBUG |
bbd86bf5 RS |
166 | |
167 | static int mem_check_on(void) | |
0f113f3e MC |
168 | { |
169 | int ret = 0; | |
a0605744 | 170 | CRYPTO_THREAD_ID cur; |
9ac42ed8 | 171 | |
0f113f3e | 172 | if (mh_mode & CRYPTO_MEM_CHECK_ON) { |
c2e4e5d2 RL |
173 | if (!RUN_ONCE(&memdbg_init, do_memdbg_init)) |
174 | return 0; | |
9471f776 | 175 | |
a0605744 | 176 | cur = CRYPTO_THREAD_get_current_id(); |
0e598a3d | 177 | CRYPTO_THREAD_read_lock(memdbg_lock); |
9ac42ed8 | 178 | |
0f113f3e | 179 | ret = (mh_mode & CRYPTO_MEM_CHECK_ENABLE) |
9471f776 | 180 | || !CRYPTO_THREAD_compare_id(disabling_threadid, cur); |
9ac42ed8 | 181 | |
0e598a3d | 182 | CRYPTO_THREAD_unlock(memdbg_lock); |
0f113f3e | 183 | } |
b4df712a | 184 | return ret; |
0f113f3e | 185 | } |
9ac42ed8 | 186 | |
3c1d6bbc | 187 | static int mem_cmp(const MEM *a, const MEM *b) |
0f113f3e | 188 | { |
1875e6db | 189 | #ifdef _WIN64 |
0f113f3e MC |
190 | const char *ap = (const char *)a->addr, *bp = (const char *)b->addr; |
191 | if (ap == bp) | |
192 | return 0; | |
193 | else if (ap > bp) | |
194 | return 1; | |
195 | else | |
196 | return -1; | |
1875e6db | 197 | #else |
0f113f3e | 198 | return (const char *)a->addr - (const char *)b->addr; |
1875e6db | 199 | #endif |
0f113f3e MC |
200 | } |
201 | ||
3c1d6bbc | 202 | static unsigned long mem_hash(const MEM *a) |
0f113f3e | 203 | { |
5f0580cc | 204 | size_t ret; |
9ac42ed8 | 205 | |
5f0580cc | 206 | ret = (size_t)a->addr; |
0f113f3e MC |
207 | |
208 | ret = ret * 17851 + (ret >> 14) * 7 + (ret >> 4) * 251; | |
b4df712a | 209 | return ret; |
0f113f3e | 210 | } |
9ac42ed8 | 211 | |
936c2b9e | 212 | #ifndef OPENSSL_NO_DEPRECATED_3_0 |
4fae386c | 213 | int CRYPTO_mem_debug_push(const char *info, const char *file, int line) |
0f113f3e | 214 | { |
e7aa7c11 | 215 | return 0; |
0f113f3e | 216 | } |
9ac42ed8 | 217 | |
4fae386c | 218 | int CRYPTO_mem_debug_pop(void) |
0f113f3e | 219 | { |
e7aa7c11 | 220 | return 0; |
0f113f3e | 221 | } |
decdb980 | 222 | #endif |
9ac42ed8 | 223 | |
0f113f3e | 224 | static unsigned long break_order_num = 0; |
bbd86bf5 RS |
225 | |
226 | void CRYPTO_mem_debug_malloc(void *addr, size_t num, int before_p, | |
227 | const char *file, int line) | |
0f113f3e MC |
228 | { |
229 | MEM *m, *mm; | |
0f113f3e MC |
230 | |
231 | switch (before_p & 127) { | |
232 | case 0: | |
233 | break; | |
234 | case 1: | |
235 | if (addr == NULL) | |
236 | break; | |
237 | ||
bbd86bf5 RS |
238 | if (mem_check_on()) { |
239 | CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_DISABLE); | |
9471f776 | 240 | |
c2e4e5d2 RL |
241 | if (!RUN_ONCE(&memdbg_init, do_memdbg_init) |
242 | || (m = OPENSSL_malloc(sizeof(*m))) == NULL) { | |
0f113f3e | 243 | OPENSSL_free(addr); |
bbd86bf5 | 244 | CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ENABLE); |
0f113f3e MC |
245 | return; |
246 | } | |
247 | if (mh == NULL) { | |
62d0577e | 248 | if ((mh = lh_MEM_new(mem_hash, mem_cmp)) == NULL) { |
0f113f3e MC |
249 | OPENSSL_free(addr); |
250 | OPENSSL_free(m); | |
251 | addr = NULL; | |
252 | goto err; | |
253 | } | |
254 | } | |
255 | ||
256 | m->addr = addr; | |
257 | m->file = file; | |
258 | m->line = line; | |
259 | m->num = num; | |
9471f776 | 260 | m->threadid = CRYPTO_THREAD_get_current_id(); |
0f113f3e MC |
261 | |
262 | if (order == break_order_num) { | |
263 | /* BREAK HERE */ | |
264 | m->order = order; | |
265 | } | |
266 | m->order = order++; | |
ef8ca6bd | 267 | # ifndef OPENSSL_NO_CRYPTO_MDEBUG_BACKTRACE |
012c5408 | 268 | m->array_siz = backtrace(m->array, OSSL_NELEM(m->array)); |
bbd86bf5 RS |
269 | # endif |
270 | m->time = time(NULL); | |
0f113f3e | 271 | |
e7aa7c11 | 272 | if ((mm = lh_MEM_insert(mh, m)) != NULL) |
0f113f3e | 273 | OPENSSL_free(mm); |
0f113f3e | 274 | err: |
bbd86bf5 | 275 | CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ENABLE); |
0f113f3e MC |
276 | } |
277 | break; | |
278 | } | |
279 | return; | |
280 | } | |
9ac42ed8 | 281 | |
05c7b163 RL |
282 | void CRYPTO_mem_debug_free(void *addr, int before_p, |
283 | const char *file, int line) | |
0f113f3e MC |
284 | { |
285 | MEM m, *mp; | |
286 | ||
287 | switch (before_p) { | |
288 | case 0: | |
289 | if (addr == NULL) | |
290 | break; | |
291 | ||
bbd86bf5 RS |
292 | if (mem_check_on() && (mh != NULL)) { |
293 | CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_DISABLE); | |
0f113f3e MC |
294 | m.addr = addr; |
295 | mp = lh_MEM_delete(mh, &m); | |
e7aa7c11 | 296 | OPENSSL_free(mp); |
bbd86bf5 | 297 | CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ENABLE); |
0f113f3e MC |
298 | } |
299 | break; | |
300 | case 1: | |
301 | break; | |
302 | } | |
303 | } | |
9ac42ed8 | 304 | |
bbd86bf5 RS |
305 | void CRYPTO_mem_debug_realloc(void *addr1, void *addr2, size_t num, |
306 | int before_p, const char *file, int line) | |
0f113f3e MC |
307 | { |
308 | MEM m, *mp; | |
9ac42ed8 | 309 | |
0f113f3e MC |
310 | switch (before_p) { |
311 | case 0: | |
312 | break; | |
313 | case 1: | |
314 | if (addr2 == NULL) | |
315 | break; | |
316 | ||
317 | if (addr1 == NULL) { | |
bbd86bf5 | 318 | CRYPTO_mem_debug_malloc(addr2, num, 128 | before_p, file, line); |
0f113f3e MC |
319 | break; |
320 | } | |
321 | ||
bbd86bf5 RS |
322 | if (mem_check_on()) { |
323 | CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_DISABLE); | |
0f113f3e MC |
324 | |
325 | m.addr = addr1; | |
326 | mp = lh_MEM_delete(mh, &m); | |
327 | if (mp != NULL) { | |
0f113f3e MC |
328 | mp->addr = addr2; |
329 | mp->num = num; | |
ef8ca6bd | 330 | #ifndef OPENSSL_NO_CRYPTO_MDEBUG_BACKTRACE |
012c5408 RL |
331 | mp->array_siz = backtrace(mp->array, OSSL_NELEM(mp->array)); |
332 | #endif | |
0f113f3e MC |
333 | (void)lh_MEM_insert(mh, mp); |
334 | } | |
335 | ||
bbd86bf5 | 336 | CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ENABLE); |
0f113f3e MC |
337 | } |
338 | break; | |
339 | } | |
340 | return; | |
341 | } | |
342 | ||
343 | typedef struct mem_leak_st { | |
20626cfd RL |
344 | int (*print_cb) (const char *str, size_t len, void *u); |
345 | void *print_cb_arg; | |
0f113f3e MC |
346 | int chunks; |
347 | long bytes; | |
348 | } MEM_LEAK; | |
9ac42ed8 | 349 | |
2a056de8 | 350 | static void print_leak(const MEM *m, MEM_LEAK *l) |
0f113f3e MC |
351 | { |
352 | char buf[1024]; | |
2d905f67 | 353 | char *bufp = buf, *hex; |
e7aa7c11 | 354 | size_t len = sizeof(buf); |
86ba26c8 | 355 | int n; |
0f113f3e | 356 | struct tm *lcl = NULL; |
9ac42ed8 | 357 | |
bbd86bf5 | 358 | lcl = localtime(&m->time); |
86ba26c8 P |
359 | n = BIO_snprintf(bufp, len, "[%02d:%02d:%02d] ", |
360 | lcl->tm_hour, lcl->tm_min, lcl->tm_sec); | |
361 | if (n <= 0) { | |
362 | bufp[0] = '\0'; | |
363 | return; | |
364 | } | |
365 | bufp += n; | |
366 | len -= n; | |
0f113f3e | 367 | |
86ba26c8 P |
368 | n = BIO_snprintf(bufp, len, "%5lu file=%s, line=%d, ", |
369 | m->order, m->file, m->line); | |
370 | if (n <= 0) | |
371 | return; | |
372 | bufp += n; | |
373 | len -= n; | |
0f113f3e | 374 | |
2d905f67 P |
375 | hex = OPENSSL_buf2hexstr((const unsigned char *)&m->threadid, |
376 | sizeof(m->threadid)); | |
377 | n = BIO_snprintf(bufp, len, "thread=%s, number=%d, address=%p\n", hex, | |
378 | m->num, m->addr); | |
379 | OPENSSL_free(hex); | |
86ba26c8 P |
380 | if (n <= 0) |
381 | return; | |
382 | bufp += n; | |
383 | len -= n; | |
0f113f3e | 384 | |
86ba26c8 | 385 | l->print_cb(buf, (size_t)(bufp - buf), l->print_cb_arg); |
0f113f3e MC |
386 | l->chunks++; |
387 | l->bytes += m->num; | |
388 | ||
ef8ca6bd | 389 | #ifndef OPENSSL_NO_CRYPTO_MDEBUG_BACKTRACE |
012c5408 RL |
390 | { |
391 | size_t i; | |
392 | char **strings = backtrace_symbols(m->array, m->array_siz); | |
bbd86bf5 | 393 | |
012c5408 RL |
394 | for (i = 0; i < m->array_siz; i++) |
395 | fprintf(stderr, "##> %s\n", strings[i]); | |
012c5408 RL |
396 | free(strings); |
397 | } | |
398 | #endif | |
0f113f3e | 399 | } |
9ac42ed8 | 400 | |
2a056de8 | 401 | IMPLEMENT_LHASH_DOALL_ARG_CONST(MEM, MEM_LEAK); |
98d517c5 | 402 | |
20626cfd RL |
403 | int CRYPTO_mem_leaks_cb(int (*cb) (const char *str, size_t len, void *u), |
404 | void *u) | |
0f113f3e MC |
405 | { |
406 | MEM_LEAK ml; | |
407 | ||
38a6d7f8 | 408 | /* Ensure all resources are released */ |
f672aee4 | 409 | OPENSSL_cleanup(); |
38a6d7f8 | 410 | |
c2e4e5d2 RL |
411 | if (!RUN_ONCE(&memdbg_init, do_memdbg_init)) |
412 | return -1; | |
9471f776 | 413 | |
bbd86bf5 | 414 | CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_DISABLE); |
0f113f3e | 415 | |
20626cfd RL |
416 | ml.print_cb = cb; |
417 | ml.print_cb_arg = u; | |
0f113f3e MC |
418 | ml.bytes = 0; |
419 | ml.chunks = 0; | |
420 | if (mh != NULL) | |
2a056de8 | 421 | lh_MEM_doall_MEM_LEAK(mh, print_leak, &ml); |
b3895f42 | 422 | |
0f113f3e | 423 | if (ml.chunks != 0) { |
20626cfd RL |
424 | char buf[256]; |
425 | ||
426 | BIO_snprintf(buf, sizeof(buf), "%ld bytes leaked in %d chunks\n", | |
427 | ml.bytes, ml.chunks); | |
428 | cb(buf, strlen(buf), u); | |
0f113f3e MC |
429 | } else { |
430 | /* | |
431 | * Make sure that, if we found no leaks, memory-leak debugging itself | |
432 | * does not introduce memory leaks (which might irritate external | |
433 | * debugging tools). (When someone enables leak checking, but does not | |
bbd86bf5 | 434 | * call this function, we declare it to be their fault.) |
0f113f3e MC |
435 | */ |
436 | int old_mh_mode; | |
437 | ||
0e598a3d | 438 | CRYPTO_THREAD_write_lock(memdbg_lock); |
0f113f3e MC |
439 | |
440 | /* | |
bbd86bf5 RS |
441 | * avoid deadlock when lh_free() uses CRYPTO_mem_debug_free(), which uses |
442 | * mem_check_on | |
0f113f3e MC |
443 | */ |
444 | old_mh_mode = mh_mode; | |
445 | mh_mode = CRYPTO_MEM_CHECK_OFF; | |
446 | ||
25aaa98a RS |
447 | lh_MEM_free(mh); |
448 | mh = NULL; | |
0f113f3e MC |
449 | |
450 | mh_mode = old_mh_mode; | |
0e598a3d | 451 | CRYPTO_THREAD_unlock(memdbg_lock); |
0f113f3e | 452 | } |
9471f776 MC |
453 | CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_OFF); |
454 | ||
455 | /* Clean up locks etc */ | |
0e598a3d RS |
456 | CRYPTO_THREAD_lock_free(memdbg_lock); |
457 | CRYPTO_THREAD_lock_free(long_memdbg_lock); | |
458 | memdbg_lock = NULL; | |
459 | long_memdbg_lock = NULL; | |
9471f776 | 460 | |
4e482ae6 | 461 | return ml.chunks == 0 ? 1 : 0; |
0f113f3e | 462 | } |
9ac42ed8 | 463 | |
20626cfd RL |
464 | static int print_bio(const char *str, size_t len, void *b) |
465 | { | |
466 | return BIO_write((BIO *)b, str, len); | |
467 | } | |
468 | ||
469 | int CRYPTO_mem_leaks(BIO *b) | |
470 | { | |
471 | /* | |
472 | * OPENSSL_cleanup() will free the ex_data locks so we can't have any | |
473 | * ex_data hanging around | |
474 | */ | |
475 | bio_free_ex_data(b); | |
476 | ||
477 | return CRYPTO_mem_leaks_cb(print_bio, b); | |
478 | } | |
479 | ||
bbd86bf5 | 480 | # ifndef OPENSSL_NO_STDIO |
4e482ae6 | 481 | int CRYPTO_mem_leaks_fp(FILE *fp) |
0f113f3e MC |
482 | { |
483 | BIO *b; | |
4e482ae6 | 484 | int ret; |
0f113f3e | 485 | |
0f113f3e MC |
486 | /* |
487 | * Need to turn off memory checking when allocated BIOs ... especially as | |
488 | * we're creating them at a time when we're trying to check we've not | |
489 | * left anything un-free()'d!! | |
490 | */ | |
bbd86bf5 | 491 | CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_DISABLE); |
0f113f3e | 492 | b = BIO_new(BIO_s_file()); |
bbd86bf5 | 493 | CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ENABLE); |
90945fa3 | 494 | if (b == NULL) |
4e482ae6 | 495 | return -1; |
0f113f3e | 496 | BIO_set_fp(b, fp, BIO_NOCLOSE); |
20626cfd | 497 | ret = CRYPTO_mem_leaks_cb(print_bio, b); |
0f113f3e | 498 | BIO_free(b); |
4e482ae6 | 499 | return ret; |
0f113f3e | 500 | } |
bbd86bf5 | 501 | # endif |
65962686 | 502 | |
bbd86bf5 | 503 | #endif |