mirror of
https://github.com/sstefani/mtrace.git
synced 2025-12-06 08:46:41 +08:00
clean up, option for invalid free releases
This commit is contained in:
parent
3e2980613c
commit
3b7a0d0552
@ -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);
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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" },
|
||||
|
||||
@ -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);
|
||||
|
||||
14
mtrace-ng.1
14
mtrace-ng.1
@ -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.
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
1
server.c
1
server.c
@ -98,7 +98,6 @@ int server_poll(void)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
|
||||
if (command_pending) {
|
||||
ret = server_handle_command();
|
||||
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user