clean up, option for invalid free releases

This commit is contained in:
Stefani Seibold 2016-05-24 10:01:41 +02:00
parent 3e2980613c
commit 3b7a0d0552
26 changed files with 153 additions and 95 deletions

View File

@ -72,6 +72,7 @@ struct rb_stack {
unsigned long long bytes_leaked;
unsigned long long tsc;
unsigned long long n_mismatched;
unsigned long long n_badfree;
};
struct map {
@ -460,6 +461,7 @@ static struct rb_stack *stack_clone(struct process *process, struct rb_stack *st
this->leaks = stack_node->leaks;
this->n_allocations = stack_node->n_allocations;
this->n_mismatched = stack_node->n_mismatched;
this->n_badfree = stack_node->n_badfree;
this->total_allocations = stack_node->total_allocations;
this->bytes_used = stack_node->bytes_used;
this->bytes_leaked = stack_node->bytes_leaked;
@ -527,6 +529,7 @@ static struct rb_stack *stack_add(struct process *process, unsigned int pid, voi
this->refcnt = 0;
this->n_allocations = 0;
this->n_mismatched = 0;
this->n_badfree = 0;
this->total_allocations = 0;
this->bytes_used = 0;
this->leaks = 0;
@ -924,7 +927,16 @@ static int sort_tsc(const struct rb_stack **p, const struct rb_stack **q)
return 0;
}
static int sort_mismatched(const struct rb_stack **p, const struct rb_stack **q)
static int _sort_badfree(const struct rb_stack **p, const struct rb_stack **q)
{
if ((*p)->n_badfree > (*q)->n_badfree)
return -1;
if ((*p)->n_badfree < (*q)->n_badfree)
return 1;
return 0;
}
static int _sort_mismatched(const struct rb_stack **p, const struct rb_stack **q)
{
if ((*p)->n_mismatched > (*q)->n_mismatched)
return -1;
@ -933,6 +945,26 @@ static int sort_mismatched(const struct rb_stack **p, const struct rb_stack **q)
return 0;
}
static int sort_badfree(const struct rb_stack **p, const struct rb_stack **q)
{
int ret;
ret = _sort_badfree(p, q);
if (ret)
return ret;
return _sort_mismatched(p, q);
}
static int sort_mismatched(const struct rb_stack **p, const struct rb_stack **q)
{
int ret;
ret = _sort_mismatched(p, q);
if (ret)
return ret;
return _sort_badfree(p, q);
}
static int sort_usage(const struct rb_stack **p, const struct rb_stack **q)
{
if ((*p)->bytes_used > (*q)->bytes_used)
@ -1047,7 +1079,18 @@ static void _process_dump(struct process *process, int (*sortby)(const struct rb
struct rb_stack *stack = arr[i];
if (!skipfunc(stack)) {
if (!stack->n_mismatched) {
if (stack->n_mismatched || stack->n_badfree) {
if (dump_printf(
"Stack (%s):\n"
" total number of mismatches: %llu\n"
" total number of bad free: %llu\n",
str_operation(stack->stack->operation),
stack->n_mismatched,
stack->n_badfree
) == -1)
break;
}
else {
if (dump_printf(
"Stack (%s):\n"
" bytes used: %llu\n"
@ -1065,15 +1108,6 @@ static void _process_dump(struct process *process, int (*sortby)(const struct rb
break;
}
}
else {
if (dump_printf(
"Stack (%s):\n"
" total number of mismatches: %llu\n",
str_operation(stack->stack->operation),
stack->n_mismatched
) == -1)
break;
}
if (dump_printf(" tsc: %llu\n", stack->tsc) == -1)
break;
@ -1118,11 +1152,6 @@ static int skip_zero_allocations(struct rb_stack *stack)
return !stack->n_allocations;
}
static int skip_non_mismatched(struct rb_stack *stack)
{
return !stack->n_mismatched;
}
static int skip_zero_leaks(struct rb_stack *stack)
{
return !stack->leaks;
@ -1165,7 +1194,12 @@ void process_dump_sort_tsc(struct process *process, const char *outfile, int lfl
void process_dump_sort_mismatched(struct process *process, const char *outfile, int lflag)
{
process_dump(process, sort_mismatched, skip_non_mismatched, outfile, lflag);
process_dump(process, sort_mismatched, skip_none, outfile, lflag);
}
void process_dump_sort_badfree(struct process *process, const char *outfile, int lflag)
{
process_dump(process, sort_badfree, skip_none, outfile, lflag);
}
void process_dump_stacks(struct process *process, const char *outfile, int lflag)
@ -1260,10 +1294,10 @@ void process_munmap(struct process *process, struct mt_msg *mt_msg, void *payloa
break;
if (!is_mmap(block->stack_node->stack->operation)) {
if (unlikely(options.kill)) {
fprintf(stderr, ">>> block missmatch pid:%d MAP<>MALLOC %#lx\n", process->pid, ptr);
if (unlikely(options.kill))
abort();
}
break;
}
@ -1388,18 +1422,20 @@ void process_free(struct process *process, struct mt_msg *mt_msg, void *payload)
block = process_rb_search(&process->block_table, ptr);
if (block) {
if (is_mmap(block->stack_node->stack->operation)) {
if (unlikely(options.kill)) {
fprintf(stderr, ">>> block missmatch pid:%d MAP<>MALLOC %#lx\n", process->pid, ptr);
if (unlikely(options.kill))
abort();
}
}
if (stack_size) {
if (!is_sane(block, mt_msg->operation)) {
struct rb_stack *stack = stack_add(process, process->pid, stack_data, stack_size, mt_msg->operation);
stack->n_mismatched++;
stack->tsc = process->tsc++;
}
}
if (mt_msg->operation == MT_REALLOC_ENTER) {
struct realloc_entry *re = malloc(sizeof(*re));
@ -1420,11 +1456,18 @@ void process_free(struct process *process, struct mt_msg *mt_msg, void *payload)
}
else {
if (!process->attached) {
if (unlikely(options.kill)) {
fprintf(stderr, ">>> block %#lx not found pid:%d\n", ptr, process->pid);
if (unlikely(options.kill))
abort();
}
if (stack_size) {
struct rb_stack *stack = stack_add(process, process->pid, stack_data, stack_size, mt_msg->operation);
stack->n_badfree++;
stack->tsc = process->tsc++;
}
}
}
}
@ -1464,7 +1507,10 @@ void process_realloc_done(struct process *process, struct mt_msg *mt_msg, void *
}
}
// fprintf(stderr, ">>> unexpected realloc done pid: %u\n", pid);
if (unlikely(options.kill)) {
fprintf(stderr, ">>> unexpected realloc done pid: %u\n", pid);
abort();
}
return;
}
@ -1579,7 +1625,10 @@ void process_dump_sortby(struct process *process)
_process_dump(process, sort_usage, skip_zero_allocations, options.output, options.lflag);
break;
case OPT_SORT_MISMATCHED:
_process_dump(process, sort_mismatched, skip_non_mismatched, options.output, options.lflag);
_process_dump(process, sort_mismatched, skip_none, options.output, options.lflag);
break;
case OPT_SORT_BADFREE:
_process_dump(process, sort_badfree, skip_none, options.output, options.lflag);
break;
default:
_process_dump(process, sort_allocations, skip_zero_allocations, options.output, options.lflag);

View File

@ -112,6 +112,7 @@ void process_dump_sort_allocations(struct process *process, const char *outfile,
void process_dump_sort_total(struct process *process, const char *outfile, int lflag);
void process_dump_sort_tsc(struct process *process, const char *outfile, int lflag);
void process_dump_sort_mismatched(struct process *process, const char *outfile, int lflag);
void process_dump_sort_badfree(struct process *process, const char *outfile, int lflag);
void process_dump_stacks(struct process *process, const char *outfile, int lflag);
void add_ignore_regex(regex_t *re);

View File

@ -92,6 +92,7 @@ static int quit;
static struct cmd_opt dump_opts[] = {
{ "allocations", 2, process_dump_sort_allocations, "sort by number of open allocations" },
{ "average", 2, process_dump_sort_average, "sort by average allocation of bytes (usage / allocations)" },
{ "badfree", 1, process_dump_sort_badfree, "sort by number of badfree releases" },
{ "bytes-leaked", 1, process_dump_sort_bytes_leaked, "sort by number of leaked bytes" },
{ "leaks", 1, process_dump_sort_leaks, "sort by number of detected leaks" },
{ "mismatched", 1, process_dump_sort_mismatched, "sort by number of mismatched releases" },

View File

@ -265,9 +265,6 @@ static struct library *_library_add(struct task *leader, struct libref *libref)
struct library *lib = malloc(sizeof(*lib));
if (lib == NULL)
return NULL;
memset(lib, 0, sizeof(*lib));
lib->libref = libref_get(libref);

View File

@ -165,6 +165,8 @@ void operator delete(void* p) __THROW
void operator delete(void* p, const std::nothrow_t& nt) __THROW
void operator delete[](void* p) __THROW
void operator delete[](void* p, const std::nothrow_t& nt) __THROW
void operator delete(void*, unsigned long)
void operator delete[](void*, unsigned long)
.fi
.in
.PP
@ -306,6 +308,12 @@ Sort by the number of average allocations (number of bytes in used / number of o
.RE
.RE
.RS
\fIbadfree\fR
.RS
Sort by number of bad free releases (only useful with \-S option).
.RE
.RE
.RS
\fIbytes-leaked\fR
.RS
Sort by number of bytes leaked (only useful with \-a option).
@ -348,8 +356,8 @@ Sort by number of bytes in use of all open allocations.
.RE
.RE
.IP "\-S, \-\-sanity"
Check mismatching operations against new/delete. This options also
sets the sort-by options to mismatched.
Check mismatching operations against new/delete or free releases. This options
also sets the sort-by options to mismatched if no other sort option was set.
.IP "\-t, \-\-trace"
Run \fBmtrace-ng\fR in trace mode. In this mode all attached processes will run under
the control of \fBmtrace-ng\fR and all dynamic memory function calls will be traced.
@ -399,7 +407,7 @@ at any time. It accepts a maximum of three parameters:
\fIsortby\fR
.RS
Sort the output of dump by the keyword. The keyword is the same as for the
\-S option (\fIallocations, \fIaverage\fR, \fIbytes-leaked\fR, \fIleaks\fR,
\-S option (\fIallocations, \fIaverage\fR, \fIbadfree\fR \fIbytes-leaked\fR, \fIleaks\fR,
\fImismatched\fR, \fIstacks\fR, \fItotal\fR, \fItsc\fR and \fIusage\fR). See
\-S option for more details about the sortby keywords. The default sort order
is \fIallocations\fR when no sortby parameter is used.

View File

@ -106,7 +106,7 @@ static void usage(void)
" allocations, average, bytes-leaked, leaks,\n"
" mismatched, stacks, total, tsc, usage\n"
#endif
" -S, --sanity check mismatching operations against new/delete\n"
" -S, --sanity check for mismatching operations\n"
" -t, --trace trace mode\n"
" -u, --user=USERNAME run command with the userid, groupid of username\n"
" -V, --version output version information and exit\n"
@ -504,6 +504,9 @@ char **process_options(int argc, char **argv)
if (!strncmp(optarg, "average", 2))
options.sort_by = OPT_SORT_AVERAGE;
else
if (!strncmp(optarg, "badfree", 1))
options.sort_by = OPT_SORT_BADFREE;
else
if (!strncmp(optarg, "bytes-leaked", 1))
options.sort_by = OPT_SORT_BYTES_LEAKED;
else
@ -666,7 +669,7 @@ char **process_options(int argc, char **argv)
}
}
else {
if (options.sanity)
if (options.sanity && options.sort_by == -1)
options.sort_by = OPT_SORT_MISMATCHED;
}

View File

@ -39,6 +39,7 @@
#define OPT_SORT_TSC 6
#define OPT_SORT_USAGE 7
#define OPT_SORT_MISMATCHED 8
#define OPT_SORT_BADFREE 9
struct options_t options;

View File

@ -98,7 +98,6 @@ int server_poll(void)
{
int ret = 0;
if (command_pending) {
ret = server_handle_command();

View File

@ -473,7 +473,6 @@ static void linkmap_del(struct task *task, struct lt_r_debug_64 *dbg)
}
static int load_debug_struct(struct task *task, arch_addr_t debug_addr, struct lt_r_debug_64 *ret)
{
debug(DEBUG_FUNCTION, "pid=%d", task->pid);