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