Support verify_depth from the SSL API without need for user-defined
[openssl.git] / crypto / mem.c
1 /* crypto/mem.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 <openssl/buffer.h>
62 #include <openssl/bio.h>
63 #include <openssl/lhash.h>
64 #include "cryptlib.h"
65
66 #ifdef CRYPTO_MDEBUG
67 static int mh_mode=CRYPTO_MEM_CHECK_ON;
68 #else
69 static int mh_mode=CRYPTO_MEM_CHECK_OFF;
70 #endif
71 static unsigned long order=0;
72
73 static LHASH *mh=NULL;
74
75 typedef struct mem_st
76         {
77         char *addr;
78         int num;
79         const char *file;
80         int line;
81         unsigned long order;
82         } MEM;
83
84 int CRYPTO_mem_ctrl(int mode)
85         {
86         int ret=mh_mode;
87
88         CRYPTO_w_lock(CRYPTO_LOCK_MALLOC);
89         switch (mode)
90                 {
91         case CRYPTO_MEM_CHECK_ON:
92                 mh_mode|=CRYPTO_MEM_CHECK_ON;
93                 break;
94         case CRYPTO_MEM_CHECK_OFF:
95                 mh_mode&= ~CRYPTO_MEM_CHECK_ON;
96                 break;
97         case CRYPTO_MEM_CHECK_DISABLE:
98                 mh_mode&= ~CRYPTO_MEM_CHECK_ENABLE;
99                 break;
100         case CRYPTO_MEM_CHECK_ENABLE:
101                 if (mh_mode&CRYPTO_MEM_CHECK_ON)
102                         mh_mode|=CRYPTO_MEM_CHECK_ENABLE;
103                 break;
104         default:
105                 break;
106                 }
107         CRYPTO_w_unlock(CRYPTO_LOCK_MALLOC);
108         return(ret);
109         }
110
111 static int mem_cmp(MEM *a, MEM *b)
112         {
113         return(a->addr - b->addr);
114         }
115
116 static unsigned long mem_hash(MEM *a)
117         {
118         unsigned long ret;
119
120         ret=(unsigned long)a->addr;
121
122         ret=ret*17851+(ret>>14)*7+(ret>>4)*251;
123         return(ret);
124         }
125
126 static char *(*malloc_locked_func)()=(char *(*)())malloc;
127 static void (*free_locked_func)()=(void (*)())free;
128 static char *(*malloc_func)()=  (char *(*)())malloc;
129 static char *(*realloc_func)()= (char *(*)())realloc;
130 static void (*free_func)()=     (void (*)())free;
131
132 void CRYPTO_set_mem_functions(char *(*m)(), char *(*r)(), void (*f)())
133         {
134         if ((m == NULL) || (r == NULL) || (f == NULL)) return;
135         malloc_func=m;
136         realloc_func=r;
137         free_func=f;
138         malloc_locked_func=m;
139         free_locked_func=f;
140         }
141
142 void CRYPTO_set_locked_mem_functions(char *(*m)(), void (*f)())
143         {
144         if ((m == NULL) || (f == NULL)) return;
145         malloc_locked_func=m;
146         free_locked_func=f;
147         }
148
149 void CRYPTO_get_mem_functions(char *(**m)(), char *(**r)(), void (**f)())
150         {
151         if (m != NULL) *m=malloc_func;
152         if (r != NULL) *r=realloc_func;
153         if (f != NULL) *f=free_func;
154         }
155
156 void CRYPTO_get_locked_mem_functions(char *(**m)(), void (**f)())
157         {
158         if (m != NULL) *m=malloc_locked_func;
159         if (f != NULL) *f=free_locked_func;
160         }
161
162 void *CRYPTO_malloc_locked(int num)
163         {
164         return(malloc_locked_func(num));
165         }
166
167 void CRYPTO_free_locked(void *str)
168         {
169         free_locked_func(str);
170         }
171
172 void *CRYPTO_malloc(int num)
173         {
174         return(malloc_func(num));
175         }
176
177 void *CRYPTO_realloc(void *str, int num)
178         {
179         return(realloc_func(str,num));
180         }
181
182 void CRYPTO_free(void *str)
183         {
184         free_func(str);
185         }
186
187 static unsigned long break_order_num=0;
188 void *CRYPTO_dbg_malloc(int num, const char *file, int line)
189         {
190         char *ret;
191         MEM *m,*mm;
192
193         if ((ret=malloc_func(num)) == NULL)
194                 return(NULL);
195
196         if (mh_mode & CRYPTO_MEM_CHECK_ENABLE)
197                 {
198                 MemCheck_off();
199                 if ((m=(MEM *)Malloc(sizeof(MEM))) == NULL)
200                         {
201                         Free(ret);
202                         MemCheck_on();
203                         return(NULL);
204                         }
205                 CRYPTO_w_lock(CRYPTO_LOCK_MALLOC);
206                 if (mh == NULL)
207                         {
208                         if ((mh=lh_new(mem_hash,mem_cmp)) == NULL)
209                                 {
210                                 Free(ret);
211                                 Free(m);
212                                 ret=NULL;
213                                 goto err;
214                                 }
215                         }
216
217                 m->addr=ret;
218                 m->file=file;
219                 m->line=line;
220                 m->num=num;
221                 if (order == break_order_num)
222                         {
223                         /* BREAK HERE */
224                         m->order=order;
225                         }
226                 m->order=order++;
227                 if ((mm=(MEM *)lh_insert(mh,(char *)m)) != NULL)
228                         {
229                         /* Not good, but don't sweat it */
230                         Free(mm);
231                         }
232 err:
233                 CRYPTO_w_unlock(CRYPTO_LOCK_MALLOC);
234                 MemCheck_on();
235                 }
236         return(ret);
237         }
238
239 void CRYPTO_dbg_free(void *addr)
240         {
241         MEM m,*mp;
242
243         if ((mh_mode & CRYPTO_MEM_CHECK_ENABLE) && (mh != NULL))
244                 {
245                 MemCheck_off();
246                 CRYPTO_w_lock(CRYPTO_LOCK_MALLOC);
247                 m.addr=addr;
248                 mp=(MEM *)lh_delete(mh,(char *)&m);
249                 if (mp != NULL)
250                         Free(mp);
251                 CRYPTO_w_unlock(CRYPTO_LOCK_MALLOC);
252                 MemCheck_on();
253                 }
254         free_func(addr);
255         }
256
257 void *CRYPTO_dbg_realloc(void *addr, int num, const char *file, int line)
258         {
259         char *ret;
260         MEM m,*mp;
261
262         ret=realloc_func(addr,num);
263         if (ret == addr) return(ret);
264
265         if (mh_mode & CRYPTO_MEM_CHECK_ENABLE)
266                 {
267                 MemCheck_off();
268                 if (ret == NULL) return(NULL);
269                 m.addr=addr;
270                 CRYPTO_w_lock(CRYPTO_LOCK_MALLOC);
271                 mp=(MEM *)lh_delete(mh,(char *)&m);
272                 if (mp != NULL)
273                         {
274                         mp->addr=ret;
275                         lh_insert(mh,(char *)mp);
276                         }
277                 CRYPTO_w_unlock(CRYPTO_LOCK_MALLOC);
278                 MemCheck_on();
279                 }
280         return(ret);
281         }
282
283 void *CRYPTO_remalloc(void *a, int n)
284         {
285         if (a != NULL) Free(a);
286         a=(char *)Malloc(n);
287         return(a);
288         }
289
290 void *CRYPTO_dbg_remalloc(void *a, int n, const char *file, int line)
291         {
292         if (a != NULL) CRYPTO_dbg_free(a);
293         a=(char *)CRYPTO_dbg_malloc(n,file,line);
294         return(a);
295         }
296
297
298 typedef struct mem_leak_st
299         {
300         BIO *bio;
301         int chunks;
302         long bytes;
303         } MEM_LEAK;
304
305 static void print_leak(MEM *m, MEM_LEAK *l)
306         {
307         char buf[128];
308
309         if(m->addr == (char *)l->bio)
310             return;
311         sprintf(buf,"%5ld file=%s, line=%d, number=%d, address=%08lX\n",
312                 m->order,m->file,m->line,m->num,(long)m->addr);
313         BIO_puts(l->bio,buf);
314         l->chunks++;
315         l->bytes+=m->num;
316         }
317
318 void CRYPTO_mem_leaks(BIO *b)
319         {
320         MEM_LEAK ml;
321         char buf[80];
322
323         if (mh == NULL) return;
324         ml.bio=b;
325         ml.bytes=0;
326         ml.chunks=0;
327         CRYPTO_w_lock(CRYPTO_LOCK_MALLOC);
328         lh_doall_arg(mh,(void (*)())print_leak,(char *)&ml);
329         CRYPTO_w_unlock(CRYPTO_LOCK_MALLOC);
330         if (ml.chunks != 0)
331                 {
332                 sprintf(buf,"%ld bytes leaked in %d chunks\n",
333                         ml.bytes,ml.chunks);
334                 BIO_puts(b,buf);
335                 }
336
337 #if 0
338         lh_stats_bio(mh,b);
339         lh_node_stats_bio(mh,b);
340         lh_node_usage_stats_bio(mh,b);
341 #endif
342         }
343
344 static void (*mem_cb)()=NULL;
345
346 static void cb_leak(MEM *m, char *cb)
347         {
348         void (*mem_callback)()=(void (*)())cb;
349         mem_callback(m->order,m->file,m->line,m->num,m->addr);
350         }
351
352 void CRYPTO_mem_leaks_cb(void (*cb)())
353         {
354         if (mh == NULL) return;
355         CRYPTO_w_lock(CRYPTO_LOCK_MALLOC);
356         mem_cb=cb;
357         lh_doall_arg(mh,(void (*)())cb_leak,(char *)mem_cb);
358         mem_cb=NULL;
359         CRYPTO_w_unlock(CRYPTO_LOCK_MALLOC);
360         }
361
362 #ifndef NO_FP_API
363 void CRYPTO_mem_leaks_fp(FILE *fp)
364         {
365         BIO *b;
366
367         if (mh == NULL) return;
368         if ((b=BIO_new(BIO_s_file())) == NULL)
369                 return;
370         BIO_set_fp(b,fp,BIO_NOCLOSE);
371         CRYPTO_mem_leaks(b);
372         BIO_free(b);
373         }
374 #endif
375