Summarize leaks with identical backtraces, as we do it with memusage
This commit is contained in:
parent
0eef27074d
commit
eb4f4551a1
|
@ -148,6 +148,37 @@ static memory_header_t first_header = {
|
||||||
*/
|
*/
|
||||||
static bool installed = FALSE;
|
static bool installed = FALSE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Installs the malloc hooks, enables leak detection
|
||||||
|
*/
|
||||||
|
static void install_hooks()
|
||||||
|
{
|
||||||
|
if (!installed)
|
||||||
|
{
|
||||||
|
old_malloc_hook = __malloc_hook;
|
||||||
|
old_realloc_hook = __realloc_hook;
|
||||||
|
old_free_hook = __free_hook;
|
||||||
|
__malloc_hook = malloc_hook;
|
||||||
|
__realloc_hook = realloc_hook;
|
||||||
|
__free_hook = free_hook;
|
||||||
|
installed = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Uninstalls the malloc hooks, disables leak detection
|
||||||
|
*/
|
||||||
|
static void uninstall_hooks()
|
||||||
|
{
|
||||||
|
if (installed)
|
||||||
|
{
|
||||||
|
__malloc_hook = old_malloc_hook;
|
||||||
|
__free_hook = old_free_hook;
|
||||||
|
__realloc_hook = old_realloc_hook;
|
||||||
|
installed = FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Leak report white list
|
* Leak report white list
|
||||||
*
|
*
|
||||||
|
@ -237,79 +268,6 @@ char *whitelist[] = {
|
||||||
"gnutls_global_init",
|
"gnutls_global_init",
|
||||||
};
|
};
|
||||||
|
|
||||||
METHOD(leak_detective_t, report, void,
|
|
||||||
private_leak_detective_t *this, bool detailed)
|
|
||||||
{
|
|
||||||
if (lib->leak_detective)
|
|
||||||
{
|
|
||||||
memory_header_t *hdr;
|
|
||||||
int leaks = 0, whitelisted = 0;
|
|
||||||
|
|
||||||
for (hdr = first_header.next; hdr != NULL; hdr = hdr->next)
|
|
||||||
{
|
|
||||||
if (hdr->backtrace->contains_function(hdr->backtrace,
|
|
||||||
whitelist, countof(whitelist)))
|
|
||||||
{
|
|
||||||
whitelisted++;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
fprintf(stderr, "Leak (%d bytes at %p):\n", hdr->bytes, hdr + 1);
|
|
||||||
/* skip the first frame, contains leak detective logic */
|
|
||||||
hdr->backtrace->log(hdr->backtrace, stderr, detailed);
|
|
||||||
leaks++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
switch (leaks)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
fprintf(stderr, "No leaks detected");
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
fprintf(stderr, "One leak detected");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
fprintf(stderr, "%d leaks detected", leaks);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
fprintf(stderr, ", %d suppressed by whitelist\n", whitelisted);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
fprintf(stderr, "Leak detective disabled\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Installs the malloc hooks, enables leak detection
|
|
||||||
*/
|
|
||||||
static void install_hooks()
|
|
||||||
{
|
|
||||||
if (!installed)
|
|
||||||
{
|
|
||||||
old_malloc_hook = __malloc_hook;
|
|
||||||
old_realloc_hook = __realloc_hook;
|
|
||||||
old_free_hook = __free_hook;
|
|
||||||
__malloc_hook = malloc_hook;
|
|
||||||
__realloc_hook = realloc_hook;
|
|
||||||
__free_hook = free_hook;
|
|
||||||
installed = TRUE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Uninstalls the malloc hooks, disables leak detection
|
|
||||||
*/
|
|
||||||
static void uninstall_hooks()
|
|
||||||
{
|
|
||||||
if (installed)
|
|
||||||
{
|
|
||||||
__malloc_hook = old_malloc_hook;
|
|
||||||
__free_hook = old_free_hook;
|
|
||||||
__realloc_hook = old_realloc_hook;
|
|
||||||
installed = FALSE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hashtable hash function
|
* Hashtable hash function
|
||||||
|
@ -338,12 +296,13 @@ static bool equals(backtrace_t *a, backtrace_t *b)
|
||||||
return a->equals(a, b);
|
return a->equals(a, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
METHOD(leak_detective_t, usage, void,
|
/**
|
||||||
private_leak_detective_t *this, FILE *out)
|
* Summarize and print backtraces
|
||||||
|
*/
|
||||||
|
static int print_traces(private_leak_detective_t *this,
|
||||||
|
FILE *out, int thresh, bool detailed, int *whitelisted)
|
||||||
{
|
{
|
||||||
int oldpolicy, thresh;
|
int leaks = 0;
|
||||||
pthread_t thread_id = pthread_self();
|
|
||||||
struct sched_param oldparams, params;
|
|
||||||
memory_header_t *hdr;
|
memory_header_t *hdr;
|
||||||
enumerator_t *enumerator;
|
enumerator_t *enumerator;
|
||||||
hashtable_t *entries;
|
hashtable_t *entries;
|
||||||
|
@ -356,19 +315,19 @@ METHOD(leak_detective_t, usage, void,
|
||||||
u_int count;
|
u_int count;
|
||||||
} *entry;
|
} *entry;
|
||||||
|
|
||||||
thresh = lib->settings->get_int(lib->settings,
|
|
||||||
"libstrongswan.leak_detective.usage_threshold", 10240);
|
|
||||||
|
|
||||||
pthread_getschedparam(thread_id, &oldpolicy, &oldparams);
|
|
||||||
params.__sched_priority = sched_get_priority_max(SCHED_FIFO);
|
|
||||||
pthread_setschedparam(thread_id, SCHED_FIFO, ¶ms);
|
|
||||||
uninstall_hooks();
|
uninstall_hooks();
|
||||||
|
|
||||||
entries = hashtable_create((hashtable_hash_t)hash,
|
entries = hashtable_create((hashtable_hash_t)hash,
|
||||||
(hashtable_equals_t)equals, 1024);
|
(hashtable_equals_t)equals, 1024);
|
||||||
|
|
||||||
for (hdr = first_header.next; hdr != NULL; hdr = hdr->next)
|
for (hdr = first_header.next; hdr != NULL; hdr = hdr->next)
|
||||||
{
|
{
|
||||||
|
if (whitelisted &&
|
||||||
|
hdr->backtrace->contains_function(hdr->backtrace,
|
||||||
|
whitelist, countof(whitelist)))
|
||||||
|
{
|
||||||
|
(*whitelisted)++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
entry = entries->get(entries, hdr->backtrace);
|
entry = entries->get(entries, hdr->backtrace);
|
||||||
if (entry)
|
if (entry)
|
||||||
{
|
{
|
||||||
|
@ -384,15 +343,16 @@ METHOD(leak_detective_t, usage, void,
|
||||||
);
|
);
|
||||||
entries->put(entries, hdr->backtrace, entry);
|
entries->put(entries, hdr->backtrace, entry);
|
||||||
}
|
}
|
||||||
|
leaks++;
|
||||||
}
|
}
|
||||||
enumerator = entries->create_enumerator(entries);
|
enumerator = entries->create_enumerator(entries);
|
||||||
while (enumerator->enumerate(enumerator, NULL, &entry))
|
while (enumerator->enumerate(enumerator, NULL, &entry))
|
||||||
{
|
{
|
||||||
if (entry->bytes >= thresh)
|
if (!thresh || entry->bytes >= thresh)
|
||||||
{
|
{
|
||||||
fprintf(out, "%d bytes total, %d allocations, %d bytes average:\n",
|
fprintf(out, "%d bytes total, %d allocations, %d bytes average:\n",
|
||||||
entry->bytes, entry->count, entry->bytes / entry->count);
|
entry->bytes, entry->count, entry->bytes / entry->count);
|
||||||
entry->backtrace->log(entry->backtrace, out, TRUE);
|
entry->backtrace->log(entry->backtrace, out, detailed);
|
||||||
}
|
}
|
||||||
free(entry);
|
free(entry);
|
||||||
}
|
}
|
||||||
|
@ -400,6 +360,56 @@ METHOD(leak_detective_t, usage, void,
|
||||||
entries->destroy(entries);
|
entries->destroy(entries);
|
||||||
|
|
||||||
install_hooks();
|
install_hooks();
|
||||||
|
return leaks;
|
||||||
|
}
|
||||||
|
|
||||||
|
METHOD(leak_detective_t, report, void,
|
||||||
|
private_leak_detective_t *this, bool detailed)
|
||||||
|
{
|
||||||
|
if (lib->leak_detective)
|
||||||
|
{
|
||||||
|
int leaks = 0, whitelisted = 0;
|
||||||
|
|
||||||
|
leaks = print_traces(this, stderr, 0, detailed, &whitelisted);
|
||||||
|
switch (leaks)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
fprintf(stderr, "No leaks detected");
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
fprintf(stderr, "One leak detected");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fprintf(stderr, "%d leaks detected", leaks);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
fprintf(stderr, ", %d suppressed by whitelist\n", whitelisted);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Leak detective disabled\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
METHOD(leak_detective_t, usage, void,
|
||||||
|
private_leak_detective_t *this, FILE *out)
|
||||||
|
{
|
||||||
|
int oldpolicy, thresh;
|
||||||
|
bool detailed;
|
||||||
|
pthread_t thread_id = pthread_self();
|
||||||
|
struct sched_param oldparams, params;
|
||||||
|
|
||||||
|
thresh = lib->settings->get_int(lib->settings,
|
||||||
|
"libstrongswan.leak_detective.usage_threshold", 10240);
|
||||||
|
detailed = lib->settings->get_bool(lib->settings,
|
||||||
|
"libstrongswan.leak_detective.detailed", TRUE);
|
||||||
|
|
||||||
|
pthread_getschedparam(thread_id, &oldpolicy, &oldparams);
|
||||||
|
params.__sched_priority = sched_get_priority_max(SCHED_FIFO);
|
||||||
|
pthread_setschedparam(thread_id, SCHED_FIFO, ¶ms);
|
||||||
|
|
||||||
|
print_traces(this, out, thresh, detailed, NULL);
|
||||||
|
|
||||||
pthread_setschedparam(thread_id, oldpolicy, &oldparams);
|
pthread_setschedparam(thread_id, oldpolicy, &oldparams);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue