OLD | NEW |
| (Empty) |
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 * Copyright (c) 1998-2006 The OpenSSL Project. All rights reserved. | |
60 * | |
61 * Redistribution and use in source and binary forms, with or without | |
62 * modification, are permitted provided that the following conditions | |
63 * are met: | |
64 * | |
65 * 1. Redistributions of source code must retain the above copyright | |
66 * notice, this list of conditions and the following disclaimer. | |
67 * | |
68 * 2. Redistributions in binary form must reproduce the above copyright | |
69 * notice, this list of conditions and the following disclaimer in | |
70 * the documentation and/or other materials provided with the | |
71 * distribution. | |
72 * | |
73 * 3. All advertising materials mentioning features or use of this | |
74 * software must display the following acknowledgment: | |
75 * "This product includes software developed by the OpenSSL Project | |
76 * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" | |
77 * | |
78 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to | |
79 * endorse or promote products derived from this software without | |
80 * prior written permission. For written permission, please contact | |
81 * openssl-core@openssl.org. | |
82 * | |
83 * 5. Products derived from this software may not be called "OpenSSL" | |
84 * nor may "OpenSSL" appear in their names without prior written | |
85 * permission of the OpenSSL Project. | |
86 * | |
87 * 6. Redistributions of any form whatsoever must retain the following | |
88 * acknowledgment: | |
89 * "This product includes software developed by the OpenSSL Project | |
90 * for use in the OpenSSL Toolkit (http://www.openssl.org/)" | |
91 * | |
92 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY | |
93 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
94 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
95 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR | |
96 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
97 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | |
98 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
99 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
100 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | |
101 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
102 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED | |
103 * OF THE POSSIBILITY OF SUCH DAMAGE. | |
104 * ==================================================================== | |
105 * | |
106 * This product includes cryptographic software written by Eric Young | |
107 * (eay@cryptsoft.com). This product includes software written by Tim | |
108 * Hudson (tjh@cryptsoft.com). | |
109 * | |
110 */ | |
111 | |
112 #include <stdio.h> | |
113 #include <stdlib.h> | |
114 #include <time.h> | |
115 #include "cryptlib.h" | |
116 #include <openssl/crypto.h> | |
117 #include <openssl/buffer.h> | |
118 #include <openssl/bio.h> | |
119 #include <openssl/lhash.h> | |
120 | |
121 static int mh_mode=CRYPTO_MEM_CHECK_OFF; | |
122 /* The state changes to CRYPTO_MEM_CHECK_ON | CRYPTO_MEM_CHECK_ENABLE | |
123 * when the application asks for it (usually after library initialisation | |
124 * for which no book-keeping is desired). | |
125 * | |
126 * State CRYPTO_MEM_CHECK_ON exists only temporarily when the library | |
127 * thinks that certain allocations should not be checked (e.g. the data | |
128 * structures used for memory checking). It is not suitable as an initial | |
129 * state: the library will unexpectedly enable memory checking when it | |
130 * executes one of those sections that want to disable checking | |
131 * temporarily. | |
132 * | |
133 * State CRYPTO_MEM_CHECK_ENABLE without ..._ON makes no sense whatsoever. | |
134 */ | |
135 | |
136 static unsigned long order = 0; /* number of memory requests */ | |
137 | |
138 DECLARE_LHASH_OF(MEM); | |
139 static LHASH_OF(MEM) *mh=NULL; /* hash-table of memory requests | |
140 * (address as key); access requires | |
141 * MALLOC2 lock */ | |
142 | |
143 | |
144 typedef struct app_mem_info_st | |
145 /* For application-defined information (static C-string `info') | |
146 * to be displayed in memory leak list. | |
147 * Each thread has its own stack. For applications, there is | |
148 * CRYPTO_push_info("...") to push an entry, | |
149 * CRYPTO_pop_info() to pop an entry, | |
150 * CRYPTO_remove_all_info() to pop all entries. | |
151 */ | |
152 { | |
153 CRYPTO_THREADID threadid; | |
154 const char *file; | |
155 int line; | |
156 const char *info; | |
157 struct app_mem_info_st *next; /* tail of thread's stack */ | |
158 int references; | |
159 } APP_INFO; | |
160 | |
161 static void app_info_free(APP_INFO *); | |
162 | |
163 DECLARE_LHASH_OF(APP_INFO); | |
164 static LHASH_OF(APP_INFO) *amih=NULL; /* hash-table with those | |
165 * app_mem_info_st's that are at | |
166 * the top of their thread's | |
167 * stack (with `thread' as key); | |
168 * access requires MALLOC2 | |
169 * lock */ | |
170 | |
171 typedef struct mem_st | |
172 /* memory-block description */ | |
173 { | |
174 void *addr; | |
175 int num; | |
176 const char *file; | |
177 int line; | |
178 CRYPTO_THREADID threadid; | |
179 unsigned long order; | |
180 time_t time; | |
181 APP_INFO *app_info; | |
182 } MEM; | |
183 | |
184 static long options = /* extra information to be recorded */ | |
185 #if defined(CRYPTO_MDEBUG_TIME) || defined(CRYPTO_MDEBUG_ALL) | |
186 V_CRYPTO_MDEBUG_TIME | | |
187 #endif | |
188 #if defined(CRYPTO_MDEBUG_THREAD) || defined(CRYPTO_MDEBUG_ALL) | |
189 V_CRYPTO_MDEBUG_THREAD | | |
190 #endif | |
191 0; | |
192 | |
193 | |
194 static unsigned int num_disable = 0; /* num_disable > 0 | |
195 * iff | |
196 * mh_mode == CRYPTO_MEM_CHECK_ON (w/o ..._
ENABLE) | |
197 */ | |
198 | |
199 /* Valid iff num_disable > 0. CRYPTO_LOCK_MALLOC2 is locked exactly in this | |
200 * case (by the thread named in disabling_thread). | |
201 */ | |
202 static CRYPTO_THREADID disabling_threadid; | |
203 | |
204 static void app_info_free(APP_INFO *inf) | |
205 { | |
206 if (--(inf->references) <= 0) | |
207 { | |
208 if (inf->next != NULL) | |
209 { | |
210 app_info_free(inf->next); | |
211 } | |
212 OPENSSL_free(inf); | |
213 } | |
214 } | |
215 | |
216 int CRYPTO_mem_ctrl(int mode) | |
217 { | |
218 int ret=mh_mode; | |
219 | |
220 CRYPTO_w_lock(CRYPTO_LOCK_MALLOC); | |
221 switch (mode) | |
222 { | |
223 /* for applications (not to be called while multiple threads | |
224 * use the library): */ | |
225 case CRYPTO_MEM_CHECK_ON: /* aka MemCheck_start() */ | |
226 mh_mode = CRYPTO_MEM_CHECK_ON|CRYPTO_MEM_CHECK_ENABLE; | |
227 num_disable = 0; | |
228 break; | |
229 case CRYPTO_MEM_CHECK_OFF: /* aka MemCheck_stop() */ | |
230 mh_mode = 0; | |
231 num_disable = 0; /* should be true *before* MemCheck_stop is use
d, | |
232 or there'll be a lot of confusion */ | |
233 break; | |
234 | |
235 /* switch off temporarily (for library-internal use): */ | |
236 case CRYPTO_MEM_CHECK_DISABLE: /* aka MemCheck_off() */ | |
237 if (mh_mode & CRYPTO_MEM_CHECK_ON) | |
238 { | |
239 CRYPTO_THREADID cur; | |
240 CRYPTO_THREADID_current(&cur); | |
241 if (!num_disable || CRYPTO_THREADID_cmp(&disabling_threa
did, &cur)) /* otherwise we already have the MALLOC2 lock */ | |
242 { | |
243 /* Long-time lock CRYPTO_LOCK_MALLOC2 must not b
e claimed while | |
244 * we're holding CRYPTO_LOCK_MALLOC, or we'll de
adlock if | |
245 * somebody else holds CRYPTO_LOCK_MALLOC2 (and
cannot release | |
246 * it because we block entry to this function). | |
247 * Give them a chance, first, and then claim the
locks in | |
248 * appropriate order (long-time lock first). | |
249 */ | |
250 CRYPTO_w_unlock(CRYPTO_LOCK_MALLOC); | |
251 /* Note that after we have waited for CRYPTO_LOC
K_MALLOC2 | |
252 * and CRYPTO_LOCK_MALLOC, we'll still be in the
right | |
253 * "case" and "if" branch because MemCheck_start
and | |
254 * MemCheck_stop may never be used while there a
re multiple | |
255 * OpenSSL threads. */ | |
256 CRYPTO_w_lock(CRYPTO_LOCK_MALLOC2); | |
257 CRYPTO_w_lock(CRYPTO_LOCK_MALLOC); | |
258 mh_mode &= ~CRYPTO_MEM_CHECK_ENABLE; | |
259 CRYPTO_THREADID_cpy(&disabling_threadid, &cur); | |
260 } | |
261 num_disable++; | |
262 } | |
263 break; | |
264 case CRYPTO_MEM_CHECK_ENABLE: /* aka MemCheck_on() */ | |
265 if (mh_mode & CRYPTO_MEM_CHECK_ON) | |
266 { | |
267 if (num_disable) /* always true, or something is going w
rong */ | |
268 { | |
269 num_disable--; | |
270 if (num_disable == 0) | |
271 { | |
272 mh_mode|=CRYPTO_MEM_CHECK_ENABLE; | |
273 CRYPTO_w_unlock(CRYPTO_LOCK_MALLOC2); | |
274 } | |
275 } | |
276 } | |
277 break; | |
278 | |
279 default: | |
280 break; | |
281 } | |
282 CRYPTO_w_unlock(CRYPTO_LOCK_MALLOC); | |
283 return(ret); | |
284 } | |
285 | |
286 int CRYPTO_is_mem_check_on(void) | |
287 { | |
288 int ret = 0; | |
289 | |
290 if (mh_mode & CRYPTO_MEM_CHECK_ON) | |
291 { | |
292 CRYPTO_THREADID cur; | |
293 CRYPTO_THREADID_current(&cur); | |
294 CRYPTO_r_lock(CRYPTO_LOCK_MALLOC); | |
295 | |
296 ret = (mh_mode & CRYPTO_MEM_CHECK_ENABLE) | |
297 || CRYPTO_THREADID_cmp(&disabling_threadid, &cur); | |
298 | |
299 CRYPTO_r_unlock(CRYPTO_LOCK_MALLOC); | |
300 } | |
301 return(ret); | |
302 } | |
303 | |
304 | |
305 void CRYPTO_dbg_set_options(long bits) | |
306 { | |
307 options = bits; | |
308 } | |
309 | |
310 long CRYPTO_dbg_get_options(void) | |
311 { | |
312 return options; | |
313 } | |
314 | |
315 static int mem_cmp(const MEM *a, const MEM *b) | |
316 { | |
317 #ifdef _WIN64 | |
318 const char *ap=(const char *)a->addr, | |
319 *bp=(const char *)b->addr; | |
320 if (ap==bp) return 0; | |
321 else if (ap>bp) return 1; | |
322 else return -1; | |
323 #else | |
324 return (const char *)a->addr - (const char *)b->addr; | |
325 #endif | |
326 } | |
327 static IMPLEMENT_LHASH_COMP_FN(mem, MEM) | |
328 | |
329 static unsigned long mem_hash(const MEM *a) | |
330 { | |
331 unsigned long ret; | |
332 | |
333 ret=(unsigned long)a->addr; | |
334 | |
335 ret=ret*17851+(ret>>14)*7+(ret>>4)*251; | |
336 return(ret); | |
337 } | |
338 static IMPLEMENT_LHASH_HASH_FN(mem, MEM) | |
339 | |
340 /* static int app_info_cmp(APP_INFO *a, APP_INFO *b) */ | |
341 static int app_info_cmp(const void *a_void, const void *b_void) | |
342 { | |
343 return CRYPTO_THREADID_cmp(&((const APP_INFO *)a_void)->threadid, | |
344 &((const APP_INFO *)b_void)->threadid); | |
345 } | |
346 static IMPLEMENT_LHASH_COMP_FN(app_info, APP_INFO) | |
347 | |
348 static unsigned long app_info_hash(const APP_INFO *a) | |
349 { | |
350 unsigned long ret; | |
351 | |
352 ret = CRYPTO_THREADID_hash(&a->threadid); | |
353 /* This is left in as a "who am I to question legacy?" measure */ | |
354 ret=ret*17851+(ret>>14)*7+(ret>>4)*251; | |
355 return(ret); | |
356 } | |
357 static IMPLEMENT_LHASH_HASH_FN(app_info, APP_INFO) | |
358 | |
359 static APP_INFO *pop_info(void) | |
360 { | |
361 APP_INFO tmp; | |
362 APP_INFO *ret = NULL; | |
363 | |
364 if (amih != NULL) | |
365 { | |
366 CRYPTO_THREADID_current(&tmp.threadid); | |
367 if ((ret=lh_APP_INFO_delete(amih,&tmp)) != NULL) | |
368 { | |
369 APP_INFO *next=ret->next; | |
370 | |
371 if (next != NULL) | |
372 { | |
373 next->references++; | |
374 (void)lh_APP_INFO_insert(amih,next); | |
375 } | |
376 #ifdef LEVITTE_DEBUG_MEM | |
377 if (CRYPTO_THREADID_cmp(&ret->threadid, &tmp.threadid)) | |
378 { | |
379 fprintf(stderr, "pop_info(): deleted info has ot
her thread ID (%lu) than the current thread (%lu)!!!!\n", | |
380 CRYPTO_THREADID_hash(&ret->threadid), | |
381 CRYPTO_THREADID_hash(&tmp.threadid)); | |
382 abort(); | |
383 } | |
384 #endif | |
385 if (--(ret->references) <= 0) | |
386 { | |
387 ret->next = NULL; | |
388 if (next != NULL) | |
389 next->references--; | |
390 OPENSSL_free(ret); | |
391 } | |
392 } | |
393 } | |
394 return(ret); | |
395 } | |
396 | |
397 int CRYPTO_push_info_(const char *info, const char *file, int line) | |
398 { | |
399 APP_INFO *ami, *amim; | |
400 int ret=0; | |
401 | |
402 if (is_MemCheck_on()) | |
403 { | |
404 MemCheck_off(); /* obtain MALLOC2 lock */ | |
405 | |
406 if ((ami = (APP_INFO *)OPENSSL_malloc(sizeof(APP_INFO))) == NULL
) | |
407 { | |
408 ret=0; | |
409 goto err; | |
410 } | |
411 if (amih == NULL) | |
412 { | |
413 if ((amih=lh_APP_INFO_new()) == NULL) | |
414 { | |
415 OPENSSL_free(ami); | |
416 ret=0; | |
417 goto err; | |
418 } | |
419 } | |
420 | |
421 CRYPTO_THREADID_current(&ami->threadid); | |
422 ami->file=file; | |
423 ami->line=line; | |
424 ami->info=info; | |
425 ami->references=1; | |
426 ami->next=NULL; | |
427 | |
428 if ((amim=lh_APP_INFO_insert(amih,ami)) != NULL) | |
429 { | |
430 #ifdef LEVITTE_DEBUG_MEM | |
431 if (CRYPTO_THREADID_cmp(&ami->threadid, &amim->threadid)
) | |
432 { | |
433 fprintf(stderr, "CRYPTO_push_info(): previous in
fo has other thread ID (%lu) than the current thread (%lu)!!!!\n", | |
434 CRYPTO_THREADID_hash(&amim->threadid), | |
435 CRYPTO_THREADID_hash(&ami->threadid)); | |
436 abort(); | |
437 } | |
438 #endif | |
439 ami->next=amim; | |
440 } | |
441 err: | |
442 MemCheck_on(); /* release MALLOC2 lock */ | |
443 } | |
444 | |
445 return(ret); | |
446 } | |
447 | |
448 int CRYPTO_pop_info(void) | |
449 { | |
450 int ret=0; | |
451 | |
452 if (is_MemCheck_on()) /* _must_ be true, or something went severely wron
g */ | |
453 { | |
454 MemCheck_off(); /* obtain MALLOC2 lock */ | |
455 | |
456 ret=(pop_info() != NULL); | |
457 | |
458 MemCheck_on(); /* release MALLOC2 lock */ | |
459 } | |
460 return(ret); | |
461 } | |
462 | |
463 int CRYPTO_remove_all_info(void) | |
464 { | |
465 int ret=0; | |
466 | |
467 if (is_MemCheck_on()) /* _must_ be true */ | |
468 { | |
469 MemCheck_off(); /* obtain MALLOC2 lock */ | |
470 | |
471 while(pop_info() != NULL) | |
472 ret++; | |
473 | |
474 MemCheck_on(); /* release MALLOC2 lock */ | |
475 } | |
476 return(ret); | |
477 } | |
478 | |
479 | |
480 static unsigned long break_order_num=0; | |
481 void CRYPTO_dbg_malloc(void *addr, int num, const char *file, int line, | |
482 int before_p) | |
483 { | |
484 MEM *m,*mm; | |
485 APP_INFO tmp,*amim; | |
486 | |
487 switch(before_p & 127) | |
488 { | |
489 case 0: | |
490 break; | |
491 case 1: | |
492 if (addr == NULL) | |
493 break; | |
494 | |
495 if (is_MemCheck_on()) | |
496 { | |
497 MemCheck_off(); /* make sure we hold MALLOC2 lock */ | |
498 if ((m=(MEM *)OPENSSL_malloc(sizeof(MEM))) == NULL) | |
499 { | |
500 OPENSSL_free(addr); | |
501 MemCheck_on(); /* release MALLOC2 lock | |
502 * if num_disabled drops to 0 */ | |
503 return; | |
504 } | |
505 if (mh == NULL) | |
506 { | |
507 if ((mh=lh_MEM_new()) == NULL) | |
508 { | |
509 OPENSSL_free(addr); | |
510 OPENSSL_free(m); | |
511 addr=NULL; | |
512 goto err; | |
513 } | |
514 } | |
515 | |
516 m->addr=addr; | |
517 m->file=file; | |
518 m->line=line; | |
519 m->num=num; | |
520 if (options & V_CRYPTO_MDEBUG_THREAD) | |
521 CRYPTO_THREADID_current(&m->threadid); | |
522 else | |
523 memset(&m->threadid, 0, sizeof(m->threadid)); | |
524 | |
525 if (order == break_order_num) | |
526 { | |
527 /* BREAK HERE */ | |
528 m->order=order; | |
529 } | |
530 m->order=order++; | |
531 #ifdef LEVITTE_DEBUG_MEM | |
532 fprintf(stderr, "LEVITTE_DEBUG_MEM: [%5ld] %c 0x%p (%d)\
n", | |
533 m->order, | |
534 (before_p & 128) ? '*' : '+', | |
535 m->addr, m->num); | |
536 #endif | |
537 if (options & V_CRYPTO_MDEBUG_TIME) | |
538 m->time=time(NULL); | |
539 else | |
540 m->time=0; | |
541 | |
542 CRYPTO_THREADID_current(&tmp.threadid); | |
543 m->app_info=NULL; | |
544 if (amih != NULL | |
545 && (amim=lh_APP_INFO_retrieve(amih,&tmp)) != NULL) | |
546 { | |
547 m->app_info = amim; | |
548 amim->references++; | |
549 } | |
550 | |
551 if ((mm=lh_MEM_insert(mh, m)) != NULL) | |
552 { | |
553 /* Not good, but don't sweat it */ | |
554 if (mm->app_info != NULL) | |
555 { | |
556 mm->app_info->references--; | |
557 } | |
558 OPENSSL_free(mm); | |
559 } | |
560 err: | |
561 MemCheck_on(); /* release MALLOC2 lock | |
562 * if num_disabled drops to 0 */ | |
563 } | |
564 break; | |
565 } | |
566 return; | |
567 } | |
568 | |
569 void CRYPTO_dbg_free(void *addr, int before_p) | |
570 { | |
571 MEM m,*mp; | |
572 | |
573 switch(before_p) | |
574 { | |
575 case 0: | |
576 if (addr == NULL) | |
577 break; | |
578 | |
579 if (is_MemCheck_on() && (mh != NULL)) | |
580 { | |
581 MemCheck_off(); /* make sure we hold MALLOC2 lock */ | |
582 | |
583 m.addr=addr; | |
584 mp=lh_MEM_delete(mh,&m); | |
585 if (mp != NULL) | |
586 { | |
587 #ifdef LEVITTE_DEBUG_MEM | |
588 fprintf(stderr, "LEVITTE_DEBUG_MEM: [%5ld] - 0x%p (%d)\n
", | |
589 mp->order, mp->addr, mp->num); | |
590 #endif | |
591 if (mp->app_info != NULL) | |
592 app_info_free(mp->app_info); | |
593 OPENSSL_free(mp); | |
594 } | |
595 | |
596 MemCheck_on(); /* release MALLOC2 lock | |
597 * if num_disabled drops to 0 */ | |
598 } | |
599 break; | |
600 case 1: | |
601 break; | |
602 } | |
603 } | |
604 | |
605 void CRYPTO_dbg_realloc(void *addr1, void *addr2, int num, | |
606 const char *file, int line, int before_p) | |
607 { | |
608 MEM m,*mp; | |
609 | |
610 #ifdef LEVITTE_DEBUG_MEM | |
611 fprintf(stderr, "LEVITTE_DEBUG_MEM: --> CRYPTO_dbg_malloc(addr1 = %p, ad
dr2 = %p, num = %d, file = \"%s\", line = %d, before_p = %d)\n", | |
612 addr1, addr2, num, file, line, before_p); | |
613 #endif | |
614 | |
615 switch(before_p) | |
616 { | |
617 case 0: | |
618 break; | |
619 case 1: | |
620 if (addr2 == NULL) | |
621 break; | |
622 | |
623 if (addr1 == NULL) | |
624 { | |
625 CRYPTO_dbg_malloc(addr2, num, file, line, 128 | before_p
); | |
626 break; | |
627 } | |
628 | |
629 if (is_MemCheck_on()) | |
630 { | |
631 MemCheck_off(); /* make sure we hold MALLOC2 lock */ | |
632 | |
633 m.addr=addr1; | |
634 mp=lh_MEM_delete(mh,&m); | |
635 if (mp != NULL) | |
636 { | |
637 #ifdef LEVITTE_DEBUG_MEM | |
638 fprintf(stderr, "LEVITTE_DEBUG_MEM: [%5ld] * 0x%
p (%d) -> 0x%p (%d)\n", | |
639 mp->order, | |
640 mp->addr, mp->num, | |
641 addr2, num); | |
642 #endif | |
643 mp->addr=addr2; | |
644 mp->num=num; | |
645 (void)lh_MEM_insert(mh,mp); | |
646 } | |
647 | |
648 MemCheck_on(); /* release MALLOC2 lock | |
649 * if num_disabled drops to 0 */ | |
650 } | |
651 break; | |
652 } | |
653 return; | |
654 } | |
655 | |
656 | |
657 typedef struct mem_leak_st | |
658 { | |
659 BIO *bio; | |
660 int chunks; | |
661 long bytes; | |
662 } MEM_LEAK; | |
663 | |
664 static void print_leak_doall_arg(const MEM *m, MEM_LEAK *l) | |
665 { | |
666 char buf[1024]; | |
667 char *bufp = buf; | |
668 APP_INFO *amip; | |
669 int ami_cnt; | |
670 struct tm *lcl = NULL; | |
671 CRYPTO_THREADID ti; | |
672 | |
673 #define BUF_REMAIN (sizeof buf - (size_t)(bufp - buf)) | |
674 | |
675 if(m->addr == (char *)l->bio) | |
676 return; | |
677 | |
678 if (options & V_CRYPTO_MDEBUG_TIME) | |
679 { | |
680 lcl = localtime(&m->time); | |
681 | |
682 BIO_snprintf(bufp, BUF_REMAIN, "[%02d:%02d:%02d] ", | |
683 lcl->tm_hour,lcl->tm_min,lcl->tm_sec); | |
684 bufp += strlen(bufp); | |
685 } | |
686 | |
687 BIO_snprintf(bufp, BUF_REMAIN, "%5lu file=%s, line=%d, ", | |
688 m->order,m->file,m->line); | |
689 bufp += strlen(bufp); | |
690 | |
691 if (options & V_CRYPTO_MDEBUG_THREAD) | |
692 { | |
693 BIO_snprintf(bufp, BUF_REMAIN, "thread=%lu, ", | |
694 CRYPTO_THREADID_hash(&m->threadid)); | |
695 bufp += strlen(bufp); | |
696 } | |
697 | |
698 BIO_snprintf(bufp, BUF_REMAIN, "number=%d, address=%08lX\n", | |
699 m->num,(unsigned long)m->addr); | |
700 bufp += strlen(bufp); | |
701 | |
702 BIO_puts(l->bio,buf); | |
703 | |
704 l->chunks++; | |
705 l->bytes+=m->num; | |
706 | |
707 amip=m->app_info; | |
708 ami_cnt=0; | |
709 if (!amip) | |
710 return; | |
711 CRYPTO_THREADID_cpy(&ti, &amip->threadid); | |
712 | |
713 do | |
714 { | |
715 int buf_len; | |
716 int info_len; | |
717 | |
718 ami_cnt++; | |
719 memset(buf,'>',ami_cnt); | |
720 BIO_snprintf(buf + ami_cnt, sizeof buf - ami_cnt, | |
721 " thread=%lu, file=%s, line=%d, info=\"", | |
722 CRYPTO_THREADID_hash(&amip->threadid), amip->file, | |
723 amip->line); | |
724 buf_len=strlen(buf); | |
725 info_len=strlen(amip->info); | |
726 if (128 - buf_len - 3 < info_len) | |
727 { | |
728 memcpy(buf + buf_len, amip->info, 128 - buf_len - 3); | |
729 buf_len = 128 - 3; | |
730 } | |
731 else | |
732 { | |
733 BUF_strlcpy(buf + buf_len, amip->info, | |
734 sizeof buf - buf_len); | |
735 buf_len = strlen(buf); | |
736 } | |
737 BIO_snprintf(buf + buf_len, sizeof buf - buf_len, "\"\n"); | |
738 | |
739 BIO_puts(l->bio,buf); | |
740 | |
741 amip = amip->next; | |
742 } | |
743 while(amip && !CRYPTO_THREADID_cmp(&amip->threadid, &ti)); | |
744 | |
745 #ifdef LEVITTE_DEBUG_MEM | |
746 if (amip) | |
747 { | |
748 fprintf(stderr, "Thread switch detected in backtrace!!!!\n"); | |
749 abort(); | |
750 } | |
751 #endif | |
752 } | |
753 | |
754 static IMPLEMENT_LHASH_DOALL_ARG_FN(print_leak, const MEM, MEM_LEAK) | |
755 | |
756 void CRYPTO_mem_leaks(BIO *b) | |
757 { | |
758 MEM_LEAK ml; | |
759 | |
760 if (mh == NULL && amih == NULL) | |
761 return; | |
762 | |
763 MemCheck_off(); /* obtain MALLOC2 lock */ | |
764 | |
765 ml.bio=b; | |
766 ml.bytes=0; | |
767 ml.chunks=0; | |
768 if (mh != NULL) | |
769 lh_MEM_doall_arg(mh, LHASH_DOALL_ARG_FN(print_leak), MEM_LEAK, | |
770 &ml); | |
771 if (ml.chunks != 0) | |
772 { | |
773 BIO_printf(b,"%ld bytes leaked in %d chunks\n", | |
774 ml.bytes,ml.chunks); | |
775 #ifdef CRYPTO_MDEBUG_ABORT | |
776 abort(); | |
777 #endif | |
778 } | |
779 else | |
780 { | |
781 /* Make sure that, if we found no leaks, memory-leak debugging i
tself | |
782 * does not introduce memory leaks (which might irritate | |
783 * external debugging tools). | |
784 * (When someone enables leak checking, but does not call | |
785 * this function, we declare it to be their fault.) | |
786 * | |
787 * XXX This should be in CRYPTO_mem_leaks_cb, | |
788 * and CRYPTO_mem_leaks should be implemented by | |
789 * using CRYPTO_mem_leaks_cb. | |
790 * (Also there should be a variant of lh_doall_arg | |
791 * that takes a function pointer instead of a void *; | |
792 * this would obviate the ugly and illegal | |
793 * void_fn_to_char kludge in CRYPTO_mem_leaks_cb. | |
794 * Otherwise the code police will come and get us.) | |
795 */ | |
796 int old_mh_mode; | |
797 | |
798 CRYPTO_w_lock(CRYPTO_LOCK_MALLOC); | |
799 | |
800 /* avoid deadlock when lh_free() uses CRYPTO_dbg_free(), | |
801 * which uses CRYPTO_is_mem_check_on */ | |
802 old_mh_mode = mh_mode; | |
803 mh_mode = CRYPTO_MEM_CHECK_OFF; | |
804 | |
805 if (mh != NULL) | |
806 { | |
807 lh_MEM_free(mh); | |
808 mh = NULL; | |
809 } | |
810 if (amih != NULL) | |
811 { | |
812 if (lh_APP_INFO_num_items(amih) == 0) | |
813 { | |
814 lh_APP_INFO_free(amih); | |
815 amih = NULL; | |
816 } | |
817 } | |
818 | |
819 mh_mode = old_mh_mode; | |
820 CRYPTO_w_unlock(CRYPTO_LOCK_MALLOC); | |
821 } | |
822 MemCheck_on(); /* release MALLOC2 lock */ | |
823 } | |
824 | |
825 #ifndef OPENSSL_NO_FP_API | |
826 void CRYPTO_mem_leaks_fp(FILE *fp) | |
827 { | |
828 BIO *b; | |
829 | |
830 if (mh == NULL) return; | |
831 /* Need to turn off memory checking when allocated BIOs ... especially | |
832 * as we're creating them at a time when we're trying to check we've not | |
833 * left anything un-free()'d!! */ | |
834 MemCheck_off(); | |
835 b = BIO_new(BIO_s_file()); | |
836 MemCheck_on(); | |
837 if(!b) return; | |
838 BIO_set_fp(b,fp,BIO_NOCLOSE); | |
839 CRYPTO_mem_leaks(b); | |
840 BIO_free(b); | |
841 } | |
842 #endif | |
843 | |
844 | |
845 | |
846 /* FIXME: We really don't allow much to the callback. For example, it has | |
847 no chance of reaching the info stack for the item it processes. Should | |
848 it really be this way? -- Richard Levitte */ | |
849 /* NB: The prototypes have been typedef'd to CRYPTO_MEM_LEAK_CB inside crypto.h | |
850 * If this code is restructured, remove the callback type if it is no longer | |
851 * needed. -- Geoff Thorpe */ | |
852 | |
853 /* Can't pass CRYPTO_MEM_LEAK_CB directly to lh_MEM_doall_arg because it | |
854 * is a function pointer and conversion to void * is prohibited. Instead | |
855 * pass its address | |
856 */ | |
857 | |
858 typedef CRYPTO_MEM_LEAK_CB *PCRYPTO_MEM_LEAK_CB; | |
859 | |
860 static void cb_leak_doall_arg(const MEM *m, PCRYPTO_MEM_LEAK_CB *cb) | |
861 { | |
862 (*cb)(m->order,m->file,m->line,m->num,m->addr); | |
863 } | |
864 | |
865 static IMPLEMENT_LHASH_DOALL_ARG_FN(cb_leak, const MEM, PCRYPTO_MEM_LEAK_CB) | |
866 | |
867 void CRYPTO_mem_leaks_cb(CRYPTO_MEM_LEAK_CB *cb) | |
868 { | |
869 if (mh == NULL) return; | |
870 CRYPTO_w_lock(CRYPTO_LOCK_MALLOC2); | |
871 lh_MEM_doall_arg(mh, LHASH_DOALL_ARG_FN(cb_leak), PCRYPTO_MEM_LEAK_CB, | |
872 &cb); | |
873 CRYPTO_w_unlock(CRYPTO_LOCK_MALLOC2); | |
874 } | |
OLD | NEW |