mem_dbg.c 18 KB

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