Add CRYPTO_mem_leaks_cb
authorRichard Levitte <levitte@openssl.org>
Wed, 19 Apr 2017 10:51:06 +0000 (12:51 +0200)
committerRichard Levitte <levitte@openssl.org>
Mon, 24 Apr 2017 16:09:01 +0000 (18:09 +0200)
Reviewed-by: Rich Salz <rsalz@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/3243)

crypto/mem_dbg.c
doc/man3/OPENSSL_malloc.pod
include/openssl/crypto.h
util/libcrypto.num

index dc3f8ff..4c4e7d3 100644 (file)
@@ -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;
@@ -486,7 +487,7 @@ static void print_leak(const MEM *m, MEM_LEAK *l)
                  m->num, m->addr);
     bufp += strlen(bufp);
 
-    BIO_puts(l->bio, buf);
+    l->print_cb(buf, strlen(buf), l->print_cb_arg);
 
     l->chunks++;
     l->bytes += m->num;
@@ -520,7 +521,7 @@ static void print_leak(const MEM *m, MEM_LEAK *l)
             }
             BIO_snprintf(buf + buf_len, sizeof buf - buf_len, "\"\n");
 
-            BIO_puts(l->bio, buf);
+            l->print_cb(buf, strlen(buf), l->print_cb_arg);
 
             amip = amip->next;
         }
@@ -541,16 +542,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 +555,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 +604,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 +637,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;
 }
index 2914143..afcdb55 100644 (file)
@@ -15,7 +15,7 @@ CRYPTO_mem_debug_push, CRYPTO_mem_debug_pop,
 CRYPTO_clear_realloc, CRYPTO_clear_free,
 CRYPTO_get_mem_functions, CRYPTO_set_mem_functions,
 CRYPTO_set_mem_debug, CRYPTO_mem_ctrl,
-CRYPTO_mem_leaks, CRYPTO_mem_leaks_fp
+CRYPTO_mem_leaks, CRYPTO_mem_leaks_fp, CRYPTO_mem_leaks_cb,
 OPENSSL_MALLOC_FAILURES,
 OPENSSL_MALLOC_FD
 - Memory allocation functions
@@ -76,6 +76,8 @@ OPENSSL_MALLOC_FD
 
  void CRYPTO_mem_leaks(BIO *b);
  void CRYPTO_mem_leaks_fp(FILE *fp);
+ void CRYPTO_mem_leaks_cb(int (*cb)(const char *str, size_t len, void *u),
+                          void *u);
 
 =head1 DESCRIPTION
 
@@ -190,6 +192,11 @@ CRYPTO_mem_leaks_fp() will report all "leaked" memory, writing it
 to the specified BIO B<b> or FILE B<fp>. These functions return 1 if
 there are no leaks, 0 if there are leaks and -1 if an error occurred.
 
+CRYPTO_mem_leaks_cb() does the same as CRYPTO_mem_leaks(), but instead
+of writing to a given BIO, the callback function is called for each
+output string with the string, length, and userdata B<u> as the callback
+parameters.
+
 =head1 RETURN VALUES
 
 OPENSSL_malloc_init(), OPENSSL_free(), OPENSSL_clear_free()
index a8b8dc1..42e888d 100644 (file)
@@ -314,6 +314,8 @@ void CRYPTO_mem_debug_realloc(void *addr1, void *addr2, size_t num, int flag,
 void CRYPTO_mem_debug_free(void *addr, int flag,
         const char *file, int line);
 
+int CRYPTO_mem_leaks_cb(int (*cb) (const char *str, size_t len, void *u),
+                        void *u);
 #  ifndef OPENSSL_NO_STDIO
 int CRYPTO_mem_leaks_fp(FILE *);
 #  endif
index 1a19273..725e075 100644 (file)
@@ -4270,3 +4270,4 @@ UINT32_it                               4214      1_1_0f  EXIST:!EXPORT_VAR_AS_FUNCTIO
 UINT32_it                               4214   1_1_0f  EXIST:EXPORT_VAR_AS_FUNCTION:FUNCTION:
 ZINT64_it                               4215   1_1_0f  EXIST:!EXPORT_VAR_AS_FUNCTION:VARIABLE:
 ZINT64_it                               4215   1_1_0f  EXIST:EXPORT_VAR_AS_FUNCTION:FUNCTION:
+CRYPTO_mem_leaks_cb                     4216   1_1_1   EXIST::FUNCTION:CRYPTO_MDEBUG