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