Use safestack.h exclusively internally.
[openssl.git] / crypto / mem_dbg.c
index dc3f8ff5713292acb9524289ffc0862ec3ef10bc..9228dcef13240b02908a5f47566e97a47be0254d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1995-2017 The OpenSSL Project Authors. All Rights Reserved.
  *
  * Licensed under the OpenSSL license (the "License").  You may not use
  * this file except in compliance with the License.  You can obtain a copy
@@ -90,8 +90,8 @@ static CRYPTO_THREAD_ID disabling_threadid;
 
 DEFINE_RUN_ONCE_STATIC(do_memdbg_init)
 {
-    malloc_lock = CRYPTO_THREAD_lock_new();
-    long_malloc_lock = CRYPTO_THREAD_lock_new();
+    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);
@@ -183,7 +183,7 @@ int CRYPTO_mem_ctrl(int mode)
         break;
     }
     CRYPTO_THREAD_unlock(malloc_lock);
-    return (ret);
+    return ret;
 #endif
 }
 
@@ -206,7 +206,7 @@ static int mem_check_on(void)
 
         CRYPTO_THREAD_unlock(malloc_lock);
     }
-    return (ret);
+    return ret;
 }
 
 static int mem_cmp(const MEM *a, const MEM *b)
@@ -231,7 +231,7 @@ static unsigned long mem_hash(const MEM *a)
     ret = (size_t)a->addr;
 
     ret = ret * 17851 + (ret >> 14) * 7 + (ret >> 4) * 251;
-    return (ret);
+    return ret;
 }
 
 /* returns 1 if there was an info to pop, 0 if the stack was empty. */
@@ -292,7 +292,7 @@ int CRYPTO_mem_debug_push(const char *info, const char *file, int line)
         CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ENABLE);
     }
 
-    return (ret);
+    return ret;
 }
 
 int CRYPTO_mem_debug_pop(void)
@@ -304,7 +304,7 @@ int CRYPTO_mem_debug_pop(void)
         ret = pop_info();
         CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ENABLE);
     }
-    return (ret);
+    return ret;
 }
 
 static unsigned long break_order_num = 0;
@@ -443,7 +443,8 @@ void CRYPTO_mem_debug_realloc(void *addr1, void *addr2, size_t num,
 }
 
 typedef struct mem_leak_st {
-    BIO *bio;
+    int (*print_cb) (const char *str, size_t len, void *u);
+    void *print_cb_arg;
     int chunks;
     long bytes;
 } MEM_LEAK;
