this->list->leases(this->list, msg, out);
}
+/**
+ * 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
*/
{
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);
}
}
*/
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
*/
#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();
* 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;
};
/**
* 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;
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);
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,
}
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,
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);
+ }
}
/**
INIT(this,
.public = {
.report = _report,
- .leaks = _leaks,
+ .set_report_cb = _set_report_cb,
.usage = _usage,
+ .leaks = _leaks,
.set_state = _set_state,
.destroy = _destroy,
},
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.
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.