AlgorithmIdentifier bugs
[oweals/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                         * access requires MALLOC2 lock */
86
87
88 typedef struct app_mem_info_st
89 /* For application-defined information (static C-string `info')
90  * to be displayed in memory leak list.
91  * Each thread has its own stack.  For applications, there is
92  *   CRYPTO_push_info("...")     to push an entry,
93  *   CRYPTO_pop_info()           to pop an entry,
94  *   CRYPTO_remove_all_info()    to pop all entries.
95  */
96         {       
97         unsigned long thread;
98         const char *file;
99         int line;
100         const char *info;
101         struct app_mem_info_st *next; /* tail of thread's stack */
102         int references;
103         } APP_INFO;
104
105 static LHASH *amih=NULL; /* hash-table with those app_mem_info_st's
106                           * that are at the top of their thread's stack
107                           * (with `thread' as key);
108                           * access requires MALLOC2 lock */
109
110 typedef struct mem_st
111 /* memory-block description */
112         {
113         void *addr;
114         int num;
115         const char *file;
116         int line;
117         unsigned long thread;
118         unsigned long order;
119         time_t time;
120         APP_INFO *app_info;
121         } MEM;
122
123 static long options =             /* extra information to be recorded */
124 #if defined(CRYPTO_MDEBUG_TIME) || defined(CRYPTO_MDEBUG_ALL)
125         V_CRYPTO_MDEBUG_TIME |
126 #endif
127 #if defined(CRYPTO_MDEBUG_THREAD) || defined(CRYPTO_MDEBUG_ALL)
128         V_CRYPTO_MDEBUG_THREAD |
129 #endif
130         0;
131
132
133 static unsigned int num_disable = 0; /* num_disable > 0
134                                       *     iff
135                                       * mh_mode == CRYPTO_MEM_CHECK_ON (w/o ..._ENABLE)
136                                       */
137 static unsigned long disabling_thread = 0; /* Valid iff num_disable > 0.
138                                             * CRYPTO_LOCK_MALLOC2 is locked
139                                             * exactly in this case (by the
140                                             * thread named in disabling_thread).
141                                             */
142
143 int CRYPTO_mem_ctrl(int mode)
144         {
145         int ret=mh_mode;
146
147         CRYPTO_w_lock(CRYPTO_LOCK_MALLOC);
148         switch (mode)
149                 {
150         /* for applications (not to be called while multiple threads
151          * use the library): */
152         case CRYPTO_MEM_CHECK_ON: /* aka MemCheck_start() */
153                 mh_mode = CRYPTO_MEM_CHECK_ON|CRYPTO_MEM_CHECK_ENABLE;
154                 num_disable = 0;
155                 break;
156         case CRYPTO_MEM_CHECK_OFF: /* aka MemCheck_stop() */
157                 mh_mode = 0;
158                 num_disable = 0; /* should be true *before* MemCheck_stop is used,
159                                     or there'll be a lot of confusion */
160                 break;
161
162         /* switch off temporarily (for library-internal use): */
163         case CRYPTO_MEM_CHECK_DISABLE: /* aka MemCheck_off() */
164                 if (mh_mode & CRYPTO_MEM_CHECK_ON)
165                         {
166                         if (!num_disable || (disabling_thread != CRYPTO_thread_id())) /* otherwise we already have the MALLOC2 lock */
167                                 {
168                                 /* Long-time lock CRYPTO_LOCK_MALLOC2 must not be claimed while
169                                  * we're holding CRYPTO_LOCK_MALLOC, or we'll deadlock if
170                                  * somebody else holds CRYPTO_LOCK_MALLOC2 (and cannot release
171                                  * it because we block entry to this function).
172                                  * Give them a chance, first, and then claim the locks in
173                                  * appropriate order (long-time lock first).
174                                  */
175                                 CRYPTO_w_unlock(CRYPTO_LOCK_MALLOC);
176                                 /* Note that after we have waited for CRYPTO_LOCK_MALLOC2
177                                  * and CRYPTO_LOCK_MALLOC, we'll still be in the right
178                                  * "case" and "if" branch because MemCheck_start and
179                                  * MemCheck_stop may never be used while there are multiple
180                                  * OpenSSL threads. */
181                                 CRYPTO_w_lock(CRYPTO_LOCK_MALLOC2);
182                                 CRYPTO_w_lock(CRYPTO_LOCK_MALLOC);
183                                 mh_mode &= ~CRYPTO_MEM_CHECK_ENABLE;
184                                 disabling_thread=CRYPTO_thread_id();
185                                 }
186                         num_disable++;
187                         }
188                 break;
189         case CRYPTO_MEM_CHECK_ENABLE: /* aka MemCheck_on() */
190                 if (mh_mode & CRYPTO_MEM_CHECK_ON)
191                         {
192                         if (num_disable) /* always true, or something is going wrong */
193                                 {
194                                 num_disable--;
195                                 if (num_disable == 0)
196                                         {
197                                         mh_mode|=CRYPTO_MEM_CHECK_ENABLE;
198                                         CRYPTO_w_unlock(CRYPTO_LOCK_MALLOC2);
199                                         }
200                                 }
201                         }
202                 break;
203
204         default:
205                 break;
206                 }
207         CRYPTO_w_unlock(CRYPTO_LOCK_MALLOC);
208         return(ret);
209         }
210
211 int CRYPTO_is_mem_check_on(void)
212         {
213         int ret = 0;
214
215         if (mh_mode & CRYPTO_MEM_CHECK_ON)
216                 {
217                 CRYPTO_r_lock(CRYPTO_LOCK_MALLOC);
218
219                 ret = (mh_mode & CRYPTO_MEM_CHECK_ENABLE)
220                         || (disabling_thread != CRYPTO_thread_id());
221
222                 CRYPTO_r_unlock(CRYPTO_LOCK_MALLOC);
223                 }
224         return(ret);
225         }       
226
227
228 void CRYPTO_dbg_set_options(long bits)
229         {
230         options = bits;
231         }
232
233 long CRYPTO_dbg_get_options(void)
234         {
235         return options;
236         }
237
238 static int mem_cmp(MEM *a, MEM *b)
239         {
240         return((char *)a->addr - (char *)b->addr);
241         }
242
243 static unsigned long mem_hash(MEM *a)
244         {
245         unsigned long ret;
246
247         ret=(unsigned long)a->addr;
248
249         ret=ret*17851+(ret>>14)*7+(ret>>4)*251;
250         return(ret);
251         }
252
253 static int app_info_cmp(APP_INFO *a, APP_INFO *b)
254         {
255         return(a->thread != b->thread);
256         }
257
258 static unsigned long app_info_hash(APP_INFO *a)
259         {
260         unsigned long ret;
261
262         ret=(unsigned long)a->thread;
263
264         ret=ret*17851+(ret>>14)*7+(ret>>4)*251;
265         return(ret);
266         }
267
268 static APP_INFO *pop_info()
269         {
270         APP_INFO tmp;
271         APP_INFO *ret = NULL;
272
273         if (amih != NULL)
274                 {
275                 tmp.thread=CRYPTO_thread_id();
276                 if ((ret=(APP_INFO *)lh_delete(amih,&tmp)) != NULL)
277                         {
278                         APP_INFO *next=ret->next;
279
280                         if (next != NULL)
281                                 {
282                                 next->references++;
283                                 lh_insert(amih,(char *)next);
284                                 }
285 #ifdef LEVITTE_DEBUG
286                         if (ret->thread != tmp.thread)
287                                 {
288                                 fprintf(stderr, "pop_info(): deleted info has other thread ID (%lu) than the current thread (%lu)!!!!\n",
289                                         ret->thread, tmp.thread);
290                                 abort();
291                                 }
292 #endif
293                         if (--(ret->references) <= 0)
294                                 {
295                                 ret->next = NULL;
296                                 if (next != NULL)
297                                         next->references--;
298                                 OPENSSL_free(ret);
299                                 }
300                         }
301                 }
302         return(ret);
303         }
304
305 int CRYPTO_push_info_(const char *info, const char *file, int line)
306         {
307         APP_INFO *ami, *amim;
308         int ret=0;
309
310         if (is_MemCheck_on())
311                 {
312                 MemCheck_off(); /* obtain MALLOC2 lock */
313
314                 if ((ami = (APP_INFO *)OPENSSL_malloc(sizeof(APP_INFO))) == NULL)
315                         {
316                         ret=0;
317                         goto err;
318                         }
319                 if (amih == NULL)
320                         {
321                         if ((amih=lh_new(app_info_hash,app_info_cmp)) == NULL)
322                                 {
323                                 OPENSSL_free(ami);
324                                 ret=0;
325                                 goto err;
326                                 }
327                         }
328
329                 ami->thread=CRYPTO_thread_id();
330                 ami->file=file;
331                 ami->line=line;
332                 ami->info=info;
333                 ami->references=1;
334                 ami->next=NULL;
335
336                 if ((amim=(APP_INFO *)lh_insert(amih,(char *)ami)) != NULL)
337                         {
338 #ifdef LEVITTE_DEBUG
339                         if (ami->thread != amim->thread)
340                                 {
341                                 fprintf(stderr, "CRYPTO_push_info(): previous info has other thread ID (%lu) than the current thread (%lu)!!!!\n",
342                                         amim->thread, ami->thread);
343                                 abort();
344                                 }
345 #endif
346                         ami->next=amim;
347                         }
348  err:
349                 MemCheck_on(); /* release MALLOC2 lock */
350                 }
351
352         return(ret);
353         }
354
355 int CRYPTO_pop_info(void)
356         {
357         int ret=0;
358
359         if (is_MemCheck_on()) /* _must_ be true, or something went severely wrong */
360                 {
361                 MemCheck_off(); /* obtain MALLOC2 lock */
362
363                 ret=(pop_info() != NULL);
364
365                 MemCheck_on(); /* release MALLOC2 lock */
366                 }
367         return(ret);
368         }
369
370 int CRYPTO_remove_all_info(void)
371         {
372         int ret=0;
373
374         if (is_MemCheck_on()) /* _must_ be true */
375                 {
376                 MemCheck_off(); /* obtain MALLOC2 lock */
377
378                 while(pop_info() != NULL)
379                         ret++;
380
381                 MemCheck_on(); /* release MALLOC2 lock */
382                 }
383         return(ret);
384         }
385
386
387 static unsigned long break_order_num=0;
388 void CRYPTO_dbg_malloc(void *addr, int num, const char *file, int line,
389         int before_p)
390         {
391         MEM *m,*mm;
392         APP_INFO tmp,*amim;
393
394         switch(before_p & 127)
395                 {
396         case 0:
397                 break;
398         case 1:
399                 if (addr == NULL)
400                         break;
401
402                 if (is_MemCheck_on())
403                         {
404                         MemCheck_off(); /* make sure we hold MALLOC2 lock */
405                         if ((m=(MEM *)OPENSSL_malloc(sizeof(MEM))) == NULL)
406                                 {
407                                 OPENSSL_free(addr);
408                                 MemCheck_on(); /* release MALLOC2 lock
409                                                 * if num_disabled drops to 0 */
410                                 return;
411                                 }
412                         if (mh == NULL)
413                                 {
414                                 if ((mh=lh_new(mem_hash,mem_cmp)) == NULL)
415                                         {
416                                         OPENSSL_free(addr);
417                                         OPENSSL_free(m);
418                                         addr=NULL;
419                                         goto err;
420                                         }
421                                 }
422
423                         m->addr=addr;
424                         m->file=file;
425                         m->line=line;
426                         m->num=num;
427                         if (options & V_CRYPTO_MDEBUG_THREAD)
428                                 m->thread=CRYPTO_thread_id();
429                         else
430                                 m->thread=0;
431
432                         if (order == break_order_num)
433                                 {
434                                 /* BREAK HERE */
435                                 m->order=order;
436                                 }
437                         m->order=order++;
438 #ifdef LEVITTE_DEBUG
439                         fprintf(stderr, "LEVITTE_DEBUG: [%5d] %c 0x%p (%d)\n",
440                                 m->order,
441                                 (before_p & 128) ? '*' : '+',
442                                 m->addr, m->num);
443 #endif
444                         if (options & V_CRYPTO_MDEBUG_TIME)
445                                 m->time=time(NULL);
446                         else
447                                 m->time=0;
448
449                         tmp.thread=CRYPTO_thread_id();
450                         m->app_info=NULL;
451                         if (amih != NULL
452                                 && (amim=(APP_INFO *)lh_retrieve(amih,(char *)&tmp)) != NULL)
453                                 {
454                                 m->app_info = amim;
455                                 amim->references++;
456                                 }
457
458                         if ((mm=(MEM *)lh_insert(mh,(char *)m)) != NULL)
459                                 {
460                                 /* Not good, but don't sweat it */
461                                 if (mm->app_info != NULL)
462                                         {
463                                         mm->app_info->references--;
464                                         }
465                                 OPENSSL_free(mm);
466                                 }
467                 err:
468                         MemCheck_on(); /* release MALLOC2 lock
469                                         * if num_disabled drops to 0 */
470                         }
471                 break;
472                 }
473         return;
474         }
475
476 void CRYPTO_dbg_free(void *addr, int before_p)
477         {
478         MEM m,*mp;
479
480         switch(before_p)
481                 {
482         case 0:
483                 if (addr == NULL)
484                         break;
485
486                 if (is_MemCheck_on() && (mh != NULL))
487                         {
488                         MemCheck_off(); /* make sure we hold MALLOC2 lock */
489
490                         m.addr=addr;
491                         mp=(MEM *)lh_delete(mh,(char *)&m);
492                         if (mp != NULL)
493                                 {
494 #ifdef LEVITTE_DEBUG
495                         fprintf(stderr, "LEVITTE_DEBUG: [%5d] - 0x%p (%d)\n",
496                                 mp->order, mp->addr, mp->num);
497 #endif
498                                 if (mp->app_info != NULL)
499                                         {
500                                         mp->app_info->references--;
501                                         }
502                                 OPENSSL_free(mp);
503                                 }
504
505                         MemCheck_on(); /* release MALLOC2 lock
506                                         * if num_disabled drops to 0 */
507                         }
508                 break;
509         case 1:
510                 break;
511                 }
512         }
513
514 void CRYPTO_dbg_realloc(void *addr1, void *addr2, int num,
515         const char *file, int line, int before_p)
516         {
517         MEM m,*mp;
518
519 #ifdef LEVITTE_DEBUG
520         fprintf(stderr, "LEVITTE_DEBUG: --> CRYPTO_dbg_malloc(addr1 = %p, addr2 = %p, num = %d, file = \"%s\", line = %d, before_p = %d)\n",
521                 addr1, addr2, num, file, line, before_p);
522 #endif
523
524         switch(before_p)
525                 {
526         case 0:
527                 break;
528         case 1:
529                 if (addr2 == NULL)
530                         break;
531
532                 if (addr1 == NULL)
533                         {
534                         CRYPTO_dbg_malloc(addr2, num, file, line, 128 | before_p);
535                         break;
536                         }
537
538                 if (is_MemCheck_on())
539                         {
540                         MemCheck_off(); /* make sure we hold MALLOC2 lock */
541
542                         m.addr=addr1;
543                         mp=(MEM *)lh_delete(mh,(char *)&m);
544                         if (mp != NULL)
545                                 {
546 #ifdef LEVITTE_DEBUG
547                                 fprintf(stderr, "LEVITTE_DEBUG: [%5d] * 0x%p (%d) -> 0x%p (%d)\n",
548                                         mp->order,
549                                         mp->addr, mp->num,
550                                         addr2, num);
551 #endif
552                                 mp->addr=addr2;
553                                 mp->num=num;
554                                 lh_insert(mh,(char *)mp);
555                                 }
556
557                         MemCheck_on(); /* release MALLOC2 lock
558                                         * if num_disabled drops to 0 */
559                         }
560                 break;
561                 }
562         return;
563         }
564
565
566 typedef struct mem_leak_st
567         {
568         BIO *bio;
569         int chunks;
570         long bytes;
571         } MEM_LEAK;
572
573 static void print_leak(MEM *m, MEM_LEAK *l)
574         {
575         char buf[1024];
576         char *bufp = buf;
577         APP_INFO *amip;
578         int ami_cnt;
579         struct tm *lcl = NULL;
580         unsigned long ti;
581
582         if(m->addr == (char *)l->bio)
583             return;
584
585         if (options & V_CRYPTO_MDEBUG_TIME)
586                 {
587                 lcl = localtime(&m->time);
588         
589                 sprintf(bufp, "[%02d:%02d:%02d] ",
590                         lcl->tm_hour,lcl->tm_min,lcl->tm_sec);
591                 bufp += strlen(bufp);
592                 }
593
594         sprintf(bufp, "%5lu file=%s, line=%d, ",
595                 m->order,m->file,m->line);
596         bufp += strlen(bufp);
597
598         if (options & V_CRYPTO_MDEBUG_THREAD)
599                 {
600                 sprintf(bufp, "thread=%lu, ", m->thread);
601                 bufp += strlen(bufp);
602                 }
603
604         sprintf(bufp, "number=%d, address=%08lX\n",
605                 m->num,(unsigned long)m->addr);
606         bufp += strlen(bufp);
607
608         BIO_puts(l->bio,buf);
609         
610         l->chunks++;
611         l->bytes+=m->num;
612
613         amip=m->app_info;
614         ami_cnt=0;
615         if (!amip)
616                 return;
617         ti=amip->thread;
618         
619         do
620                 {
621                 int buf_len;
622                 int info_len;
623
624                 ami_cnt++;
625                 memset(buf,'>',ami_cnt);
626                 sprintf(buf + ami_cnt,
627                         " thread=%lu, file=%s, line=%d, info=\"",
628                         amip->thread, amip->file, amip->line);
629                 buf_len=strlen(buf);
630                 info_len=strlen(amip->info);
631                 if (128 - buf_len - 3 < info_len)
632                         {
633                         memcpy(buf + buf_len, amip->info, 128 - buf_len - 3);
634                         buf_len = 128 - 3;
635                         }
636                 else
637                         {
638                         strcpy(buf + buf_len, amip->info);
639                         buf_len = strlen(buf);
640                         }
641                 sprintf(buf + buf_len, "\"\n");
642                 
643                 BIO_puts(l->bio,buf);
644
645                 amip = amip->next;
646                 }
647         while(amip && amip->thread == ti);
648                 
649 #ifdef LEVITTE_DEBUG
650         if (amip)
651                 {
652                 fprintf(stderr, "Thread switch detected in backtrace!!!!\n");
653                 abort();
654                 }
655 #endif
656         }
657
658 void CRYPTO_mem_leaks(BIO *b)
659         {
660         MEM_LEAK ml;
661         char buf[80];
662
663         if (mh == NULL && amih == NULL)
664                 return;
665
666         MemCheck_off(); /* obtain MALLOC2 lock */
667
668         ml.bio=b;
669         ml.bytes=0;
670         ml.chunks=0;
671         if (mh != NULL)
672                 lh_doall_arg(mh,(void (*)())print_leak,(char *)&ml);
673         if (ml.chunks != 0)
674                 {
675                 sprintf(buf,"%ld bytes leaked in %d chunks\n",
676                         ml.bytes,ml.chunks);
677                 BIO_puts(b,buf);
678                 }
679         else
680                 {
681                 /* Make sure that, if we found no leaks, memory-leak debugging itself
682                  * does not introduce memory leaks (which might irritate
683                  * external debugging tools).
684                  * (When someone enables leak checking, but does not call
685                  * this function, we declare it to be their fault.)
686                  *
687                  * XXX    This should be in CRYPTO_mem_leaks_cb,
688                  * and CRYPTO_mem_leaks should be implemented by
689                  * using CRYPTO_mem_leaks_cb.
690                  * (Also their should be a variant of lh_doall_arg
691                  * that takes a function pointer instead of a void *;
692                  * this would obviate the ugly and illegal
693                  * void_fn_to_char kludge in CRYPTO_mem_leaks_cb.
694                  * Otherwise the code police will come and get us.)
695                  */
696                 int old_mh_mode;
697
698                 CRYPTO_w_lock(CRYPTO_LOCK_MALLOC);
699
700                 /* avoid deadlock when lh_free() uses CRYPTO_dbg_free(),
701                  * which uses CRYPTO_is_mem_check_on */
702                 old_mh_mode = mh_mode;
703                 mh_mode = CRYPTO_MEM_CHECK_OFF;
704
705                 if (mh != NULL)
706                         {
707                         lh_free(mh);
708                         mh = NULL;
709                         }
710                 if (amih != NULL)
711                         {
712                         if (lh_num_items(amih) == 0) 
713                                 {
714                                 lh_free(amih);
715                                 amih = NULL;
716                                 }
717                         }
718
719                 mh_mode = old_mh_mode;
720                 CRYPTO_w_unlock(CRYPTO_LOCK_MALLOC);
721                 }
722         MemCheck_on(); /* release MALLOC2 lock */
723         }
724
725 #ifndef NO_FP_API
726 void CRYPTO_mem_leaks_fp(FILE *fp)
727         {
728         BIO *b;
729
730         if (mh == NULL) return;
731         if ((b=BIO_new(BIO_s_file())) == NULL)
732                 return;
733         BIO_set_fp(b,fp,BIO_NOCLOSE);
734         CRYPTO_mem_leaks(b);
735         BIO_free(b);
736         }
737 #endif
738
739
740
741 /* FIXME: We really don't allow much to the callback.  For example, it has
742    no chance of reaching the info stack for the item it processes.  Should
743    it really be this way?  -- Richard Levitte */
744 static void cb_leak(MEM *m,
745                     void (**cb)(unsigned long, const char *, int, int, void *))
746         {
747         (**cb)(m->order,m->file,m->line,m->num,m->addr);
748         }
749
750 void CRYPTO_mem_leaks_cb(void (*cb)(unsigned long, const char *, int, int, void *))
751         {
752         if (mh == NULL) return;
753         CRYPTO_w_lock(CRYPTO_LOCK_MALLOC2);
754         lh_doall_arg(mh,(void (*)())cb_leak,(void *)&cb);
755         CRYPTO_w_unlock(CRYPTO_LOCK_MALLOC2);
756         }