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

@ -383,7 +383,7 @@ struct breakpoint *breakpoint_new_ext(struct task *task, arch_addr_t addr, struc
case BP_AUTO: case BP_AUTO:
case BP_HW: case BP_HW:
#if HW_BREAKPOINTS > 1 #if HW_BREAKPOINTS > 1
list_add_tail(&bp->link_list, &leader->hw_bp_list); list_add_tail(&bp->link_list, &leader->hw_bp_list);
leader->hw_bp_num++; leader->hw_bp_num++;
#endif #endif
case BP_SW: case BP_SW:

View File

@ -807,7 +807,7 @@ int client_send_msg(struct process *process, enum mt_operation op, void *payload
ret = sock_send_msg(client_fd, process->val16(op), process->pid, payload, payload_len); ret = sock_send_msg(client_fd, process->val16(op), process->pid, payload, payload_len);
if (ret < 0) if (ret < 0)
client_broken(); client_broken();
return ret; return ret;
} }

View File

@ -72,6 +72,7 @@ struct rb_stack {
unsigned long long bytes_leaked; unsigned long long bytes_leaked;
unsigned long long tsc; unsigned long long tsc;
unsigned long long n_mismatched; unsigned long long n_mismatched;
unsigned long long n_badfree;
}; };
struct map { 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->leaks = stack_node->leaks;
this->n_allocations = stack_node->n_allocations; this->n_allocations = stack_node->n_allocations;
this->n_mismatched = stack_node->n_mismatched; this->n_mismatched = stack_node->n_mismatched;
this->n_badfree = stack_node->n_badfree;
this->total_allocations = stack_node->total_allocations; this->total_allocations = stack_node->total_allocations;
this->bytes_used = stack_node->bytes_used; this->bytes_used = stack_node->bytes_used;
this->bytes_leaked = stack_node->bytes_leaked; 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->refcnt = 0;
this->n_allocations = 0; this->n_allocations = 0;
this->n_mismatched = 0; this->n_mismatched = 0;
this->n_badfree = 0;
this->total_allocations = 0; this->total_allocations = 0;
this->bytes_used = 0; this->bytes_used = 0;
this->leaks = 0; this->leaks = 0;
@ -924,7 +927,16 @@ static int sort_tsc(const struct rb_stack **p, const struct rb_stack **q)
return 0; 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) if ((*p)->n_mismatched > (*q)->n_mismatched)
return -1; return -1;
@ -933,6 +945,26 @@ static int sort_mismatched(const struct rb_stack **p, const struct rb_stack **q)
return 0; 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) static int sort_usage(const struct rb_stack **p, const struct rb_stack **q)
{ {
if ((*p)->bytes_used > (*q)->bytes_used) 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]; struct rb_stack *stack = arr[i];
if (!skipfunc(stack)) { 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( if (dump_printf(
"Stack (%s):\n" "Stack (%s):\n"
" bytes used: %llu\n" " bytes used: %llu\n"
@ -1065,15 +1108,6 @@ static void _process_dump(struct process *process, int (*sortby)(const struct rb
break; 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) if (dump_printf(" tsc: %llu\n", stack->tsc) == -1)
break; break;
@ -1118,11 +1152,6 @@ static int skip_zero_allocations(struct rb_stack *stack)
return !stack->n_allocations; 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) static int skip_zero_leaks(struct rb_stack *stack)
{ {
return !stack->leaks; 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) 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) 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; break;
if (!is_mmap(block->stack_node->stack->operation)) { if (!is_mmap(block->stack_node->stack->operation)) {
fprintf(stderr, ">>> block missmatch pid:%d MAP<>MALLOC %#lx\n", process->pid, ptr); if (unlikely(options.kill)) {
fprintf(stderr, ">>> block missmatch pid:%d MAP<>MALLOC %#lx\n", process->pid, ptr);
if (unlikely(options.kill))
abort(); abort();
}
break; break;
} }
@ -1388,17 +1422,19 @@ void process_free(struct process *process, struct mt_msg *mt_msg, void *payload)
block = process_rb_search(&process->block_table, ptr); block = process_rb_search(&process->block_table, ptr);
if (block) { if (block) {
if (is_mmap(block->stack_node->stack->operation)) { if (is_mmap(block->stack_node->stack->operation)) {
fprintf(stderr, ">>> block missmatch pid:%d MAP<>MALLOC %#lx\n", process->pid, ptr); if (unlikely(options.kill)) {
fprintf(stderr, ">>> block missmatch pid:%d MAP<>MALLOC %#lx\n", process->pid, ptr);
if (unlikely(options.kill))
abort(); abort();
}
} }
if (!is_sane(block, mt_msg->operation)) { if (stack_size) {
struct rb_stack *stack = stack_add(process, process->pid, stack_data, stack_size, mt_msg->operation); 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->n_mismatched++;
stack->tsc = process->tsc++; stack->tsc = process->tsc++;
}
} }
if (mt_msg->operation == MT_REALLOC_ENTER) { if (mt_msg->operation == MT_REALLOC_ENTER) {
@ -1420,10 +1456,17 @@ void process_free(struct process *process, struct mt_msg *mt_msg, void *payload)
} }
else { else {
if (!process->attached) { if (!process->attached) {
fprintf(stderr, ">>> block %#lx not found pid:%d\n", ptr, process->pid); if (unlikely(options.kill)) {
fprintf(stderr, ">>> block %#lx not found pid:%d\n", ptr, process->pid);
if (unlikely(options.kill))
abort(); 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; return;
} }
@ -1579,7 +1625,10 @@ void process_dump_sortby(struct process *process)
_process_dump(process, sort_usage, skip_zero_allocations, options.output, options.lflag); _process_dump(process, sort_usage, skip_zero_allocations, options.output, options.lflag);
break; break;
case OPT_SORT_MISMATCHED: 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; break;
default: default:
_process_dump(process, sort_allocations, skip_zero_allocations, options.output, options.lflag); _process_dump(process, sort_allocations, skip_zero_allocations, options.output, options.lflag);
@ -1688,7 +1737,7 @@ struct block_helper {
unsigned long mask; unsigned long mask;
unsigned long fmask; unsigned long fmask;
unsigned long fmode; unsigned long fmode;
void * data; void * data;
}; };
static void set_block(struct rb_block *block, void *data) static void set_block(struct rb_block *block, void *data)

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_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_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_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 process_dump_stacks(struct process *process, const char *outfile, int lflag);
void add_ignore_regex(regex_t *re); void add_ignore_regex(regex_t *re);

View File

@ -92,6 +92,7 @@ static int quit;
static struct cmd_opt dump_opts[] = { static struct cmd_opt dump_opts[] = {
{ "allocations", 2, process_dump_sort_allocations, "sort by number of open allocations" }, { "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)" }, { "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" }, { "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" }, { "leaks", 1, process_dump_sort_leaks, "sort by number of detected leaks" },
{ "mismatched", 1, process_dump_sort_mismatched, "sort by number of mismatched releases" }, { "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)); struct library *lib = malloc(sizeof(*lib));
if (lib == NULL)
return NULL;
memset(lib, 0, sizeof(*lib)); memset(lib, 0, sizeof(*lib));
lib->libref = libref_get(libref); lib->libref = libref_get(libref);

2
list.h
View File

@ -212,7 +212,7 @@ static inline void list_splice_init(struct list_head *list,
*/ */
#define list_for_each(pos, head) \ #define list_for_each(pos, head) \
for (pos = (head)->next; prefetch(pos->next), pos != (head); \ for (pos = (head)->next; prefetch(pos->next), pos != (head); \
pos = pos->next) pos = pos->next)
/** /**
* list_for_each_safe - iterate over a list safe against removal of list entry * list_for_each_safe - iterate over a list safe against removal of list entry

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, const std::nothrow_t& nt) __THROW
void operator delete[](void* p) __THROW void operator delete[](void* p) __THROW
void operator delete[](void* p, const std::nothrow_t& nt) __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 .fi
.in .in
.PP .PP
@ -306,6 +308,12 @@ Sort by the number of average allocations (number of bytes in used / number of o
.RE .RE
.RE .RE
.RS .RS
\fIbadfree\fR
.RS
Sort by number of bad free releases (only useful with \-S option).
.RE
.RE
.RS
\fIbytes-leaked\fR \fIbytes-leaked\fR
.RS .RS
Sort by number of bytes leaked (only useful with \-a option). 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
.RE .RE
.IP "\-S, \-\-sanity" .IP "\-S, \-\-sanity"
Check mismatching operations against new/delete. This options also Check mismatching operations against new/delete or free releases. This options
sets the sort-by options to mismatched. also sets the sort-by options to mismatched if no other sort option was set.
.IP "\-t, \-\-trace" .IP "\-t, \-\-trace"
Run \fBmtrace-ng\fR in trace mode. In this mode all attached processes will run under 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. 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 \fIsortby\fR
.RS .RS
Sort the output of dump by the keyword. The keyword is the same as for the 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 \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 \-S option for more details about the sortby keywords. The default sort order
is \fIallocations\fR when no sortby parameter is used. 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" " allocations, average, bytes-leaked, leaks,\n"
" mismatched, stacks, total, tsc, usage\n" " mismatched, stacks, total, tsc, usage\n"
#endif #endif
" -S, --sanity check mismatching operations against new/delete\n" " -S, --sanity check for mismatching operations\n"
" -t, --trace trace mode\n" " -t, --trace trace mode\n"
" -u, --user=USERNAME run command with the userid, groupid of username\n" " -u, --user=USERNAME run command with the userid, groupid of username\n"
" -V, --version output version information and exit\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)) if (!strncmp(optarg, "average", 2))
options.sort_by = OPT_SORT_AVERAGE; options.sort_by = OPT_SORT_AVERAGE;
else else
if (!strncmp(optarg, "badfree", 1))
options.sort_by = OPT_SORT_BADFREE;
else
if (!strncmp(optarg, "bytes-leaked", 1)) if (!strncmp(optarg, "bytes-leaked", 1))
options.sort_by = OPT_SORT_BYTES_LEAKED; options.sort_by = OPT_SORT_BYTES_LEAKED;
else else
@ -666,7 +669,7 @@ char **process_options(int argc, char **argv)
} }
} }
else { else {
if (options.sanity) if (options.sanity && options.sort_by == -1)
options.sort_by = OPT_SORT_MISMATCHED; options.sort_by = OPT_SORT_MISMATCHED;
} }

View File

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

View File

@ -63,7 +63,7 @@ static void report_alloc64(struct task *task, enum mt_operation op, unsigned lon
if (unlikely(!alloc->data[i])) if (unlikely(!alloc->data[i]))
break; break;
++i; ++i;
} }
} }

View File

@ -98,8 +98,7 @@ int server_poll(void)
{ {
int ret = 0; int ret = 0;
if (command_pending) {
if (command_pending) {
ret = server_handle_command(); ret = server_handle_command();
if (options.trace) if (options.trace)

View File

@ -207,7 +207,7 @@ static int arm_get_next_pcs(struct task *task, const uint32_t pc, uint32_t next_
if (BITS(this_instr, 12, 15) != ARM_REG_PC) if (BITS(this_instr, 12, 15) != ARM_REG_PC)
break; break;
if (BITS(this_instr, 22, 25) == 0 && BITS(this_instr, 4, 7) == 9) /* multiply */ if (BITS(this_instr, 22, 25) == 0 && BITS(this_instr, 4, 7) == 9) /* multiply */
goto invalid; goto invalid;
/* BX <reg>, BLX <reg> */ /* BX <reg>, BLX <reg> */

View File

@ -70,34 +70,34 @@ static void report_fault(int signo, siginfo_t* siginf, void* arg)
void *trace[48]; void *trace[48];
char **strings; char **strings;
Dl_info info; Dl_info info;
char linkname[PATH_MAX]; char linkname[PATH_MAX];
bfd* abfd = 0; bfd* abfd = 0;
asymbol **syms = 0; asymbol **syms = 0;
asection *text = 0; asection *text = 0;
int l; int l;
l = readlink("/proc/self/exe", linkname, sizeof(linkname)); l = readlink("/proc/self/exe", linkname, sizeof(linkname));
if (l == -1) { if (l == -1) {
perror("failed to find executable\n"); perror("failed to find executable\n");
return; return;
} }
linkname[l] = 0; linkname[l] = 0;
bfd_init(); bfd_init();
abfd = bfd_openr(linkname, 0); abfd = bfd_openr(linkname, 0);
if (!abfd) { if (!abfd) {
perror("bfd_openr failed: "); perror("bfd_openr failed: ");
return; return;
} }
/* oddly, this is required for it to work... */ /* oddly, this is required for it to work... */
bfd_check_format(abfd,bfd_object); bfd_check_format(abfd,bfd_object);
unsigned storage_needed = bfd_get_symtab_upper_bound(abfd); unsigned storage_needed = bfd_get_symtab_upper_bound(abfd);
syms = (asymbol **) malloc(storage_needed); syms = (asymbol **) malloc(storage_needed);
bfd_canonicalize_symtab(abfd, syms); bfd_canonicalize_symtab(abfd, syms);
text = bfd_get_section_by_name(abfd, ".text"); text = bfd_get_section_by_name(abfd, ".text");

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) 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); debug(DEBUG_FUNCTION, "pid=%d", task->pid);