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