Loops like this one:
[openssl.git] / crypto / mem_dbg.c
1 /* crypto/mem_dbg.c */
2 /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
3  * All rights reserved.
4  *
5  * This package is an SSL implementation written
6  * by Eric Young (eay@cryptsoft.com).
7  * The implementation was written so as to conform with Netscapes SSL.
8  * 
9  * This library is free for commercial and non-commercial use as long as
10  * the following conditions are aheared to.  The following conditions
11  * apply to all code found in this distribution, be it the RC4, RSA,
12  * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
13  * included with this distribution is covered by the same copyright terms
14  * except that the holder is Tim Hudson (tjh@cryptsoft.com).
15  * 
16  * Copyright remains Eric Young's, and as such any Copyright notices in
17  * the code are not to be removed.
18  * If this package is used in a product, Eric Young should be given attribution
19  * as the author of the parts of the library used.
20  * This can be in the form of a textual message at program startup or
21  * in documentation (online or textual) provided with the package.
22  * 
23  * Redistribution and use in source and binary forms, with or without
24  * modification, are permitted provided that the following conditions
25  * are met:
26  * 1. Redistributions of source code must retain the copyright
27  *    notice, this list of conditions and the following disclaimer.
28  * 2. Redistributions in binary form must reproduce the above copyright
29  *    notice, this list of conditions and the following disclaimer in the
30  *    documentation and/or other materials provided with the distribution.
31  * 3. All advertising materials mentioning features or use of this software
32  *    must display the following acknowledgement:
33  *    "This product includes cryptographic software written by
34  *     Eric Young (eay@cryptsoft.com)"
35  *    The word 'cryptographic' can be left out if the rouines from the library
36  *    being used are not cryptographic related :-).
37  * 4. If you include any Windows specific code (or a derivative thereof) from 
38  *    the apps directory (application code) you must include an acknowledgement:
39  *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
40  * 
41  * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
42  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
43  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
44  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
45  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
46  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
47  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
49  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
50  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
51  * SUCH DAMAGE.
52  * 
53  * The licence and distribution terms for any publically available version or
54  * derivative of this code cannot be changed.  i.e. this code cannot simply be
55  * copied and put under another distribution licence
56  * [including the GNU Public Licence.]
57  */
58
59 #include <stdio.h>
60 #include <stdlib.h>
61 #include <time.h>       
62 #include <openssl/crypto.h>
63 #include <openssl/buffer.h>
64 #include <openssl/bio.h>
65 #include <openssl/lhash.h>
66 #include "cryptlib.h"
67
68 static int mh_mode=CRYPTO_MEM_CHECK_OFF;
69 /* The state changes to CRYPTO_MEM_CHECK_ON | CRYPTO_MEM_CHECK_ENABLE
70  * when the application asks for it (usually after library initialisation
71  * for which no book-keeping is desired).
72  *
73  * State CRYPTO_MEM_CHECK_ON exists only temporarily when the library
74  * thinks that certain allocations should not be checked (e.g. the data
75  * structures used for memory checking).  It is not suitable as an initial
76  * state: the library will unexpectedly enable memory checking when it
77  * executes one of those sections that want to disable checking
78  * temporarily.
79  *
80  * State CRYPTO_MEM_CHECK_ENABLE without ..._ON makes no sense whatsoever.
81  */
82
83 static unsigned long order = 0; /* number of memory requests */
84 static LHASH *mh=NULL; /* hash-table of memory requests (address as key) */
85
86
87 typedef struct app_mem_info_st
88 /* For application-defined information (static C-string `info')
89  * to be displayed in memory leak list.
90  * Each thread has its own stack.  For applications, there is
91  *   CRYPTO_push_info("...")     to push an entry,
92  *   CRYPTO_pop_info()           to pop an entry,
93  *   CRYPTO_remove_all_info()    to pop all entries.
94  */
95         {       
96         unsigned long thread;
97         const char *file;
98         int line;
99         const char *info;
100         struct app_mem_info_st *next; /* tail of thread's stack */
101         int references;
102         } APP_INFO;
103
104 static LHASH *amih=NULL; /* hash-table with those app_mem_info_st's
105                           * that are at the top of their thread's stack
106                           * (with `thread' as key) */
107
108 typedef struct mem_st
109 /* memory-block description */
110         {
111         void *addr;
112         int num;
113         const char *file;
114         int line;
115         unsigned long thread;
116         unsigned long order;
117         time_t time;
118         APP_INFO *app_info;
119         } MEM;
120
121 static long options =             /* extra information to be recorded */
122 #if defined(CRYPTO_MDEBUG_TIME) || defined(CRYPTO_MDEBUG_ALL)
123         V_CRYPTO_MDEBUG_TIME |
124 #endif
125 #if defined(CRYPTO_MDEBUG_THREAD) || defined(CRYPTO_MDEBUG_ALL)
126         V_CRYPTO_MDEBUG_THREAD |
127 #endif
128         0;
129
130
131 static unsigned long disabling_thread = 0;
132
133 int CRYPTO_mem_ctrl(int mode)
134         {
135         int ret=mh_mode;
136
137         CRYPTO_w_lock(CRYPTO_LOCK_MALLOC);
138         switch (mode)
139                 {
140         /* for applications: */
141         case CRYPTO_MEM_CHECK_ON: /* aka MemCheck_start() */
142                 mh_mode = CRYPTO_MEM_CHECK_ON|CRYPTO_MEM_CHECK_ENABLE;
143                 disabling_thread = 0;
144                 break;
145         case CRYPTO_MEM_CHECK_OFF: /* aka MemCheck_stop() */
146                 mh_mode = 0;
147                 disabling_thread = 0;
148                 break;
149
150         /* switch off temporarily (for library-internal use): */
151         case CRYPTO_MEM_CHECK_DISABLE: /* aka MemCheck_off() */
152                 if (mh_mode & CRYPTO_MEM_CHECK_ON)
153                         {
154                         mh_mode&= ~CRYPTO_MEM_CHECK_ENABLE;
155                         if (disabling_thread != CRYPTO_thread_id()) /* otherwise we already have the MALLOC2 lock */
156                                 {
157                                 /* Long-time lock CRYPTO_LOCK_MALLOC2 must not be claimed while
158                                  * we're holding CRYPTO_LOCK_MALLOC, or we'll deadlock if
159                                  * somebody else holds CRYPTO_LOCK_MALLOC2 (and cannot release
160                                  * it because we block entry to this function).
161                                  * Give them a chance, first, and then claim the locks in
162                                  * appropriate order (long-time lock first).
163                                  */
164                                 CRYPTO_w_unlock(CRYPTO_LOCK_MALLOC);
165                                 /* Note that after we have waited for CRYPTO_LOCK_MALLOC2
166                                  * and CRYPTO_LOCK_MALLOC, we'll still be in the right
167                                  * "case" and "if" branch because MemCheck_start and
168                                  * MemCheck_stop may never be used while there are multiple
169                                  * OpenSSL threads. */
170                                 CRYPTO_w_lock(CRYPTO_LOCK_MALLOC2);
171                                 CRYPTO_w_lock(CRYPTO_LOCK_MALLOC);
172                                 disabling_thread=CRYPTO_thread_id();
173                                 }
174                         }
175                 break;
176         case CRYPTO_MEM_CHECK_ENABLE: /* aka MemCheck_on() */
177                 if (mh_mode & CRYPTO_MEM_CHECK_ON)
178                         {
179                         mh_mode|=CRYPTO_MEM_CHECK_ENABLE;
180                         if (disabling_thread != 0)
181                                 {
182                                 disabling_thread=0;
183                                 CRYPTO_w_unlock(CRYPTO_LOCK_MALLOC2);
184                                 }
185                         }
186                 break;
187
188         default:
189                 break;
190                 }
191         CRYPTO_w_unlock(CRYPTO_LOCK_MALLOC);
192         return(ret);
193         }
194
195 int CRYPTO_is_mem_check_on(void)
196         {
197         int ret = 0;
198
199         if (mh_mode & CRYPTO_MEM_CHECK_ON)
200                 {
201                 CRYPTO_w_lock(CRYPTO_LOCK_MALLOC);
202
203                 ret = (mh_mode & CRYPTO_MEM_CHECK_ENABLE)
204                         && disabling_thread != CRYPTO_thread_id();
205
206                 CRYPTO_w_unlock(CRYPTO_LOCK_MALLOC);
207                 }
208         return(ret);
209         }       
210
211
212 void CRYPTO_dbg_set_options(long bits)
213         {
214         options = bits;
215         }
216
217 long CRYPTO_dbg_get_options(void)
218         {
219         return options;
220         }
221
222 static int mem_cmp(MEM *a, MEM *b)
223         {
224         return((char *)a->addr - (char *)b->addr);
225         }
226
227 static unsigned long mem_hash(MEM *a)
228         {
229         unsigned long ret;
230
231         ret=(unsigned long)a->addr;
232
233         ret=ret*17851+(ret>>14)*7+(ret>>4)*251;
234         return(ret);
235         }
236
237 static int app_info_cmp(APP_INFO *a, APP_INFO *b)
238         {
239         return(a->thread != b->thread);
240         }
241
242 static unsigned long app_info_hash(APP_INFO *a)
243         {
244         unsigned long ret;
245
246         ret=(unsigned long)a->thread;
247
248         ret=ret*17851+(ret>>14)*7+(ret>>4)*251;
249         return(ret);
250         }
251
252 static APP_INFO *pop_info(void)
253         {
254         APP_INFO tmp;
255         APP_INFO *ret = NULL;
256
257         if (amih != NULL)
258                 {
259                 tmp.thread=CRYPTO_thread_id();
260                 if ((ret=(APP_INFO *)lh_delete(amih,&tmp)) != NULL)
261                         {
262                         APP_INFO *next=ret->next;
263
264                         if (next != NULL)
265                                 {
266                                 next->references++;
267                                 lh_insert(amih,(char *)next);
268                                 }
269 #ifdef LEVITTE_DEBUG_MEM
270                         if (ret->thread != tmp.thread)
271                                 {
272                                 fprintf(stderr, "pop_info(): deleted info has other thread ID (%lu) than the current thread (%lu)!!!!\n",
273                                         ret->thread, tmp.thread);
274                                 abort();
275                                 }
276 #endif
277                         if (--(ret->references) <= 0)
278                                 {
279                                 ret->next = NULL;
280                                 if (next != NULL)
281                                         next->references--;
282                                 OPENSSL_free(ret);
283                                 }
284                         }
285                 }
286         return(ret);
287         }
288
289 int CRYPTO_push_info_(const char *info, const char *file, int line)
290         {
291         APP_INFO *ami, *amim;
292         int ret=0;
293
294         if (is_MemCheck_on())
295                 {
296                 MemCheck_off(); /* obtains CRYPTO_LOCK_MALLOC2 */
297
298                 if ((ami = (APP_INFO *)OPENSSL_malloc(sizeof(APP_INFO))) == NULL)
299                         {
300                         ret=0;
301                         goto err;
302                         }
303                 if (amih == NULL)
304                         {
305                         if ((amih=lh_new((LHASH_HASH_FN_TYPE)app_info_hash,
306                                         (LHASH_COMP_FN_TYPE)app_info_cmp)) == NULL)
307                                 {
308                                 OPENSSL_free(ami);
309                                 ret=0;
310                                 goto err;
311                                 }
312                         }
313
314                 ami->thread=CRYPTO_thread_id();
315                 ami->file=file;
316                 ami->line=line;
317                 ami->info=info;
318                 ami->references=1;
319                 ami->next=NULL;
320
321                 if ((amim=(APP_INFO *)lh_insert(amih,(char *)ami)) != NULL)
322                         {
323 #ifdef LEVITTE_DEBUG_MEM
324                         if (ami->thread != amim->thread)
325                                 {
326                                 fprintf(stderr, "CRYPTO_push_info(): previous info has other thread ID (%lu) than the current thread (%lu)!!!!\n",
327                                         amim->thread, ami->thread);
328                                 abort();
329                                 }
330 #endif
331                         ami->next=amim;
332                         }
333  err:
334                 MemCheck_on(); /* releases CRYPTO_LOCK_MALLOC2 */
335                 }
336
337         return(ret);
338         }
339
340 int CRYPTO_pop_info(void)
341         {
342         int ret=0;
343
344         if (is_MemCheck_on()) /* _must_ be true, or something went severely wrong */
345                 {
346                 MemCheck_off(); /* obtains CRYPTO_LOCK_MALLOC2 */
347
348                 ret=(pop_info() != NULL);
349
350                 MemCheck_on(); /* releases CRYPTO_LOCK_MALLOC2 */
351                 }
352         return(ret);
353         }
354
355 int CRYPTO_remove_all_info(void)
356         {
357         int ret=0;
358
359         if (is_MemCheck_on()) /* _must_ be true */
360                 {
361                 MemCheck_off(); /* obtains CRYPTO_LOCK_MALLOC2 */
362
363                 while(pop_info() != NULL)
364                         ret++;
365
366                 MemCheck_on(); /* releases CRYPTO_LOCK_MALLOC2 */
367                 }
368         return(ret);
369         }
370
371
372 static unsigned long break_order_num=0;
373 void CRYPTO_dbg_malloc(void *addr, int num, const char *file, int line,
374         int before_p)
375         {
376         MEM *m,*mm;
377         APP_INFO tmp,*amim;
378
379         switch(before_p & 127)
380                 {
381         case 0:
382                 break;
383         case 1:
384                 if (addr == NULL)
385                         break;
386
387                 if (is_MemCheck_on())
388                         {
389                         MemCheck_off(); /* obtains CRYPTO_LOCK_MALLOC2 */
390                         if ((m=(MEM *)OPENSSL_malloc(sizeof(MEM))) == NULL)
391                                 {
392                                 OPENSSL_free(addr);
393                                 MemCheck_on(); /* releases CRYPTO_LOCK_MALLOC2 */
394                                 return;
395                                 }
396                         if (mh == NULL)
397                                 {
398                                 if ((mh=lh_new((LHASH_HASH_FN_TYPE)mem_hash,
399                                         (LHASH_COMP_FN_TYPE)mem_cmp)) == NULL)
400                                         {
401                                         OPENSSL_free(addr);
402                                         OPENSSL_free(m);
403                                         addr=NULL;
404                                         goto err;
405                                         }
406                                 }
407
408                         m->addr=addr;
409                         m->file=file;
410                         m->line=line;
411                         m->num=num;
412                         if (options & V_CRYPTO_MDEBUG_THREAD)
413                                 m->thread=CRYPTO_thread_id();
414                         else
415                                 m->thread=0;
416
417                         if (order == break_order_num)
418                                 {
419                                 /* BREAK HERE */
420                                 m->order=order;
421                                 }
422                         m->order=order++;
423 #ifdef LEVITTE_DEBUG_MEM
424                         fprintf(stderr, "LEVITTE_DEBUG_MEM: [%5d] %c 0x%p (%d)\n",
425                                 m->order,
426                                 (before_p & 128) ? '*' : '+',
427                                 m->addr, m->num);
428 #endif
429                         if (options & V_CRYPTO_MDEBUG_TIME)
430                                 m->time=time(NULL);
431                         else
432                                 m->time=0;
433
434                         tmp.thread=CRYPTO_thread_id();
435                         m->app_info=NULL;
436                         if (amih != NULL
437                                 && (amim=(APP_INFO *)lh_retrieve(amih,(char *)&tmp)) != NULL)
438                                 {
439                                 m->app_info = amim;
440                                 amim->references++;
441                                 }
442
443                         if ((mm=(MEM *)lh_insert(mh,(char *)m)) != NULL)
444                                 {
445                                 /* Not good, but don't sweat it */
446                                 if (mm->app_info != NULL)
447                                         {
448                                         mm->app_info->references--;
449                                         }
450                                 OPENSSL_free(mm);
451                                 }
452                 err:
453                         MemCheck_on(); /* releases CRYPTO_LOCK_MALLOC2 */
454                         }
455                 break;
456                 }
457         return;
458         }
459
460 void CRYPTO_dbg_free(void *addr, int before_p)
461         {
462         MEM m,*mp;
463
464         switch(before_p)
465                 {
466         case 0:
467                 if (addr == NULL)
468                         break;
469
470                 if (is_MemCheck_on() && (mh != NULL))
471                         {
472                         MemCheck_off();
473
474                         m.addr=addr;
475                         mp=(MEM *)lh_delete(mh,(char *)&m);
476                         if (mp != NULL)
477                                 {
478 #ifdef LEVITTE_DEBUG_MEM
479                         fprintf(stderr, "LEVITTE_DEBUG_MEM: [%5d] - 0x%p (%d)\n",
480                                 mp->order, mp->addr, mp->num);
481 #endif
482                                 if (mp->app_info != NULL)
483                                         {
484                                         mp->app_info->references--;
485                                         }
486                                 OPENSSL_free(mp);
487                                 }
488
489                         MemCheck_on(); /* releases CRYPTO_LOCK_MALLOC2 */
490                         }
491                 break;
492         case 1:
493                 break;
494                 }
495         }
496
497 void CRYPTO_dbg_realloc(void *addr1, void *addr2, int num,
498         const char *file, int line, int before_p)
499         {
500         MEM m,*mp;
501
502 #ifdef LEVITTE_DEBUG_MEM
503         fprintf(stderr, "LEVITTE_DEBUG_MEM: --> CRYPTO_dbg_malloc(addr1 = %p, addr2 = %p, num = %d, file = \"%s\", line = %d, before_p = %d)\n",
504                 addr1, addr2, num, file, line, before_p);
505 #endif
506
507         switch(before_p)
508                 {
509         case 0:
510                 break;
511         case 1:
512                 if (addr2 == NULL)
513                         break;
514
515                 if (addr1 == NULL)
516                         {
517                         CRYPTO_dbg_malloc(addr2, num, file, line, 128 | before_p);
518                         break;
519                         }
520
521                 if (is_MemCheck_on())
522                         {
523                         MemCheck_off(); /* obtains CRYPTO_LOCK_MALLOC2 */
524
525                         m.addr=addr1;
526                         mp=(MEM *)lh_delete(mh,(char *)&m);
527                         if (mp != NULL)
528                                 {
529 #ifdef LEVITTE_DEBUG_MEM
530                                 fprintf(stderr, "LEVITTE_DEBUG_MEM: [%5d] * 0x%p (%d) -> 0x%p (%d)\n",
531                                         mp->order,
532                                         mp->addr, mp->num,
533                                         addr2, num);
534 #endif
535                                 mp->addr=addr2;
536                                 mp->num=num;
537                                 lh_insert(mh,(char *)mp);
538                                 }
539
540                         MemCheck_on(); /* releases CRYPTO_LOCK_MALLOC2 */
541                         }
542                 break;
543                 }
544         return;
545         }
546
547
548 typedef struct mem_leak_st
549         {
550         BIO *bio;
551         int chunks;
552         long bytes;
553         } MEM_LEAK;
554
555 static void print_leak(MEM *m, MEM_LEAK *l)
556         {
557         char buf[1024];
558         char *bufp = buf;
559         APP_INFO *amip;
560         int ami_cnt;
561         struct tm *lcl = NULL;
562         unsigned long ti;
563
564         if(m->addr == (char *)l->bio)
565             return;
566
567         if (options & V_CRYPTO_MDEBUG_TIME)
568                 {
569                 lcl = localtime(&m->time);
570         
571                 sprintf(bufp, "[%02d:%02d:%02d] ",
572                         lcl->tm_hour,lcl->tm_min,lcl->tm_sec);
573                 bufp += strlen(bufp);
574                 }
575
576         sprintf(bufp, "%5lu file=%s, line=%d, ",
577                 m->order,m->file,m->line);
578         bufp += strlen(bufp);
579
580         if (options & V_CRYPTO_MDEBUG_THREAD)
581                 {
582                 sprintf(bufp, "thread=%lu, ", m->thread);
583                 bufp += strlen(bufp);
584                 }
585
586         sprintf(bufp, "number=%d, address=%08lX\n",
587                 m->num,(unsigned long)m->addr);
588         bufp += strlen(bufp);
589
590         BIO_puts(l->bio,buf);
591         
592         l->chunks++;
593         l->bytes+=m->num;
594
595         amip=m->app_info;
596         ami_cnt=0;
597         if (!amip)
598                 return;
599         ti=amip->thread;
600         
601         do
602                 {
603                 int buf_len;
604                 int info_len;
605
606                 ami_cnt++;
607                 memset(buf,'>',ami_cnt);
608                 sprintf(buf + ami_cnt,
609                         " thread=%lu, file=%s, line=%d, info=\"",
610                         amip->thread, amip->file, amip->line);
611                 buf_len=strlen(buf);
612                 info_len=strlen(amip->info);
613                 if (128 - buf_len - 3 < info_len)
614                         {
615                         memcpy(buf + buf_len, amip->info, 128 - buf_len - 3);
616                         buf_len = 128 - 3;
617                         }
618                 else
619                         {
620                         strcpy(buf + buf_len, amip->info);
621                         buf_len = strlen(buf);
622                         }
623                 sprintf(buf + buf_len, "\"\n");
624                 
625                 BIO_puts(l->bio,buf);
626
627                 amip = amip->next;
628                 }
629         while(amip && amip->thread == ti);
630                 
631 #ifdef LEVITTE_DEBUG_MEM
632         if (amip)
633                 {
634                 fprintf(stderr, "Thread switch detected in backtrace!!!!\n");
635                 abort();
636                 }
637 #endif
638         }
639
640 void CRYPTO_mem_leaks(BIO *b)
641         {
642         MEM_LEAK ml;
643         char buf[80];
644
645         if (mh == NULL && amih == NULL)
646                 return;
647         ml.bio=b;
648         ml.bytes=0;
649         ml.chunks=0;
650         MemCheck_off(); /* obtains CRYPTO_LOCK_MALLOC2 */
651         if (mh != NULL)
652                 lh_doall_arg(mh, (LHASH_DOALL_ARG_FN_TYPE)print_leak,
653                                 (char *)&ml);
654         if (ml.chunks != 0)
655                 {
656                 sprintf(buf,"%ld bytes leaked in %d chunks\n",
657                         ml.bytes,ml.chunks);
658                 BIO_puts(b,buf);
659                 }
660         else
661                 {
662                 /* Make sure that, if we found no leaks, memory-leak debugging itself
663                  * does not introduce memory leaks (which might irritate
664                  * external debugging tools).
665                  * (When someone enables leak checking, but does not call
666                  * this function, we declare it to be their fault.)
667                  *
668                  * XXX    This should be in CRYPTO_mem_leaks_cb,
669                  * and CRYPTO_mem_leaks should be implemented by
670                  * using CRYPTO_mem_leaks_cb.
671                  * (Also their should be a variant of lh_doall_arg
672                  * that takes a function pointer instead of a void *;
673                  * this would obviate the ugly and illegal
674                  * void_fn_to_char kludge in CRYPTO_mem_leaks_cb.
675                  * Otherwise the code police will come and get us.)
676                  */
677                 CRYPTO_w_lock(CRYPTO_LOCK_MALLOC);
678                 if (mh != NULL)
679                         {
680                         lh_free(mh);
681                         mh = NULL;
682                         }
683                 if (amih != NULL)
684                         {
685                         if (lh_num_items(amih) == 0) 
686                                 {
687                                 lh_free(amih);
688                                 amih = NULL;
689                                 }
690                         }
691                 CRYPTO_w_unlock(CRYPTO_LOCK_MALLOC);
692                 }
693         MemCheck_on(); /* releases CRYPTO_LOCK_MALLOC2 */
694
695 #if 0
696         lh_stats_bio(mh,b);
697         lh_node_stats_bio(mh,b);
698         lh_node_usage_stats_bio(mh,b);
699 #endif
700         }
701
702 #ifndef NO_FP_API
703 void CRYPTO_mem_leaks_fp(FILE *fp)
704         {
705         BIO *b;
706
707         if (mh == NULL) return;
708         if ((b=BIO_new(BIO_s_file())) == NULL)
709                 return;
710         BIO_set_fp(b,fp,BIO_NOCLOSE);
711         CRYPTO_mem_leaks(b);
712         BIO_free(b);
713         }
714 #endif
715
716
717
718 /* FIXME: We really don't allow much to the callback.  For example, it has
719    no chance of reaching the info stack for the item it processes.  Should
720    it really be this way?  -- Richard Levitte */
721 static void cb_leak(MEM *m,
722                     void (**cb)(unsigned long, const char *, int, int, void *))
723         {
724         (**cb)(m->order,m->file,m->line,m->num,m->addr);
725         }
726
727 void CRYPTO_mem_leaks_cb(void (*cb)(unsigned long, const char *, int, int, void *))
728         {
729         if (mh == NULL) return;
730         CRYPTO_w_lock(CRYPTO_LOCK_MALLOC2);
731         lh_doall_arg(mh, (LHASH_DOALL_ARG_FN_TYPE)cb_leak,(void *)&cb);
732         CRYPTO_w_unlock(CRYPTO_LOCK_MALLOC2);
733         }