leak-detective: Use callback functions to report leaks and usage information
authorMartin Willi <martin@revosec.ch>
Wed, 16 Oct 2013 08:37:38 +0000 (10:37 +0200)
committerMartin Willi <martin@revosec.ch>
Wed, 6 Nov 2013 09:30:59 +0000 (10:30 +0100)
This is more flexible than printing reports to a FILE.

src/libcharon/plugins/stroke/stroke_socket.c
src/libstrongswan/library.c
src/libstrongswan/utils/backtrace.h
src/libstrongswan/utils/leak_detective.c
src/libstrongswan/utils/leak_detective.h

index 3adebb5..cf7ec36 100644 (file)
@@ -490,6 +490,25 @@ static void stroke_leases(private_stroke_socket_t *this,
 }
 
 /**
+ * Callback function for usage report
+ */
+static void report_usage(FILE *out, int count, size_t bytes,
+                                                backtrace_t *bt, bool detailed)
+{
+       fprintf(out, "%d bytes total, %d allocations, %d bytes average:\n",
+                       bytes, count, bytes / count);
+       bt->log(bt, out, detailed);
+}
+
+/**
+ * Callback function for memusage summary
+ */
+static void sum_usage(FILE *out, int count, size_t bytes, int whitelisted)
+{
+       fprintf(out, "Total memory usage: %zu\n", bytes);
+}
+
+/**
  * Show memory usage
  */
 static void stroke_memusage(private_stroke_socket_t *this,
@@ -497,7 +516,9 @@ static void stroke_memusage(private_stroke_socket_t *this,
 {
        if (lib->leak_detective)
        {
-               lib->leak_detective->usage(lib->leak_detective, out);
+               lib->leak_detective->usage(lib->leak_detective,
+                                                                  (leak_detective_report_cb_t)report_usage,
+                                                                  (leak_detective_summary_cb_t)sum_usage, out);
        }
 }
 
index f2fa3e0..72fc2fa 100644 (file)
@@ -61,6 +61,39 @@ struct private_library_t {
  */
 library_t *lib = NULL;
 
+#ifdef LEAK_DETECTIVE
+/**
+ * Default leak report callback
+ */
+static void report_leaks(void *user, int count, size_t bytes,
+                                                backtrace_t *bt, bool detailed)
+{
+       fprintf(stderr, "%zu bytes total, %d allocations, %zu bytes average:\n",
+                       bytes, count, bytes / count);
+       bt->log(bt, stderr, detailed);
+}
+
+/**
+ * Default leak report summary callback
+ */
+static void sum_leaks(void* user, int count, size_t bytes, int whitelisted)
+{
+       switch (count)
+       {
+               case 0:
+                       fprintf(stderr, "No leaks detected");
+                       break;
+               case 1:
+                       fprintf(stderr, "One leak detected");
+                       break;
+               default:
+                       fprintf(stderr, "%d leaks detected, %zu bytes", count, bytes);
+                       break;
+       }
+       fprintf(stderr, ", %d suppressed by whitelist\n", whitelisted);
+}
+#endif /* LEAK_DETECTIVE */
+
 /**
  * Deinitialize library
  */
@@ -227,6 +260,8 @@ bool library_init(char *settings)
 
 #ifdef LEAK_DETECTIVE
        lib->leak_detective = leak_detective_create();
+       lib->leak_detective->set_report_cb(lib->leak_detective,
+                                                                          report_leaks, sum_leaks, NULL);
 #endif /* LEAK_DETECTIVE */
 
        pfh = printf_hook_create();
index 416f588..16e84c4 100644 (file)
 #ifndef BACKTRACE_H_
 #define BACKTRACE_H_
 
+typedef struct backtrace_t backtrace_t;
+
 #include <stdio.h>
 
 #include <library.h>
 
-typedef struct backtrace_t backtrace_t;
-
 /**
  * A backtrace registers the frames on the stack during creation.
  */
index 725e04f..b001eee 100644 (file)
@@ -59,6 +59,21 @@ struct private_leak_detective_t {
         * public functions
         */
        leak_detective_t public;
+
+       /**
+        * Registered report() function
+        */
+       leak_detective_report_cb_t report_cb;
+
+       /**
+        * Registered report() summary function
+        */
+       leak_detective_summary_cb_t report_scb;
+
+       /**
+        * Registered user data for callbacks
+        */
+       void *report_data;
 };
 
 /**
@@ -599,7 +614,8 @@ static bool equals(backtrace_t *a, backtrace_t *b)
  * Summarize and print backtraces
  */
 static int print_traces(private_leak_detective_t *this,
-                                               FILE *out, int thresh, int thresh_count,
+                                               leak_detective_report_cb_t cb, void *user,
+                                               int thresh, int thresh_count,
                                                bool detailed, int *whitelisted, size_t *sum)
 {
        int leaks = 0;
@@ -652,16 +668,20 @@ static int print_traces(private_leak_detective_t *this,
                leaks++;
        }
        lock->unlock(lock);
+
        enumerator = entries->create_enumerator(entries);
        while (enumerator->enumerate(enumerator, NULL, &entry))
        {
-               if (out &&
-                       (!thresh || entry->bytes >= thresh) &&
-                       (!thresh_count || entry->count >= thresh_count))
+               if (cb)
                {
-                       fprintf(out, "%d bytes total, %d allocations, %d bytes average:\n",
-                                       entry->bytes, entry->count, entry->bytes / entry->count);
-                       entry->backtrace->log(entry->backtrace, out, detailed);
+                       if (!thresh || entry->bytes >= thresh)
+                       {
+                               if (!thresh_count || entry->count >= thresh_count)
+                               {
+                                       this->report_cb(this->report_data, entry->count,
+                                                                       entry->bytes, entry->backtrace, detailed);
+                               }
+                       }
                }
                entry->backtrace->destroy(entry->backtrace);
                free(entry);
@@ -681,38 +701,30 @@ METHOD(leak_detective_t, report, void,
                int leaks, whitelisted = 0;
                size_t sum = 0;
 
-               leaks = print_traces(this, stderr, 0, 0, detailed, &whitelisted, &sum);
-               switch (leaks)
+               leaks = print_traces(this, this->report_cb, this->report_data,
+                                                        0, 0, detailed, &whitelisted, &sum);
+               if (this->report_scb)
                {
-                       case 0:
-                               fprintf(stderr, "No leaks detected");
-                               break;
-                       case 1:
-                               fprintf(stderr, "One leak detected");
-                               break;
-                       default:
-                               fprintf(stderr, "%d leaks detected, %zu bytes", leaks, sum);
-                               break;
+                       this->report_scb(this->report_data, leaks, sum, whitelisted);
                }
-               fprintf(stderr, ", %d suppressed by whitelist\n", whitelisted);
-       }
-       else
-       {
-               fprintf(stderr, "Leak detective disabled\n");
        }
 }
 
+METHOD(leak_detective_t, set_report_cb, void,
+       private_leak_detective_t *this, leak_detective_report_cb_t cb,
+       leak_detective_summary_cb_t scb, void *user)
+{
+       this->report_cb = cb;
+       this->report_scb = scb;
+       this->report_data = user;
+}
+
 METHOD(leak_detective_t, leaks, int,
        private_leak_detective_t *this)
 {
-       if (lib->leak_detective)
-       {
-               int leaks, whitelisted = 0;
+       int whitelisted = 0;
 
-               leaks = print_traces(this, NULL, 0, 0, FALSE, &whitelisted, NULL);
-               return leaks;
-       }
-       return 0;
+       return print_traces(this, NULL, NULL, 0, 0, FALSE, &whitelisted, NULL);
 }
 
 METHOD(leak_detective_t, set_state, bool,
@@ -722,10 +734,11 @@ METHOD(leak_detective_t, set_state, bool,
 }
 
 METHOD(leak_detective_t, usage, void,
-       private_leak_detective_t *this, FILE *out)
+       private_leak_detective_t *this, leak_detective_report_cb_t cb,
+       leak_detective_summary_cb_t scb, void *user)
 {
        bool detailed;
-       int thresh, thresh_count;
+       int thresh, thresh_count, leaks, whitelisted = 0;
        size_t sum = 0;
 
        thresh = lib->settings->get_int(lib->settings,
@@ -735,9 +748,12 @@ METHOD(leak_detective_t, usage, void,
        detailed = lib->settings->get_bool(lib->settings,
                                        "libstrongswan.leak_detective.detailed", TRUE);
 
-       print_traces(this, out, thresh, thresh_count, detailed, NULL, &sum);
-
-       fprintf(out, "Total memory usage: %zu\n", sum);
+       leaks = print_traces(this, cb, user, thresh, thresh_count,
+                                                detailed, &whitelisted, &sum);
+       if (scb)
+       {
+               scb(user, leaks, sum, whitelisted);
+       }
 }
 
 /**
@@ -936,8 +952,9 @@ leak_detective_t *leak_detective_create()
        INIT(this,
                .public = {
                        .report = _report,
-                       .leaks = _leaks,
+                       .set_report_cb = _set_report_cb,
                        .usage = _usage,
+                       .leaks = _leaks,
                        .set_state = _set_state,
                        .destroy = _destroy,
                },
index 7a29e81..3fd0b8c 100644 (file)
 typedef struct leak_detective_t leak_detective_t;
 
 #include <library.h>
+#include <utils/backtrace.h>
+
+/**
+ * Callback function to report leak/usage information
+ *
+ * @param user                 user specific data
+ * @param count                        number of allocations
+ * @param bytes                        total size of allocations
+ * @param bt                   backtrace of allocation
+ * @param detailed             TRUE to show a detailed backtrace
+ */
+typedef void (*leak_detective_report_cb_t)(void *user, int count, size_t bytes,
+                                                                                  backtrace_t *bt, bool detailed);
+
+/**
+ * Callback function to report leak/usage summary information
+ *
+ * @param user                 user specific data
+ * @param count                        total number of allocations
+ * @param bytes                        total size of all reported allocations
+ * @param whitelisted  number of allocations suppressed by whitelist
+ */
+typedef void (*leak_detective_summary_cb_t)(void* user, int count, size_t bytes,
+                                                                                   int whitelisted);
 
 /**
  * Leak detective finds leaks and bad frees using malloc hooks.
@@ -36,25 +60,39 @@ typedef struct leak_detective_t leak_detective_t;
 struct leak_detective_t {
 
        /**
-        * Report leaks to stderr.
+        * Report leaks to the registered callback functions.
         *
         * @param detailed              TRUE to resolve line/filename of leak (slow)
         */
        void (*report)(leak_detective_t *this, bool detailed);
 
        /**
-        * Number of detected leaks.
+        * Report current memory usage to out.
+        * Set callback functions invoked during a report().
         *
-        * @return                              number of leaks
+        * @param cb                    callback invoked for each detected leak
+        * @param scb                   summary callback invoked at end of report
+        * @param user                  user data to supply to callbacks
         */
-       int (*leaks)(leak_detective_t *this);
+       void (*set_report_cb)(leak_detective_t *this, leak_detective_report_cb_t cb,
+                                                 leak_detective_summary_cb_t scb, void *user);
 
        /**
-        * Report current memory usage to out.
+        * Report current memory usage using a callbacks.
+        *
+        * @param cb                    callback invoked for each allocation
+        * @param scb                   summary callback invoked at end of usage report
+        * @param user                  user data supplied to callbacks
+        */
+       void (*usage)(leak_detective_t *this, leak_detective_report_cb_t cb,
+                                 leak_detective_summary_cb_t scb, void *user);
+
+       /**
+        * Number of detected leaks.
         *
-        * @param out                   target to write usage report to
+        * @return                              number of leaks
         */
-       void (*usage)(leak_detective_t *this, FILE *out);
+       int (*leaks)(leak_detective_t *this);
 
        /**
         * Enable/disable leak detective hooks for the current thread.