@@ -452,8 +453,9 @@ 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;
-    int ami_cnt;
+    int n;
     struct tm *lcl = NULL;
     /*
      * Convert between CRYPTO_THREAD_ID (which could be anything at all) and
@@ -466,27 +468,38 @@ static void print_leak(const MEM *m, MEM_LEAK *l)
     } tid;
     CRYPTO_THREAD_ID ti;
 
-#define BUF_REMAIN (sizeof buf - (size_t)(bufp - buf))
-
     lcl = localtime(&m->time);
-    BIO_snprintf(bufp, BUF_REMAIN, "[%02d:%02d:%02d] ",
-                 lcl->tm_hour, lcl->tm_min, lcl->tm_sec);
-    bufp += strlen(bufp);
+    n = BIO_snprintf(bufp, len, "[%02d:%02d:%02d] ",
+                     lcl->tm_hour, lcl->tm_min, lcl->tm_sec);
+    if (n <= 0) {
+        bufp[0] = '\0';
+        return;
+    }
+    bufp += n;
+    len -= n;
 
-    BIO_snprintf(bufp, BUF_REMAIN, "%5lu file=%s, line=%d, ",
-                 m->order, m->file, m->line);
-    bufp += strlen(bufp);
+    n = BIO_snprintf(bufp, len, "%5lu file=%s, line=%d, ",
+                     m->order, m->file, m->line);
+    if (n <= 0)
+        return;
+    bufp += n;
+    len -= n;
 
     tid.ltid = 0;
     tid.tid = m->threadid;
-    BIO_snprintf(bufp, BUF_REMAIN, "thread=%lu, ", tid.ltid);
-    bufp += strlen(bufp);
+    n = BIO_snprintf(bufp, len, "thread=%lu, ", tid.ltid);
+    if (n <= 0)
+        return;
+    bufp += n;
+    len -= n;
 
-    BIO_snprintf(bufp, BUF_REMAIN, "number=%d, address=%p\n",
-                 m->num, m->addr);
-    bufp += strlen(bufp);
+    n = BIO_snprintf(bufp, len, "number=%d, address=%p\n", m->num, m->addr);
+    if (n <= 0)
+        return;
+    bufp += n;
+    len -= n;
 
-    BIO_puts(l->bio, buf);
+    l->print_cb(buf, (size_t)(bufp - buf), l->print_cb_arg);
 
     l->chunks++;
     l->bytes += m->num;
@@ -502,25 +515,34 @@ static void print_leak(const MEM *m, MEM_LEAK *l)
             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;
-            BIO_snprintf(buf + ami_cnt, sizeof buf - ami_cnt,
-                         " thread=%lu, file=%s, line=%d, info=\"",
-                         tid.ltid, amip->file,
-                         amip->line);
-            buf_len = strlen(buf);
+            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 {
-                OPENSSL_strlcpy(buf + buf_len, amip->info, sizeof buf - buf_len);
-                buf_len = strlen(buf);
+                n = BIO_snprintf(buf + buf_len, sizeof(buf) - buf_len, "%s",
+                                 amip->info);
+                if (n < 0)
+                    break;
+                buf_len += n;
             }
-            BIO_snprintf(buf + buf_len, sizeof buf - buf_len, "\"\n");
+            n = BIO_snprintf(buf + buf_len, sizeof(buf) - buf_len, "\"\n");
+            if (n <= 0)
+                break;
 
-            BIO_puts(l->bio, buf);
+            l->print_cb(buf, buf_len + n, l->print_cb_arg);
 
             amip = amip->next;
         }
@@ -541,16 +563,11 @@ static void print_leak(const MEM *m, MEM_LEAK *l)
 
 IMPLEMENT_LHASH_DOALL_ARG_CONST(MEM, MEM_LEAK);
 
-int CRYPTO_mem_leaks(BIO *b)
+int CRYPTO_mem_leaks_cb(int (*cb) (const char *str, size_t len, void *u),
+                        void *u)
 {
     MEM_LEAK ml;
 
-    /*
-     * OPENSSL_cleanup() will free the ex_data locks so we can't have any
-     * ex_data hanging around
-     */
-    bio_free_ex_data(b);
-
     /* Ensure all resources are released */
     OPENSSL_cleanup();
 
@@ -559,14 +576,19 @@ int CRYPTO_mem_leaks(BIO *b)
 
     CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_DISABLE);
 
-    ml.bio = b;
+    ml.print_cb = cb;
+    ml.print_cb_arg = u;
     ml.bytes = 0;
     ml.chunks = 0;
     if (mh != NULL)
         lh_MEM_doall_MEM_LEAK(mh, print_leak, &ml);
 
     if (ml.chunks != 0) {
-        BIO_printf(b, "%ld bytes leaked in %d chunks\n", ml.bytes, ml.chunks);
+        char buf[256];
+
+        BIO_snprintf(buf, sizeof(buf), "%ld bytes leaked in %d chunks\n",
+                     ml.bytes, ml.chunks);
+        cb(buf, strlen(buf), u);
     } else {
         /*
          * Make sure that, if we found no leaks, memory-leak debugging itself
@@ -603,6 +625,22 @@ int CRYPTO_mem_leaks(BIO *b)
     return ml.chunks == 0 ? 1 : 0;
 }
 
+static int print_bio(const char *str, size_t len, void *b)
+{
+    return BIO_write((BIO *)b, str, len);
+}
+
+int CRYPTO_mem_leaks(BIO *b)
+{
+    /*
+     * OPENSSL_cleanup() will free the ex_data locks so we can't have any
+     * ex_data hanging around
+     */
+    bio_free_ex_data(b);
+
+    return CRYPTO_mem_leaks_cb(print_bio, b);
+}
+
 # ifndef OPENSSL_NO_STDIO
 int CRYPTO_mem_leaks_fp(FILE *fp)
 {
@@ -620,7 +658,7 @@ int CRYPTO_mem_leaks_fp(FILE *fp)
     if (b == NULL)
         return -1;
     BIO_set_fp(b, fp, BIO_NOCLOSE);
-    ret = CRYPTO_mem_leaks(b);
+    ret = CRYPTO_mem_leaks_cb(print_bio, b);
     BIO_free(b);
     return ret;
 }