OpenCoverage

mem_dbg.c

Absolute File Name:/home/opencoverage/opencoverage/guest-scripts/openssl/src/crypto/mem_dbg.c
Source codeSwitch to Preprocessed file
LineSourceCount
1/*-
2 * Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved.-
3 *-
4 * Licensed under the OpenSSL license (the "License"). You may not use-
5 * this file except in compliance with the License. You can obtain a copy-
6 * in the file LICENSE in the source distribution or at-
7 * https://www.openssl.org/source/license.html-
8 */-
9-
10#include <stdio.h>-
11#include <stdlib.h>-
12#include <time.h>-
13#include "internal/cryptlib.h"-
14#include "internal/thread_once.h"-
15#include <openssl/crypto.h>-
16#include <openssl/buffer.h>-
17#include "internal/bio.h"-
18#include <openssl/lhash.h>-
19-
20#ifndef OPENSSL_NO_CRYPTO_MDEBUG_BACKTRACE-
21# include <execinfo.h>-
22#endif-
23-
24/*-
25 * The state changes to CRYPTO_MEM_CHECK_ON | CRYPTO_MEM_CHECK_ENABLE when-
26 * the application asks for it (usually after library initialisation for-
27 * which no book-keeping is desired). State CRYPTO_MEM_CHECK_ON exists only-
28 * temporarily when the library thinks that certain allocations should not be-
29 * checked (e.g. the data structures used for memory checking). It is not-
30 * suitable as an initial state: the library will unexpectedly enable memory-
31 * checking when it executes one of those sections that want to disable-
32 * checking temporarily. State CRYPTO_MEM_CHECK_ENABLE without ..._ON makes-
33 * no sense whatsoever.-
34 */-
35#ifndef OPENSSL_NO_CRYPTO_MDEBUG-
36static int mh_mode = CRYPTO_MEM_CHECK_OFF;-
37#endif-
38-
39#ifndef OPENSSL_NO_CRYPTO_MDEBUG-
40static unsigned long order = 0; /* number of memory requests */-
41-
42/*--
43 * For application-defined information (static C-string `info')-
44 * to be displayed in memory leak list.-
45 * Each thread has its own stack. For applications, there is-
46 * OPENSSL_mem_debug_push("...") to push an entry,-
47 * OPENSSL_mem_debug_pop() to pop an entry,-
48 */-
49struct app_mem_info_st {-
50 CRYPTO_THREAD_ID threadid;-
51 const char *file;-
52 int line;-
53 const char *info;-
54 struct app_mem_info_st *next; /* tail of thread's stack */-
55 int references;-
56};-
57-
58static CRYPTO_ONCE memdbg_init = CRYPTO_ONCE_STATIC_INIT;-
59CRYPTO_RWLOCK *memdbg_lock;-
60static CRYPTO_RWLOCK *long_memdbg_lock;-
61static CRYPTO_THREAD_LOCAL appinfokey;-
62-
63/* memory-block description */-
64struct mem_st {-
65 void *addr;-
66 int num;-
67 const char *file;-
68 int line;-
69 CRYPTO_THREAD_ID threadid;-
70 unsigned long order;-
71 time_t time;-
72 APP_INFO *app_info;-
73#ifndef OPENSSL_NO_CRYPTO_MDEBUG_BACKTRACE-
74 void *array[30];-
75 size_t array_siz;-
76#endif-
77};-
78-
79/*-
80 * hash-table of memory requests (address as * key); access requires-
81 * long_memdbg_lock lock-
82 */-
83static LHASH_OF(MEM) *mh = NULL;-
84-
85/* num_disable > 0 iff mh_mode == CRYPTO_MEM_CHECK_ON (w/o ..._ENABLE) */-
86static unsigned int num_disable = 0;-
87-
88/*-
89 * Valid iff num_disable > 0. long_memdbg_lock is locked exactly in this-
90 * case (by the thread named in disabling_thread).-
91 */-
92static CRYPTO_THREAD_ID disabling_threadid;-
93-
94DEFINE_RUN_ONCE_STATIC(do_memdbg_init)-
95{-
96 memdbg_lock = CRYPTO_THREAD_lock_new();-
97 long_memdbg_lock = CRYPTO_THREAD_lock_new();-
98 if (memdbg_lock == NULL || long_memdbg_lock == NULL-
99 || !CRYPTO_THREAD_init_local(&appinfokey, NULL)) {-
100 CRYPTO_THREAD_lock_free(memdbg_lock);-
101 memdbg_lock = NULL;-
102 CRYPTO_THREAD_lock_free(long_memdbg_lock);-
103 long_memdbg_lock = NULL;-
104 return 0;-
105 }-
106 return 1;-
107}-
108-
109static void app_info_free(APP_INFO *inf)-
110{-
111 if (inf == NULL)-
112 return;-
113 if (--(inf->references) <= 0) {-
114 app_info_free(inf->next);-
115 OPENSSL_free(inf);-
116 }-
117}-
118#endif-
119-
120int CRYPTO_mem_ctrl(int mode)-
121{-
122#ifdef OPENSSL_NO_CRYPTO_MDEBUG-
123 return mode - mode;
executed 9767 times by 1 test: return mode - mode;
Executed by:
  • libcrypto.so.1.1
9767
124#else-
125 int ret = mh_mode;-
126-
127 if (!RUN_ONCE(&memdbg_init, do_memdbg_init))-
128 return -1;-
129-
130 CRYPTO_THREAD_write_lock(memdbg_lock);-
131 switch (mode) {-
132 default:-
133 break;-
134-
135 case CRYPTO_MEM_CHECK_ON:-
136 mh_mode = CRYPTO_MEM_CHECK_ON | CRYPTO_MEM_CHECK_ENABLE;-
137 num_disable = 0;-
138 break;-
139-
140 case CRYPTO_MEM_CHECK_OFF:-
141 mh_mode = 0;-
142 num_disable = 0;-
143 break;-
144-
145 /* switch off temporarily (for library-internal use): */-
146 case CRYPTO_MEM_CHECK_DISABLE:-
147 if (mh_mode & CRYPTO_MEM_CHECK_ON) {-
148 CRYPTO_THREAD_ID cur = CRYPTO_THREAD_get_current_id();-
149 /* see if we don't have long_memdbg_lock already */-
150 if (!num_disable-
151 || !CRYPTO_THREAD_compare_id(disabling_threadid, cur)) {-
152 /*-
153 * Long-time lock long_memdbg_lock must not be claimed-
154 * while we're holding memdbg_lock, or we'll deadlock-
155 * if somebody else holds long_memdbg_lock (and cannot-
156 * release it because we block entry to this function). Give-
157 * them a chance, first, and then claim the locks in-
158 * appropriate order (long-time lock first).-
159 */-
160 CRYPTO_THREAD_unlock(memdbg_lock);-
161 /*-
162 * Note that after we have waited for long_memdbg_lock and-
163 * memdbg_lock, we'll still be in the right "case" and-
164 * "if" branch because MemCheck_start and MemCheck_stop may-
165 * never be used while there are multiple OpenSSL threads.-
166 */-
167 CRYPTO_THREAD_write_lock(long_memdbg_lock);-
168 CRYPTO_THREAD_write_lock(memdbg_lock);-
169 mh_mode &= ~CRYPTO_MEM_CHECK_ENABLE;-
170 disabling_threadid = cur;-
171 }-
172 num_disable++;-
173 }-
174 break;-
175-
176 case CRYPTO_MEM_CHECK_ENABLE:-
177 if (mh_mode & CRYPTO_MEM_CHECK_ON) {-
178 if (num_disable) { /* always true, or something is going wrong */-
179 num_disable--;-
180 if (num_disable == 0) {-
181 mh_mode |= CRYPTO_MEM_CHECK_ENABLE;-
182 CRYPTO_THREAD_unlock(long_memdbg_lock);-
183 }-
184 }-
185 }-
186 break;-
187 }-
188 CRYPTO_THREAD_unlock(memdbg_lock);-
189 return ret;-
190#endif-
191}-
192-
193#ifndef OPENSSL_NO_CRYPTO_MDEBUG-
194-
195static int mem_check_on(void)-
196{-
197 int ret = 0;-
198 CRYPTO_THREAD_ID cur;-
199-
200 if (mh_mode & CRYPTO_MEM_CHECK_ON) {-
201 if (!RUN_ONCE(&memdbg_init, do_memdbg_init))-
202 return 0;-
203-
204 cur = CRYPTO_THREAD_get_current_id();-
205 CRYPTO_THREAD_read_lock(memdbg_lock);-
206-
207 ret = (mh_mode & CRYPTO_MEM_CHECK_ENABLE)-
208 || !CRYPTO_THREAD_compare_id(disabling_threadid, cur);-
209-
210 CRYPTO_THREAD_unlock(memdbg_lock);-
211 }-
212 return ret;-
213}-
214-
215static int mem_cmp(const MEM *a, const MEM *b)-
216{-
217#ifdef _WIN64-
218 const char *ap = (const char *)a->addr, *bp = (const char *)b->addr;-
219 if (ap == bp)-
220 return 0;-
221 else if (ap > bp)-
222 return 1;-
223 else-
224 return -1;-
225#else-
226 return (const char *)a->addr - (const char *)b->addr;-
227#endif-
228}-
229-
230static unsigned long mem_hash(const MEM *a)-
231{-
232 size_t ret;-
233-
234 ret = (size_t)a->addr;-
235-
236 ret = ret * 17851 + (ret >> 14) * 7 + (ret >> 4) * 251;-
237 return ret;-
238}-
239-
240/* returns 1 if there was an info to pop, 0 if the stack was empty. */-
241static int pop_info(void)-
242{-
243 APP_INFO *current = NULL;-
244-
245 if (!RUN_ONCE(&memdbg_init, do_memdbg_init))-
246 return 0;-
247-
248 current = (APP_INFO *)CRYPTO_THREAD_get_local(&appinfokey);-
249 if (current != NULL) {-
250 APP_INFO *next = current->next;-
251-
252 if (next != NULL) {-
253 next->references++;-
254 CRYPTO_THREAD_set_local(&appinfokey, next);-
255 } else {-
256 CRYPTO_THREAD_set_local(&appinfokey, NULL);-
257 }-
258 if (--(current->references) <= 0) {-
259 current->next = NULL;-
260 if (next != NULL)-
261 next->references--;-
262 OPENSSL_free(current);-
263 }-
264 return 1;-
265 }-
266 return 0;-
267}-
268-
269int CRYPTO_mem_debug_push(const char *info, const char *file, int line)-
270{-
271 APP_INFO *ami, *amim;-
272 int ret = 0;-
273-
274 if (mem_check_on()) {-
275 CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_DISABLE);-
276-
277 if (!RUN_ONCE(&memdbg_init, do_memdbg_init)-
278 || (ami = OPENSSL_malloc(sizeof(*ami))) == NULL)-
279 goto err;-
280-
281 ami->threadid = CRYPTO_THREAD_get_current_id();-
282 ami->file = file;-
283 ami->line = line;-
284 ami->info = info;-
285 ami->references = 1;-
286 ami->next = NULL;-
287-
288 amim = (APP_INFO *)CRYPTO_THREAD_get_local(&appinfokey);-
289 CRYPTO_THREAD_set_local(&appinfokey, ami);-
290-
291 if (amim != NULL)-
292 ami->next = amim;-
293 ret = 1;-
294 err:-
295 CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ENABLE);-
296 }-
297-
298 return ret;-
299}-
300-
301int CRYPTO_mem_debug_pop(void)-
302{-
303 int ret = 0;-
304-
305 if (mem_check_on()) {-
306 CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_DISABLE);-
307 ret = pop_info();-
308 CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ENABLE);-
309 }-
310 return ret;-
311}-
312-
313static unsigned long break_order_num = 0;-
314-
315void CRYPTO_mem_debug_malloc(void *addr, size_t num, int before_p,-
316 const char *file, int line)-
317{-
318 MEM *m, *mm;-
319 APP_INFO *amim;-
320-
321 switch (before_p & 127) {-
322 case 0:-
323 break;-
324 case 1:-
325 if (addr == NULL)-
326 break;-
327-
328 if (mem_check_on()) {-
329 CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_DISABLE);-
330-
331 if (!RUN_ONCE(&memdbg_init, do_memdbg_init)-
332 || (m = OPENSSL_malloc(sizeof(*m))) == NULL) {-
333 OPENSSL_free(addr);-
334 CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ENABLE);-
335 return;-
336 }-
337 if (mh == NULL) {-
338 if ((mh = lh_MEM_new(mem_hash, mem_cmp)) == NULL) {-
339 OPENSSL_free(addr);-
340 OPENSSL_free(m);-
341 addr = NULL;-
342 goto err;-
343 }-
344 }-
345-
346 m->addr = addr;-
347 m->file = file;-
348 m->line = line;-
349 m->num = num;-
350 m->threadid = CRYPTO_THREAD_get_current_id();-
351-
352 if (order == break_order_num) {-
353 /* BREAK HERE */-
354 m->order = order;-
355 }-
356 m->order = order++;-
357# ifndef OPENSSL_NO_CRYPTO_MDEBUG_BACKTRACE-
358 m->array_siz = backtrace(m->array, OSSL_NELEM(m->array));-
359# endif-
360 m->time = time(NULL);-
361-
362 amim = (APP_INFO *)CRYPTO_THREAD_get_local(&appinfokey);-
363 m->app_info = amim;-
364 if (amim != NULL)-
365 amim->references++;-
366-
367 if ((mm = lh_MEM_insert(mh, m)) != NULL) {-
368 /* Not good, but don't sweat it */-
369 if (mm->app_info != NULL) {-
370 mm->app_info->references--;-
371 }-
372 OPENSSL_free(mm);-
373 }-
374 err:-
375 CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ENABLE);-
376 }-
377 break;-
378 }-
379 return;-
380}-
381-
382void CRYPTO_mem_debug_free(void *addr, int before_p,-
383 const char *file, int line)-
384{-
385 MEM m, *mp;-
386-
387 switch (before_p) {-
388 case 0:-
389 if (addr == NULL)-
390 break;-
391-
392 if (mem_check_on() && (mh != NULL)) {-
393 CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_DISABLE);-
394-
395 m.addr = addr;-
396 mp = lh_MEM_delete(mh, &m);-
397 if (mp != NULL) {-
398 app_info_free(mp->app_info);-
399 OPENSSL_free(mp);-
400 }-
401-
402 CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ENABLE);-
403 }-
404 break;-
405 case 1:-
406 break;-
407 }-
408}-
409-
410void CRYPTO_mem_debug_realloc(void *addr1, void *addr2, size_t num,-
411 int before_p, const char *file, int line)-
412{-
413 MEM m, *mp;-
414-
415 switch (before_p) {-
416 case 0:-
417 break;-
418 case 1:-
419 if (addr2 == NULL)-
420 break;-
421-
422 if (addr1 == NULL) {-
423 CRYPTO_mem_debug_malloc(addr2, num, 128 | before_p, file, line);-
424 break;-
425 }-
426-
427 if (mem_check_on()) {-
428 CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_DISABLE);-
429-
430 m.addr = addr1;-
431 mp = lh_MEM_delete(mh, &m);-
432 if (mp != NULL) {-
433 mp->addr = addr2;-
434 mp->num = num;-
435#ifndef OPENSSL_NO_CRYPTO_MDEBUG_BACKTRACE-
436 mp->array_siz = backtrace(mp->array, OSSL_NELEM(mp->array));-
437#endif-
438 (void)lh_MEM_insert(mh, mp);-
439 }-
440-
441 CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ENABLE);-
442 }-
443 break;-
444 }-
445 return;-
446}-
447-
448typedef struct mem_leak_st {-
449 int (*print_cb) (const char *str, size_t len, void *u);-
450 void *print_cb_arg;-
451 int chunks;-
452 long bytes;-
453} MEM_LEAK;-
454-
455static void print_leak(const MEM *m, MEM_LEAK *l)-
456{-
457 char buf[1024];-
458 char *bufp = buf;-
459 size_t len = sizeof(buf), ami_cnt;-
460 APP_INFO *amip;-
461 int n;-
462 struct tm *lcl = NULL;-
463 /*-
464 * Convert between CRYPTO_THREAD_ID (which could be anything at all) and-
465 * a long. This may not be meaningful depending on what CRYPTO_THREAD_ID is-
466 * but hopefully should give something sensible on most platforms-
467 */-
468 union {-
469 CRYPTO_THREAD_ID tid;-
470 unsigned long ltid;-
471 } tid;-
472 CRYPTO_THREAD_ID ti;-
473-
474 lcl = localtime(&m->time);-
475 n = BIO_snprintf(bufp, len, "[%02d:%02d:%02d] ",-
476 lcl->tm_hour, lcl->tm_min, lcl->tm_sec);-
477 if (n <= 0) {-
478 bufp[0] = '\0';-
479 return;-
480 }-
481 bufp += n;-
482 len -= n;-
483-
484 n = BIO_snprintf(bufp, len, "%5lu file=%s, line=%d, ",-
485 m->order, m->file, m->line);-
486 if (n <= 0)-
487 return;-
488 bufp += n;-
489 len -= n;-
490-
491 tid.ltid = 0;-
492 tid.tid = m->threadid;-
493 n = BIO_snprintf(bufp, len, "thread=%lu, ", tid.ltid);-
494 if (n <= 0)-
495 return;-
496 bufp += n;-
497 len -= n;-
498-
499 n = BIO_snprintf(bufp, len, "number=%d, address=%p\n", m->num, m->addr);-
500 if (n <= 0)-
501 return;-
502 bufp += n;-
503 len -= n;-
504-
505 l->print_cb(buf, (size_t)(bufp - buf), l->print_cb_arg);-
506-
507 l->chunks++;-
508 l->bytes += m->num;-
509-
510 amip = m->app_info;-
511 ami_cnt = 0;-
512-
513 if (amip) {-
514 ti = amip->threadid;-
515-
516 do {-
517 int buf_len;-
518 int info_len;-
519-
520 ami_cnt++;-
521 if (ami_cnt >= sizeof(buf) - 1)-
522 break;-
523 memset(buf, '>', ami_cnt);-
524 buf[ami_cnt] = '\0';-
525 tid.ltid = 0;-
526 tid.tid = amip->threadid;-
527 n = BIO_snprintf(buf + ami_cnt, sizeof(buf) - ami_cnt,-
528 " thread=%lu, file=%s, line=%d, info=\"",-
529 tid.ltid, amip->file, amip->line);-
530 if (n <= 0)-
531 break;-
532 buf_len = ami_cnt + n;-
533 info_len = strlen(amip->info);-
534 if (128 - buf_len - 3 < info_len) {-
535 memcpy(buf + buf_len, amip->info, 128 - buf_len - 3);-
536 buf_len = 128 - 3;-
537 } else {-
538 n = BIO_snprintf(buf + buf_len, sizeof(buf) - buf_len, "%s",-
539 amip->info);-
540 if (n < 0)-
541 break;-
542 buf_len += n;-
543 }-
544 n = BIO_snprintf(buf + buf_len, sizeof(buf) - buf_len, "\"\n");-
545 if (n <= 0)-
546 break;-
547-
548 l->print_cb(buf, buf_len + n, l->print_cb_arg);-
549-
550 amip = amip->next;-
551 }-
552 while (amip && CRYPTO_THREAD_compare_id(amip->threadid, ti));-
553 }-
554-
555#ifndef OPENSSL_NO_CRYPTO_MDEBUG_BACKTRACE-
556 {-
557 size_t i;-
558 char **strings = backtrace_symbols(m->array, m->array_siz);-
559-
560 for (i = 0; i < m->array_siz; i++)-
561 fprintf(stderr, "##> %s\n", strings[i]);-
562 free(strings);-
563 }-
564#endif-
565}-
566-
567IMPLEMENT_LHASH_DOALL_ARG_CONST(MEM, MEM_LEAK);-
568-
569int CRYPTO_mem_leaks_cb(int (*cb) (const char *str, size_t len, void *u),-
570 void *u)-
571{-
572 MEM_LEAK ml;-
573-
574 /* Ensure all resources are released */-
575 OPENSSL_cleanup();-
576-
577 if (!RUN_ONCE(&memdbg_init, do_memdbg_init))-
578 return -1;-
579-
580 CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_DISABLE);-
581-
582 ml.print_cb = cb;-
583 ml.print_cb_arg = u;-
584 ml.bytes = 0;-
585 ml.chunks = 0;-
586 if (mh != NULL)-
587 lh_MEM_doall_MEM_LEAK(mh, print_leak, &ml);-
588-
589 if (ml.chunks != 0) {-
590 char buf[256];-
591-
592 BIO_snprintf(buf, sizeof(buf), "%ld bytes leaked in %d chunks\n",-
593 ml.bytes, ml.chunks);-
594 cb(buf, strlen(buf), u);-
595 } else {-
596 /*-
597 * Make sure that, if we found no leaks, memory-leak debugging itself-
598 * does not introduce memory leaks (which might irritate external-
599 * debugging tools). (When someone enables leak checking, but does not-
600 * call this function, we declare it to be their fault.)-
601 */-
602 int old_mh_mode;-
603-
604 CRYPTO_THREAD_write_lock(memdbg_lock);-
605-
606 /*-
607 * avoid deadlock when lh_free() uses CRYPTO_mem_debug_free(), which uses-
608 * mem_check_on-
609 */-
610 old_mh_mode = mh_mode;-
611 mh_mode = CRYPTO_MEM_CHECK_OFF;-
612-
613 lh_MEM_free(mh);-
614 mh = NULL;-
615-
616 mh_mode = old_mh_mode;-
617 CRYPTO_THREAD_unlock(memdbg_lock);-
618 }-
619 CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_OFF);-
620-
621 /* Clean up locks etc */-
622 CRYPTO_THREAD_cleanup_local(&appinfokey);-
623 CRYPTO_THREAD_lock_free(memdbg_lock);-
624 CRYPTO_THREAD_lock_free(long_memdbg_lock);-
625 memdbg_lock = NULL;-
626 long_memdbg_lock = NULL;-
627-
628 return ml.chunks == 0 ? 1 : 0;-
629}-
630-
631static int print_bio(const char *str, size_t len, void *b)-
632{-
633 return BIO_write((BIO *)b, str, len);-
634}-
635-
636int CRYPTO_mem_leaks(BIO *b)-
637{-
638 /*-
639 * OPENSSL_cleanup() will free the ex_data locks so we can't have any-
640 * ex_data hanging around-
641 */-
642 bio_free_ex_data(b);-
643-
644 return CRYPTO_mem_leaks_cb(print_bio, b);-
645}-
646-
647# ifndef OPENSSL_NO_STDIO-
648int CRYPTO_mem_leaks_fp(FILE *fp)-
649{-
650 BIO *b;-
651 int ret;-
652-
653 /*-
654 * Need to turn off memory checking when allocated BIOs ... especially as-
655 * we're creating them at a time when we're trying to check we've not-
656 * left anything un-free()'d!!-
657 */-
658 CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_DISABLE);-
659 b = BIO_new(BIO_s_file());-
660 CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ENABLE);-
661 if (b == NULL)-
662 return -1;-
663 BIO_set_fp(b, fp, BIO_NOCLOSE);-
664 ret = CRYPTO_mem_leaks_cb(print_bio, b);-
665 BIO_free(b);-
666 return ret;-
667}-
668# endif-
669-
670#endif-
Source codeSwitch to Preprocessed file

Generated by Squish Coco 4.2.2