From: Martin Willi Date: Wed, 16 Oct 2013 08:37:38 +0000 (+0200) Subject: leak-detective: Use callback functions to report leaks and usage information X-Git-Tag: 5.1.2dr1~33^2~52 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=a426851f6362f8d1d6cbecd133ef39a831b4ea2a;p=thirdparty%2Fstrongswan.git leak-detective: Use callback functions to report leaks and usage information This is more flexible than printing reports to a FILE. --- diff --git a/src/libcharon/plugins/stroke/stroke_socket.c b/src/libcharon/plugins/stroke/stroke_socket.c index 3adebb5231..cf7ec369cf 100644 --- a/src/libcharon/plugins/stroke/stroke_socket.c +++ b/src/libcharon/plugins/stroke/stroke_socket.c @@ -489,6 +489,25 @@ static void stroke_leases(private_stroke_socket_t *this, 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 */ @@ -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); } } diff --git a/src/libstrongswan/library.c b/src/libstrongswan/library.c index f2fa3e0aa2..72fc2fa441 100644 --- a/src/libstrongswan/library.c +++ b/src/libstrongswan/library.c @@ -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(); diff --git a/src/libstrongswan/utils/backtrace.h b/src/libstrongswan/utils/backtrace.h index 416f588988..16e84c4d9e 100644 --- a/src/libstrongswan/utils/backtrace.h +++ b/src/libstrongswan/utils/backtrace.h @@ -21,12 +21,12 @@ #ifndef BACKTRACE_H_ #define BACKTRACE_H_ +typedef struct backtrace_t backtrace_t; + #include #include -typedef struct backtrace_t backtrace_t; - /** * A backtrace registers the frames on the stack during creation. */ diff --git a/src/libstrongswan/utils/leak_detective.c b/src/libstrongswan/utils/leak_detective.c index 725e04f7ca..b001eeedce 100644 --- a/src/libstrongswan/utils/leak_detective.c +++ b/src/libstrongswan/utils/leak_detective.c @@ -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, }, diff --git a/src/libstrongswan/utils/leak_detective.h b/src/libstrongswan/utils/leak_detective.h index 7a29e81d79..3fd0b8c931 100644 --- a/src/libstrongswan/utils/leak_detective.h +++ b/src/libstrongswan/utils/leak_detective.h @@ -24,6 +24,30 @@ typedef struct leak_detective_t leak_detective_t; #include +#include + +/** + * 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.