/*
- * Copyright 1995-2017 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1995-2019 The OpenSSL Project Authors. All Rights Reserved.
*
- * Licensed under the OpenSSL license (the "License"). You may not use
+ * Licensed under the Apache License 2.0 (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
#ifndef OPENSSL_NO_CRYPTO_MDEBUG
static unsigned long order = 0; /* number of memory requests */
-/*-
- * For application-defined information (static C-string `info')
- * to be displayed in memory leak list.
- * Each thread has its own stack. For applications, there is
- * OPENSSL_mem_debug_push("...") to push an entry,
- * OPENSSL_mem_debug_pop() to pop an entry,
- */
-struct app_mem_info_st {
- CRYPTO_THREAD_ID threadid;
- const char *file;
- int line;
- const char *info;
- struct app_mem_info_st *next; /* tail of thread's stack */
- int references;
-};
-
static CRYPTO_ONCE memdbg_init = CRYPTO_ONCE_STATIC_INIT;
-static CRYPTO_RWLOCK *malloc_lock = NULL;
-static CRYPTO_RWLOCK *long_malloc_lock = NULL;
-static CRYPTO_THREAD_LOCAL appinfokey;
+CRYPTO_RWLOCK *memdbg_lock;
+static CRYPTO_RWLOCK *long_memdbg_lock;
/* memory-block description */
struct mem_st {
CRYPTO_THREAD_ID threadid;
unsigned long order;
time_t time;
- APP_INFO *app_info;
#ifndef OPENSSL_NO_CRYPTO_MDEBUG_BACKTRACE
void *array[30];
size_t array_siz;
#endif
};
-static LHASH_OF(MEM) *mh = NULL; /* hash-table of memory requests (address as
- * key); access requires MALLOC2 lock */
+/*
+ * hash-table of memory requests (address as * key); access requires
+ * long_memdbg_lock lock
+ */
+static LHASH_OF(MEM) *mh = NULL;
/* num_disable > 0 iff mh_mode == CRYPTO_MEM_CHECK_ON (w/o ..._ENABLE) */
static unsigned int num_disable = 0;
/*
- * Valid iff num_disable > 0. long_malloc_lock is locked exactly in this
+ * Valid iff num_disable > 0. long_memdbg_lock is locked exactly in this
* case (by the thread named in disabling_thread).
*/
static CRYPTO_THREAD_ID disabling_threadid;
DEFINE_RUN_ONCE_STATIC(do_memdbg_init)
{
- malloc_lock = CRYPTO_THREAD_glock_new("malloc");
- long_malloc_lock = CRYPTO_THREAD_glock_new("long_malloc");
- if (malloc_lock == NULL || long_malloc_lock == NULL
- || !CRYPTO_THREAD_init_local(&appinfokey, NULL)) {
- CRYPTO_THREAD_lock_free(malloc_lock);
- malloc_lock = NULL;
- CRYPTO_THREAD_lock_free(long_malloc_lock);
- long_malloc_lock = NULL;
+ memdbg_lock = CRYPTO_THREAD_lock_new();
+ long_memdbg_lock = CRYPTO_THREAD_lock_new();
+ if (memdbg_lock == NULL || long_memdbg_lock == NULL) {
+ CRYPTO_THREAD_lock_free(memdbg_lock);
+ memdbg_lock = NULL;
+ CRYPTO_THREAD_lock_free(long_memdbg_lock);
+ long_memdbg_lock = NULL;
return 0;
}
return 1;
}
-static void app_info_free(APP_INFO *inf)
-{
- if (!inf)
- return;
- if (--(inf->references) <= 0) {
- app_info_free(inf->next);
- OPENSSL_free(inf);
- }
-}
#endif
int CRYPTO_mem_ctrl(int mode)
if (!RUN_ONCE(&memdbg_init, do_memdbg_init))
return -1;
- CRYPTO_THREAD_write_lock(malloc_lock);
+ CRYPTO_THREAD_write_lock(memdbg_lock);
switch (mode) {
default:
break;
case CRYPTO_MEM_CHECK_DISABLE:
if (mh_mode & CRYPTO_MEM_CHECK_ON) {
CRYPTO_THREAD_ID cur = CRYPTO_THREAD_get_current_id();
- /* see if we don't have long_malloc_lock already */
+ /* see if we don't have long_memdbg_lock already */
if (!num_disable
|| !CRYPTO_THREAD_compare_id(disabling_threadid, cur)) {
/*
- * Long-time lock long_malloc_lock must not be claimed
- * while we're holding malloc_lock, or we'll deadlock
- * if somebody else holds long_malloc_lock (and cannot
+ * Long-time lock long_memdbg_lock must not be claimed
+ * while we're holding memdbg_lock, or we'll deadlock
+ * if somebody else holds long_memdbg_lock (and cannot
* release it because we block entry to this function). Give
* them a chance, first, and then claim the locks in
* appropriate order (long-time lock first).
*/
- CRYPTO_THREAD_unlock(malloc_lock);
+ CRYPTO_THREAD_unlock(memdbg_lock);
/*
- * Note that after we have waited for long_malloc_lock and
- * malloc_lock, we'll still be in the right "case" and
+ * Note that after we have waited for long_memdbg_lock and
+ * memdbg_lock, we'll still be in the right "case" and
* "if" branch because MemCheck_start and MemCheck_stop may
* never be used while there are multiple OpenSSL threads.
*/
- CRYPTO_THREAD_write_lock(long_malloc_lock);
- CRYPTO_THREAD_write_lock(malloc_lock);
+ CRYPTO_THREAD_write_lock(long_memdbg_lock);
+ CRYPTO_THREAD_write_lock(memdbg_lock);
mh_mode &= ~CRYPTO_MEM_CHECK_ENABLE;
disabling_threadid = cur;
}
num_disable--;
if (num_disable == 0) {
mh_mode |= CRYPTO_MEM_CHECK_ENABLE;
- CRYPTO_THREAD_unlock(long_malloc_lock);
+ CRYPTO_THREAD_unlock(long_memdbg_lock);
}
}
}
break;
}
- CRYPTO_THREAD_unlock(malloc_lock);
+ CRYPTO_THREAD_unlock(memdbg_lock);
return ret;
#endif
}
return 0;
cur = CRYPTO_THREAD_get_current_id();
- CRYPTO_THREAD_read_lock(malloc_lock);
+ CRYPTO_THREAD_read_lock(memdbg_lock);
ret = (mh_mode & CRYPTO_MEM_CHECK_ENABLE)
|| !CRYPTO_THREAD_compare_id(disabling_threadid, cur);
- CRYPTO_THREAD_unlock(malloc_lock);
+ CRYPTO_THREAD_unlock(memdbg_lock);
}
return ret;
}
return ret;
}
-/* returns 1 if there was an info to pop, 0 if the stack was empty. */
-static int pop_info(void)
-{
- APP_INFO *current = NULL;
-
- if (!RUN_ONCE(&memdbg_init, do_memdbg_init))
- return 0;
-
- current = (APP_INFO *)CRYPTO_THREAD_get_local(&appinfokey);
- if (current != NULL) {
- APP_INFO *next = current->next;
-
- if (next != NULL) {
- next->references++;
- CRYPTO_THREAD_set_local(&appinfokey, next);
- } else {
- CRYPTO_THREAD_set_local(&appinfokey, NULL);
- }
- if (--(current->references) <= 0) {
- current->next = NULL;
- if (next != NULL)
- next->references--;
- OPENSSL_free(current);
- }
- return 1;
- }
- return 0;
-}
-
+#if !OPENSSL_API_3
int CRYPTO_mem_debug_push(const char *info, const char *file, int line)
{
- APP_INFO *ami, *amim;
- int ret = 0;
-
- if (mem_check_on()) {
- CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_DISABLE);
-
- if (!RUN_ONCE(&memdbg_init, do_memdbg_init)
- || (ami = OPENSSL_malloc(sizeof(*ami))) == NULL)
- goto err;
-
- ami->threadid = CRYPTO_THREAD_get_current_id();
- ami->file = file;
- ami->line = line;
- ami->info = info;
- ami->references = 1;
- ami->next = NULL;
-
- amim = (APP_INFO *)CRYPTO_THREAD_get_local(&appinfokey);
- CRYPTO_THREAD_set_local(&appinfokey, ami);
-
- if (amim != NULL)
- ami->next = amim;
- ret = 1;
- err:
- CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ENABLE);
- }
-
- return ret;
+ return 0;
}
int CRYPTO_mem_debug_pop(void)
{
- int ret = 0;
-
- if (mem_check_on()) {
- CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_DISABLE);
- ret = pop_info();
- CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ENABLE);
- }
- return ret;
+ return 0;
}
+#endif
static unsigned long break_order_num = 0;
const char *file, int line)
{
MEM *m, *mm;
- APP_INFO *amim;
switch (before_p & 127) {
case 0:
# endif
m->time = time(NULL);
- amim = (APP_INFO *)CRYPTO_THREAD_get_local(&appinfokey);
- m->app_info = amim;
- if (amim != NULL)
- amim->references++;
-
- if ((mm = lh_MEM_insert(mh, m)) != NULL) {
- /* Not good, but don't sweat it */
- if (mm->app_info != NULL) {
- mm->app_info->references--;
- }
+ if ((mm = lh_MEM_insert(mh, m)) != NULL)
OPENSSL_free(mm);
- }
err:
CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ENABLE);
}
if (mem_check_on() && (mh != NULL)) {
CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_DISABLE);
-
m.addr = addr;
mp = lh_MEM_delete(mh, &m);
- if (mp != NULL) {
- app_info_free(mp->app_info);
- OPENSSL_free(mp);
- }
-
+ OPENSSL_free(mp);
CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ENABLE);
}
break;
static void print_leak(const MEM *m, MEM_LEAK *l)
{
char buf[1024];
- char *bufp = buf;
- size_t len = sizeof(buf), ami_cnt;
- APP_INFO *amip;
+ char *bufp = buf, *hex;
+ size_t len = sizeof(buf);
int n;
struct tm *lcl = NULL;
- /*
- * Convert between CRYPTO_THREAD_ID (which could be anything at all) and
- * a long. This may not be meaningful depending on what CRYPTO_THREAD_ID is
- * but hopefully should give something sensible on most platforms
- */
- union {
- CRYPTO_THREAD_ID tid;
- unsigned long ltid;
- } tid;
- CRYPTO_THREAD_ID ti;
lcl = localtime(&m->time);
n = BIO_snprintf(bufp, len, "[%02d:%02d:%02d] ",
bufp += n;
len -= n;
- tid.ltid = 0;
- tid.tid = m->threadid;
- n = BIO_snprintf(bufp, len, "thread=%lu, ", tid.ltid);
- if (n <= 0)
- return;
- bufp += n;
- len -= n;
-
- n = BIO_snprintf(bufp, len, "number=%d, address=%p\n", m->num, m->addr);
+ hex = OPENSSL_buf2hexstr((const unsigned char *)&m->threadid,
+ sizeof(m->threadid));
+ n = BIO_snprintf(bufp, len, "thread=%s, number=%d, address=%p\n", hex,
+ m->num, m->addr);
+ OPENSSL_free(hex);
if (n <= 0)
return;
bufp += n;
len -= n;
l->print_cb(buf, (size_t)(bufp - buf), l->print_cb_arg);
-
l->chunks++;
l->bytes += m->num;
- amip = m->app_info;
- ami_cnt = 0;
-
- if (amip) {
- ti = amip->threadid;
-
- do {
- int buf_len;
- int info_len;
-
- ami_cnt++;
- if (ami_cnt >= sizeof(buf) - 1)
- break;
- memset(buf, '>', ami_cnt);
- buf[ami_cnt] = '\0';
- tid.ltid = 0;
- tid.tid = amip->threadid;
- n = BIO_snprintf(buf + ami_cnt, sizeof(buf) - ami_cnt,
- " thread=%lu, file=%s, line=%d, info=\"",
- tid.ltid, amip->file, amip->line);
- if (n <= 0)
- break;
- buf_len = ami_cnt + n;
- info_len = strlen(amip->info);
- if (128 - buf_len - 3 < info_len) {
- memcpy(buf + buf_len, amip->info, 128 - buf_len - 3);
- buf_len = 128 - 3;
- } else {
- n = BIO_snprintf(buf + buf_len, sizeof(buf) - buf_len, "%s",
- amip->info);
- if (n < 0)
- break;
- buf_len += n;
- }
- n = BIO_snprintf(buf + buf_len, sizeof(buf) - buf_len, "\"\n");
- if (n <= 0)
- break;
-
- l->print_cb(buf, buf_len + n, l->print_cb_arg);
-
- amip = amip->next;
- }
- while (amip && CRYPTO_THREAD_compare_id(amip->threadid, ti));
- }
-
#ifndef OPENSSL_NO_CRYPTO_MDEBUG_BACKTRACE
{
size_t i;
*/
int old_mh_mode;
- CRYPTO_THREAD_write_lock(malloc_lock);
+ CRYPTO_THREAD_write_lock(memdbg_lock);
/*
* avoid deadlock when lh_free() uses CRYPTO_mem_debug_free(), which uses
mh = NULL;
mh_mode = old_mh_mode;
- CRYPTO_THREAD_unlock(malloc_lock);
+ CRYPTO_THREAD_unlock(memdbg_lock);
}
CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_OFF);
/* Clean up locks etc */
- CRYPTO_THREAD_cleanup_local(&appinfokey);
- CRYPTO_THREAD_lock_free(malloc_lock);
- CRYPTO_THREAD_lock_free(long_malloc_lock);
- malloc_lock = NULL;
- long_malloc_lock = NULL;
+ CRYPTO_THREAD_lock_free(memdbg_lock);
+ CRYPTO_THREAD_lock_free(long_memdbg_lock);
+ memdbg_lock = NULL;
+ long_memdbg_lock = NULL;
return ml.chunks == 0 ? 1 : 0;
}