]>
Commit | Line | Data |
---|---|---|
9ac42ed8 | 1 | /* crypto/mem_dbg.c */ |
08807172 RL |
2 | /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) |
3 | * All rights reserved. | |
9ac42ed8 | 4 | * |
08807172 RL |
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 | * | |
9ac42ed8 RL |
23 | * Redistribution and use in source and binary forms, with or without |
24 | * modification, are permitted provided that the following conditions | |
25 | * are met: | |
08807172 RL |
26 | * 1. Redistributions of source code must retain the copyright |
27 | * notice, this list of conditions and the following disclaimer. | |
9ac42ed8 | 28 | * 2. Redistributions in binary form must reproduce the above copyright |
08807172 RL |
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.] | |
9ac42ed8 RL |
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 | ||
0cd08cce BM |
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 | |
9ac42ed8 RL |
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 | */ | |
9ac42ed8 | 82 | |
0cd08cce | 83 | static unsigned long order = 0; /* number of memory requests */ |
934397ec BM |
84 | static LHASH *mh=NULL; /* hash-table of memory requests (address as key); |
85 | * access requires MALLOC2 lock */ | |
9ac42ed8 | 86 | |
9ac42ed8 RL |
87 | |
88 | typedef struct app_mem_info_st | |
0cd08cce BM |
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 | |
2b6313d0 BM |
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. | |
0cd08cce | 95 | */ |
9ac42ed8 RL |
96 | { |
97 | unsigned long thread; | |
98 | const char *file; | |
99 | int line; | |
100 | const char *info; | |
0cd08cce | 101 | struct app_mem_info_st *next; /* tail of thread's stack */ |
9ac42ed8 RL |
102 | int references; |
103 | } APP_INFO; | |
104 | ||
0cd08cce BM |
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 | |
934397ec BM |
107 | * (with `thread' as key); |
108 | * access requires MALLOC2 lock */ | |
9ac42ed8 RL |
109 | |
110 | typedef struct mem_st | |
0cd08cce | 111 | /* memory-block description */ |
9ac42ed8 | 112 | { |
65962686 | 113 | void *addr; |
9ac42ed8 RL |
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 | ||
0cd08cce BM |
123 | static long options = /* extra information to be recorded */ |
124 | #if defined(CRYPTO_MDEBUG_TIME) || defined(CRYPTO_MDEBUG_ALL) | |
125 | V_CRYPTO_MDEBUG_TIME | | |
d8df48a9 | 126 | #endif |
0cd08cce BM |
127 | #if defined(CRYPTO_MDEBUG_THREAD) || defined(CRYPTO_MDEBUG_ALL) |
128 | V_CRYPTO_MDEBUG_THREAD | | |
d8df48a9 | 129 | #endif |
0cd08cce | 130 | 0; |
d8df48a9 | 131 | |
9ac42ed8 | 132 | |
934397ec BM |
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 | */ | |
9ac42ed8 RL |
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 | { | |
934397ec BM |
150 | /* for applications (not to be called while multiple threads |
151 | * use the library): */ | |
9ac42ed8 RL |
152 | case CRYPTO_MEM_CHECK_ON: /* aka MemCheck_start() */ |
153 | mh_mode = CRYPTO_MEM_CHECK_ON|CRYPTO_MEM_CHECK_ENABLE; | |
934397ec | 154 | num_disable = 0; |
9ac42ed8 RL |
155 | break; |
156 | case CRYPTO_MEM_CHECK_OFF: /* aka MemCheck_stop() */ | |
157 | mh_mode = 0; | |
934397ec BM |
158 | num_disable = 0; /* should be true *before* MemCheck_stop is used, |
159 | or there'll be a lot of confusion */ | |
9ac42ed8 RL |
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 | { | |
934397ec | 166 | if (!num_disable || (disabling_thread != CRYPTO_thread_id())) /* otherwise we already have the MALLOC2 lock */ |
9ac42ed8 RL |
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 | |
0cd08cce BM |
170 | * somebody else holds CRYPTO_LOCK_MALLOC2 (and cannot release |
171 | * it because we block entry to this function). | |
9ac42ed8 RL |
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); | |
934397ec | 183 | mh_mode &= ~CRYPTO_MEM_CHECK_ENABLE; |
9ac42ed8 RL |
184 | disabling_thread=CRYPTO_thread_id(); |
185 | } | |
934397ec | 186 | num_disable++; |
9ac42ed8 RL |
187 | } |
188 | break; | |
189 | case CRYPTO_MEM_CHECK_ENABLE: /* aka MemCheck_on() */ | |
190 | if (mh_mode & CRYPTO_MEM_CHECK_ON) | |
191 | { | |
934397ec | 192 | if (num_disable) /* always true, or something is going wrong */ |
9ac42ed8 | 193 | { |
934397ec BM |
194 | num_disable--; |
195 | if (num_disable == 0) | |
196 | { | |
197 | mh_mode|=CRYPTO_MEM_CHECK_ENABLE; | |
198 | CRYPTO_w_unlock(CRYPTO_LOCK_MALLOC2); | |
199 | } | |
9ac42ed8 RL |
200 | } |
201 | } | |
202 | break; | |
203 | ||
204 | default: | |
205 | break; | |
206 | } | |
207 | CRYPTO_w_unlock(CRYPTO_LOCK_MALLOC); | |
208 | return(ret); | |
209 | } | |
210 | ||
0cd08cce | 211 | int CRYPTO_is_mem_check_on(void) |
9ac42ed8 RL |
212 | { |
213 | int ret = 0; | |
214 | ||
215 | if (mh_mode & CRYPTO_MEM_CHECK_ON) | |
216 | { | |
934397ec | 217 | CRYPTO_r_lock(CRYPTO_LOCK_MALLOC); |
9ac42ed8 RL |
218 | |
219 | ret = (mh_mode & CRYPTO_MEM_CHECK_ENABLE) | |
934397ec | 220 | || (disabling_thread != CRYPTO_thread_id()); |
9ac42ed8 | 221 | |
934397ec | 222 | CRYPTO_r_unlock(CRYPTO_LOCK_MALLOC); |
9ac42ed8 RL |
223 | } |
224 | return(ret); | |
225 | } | |
226 | ||
227 | ||
0cd08cce | 228 | void CRYPTO_dbg_set_options(long bits) |
9ac42ed8 RL |
229 | { |
230 | options = bits; | |
231 | } | |
232 | ||
667ac4ec | 233 | long CRYPTO_dbg_get_options(void) |
9ac42ed8 RL |
234 | { |
235 | return options; | |
236 | } | |
237 | ||
d0fa136c | 238 | /* static int mem_cmp(MEM *a, MEM *b) */ |
8d28d5f8 | 239 | static int mem_cmp(const void *a_void, const void *b_void) |
9ac42ed8 | 240 | { |
0774f470 BL |
241 | return((const char *)((const MEM *)a_void)->addr |
242 | - (const char *)((const MEM *)b_void)->addr); | |
9ac42ed8 RL |
243 | } |
244 | ||
d0fa136c | 245 | /* static unsigned long mem_hash(MEM *a) */ |
8d28d5f8 | 246 | static unsigned long mem_hash(const void *a_void) |
9ac42ed8 RL |
247 | { |
248 | unsigned long ret; | |
249 | ||
8d28d5f8 | 250 | ret=(unsigned long)((const MEM *)a_void)->addr; |
9ac42ed8 RL |
251 | |
252 | ret=ret*17851+(ret>>14)*7+(ret>>4)*251; | |
253 | return(ret); | |
254 | } | |
255 | ||
d0fa136c | 256 | /* static int app_info_cmp(APP_INFO *a, APP_INFO *b) */ |
8d28d5f8 | 257 | static int app_info_cmp(const void *a_void, const void *b_void) |
9ac42ed8 | 258 | { |
8d28d5f8 RL |
259 | return(((const APP_INFO *)a_void)->thread |
260 | != ((const APP_INFO *)b_void)->thread); | |
9ac42ed8 RL |
261 | } |
262 | ||
d0fa136c | 263 | /* static unsigned long app_info_hash(APP_INFO *a) */ |
8d28d5f8 | 264 | static unsigned long app_info_hash(const void *a_void) |
9ac42ed8 RL |
265 | { |
266 | unsigned long ret; | |
267 | ||
8d28d5f8 | 268 | ret=(unsigned long)((const APP_INFO *)a_void)->thread; |
9ac42ed8 RL |
269 | |
270 | ret=ret*17851+(ret>>14)*7+(ret>>4)*251; | |
271 | return(ret); | |
272 | } | |
273 | ||
fe8686ba | 274 | static APP_INFO *pop_info(void) |
9ac42ed8 RL |
275 | { |
276 | APP_INFO tmp; | |
277 | APP_INFO *ret = NULL; | |
278 | ||
279 | if (amih != NULL) | |
280 | { | |
281 | tmp.thread=CRYPTO_thread_id(); | |
9d1a01be | 282 | if ((ret=(APP_INFO *)lh_delete(amih,&tmp)) != NULL) |
9ac42ed8 RL |
283 | { |
284 | APP_INFO *next=ret->next; | |
285 | ||
286 | if (next != NULL) | |
287 | { | |
288 | next->references++; | |
289 | lh_insert(amih,(char *)next); | |
290 | } | |
3d6001f7 | 291 | #ifdef LEVITTE_DEBUG_MEM |
9ac42ed8 RL |
292 | if (ret->thread != tmp.thread) |
293 | { | |
2b6313d0 | 294 | fprintf(stderr, "pop_info(): deleted info has other thread ID (%lu) than the current thread (%lu)!!!!\n", |
9ac42ed8 RL |
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--; | |
26a3a48d | 304 | OPENSSL_free(ret); |
9ac42ed8 RL |
305 | } |
306 | } | |
307 | } | |
308 | return(ret); | |
309 | } | |
310 | ||
2b6313d0 | 311 | int CRYPTO_push_info_(const char *info, const char *file, int line) |
9ac42ed8 RL |
312 | { |
313 | APP_INFO *ami, *amim; | |
314 | int ret=0; | |
315 | ||
316 | if (is_MemCheck_on()) | |
317 | { | |
934397ec | 318 | MemCheck_off(); /* obtain MALLOC2 lock */ |
9ac42ed8 | 319 | |
26a3a48d | 320 | if ((ami = (APP_INFO *)OPENSSL_malloc(sizeof(APP_INFO))) == NULL) |
9ac42ed8 RL |
321 | { |
322 | ret=0; | |
323 | goto err; | |
324 | } | |
325 | if (amih == NULL) | |
326 | { | |
d0fa136c | 327 | if ((amih=lh_new(app_info_hash, app_info_cmp)) == NULL) |
9ac42ed8 | 328 | { |
26a3a48d | 329 | OPENSSL_free(ami); |
9ac42ed8 RL |
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 | { | |
3d6001f7 | 344 | #ifdef LEVITTE_DEBUG_MEM |
9ac42ed8 RL |
345 | if (ami->thread != amim->thread) |
346 | { | |
2b6313d0 | 347 | fprintf(stderr, "CRYPTO_push_info(): previous info has other thread ID (%lu) than the current thread (%lu)!!!!\n", |
9ac42ed8 RL |
348 | amim->thread, ami->thread); |
349 | abort(); | |
350 | } | |
351 | #endif | |
352 | ami->next=amim; | |
353 | } | |
354 | err: | |
934397ec | 355 | MemCheck_on(); /* release MALLOC2 lock */ |
9ac42ed8 RL |
356 | } |
357 | ||
358 | return(ret); | |
359 | } | |
360 | ||
2b6313d0 | 361 | int CRYPTO_pop_info(void) |
9ac42ed8 RL |
362 | { |
363 | int ret=0; | |
364 | ||
75acc288 | 365 | if (is_MemCheck_on()) /* _must_ be true, or something went severely wrong */ |
9ac42ed8 | 366 | { |
934397ec | 367 | MemCheck_off(); /* obtain MALLOC2 lock */ |
9ac42ed8 | 368 | |
2b6313d0 | 369 | ret=(pop_info() != NULL); |
9ac42ed8 | 370 | |
934397ec | 371 | MemCheck_on(); /* release MALLOC2 lock */ |
9ac42ed8 RL |
372 | } |
373 | return(ret); | |
374 | } | |
375 | ||
376 | int CRYPTO_remove_all_info(void) | |
377 | { | |
378 | int ret=0; | |
379 | ||
0cd08cce | 380 | if (is_MemCheck_on()) /* _must_ be true */ |
9ac42ed8 | 381 | { |
934397ec | 382 | MemCheck_off(); /* obtain MALLOC2 lock */ |
9ac42ed8 | 383 | |
2b6313d0 | 384 | while(pop_info() != NULL) |
9ac42ed8 RL |
385 | ret++; |
386 | ||
934397ec | 387 | MemCheck_on(); /* release MALLOC2 lock */ |
9ac42ed8 RL |
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 | { | |
934397ec | 410 | MemCheck_off(); /* make sure we hold MALLOC2 lock */ |
26a3a48d | 411 | if ((m=(MEM *)OPENSSL_malloc(sizeof(MEM))) == NULL) |
9ac42ed8 | 412 | { |
26a3a48d | 413 | OPENSSL_free(addr); |
934397ec BM |
414 | MemCheck_on(); /* release MALLOC2 lock |
415 | * if num_disabled drops to 0 */ | |
9ac42ed8 RL |
416 | return; |
417 | } | |
418 | if (mh == NULL) | |
419 | { | |
d0fa136c | 420 | if ((mh=lh_new(mem_hash, mem_cmp)) == NULL) |
9ac42ed8 | 421 | { |
26a3a48d RL |
422 | OPENSSL_free(addr); |
423 | OPENSSL_free(m); | |
9ac42ed8 RL |
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++; | |
3d6001f7 RL |
444 | #ifdef LEVITTE_DEBUG_MEM |
445 | fprintf(stderr, "LEVITTE_DEBUG_MEM: [%5d] %c 0x%p (%d)\n", | |
9ac42ed8 RL |
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 | } | |
26a3a48d | 471 | OPENSSL_free(mm); |
9ac42ed8 RL |
472 | } |
473 | err: | |
934397ec BM |
474 | MemCheck_on(); /* release MALLOC2 lock |
475 | * if num_disabled drops to 0 */ | |
9ac42ed8 RL |
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 | { | |
934397ec | 494 | MemCheck_off(); /* make sure we hold MALLOC2 lock */ |
9ac42ed8 RL |
495 | |
496 | m.addr=addr; | |
497 | mp=(MEM *)lh_delete(mh,(char *)&m); | |
498 | if (mp != NULL) | |
499 | { | |
3d6001f7 RL |
500 | #ifdef LEVITTE_DEBUG_MEM |
501 | fprintf(stderr, "LEVITTE_DEBUG_MEM: [%5d] - 0x%p (%d)\n", | |
9ac42ed8 RL |
502 | mp->order, mp->addr, mp->num); |
503 | #endif | |
504 | if (mp->app_info != NULL) | |
505 | { | |
506 | mp->app_info->references--; | |
507 | } | |
26a3a48d | 508 | OPENSSL_free(mp); |
9ac42ed8 RL |
509 | } |
510 | ||
934397ec BM |
511 | MemCheck_on(); /* release MALLOC2 lock |
512 | * if num_disabled drops to 0 */ | |
9ac42ed8 RL |
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 | ||
3d6001f7 RL |
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", | |
9ac42ed8 RL |
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 | { | |
934397ec | 546 | MemCheck_off(); /* make sure we hold MALLOC2 lock */ |
9ac42ed8 RL |
547 | |
548 | m.addr=addr1; | |
549 | mp=(MEM *)lh_delete(mh,(char *)&m); | |
550 | if (mp != NULL) | |
551 | { | |
3d6001f7 RL |
552 | #ifdef LEVITTE_DEBUG_MEM |
553 | fprintf(stderr, "LEVITTE_DEBUG_MEM: [%5d] * 0x%p (%d) -> 0x%p (%d)\n", | |
9ac42ed8 RL |
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 | ||
934397ec BM |
563 | MemCheck_on(); /* release MALLOC2 lock |
564 | * if num_disabled drops to 0 */ | |
9ac42ed8 RL |
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 | ||
0774f470 | 579 | static void print_leak(const MEM *m, MEM_LEAK *l) |
9ac42ed8 RL |
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; | |
a8eeb155 BM |
621 | if (!amip) |
622 | return; | |
623 | ti=amip->thread; | |
624 | ||
625 | do | |
9ac42ed8 RL |
626 | { |
627 | int buf_len; | |
628 | int info_len; | |
629 | ||
630 | ami_cnt++; | |
631 | memset(buf,'>',ami_cnt); | |
632 | sprintf(buf + ami_cnt, | |
75acc288 | 633 | " thread=%lu, file=%s, line=%d, info=\"", |
9ac42ed8 RL |
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 | } | |
a8eeb155 BM |
653 | while(amip && amip->thread == ti); |
654 | ||
3d6001f7 | 655 | #ifdef LEVITTE_DEBUG_MEM |
9ac42ed8 RL |
656 | if (amip) |
657 | { | |
ed84dfab | 658 | fprintf(stderr, "Thread switch detected in backtrace!!!!\n"); |
9ac42ed8 RL |
659 | abort(); |
660 | } | |
661 | #endif | |
662 | } | |
663 | ||
0774f470 | 664 | static IMPLEMENT_LHASH_DOALL_ARG_FN(print_leak, const MEM *, MEM_LEAK *) |
98d517c5 | 665 | |
9ac42ed8 RL |
666 | void CRYPTO_mem_leaks(BIO *b) |
667 | { | |
668 | MEM_LEAK ml; | |
9ac42ed8 | 669 | |
6e22639f BM |
670 | if (mh == NULL && amih == NULL) |
671 | return; | |
934397ec BM |
672 | |
673 | MemCheck_off(); /* obtain MALLOC2 lock */ | |
674 | ||
9ac42ed8 RL |
675 | ml.bio=b; |
676 | ml.bytes=0; | |
677 | ml.chunks=0; | |
6e22639f | 678 | if (mh != NULL) |
98d517c5 | 679 | lh_doall_arg(mh, LHASH_DOALL_ARG_FN(print_leak), |
385d8138 | 680 | (char *)&ml); |
9ac42ed8 RL |
681 | if (ml.chunks != 0) |
682 | { | |
54a656ef BL |
683 | BIO_printf(b,"%ld bytes leaked in %d chunks\n", |
684 | ml.bytes,ml.chunks); | |
9ac42ed8 | 685 | } |
6e22639f BM |
686 | else |
687 | { | |
688 | /* Make sure that, if we found no leaks, memory-leak debugging itself | |
689 | * does not introduce memory leaks (which might irritate | |
690 | * external debugging tools). | |
691 | * (When someone enables leak checking, but does not call | |
692 | * this function, we declare it to be their fault.) | |
693 | * | |
694 | * XXX This should be in CRYPTO_mem_leaks_cb, | |
695 | * and CRYPTO_mem_leaks should be implemented by | |
696 | * using CRYPTO_mem_leaks_cb. | |
697 | * (Also their should be a variant of lh_doall_arg | |
698 | * that takes a function pointer instead of a void *; | |
699 | * this would obviate the ugly and illegal | |
700 | * void_fn_to_char kludge in CRYPTO_mem_leaks_cb. | |
701 | * Otherwise the code police will come and get us.) | |
702 | */ | |
3ac82faa BM |
703 | int old_mh_mode; |
704 | ||
6e22639f | 705 | CRYPTO_w_lock(CRYPTO_LOCK_MALLOC); |
3ac82faa BM |
706 | |
707 | /* avoid deadlock when lh_free() uses CRYPTO_dbg_free(), | |
708 | * which uses CRYPTO_is_mem_check_on */ | |
709 | old_mh_mode = mh_mode; | |
710 | mh_mode = CRYPTO_MEM_CHECK_OFF; | |
711 | ||
6e22639f BM |
712 | if (mh != NULL) |
713 | { | |
714 | lh_free(mh); | |
715 | mh = NULL; | |
716 | } | |
717 | if (amih != NULL) | |
718 | { | |
719 | if (lh_num_items(amih) == 0) | |
720 | { | |
721 | lh_free(amih); | |
722 | amih = NULL; | |
723 | } | |
724 | } | |
3ac82faa BM |
725 | |
726 | mh_mode = old_mh_mode; | |
6e22639f BM |
727 | CRYPTO_w_unlock(CRYPTO_LOCK_MALLOC); |
728 | } | |
934397ec | 729 | MemCheck_on(); /* release MALLOC2 lock */ |
9ac42ed8 RL |
730 | } |
731 | ||
cf1b7d96 | 732 | #ifndef OPENSSL_NO_FP_API |
9ac42ed8 RL |
733 | void CRYPTO_mem_leaks_fp(FILE *fp) |
734 | { | |
735 | BIO *b; | |
736 | ||
737 | if (mh == NULL) return; | |
5e2c4e23 GT |
738 | /* Need to turn off memory checking when allocated BIOs ... especially |
739 | * as we're creating them at a time when we're trying to check we've not | |
740 | * left anything un-free()'d!! */ | |
741 | MemCheck_off(); | |
3ae34e3a | 742 | b = BIO_new(BIO_s_file()); |
5e2c4e23 | 743 | MemCheck_on(); |
3ae34e3a | 744 | if(!b) return; |
9ac42ed8 RL |
745 | BIO_set_fp(b,fp,BIO_NOCLOSE); |
746 | CRYPTO_mem_leaks(b); | |
747 | BIO_free(b); | |
748 | } | |
749 | #endif | |
750 | ||
65962686 RL |
751 | |
752 | ||
753 | /* FIXME: We really don't allow much to the callback. For example, it has | |
754 | no chance of reaching the info stack for the item it processes. Should | |
755 | it really be this way? -- Richard Levitte */ | |
98d517c5 GT |
756 | /* NB: The prototypes have been typedef'd to CRYPTO_MEM_LEAK_CB inside crypto.h |
757 | * If this code is restructured, remove the callback type if it is no longer | |
758 | * needed. -- Geoff Thorpe */ | |
0774f470 | 759 | static void cb_leak(const MEM *m, CRYPTO_MEM_LEAK_CB **cb) |
65962686 RL |
760 | { |
761 | (**cb)(m->order,m->file,m->line,m->num,m->addr); | |
762 | } | |
763 | ||
0774f470 | 764 | static IMPLEMENT_LHASH_DOALL_ARG_FN(cb_leak, const MEM *, CRYPTO_MEM_LEAK_CB **) |
98d517c5 | 765 | |
32654e79 | 766 | void CRYPTO_mem_leaks_cb(CRYPTO_MEM_LEAK_CB *cb) |
65962686 RL |
767 | { |
768 | if (mh == NULL) return; | |
769 | CRYPTO_w_lock(CRYPTO_LOCK_MALLOC2); | |
98d517c5 | 770 | lh_doall_arg(mh, LHASH_DOALL_ARG_FN(cb_leak), &cb); |
65962686 RL |
771 | CRYPTO_w_unlock(CRYPTO_LOCK_MALLOC2); |
772 | } |