HP-UX shared libraries do not build any longer, as EX_LIBS contains
[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()
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(app_info_hash,app_info_cmp)) == NULL)
306                                 {
307                                 OPENSSL_free(ami);
308                                 ret=0;
309                                 goto err;
310                                 }
311                         }
312
313                 ami->thread=CRYPTO_thread_id();
314                 ami->file=file;
315                 ami->line=line;
316                 ami->info=info;
317                 ami->references=1;
318                 ami->next=NULL;
319
320                 if ((amim=(APP_INFO *)lh_insert(amih,(char *)ami)) != NULL)
321                         {
322 #ifdef LEVITTE_DEBUG_MEM
323                         if (ami->thread != amim->thread)
324                                 {
325                                 fprintf(stderr, "CRYPTO_push_info(): previous info has other thread ID (%lu) than the current thread (%lu)!!!!\n",
326                                         amim->thread, ami->thread);
327                                 abort();
328                                 }
329 #endif
330                         ami->next=amim;
331                         }
332  err:
333                 MemCheck_on(); /* releases CRYPTO_LOCK_MALLOC2 */
334                 }
335
336         return(ret);
337         }
338
339 int CRYPTO_pop_info(void)
340         {
341         int ret=0;
342
343         if (is_MemCheck_on()) /* _must_ be true, or something went severely wrong */
344                 {
345                 MemCheck_off(); /* obtains CRYPTO_LOCK_MALLOC2 */
346
347                 ret=(pop_info() != NULL);
348
349                 MemCheck_on(); /* releases CRYPTO_LOCK_MALLOC2 */
350                 }
351         return(ret);
352         }
353
354 int CRYPTO_remove_all_info(void)
355         {
356         int ret=0;
357
358         if (is_MemCheck_on()) /* _must_ be true */
359                 {
360                 MemCheck_off(); /* obtains CRYPTO_LOCK_MALLOC2 */
361
362                 while(pop_info() != NULL)
363                         ret++;
364
365                 MemCheck_on(); /* releases CRYPTO_LOCK_MALLOC2 */
366                 }
367         return(ret);
368         }
369
370
371 static unsigned long break_order_num=0;
372 void CRYPTO_dbg_malloc(void *addr, int num, const char *file, int line,
373         int before_p)
374         {
375         MEM *m,*mm;
376         APP_INFO tmp,*amim;
377
378         switch(before_p & 127)
379                 {
380         case 0:
381                 break;
382         case 1:
383                 if (addr == NULL)
384                         break;
385
386                 if (is_MemCheck_on())
387                         {
388                         MemCheck_off(); /* obtains CRYPTO_LOCK_MALLOC2 */
389                         if ((m=(MEM *)OPENSSL_malloc(sizeof(MEM))) == NULL)
390                                 {
391                                 OPENSSL_free(addr);
392                                 MemCheck_on(); /* releases CRYPTO_LOCK_MALLOC2 */
393                                 return;
394                                 }
395                         if (mh == NULL)
396                                 {
397                                 if ((mh=lh_new(mem_hash,mem_cmp)) == NULL)
398                                         {
399                                         OPENSSL_free(addr);
400                                         OPENSSL_free(m);
401                                         addr=NULL;
402                                         goto err;
403                                         }
404                                 }
405
406                         m->addr=addr;
407                         m->file=file;
408                         m->line=line;
409                         m->num=num;
410                         if (options & V_CRYPTO_MDEBUG_THREAD)
411                                 m->thread=CRYPTO_thread_id();
412                         else
413                                 m->thread=0;
414
415                         if (order == break_order_num)
416                                 {
417                                 /* BREAK HERE */
418                                 m->order=order;
419                                 }
420                         m->order=order++;
421 #ifdef LEVITTE_DEBUG_MEM
422                         fprintf(stderr, "LEVITTE_DEBUG_MEM: [%5d] %c 0x%p (%d)\n",
423                                 m->order,
424                                 (before_p & 128) ? '*' : '+',
425                                 m->addr, m->num);
426 #endif
427                         if (options & V_CRYPTO_MDEBUG_TIME)
428                                 m->time=time(NULL);
429                         else
430                                 m->time=0;
431
432                         tmp.thread=CRYPTO_thread_id();
433                         m->app_info=NULL;
434                         if (amih != NULL
435                                 && (amim=(APP_INFO *)lh_retrieve(amih,(char *)&tmp)) != NULL)
436                                 {
437                                 m->app_info = amim;
438                                 amim->references++;
439                                 }
440
441                         if ((mm=(MEM *)lh_insert(mh,(char *)m)) != NULL)
442                                 {
443                                 /* Not good, but don't sweat it */
444                                 if (mm->app_info != NULL)
445                                         {
446                                         mm->app_info->references--;
447                                         }
448                                 OPENSSL_free(mm);
449                                 }
450                 err:
451                         MemCheck_on(); /* releases CRYPTO_LOCK_MALLOC2 */
452                         }
453                 break;
454                 }
455         return;
456         }
457
458 void CRYPTO_dbg_free(void *addr, int before_p)
459         {
460         MEM m,*mp;
461
462         switch(before_p)
463                 {
464         case 0:
465                 if (addr == NULL)
466                         break;
467
468                 if (is_MemCheck_on() && (mh != NULL))
469                         {
470                         MemCheck_off();
471
472                         m.addr=addr;
473                         mp=(MEM *)lh_delete(mh,(char *)&m);
474                         if (mp != NULL)
475                                 {
476 #ifdef LEVITTE_DEBUG_MEM
477                         fprintf(stderr, "LEVITTE_DEBUG_MEM: [%5d] - 0x%p (%d)\n",
478                                 mp->order, mp->addr, mp->num);
479 #endif
480                                 if (mp->app_info != NULL)
481                                         {
482                                         mp->app_info->references--;
483                                         }
484                                 OPENSSL_free(mp);
485                                 }
486
487                         MemCheck_on(); /* releases CRYPTO_LOCK_MALLOC2 */
488                         }
489                 break;
490         case 1:
491                 break;
492                 }
493         }
494
495 void CRYPTO_dbg_realloc(void *addr1, void *addr2, int num,
496         const char *file, int line, int before_p)
497         {
498         MEM m,*mp;
499
500 #ifdef LEVITTE_DEBUG_MEM
501         fprintf(stderr, "LEVITTE_DEBUG_MEM: --> CRYPTO_dbg_malloc(addr1 = %p, addr2 = %p, num = %d, file = \"%s\", line = %d, before_p = %d)\n",
502                 addr1, addr2, num, file, line, before_p);
503 #endif
504
505         switch(before_p)
506                 {
507         case 0:
508                 break;
509         case 1:
510                 if (addr2 == NULL)
511                         break;
512
513                 if (addr1 == NULL)
514                         {
515                         CRYPTO_dbg_malloc(addr2, num, file, line, 128 | before_p);
516                         break;
517                         }
518
519                 if (is_MemCheck_on())
520                         {
521                         MemCheck_off(); /* obtains CRYPTO_LOCK_MALLOC2 */
522
523                         m.addr=addr1;
524                         mp=(MEM *)lh_delete(mh,(char *)&m);
525                         if (mp != NULL)
526                                 {
527 #ifdef LEVITTE_DEBUG_MEM
528                                 fprintf(stderr, "LEVITTE_DEBUG_MEM: [%5d] * 0x%p (%d) -> 0x%p (%d)\n",
529                                         mp->order,
530                                         mp->addr, mp->num,
531                                         addr2, num);
532 #endif
533                                 mp->addr=addr2;
534                                 mp->num=num;
535                                 lh_insert(mh,(char *)mp);
536                                 }
537
538                         MemCheck_on(); /* releases CRYPTO_LOCK_MALLOC2 */
539                         }
540                 break;
541                 }
542         return;
543         }
544
545
546 typedef struct mem_leak_st
547         {
548         BIO *bio;
549         int chunks;
550         long bytes;
551         } MEM_LEAK;
552
553 static void print_leak(MEM *m, MEM_LEAK *l)
554         {
555         char buf[1024];
556         char *bufp = buf;
557         APP_INFO *amip;
558         int ami_cnt;
559         struct tm *lcl = NULL;
560         unsigned long ti;
561
562         if(m->addr == (char *)l->bio)
563             return;
564
565         if (options & V_CRYPTO_MDEBUG_TIME)
566                 {
567                 lcl = localtime(&m->time);
568         
569                 sprintf(bufp, "[%02d:%02d:%02d] ",
570                         lcl->tm_hour,lcl->tm_min,lcl->tm_sec);
571                 bufp += strlen(bufp);
572                 }
573
574         sprintf(bufp, "%5lu file=%s, line=%d, ",
575                 m->order,m->file,m->line);
576         bufp += strlen(bufp);
577
578         if (options & V_CRYPTO_MDEBUG_THREAD)
579                 {
580                 sprintf(bufp, "thread=%lu, ", m->thread);
581                 bufp += strlen(bufp);
582                 }
583
584         sprintf(bufp, "number=%d, address=%08lX\n",
585                 m->num,(unsigned long)m->addr);
586         bufp += strlen(bufp);
587
588         BIO_puts(l->bio,buf);
589         
590         l->chunks++;
591         l->bytes+=m->num;
592
593         amip=m->app_info;
594         ami_cnt=0;
595         if (!amip)
596                 return;
597         ti=amip->thread;
598         
599         do
600                 {
601                 int buf_len;
602                 int info_len;
603
604                 ami_cnt++;
605                 memset(buf,'>',ami_cnt);
606                 sprintf(buf + ami_cnt,
607                         " thread=%lu, file=%s, line=%d, info=\"",
608                         amip->thread, amip->file, amip->line);
609                 buf_len=strlen(buf);
610                 info_len=strlen(amip->info);
611                 if (128 - buf_len - 3 < info_len)
612                         {
613                         memcpy(buf + buf_len, amip->info, 128 - buf_len - 3);
614                         buf_len = 128 - 3;
615                         }
616                 else
617                         {
618                         strcpy(buf + buf_len, amip->info);
619                         buf_len = strlen(buf);
620                         }
621                 sprintf(buf + buf_len, "\"\n");
622                 
623                 BIO_puts(l->bio,buf);
624
625                 amip = amip->next;
626                 }
627         while(amip && amip->thread == ti);
628                 
629 #ifdef LEVITTE_DEBUG_MEM
630         if (amip)
631                 {
632                 fprintf(stderr, "Thread switch detected in backtrace!!!!\n");
633                 abort();
634                 }
635 #endif
636         }
637
638 void CRYPTO_mem_leaks(BIO *b)
639         {
640         MEM_LEAK ml;
641         char buf[80];
642
643         if (mh == NULL && amih == NULL)
644                 return;
645         ml.bio=b;
646         ml.bytes=0;
647         ml.chunks=0;
648         MemCheck_off(); /* obtains CRYPTO_LOCK_MALLOC2 */
649         if (mh != NULL)
650                 lh_doall_arg(mh,(void (*)())print_leak,(char *)&ml);
651         if (ml.chunks != 0)
652                 {
653                 sprintf(buf,"%ld bytes leaked in %d chunks\n",
654                         ml.bytes,ml.chunks);
655                 BIO_puts(b,buf);
656                 }
657         else
658                 {
659                 /* Make sure that, if we found no leaks, memory-leak debugging itself
660                  * does not introduce memory leaks (which might irritate
661                  * external debugging tools).
662                  * (When someone enables leak checking, but does not call
663                  * this function, we declare it to be their fault.)
664                  *
665                  * XXX    This should be in CRYPTO_mem_leaks_cb,
666                  * and CRYPTO_mem_leaks should be implemented by
667                  * using CRYPTO_mem_leaks_cb.
668                  * (Also their should be a variant of lh_doall_arg
669                  * that takes a function pointer instead of a void *;
670                  * this would obviate the ugly and illegal
671                  * void_fn_to_char kludge in CRYPTO_mem_leaks_cb.
672                  * Otherwise the code police will come and get us.)
673                  */
674                 CRYPTO_w_lock(CRYPTO_LOCK_MALLOC);
675                 if (mh != NULL)
676                         {
677                         lh_free(mh);
678                         mh = NULL;
679                         }
680                 if (amih != NULL)
681                         {
682                         if (lh_num_items(amih) == 0) 
683                                 {
684                                 lh_free(amih);
685                                 amih = NULL;
686                                 }
687                         }
688                 CRYPTO_w_unlock(CRYPTO_LOCK_MALLOC);
689                 }
690         MemCheck_on(); /* releases CRYPTO_LOCK_MALLOC2 */
691
692 #if 0
693         lh_stats_bio(mh,b);
694         lh_node_stats_bio(mh,b);
695         lh_node_usage_stats_bio(mh,b);
696 #endif
697         }
698
699 #ifndef NO_FP_API
700 void CRYPTO_mem_leaks_fp(FILE *fp)
701         {
702         BIO *b;
703
704         if (mh == NULL) return;
705         if ((b=BIO_new(BIO_s_file())) == NULL)
706                 return;
707         BIO_set_fp(b,fp,BIO_NOCLOSE);
708         CRYPTO_mem_leaks(b);
709         BIO_free(b);
710         }
711 #endif
712
713
714
715 /* FIXME: We really don't allow much to the callback.  For example, it has
716    no chance of reaching the info stack for the item it processes.  Should
717    it really be this way?  -- Richard Levitte */
718 static void cb_leak(MEM *m,
719                     void (**cb)(unsigned long, const char *, int, int, void *))
720         {
721         (**cb)(m->order,m->file,m->line,m->num,m->addr);
722         }
723
724 void CRYPTO_mem_leaks_cb(void (*cb)(unsigned long, const char *, int, int, void *))
725         {
726         if (mh == NULL) return;
727         CRYPTO_w_lock(CRYPTO_LOCK_MALLOC2);
728         lh_doall_arg(mh,(void (*)())cb_leak,(void *)&cb);
729         CRYPTO_w_unlock(CRYPTO_LOCK_MALLOC2);
730         }