From 8cc4949b0048fc589232a035349c791ce85f9e0d Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 11 Mar 2009 12:31:17 -0300 Subject: [PATCH] dwarves: Add destructors So that at program exit we can verify, using tools, that no memory was leaked. Signed-off-by: Arnaldo Carvalho de Melo --- codiff.c | 37 ++++++++++++++++++++++------ ctracer.c | 27 ++++++++++++--------- dtagnames.c | 12 ++++++--- dwarf_loader.c | 7 ++++++ dwarves.c | 65 ++++++++++++++++++++++++++++++++++++++----------- dwarves.h | 11 ++++++++- pahole.c | 66 ++++++++++++++++++++++++++++++++++++-------------- pdwtags.c | 14 +++++++---- pfunct.c | 41 +++++++++++++++++++++++-------- pglobal.c | 26 +++++++++++--------- 10 files changed, 225 insertions(+), 81 deletions(-) diff --git a/codiff.c b/codiff.c index 2773546..557ad8b 100644 --- a/codiff.c +++ b/codiff.c @@ -679,6 +679,21 @@ static int cu_show_diffs_iterator(struct cu *cu, void *cookie) return 0; } +static int cu_delete_priv(struct cu *cu, void *cookie __unused) +{ + struct class *c; + struct function *f; + uint32_t id; + + cu__for_each_struct(cu, id, c) + free(c->priv); + + cu__for_each_function(cu, id, f) + free(f->priv); + + return 0; +} + static void print_total_function_diff(const char *filename) { printf("\n%s:\n", filename); @@ -750,17 +765,12 @@ static struct argp codiff__argp = { int main(int argc, char *argv[]) { - int remaining, err; + int remaining, err, rc = EXIT_FAILURE; struct cus *old_cus, *new_cus; char *old_filename, *new_filename; char *filenames[2]; struct stat st; - if (dwarves__init(0)) { - fputs("codiff: insufficient memory\n", stderr); - return EXIT_FAILURE; - } - if (argp_parse(&codiff__argp, argc, argv, 0, &remaining, NULL) || remaining < argc) { switch (argc - remaining) { @@ -772,6 +782,11 @@ int main(int argc, char *argv[]) } else { failure: argp_help(&codiff__argp, stderr, ARGP_HELP_SEE, argv[0]); + goto out; + } + + if (dwarves__init(0)) { + fputs("codiff: insufficient memory\n", stderr); return EXIT_FAILURE; } @@ -829,5 +844,13 @@ failure: print_total_function_diff(new_filename); } - return EXIT_SUCCESS; + rc = EXIT_SUCCESS; +out: + cus__for_each_cu(old_cus, cu_delete_priv, NULL, NULL); + cus__for_each_cu(new_cus, cu_delete_priv, NULL, NULL); + cus__delete(old_cus); + cus__delete(new_cus); + strlist__delete(structs_printed); + dwarves__exit(); + return rc; } diff --git a/ctracer.c b/ctracer.c index 022ffa3..1a55b62 100644 --- a/ctracer.c +++ b/ctracer.c @@ -875,10 +875,11 @@ int main(int argc, char *argv[]) char classes_filename[PATH_MAX]; struct structure *pos; FILE *fp_functions; + int rc = EXIT_FAILURE; if (dwarves__init(0)) { fputs("ctracer: insufficient memory\n", stderr); - return EXIT_FAILURE; + goto out; } if (argp_parse(&ctracer__argp, argc, argv, 0, &remaining, NULL) || @@ -892,7 +893,7 @@ int main(int argc, char *argv[]) } else { failure: argp_help(&ctracer__argp, stderr, ARGP_HELP_SEE, argv[0]); - return EXIT_FAILURE; + goto out; } type_emissions__init(&emissions); @@ -906,7 +907,7 @@ failure: methods_cus = cus__new(); if (methods_cus == NULL) { fputs("ctracer: insufficient memory\n", stderr); - return EXIT_FAILURE; + goto out; } /* @@ -920,7 +921,7 @@ failure: fprintf(stderr, "ctracer: couldn't load DWARF info " "from %s dir with glob %s\n", dirname, glob); - return EXIT_FAILURE; + goto out; } /* @@ -930,7 +931,7 @@ failure: err = cus__load(methods_cus, filename); if (err != 0) { cus__print_error_msg("ctracer", methods_cus, filename, err); - return EXIT_FAILURE; + goto out; } } @@ -940,7 +941,7 @@ failure: class = cus__find_struct_by_name(methods_cus, &cu, class_name, 0, NULL); if (class == NULL) { fprintf(stderr, "ctracer: struct %s not found!\n", class_name); - return EXIT_FAILURE; + goto out; } snprintf(functions_filename, sizeof(functions_filename), @@ -949,7 +950,7 @@ failure: if (fp_functions == NULL) { fprintf(stderr, "ctracer: couldn't create %s\n", functions_filename); - exit(EXIT_FAILURE); + goto out; } snprintf(methods_filename, sizeof(methods_filename), @@ -958,7 +959,7 @@ failure: if (fp_methods == NULL) { fprintf(stderr, "ctracer: couldn't create %s\n", methods_filename); - exit(EXIT_FAILURE); + goto out; } snprintf(collector_filename, sizeof(collector_filename), @@ -967,7 +968,7 @@ failure: if (fp_collector == NULL) { fprintf(stderr, "ctracer: couldn't create %s\n", collector_filename); - exit(EXIT_FAILURE); + goto out; } snprintf(classes_filename, sizeof(classes_filename), @@ -976,7 +977,7 @@ failure: if (fp_classes == NULL) { fprintf(stderr, "ctracer: couldn't create %s\n", classes_filename); - exit(EXIT_FAILURE); + goto out; } fputs("%{\n" @@ -1037,5 +1038,9 @@ failure: fclose(fp_classes); strlist__delete(cu_blacklist); - return EXIT_SUCCESS; + rc = EXIT_SUCCESS; +out: + cus__delete(methods_cus); + dwarves__exit(); + return rc; } diff --git a/dtagnames.c b/dtagnames.c index bb196e5..ac1c12b 100644 --- a/dtagnames.c +++ b/dtagnames.c @@ -41,19 +41,23 @@ static void cus__dump_class_tag_names(struct cus *self) int main(int argc __unused, char *argv[]) { - int err; + int err, rc = EXIT_FAILURE; struct cus *cus = cus__new(); if (dwarves__init(0) || cus == NULL) { fputs("dtagnames: insufficient memory\n", stderr); - return EXIT_FAILURE; + goto out; } err = cus__loadfl(cus, NULL, argv + 1); if (err != 0) - return EXIT_FAILURE; + goto out; cus__dump_class_tag_names(cus); print_malloc_stats(); - return EXIT_SUCCESS; + rc = EXIT_SUCCESS; +out: + cus__delete(cus); + dwarves__exit(); + return rc; } diff --git a/dwarf_loader.c b/dwarf_loader.c index 0473834..5903e31 100644 --- a/dwarf_loader.c +++ b/dwarf_loader.c @@ -1530,11 +1530,18 @@ static unsigned long long dwarf_tag__orig_type(const struct tag *self, return cu->extra_dbg_info ? dtag->type : 0; } +static void dwarf_tag__free_orig_info(struct tag *self, struct cu *cu __unused) +{ + free(self->priv); + self->priv = NULL; +} + static struct cu_orig_info dwarf_orig_info_ops = { .tag__decl_file = dwarf_tag__decl_file, .tag__decl_line = dwarf_tag__decl_line, .tag__orig_id = dwarf_tag__orig_id, .tag__orig_type = dwarf_tag__orig_type, + .tag__free_orig_info = dwarf_tag__free_orig_info, }; static int tag__delete_priv(struct tag *self, struct cu *cu __unused, diff --git a/dwarves.c b/dwarves.c index acad470..1473086 100644 --- a/dwarves.c +++ b/dwarves.c @@ -563,20 +563,31 @@ out_free: goto out; } +static void array_type__delete(struct tag *self) +{ + free(tag__array_type(self)->nr_entries); + free(self); +} + +static int cu__delete_tag(struct tag *self, struct cu *cu __unused, + void *cookie __unused) +{ + tag__free_orig_info(self, cu); + switch (self->tag) { + case DW_TAG_array_type: + array_type__delete(self); break; + default: + free(self); break; + } + return 0; +} + void cu__delete(struct cu *self) { - struct tag *pos, *n; - - list_for_each_entry_safe(pos, n, &self->tags, node) { - list_del_init(&pos->node); - - /* Look for nested namespaces */ - if (tag__has_namespace(pos)) - namespace__delete(tag__namespace(pos)); - } - + cu__for_all_tags(self, cu__delete_tag, NULL); ptr_table__exit(&self->tags_table); ptr_table__exit(&self->types_table); + free(self->name); free(self); } @@ -2474,9 +2485,9 @@ static int list__for_all_tags(struct list_head *self, struct cu *cu, struct cu *cu, void *cookie), void *cookie) { - struct tag *pos; + struct tag *pos, *n; - list_for_each_entry(pos, self, node) { + list_for_each_entry_safe(pos, n, self, node) { if (tag__has_namespace(pos)) { if (list__for_all_tags(&tag__namespace(pos)->tags, cu, iterator, cookie)) @@ -2486,18 +2497,23 @@ static int list__for_all_tags(struct list_head *self, struct cu *cu, cu, iterator, cookie)) return 1; } - } if (tag__is_function(pos)) { + } else if (tag__is_function(pos)) { if (list__for_all_tags(&tag__ftype(pos)->parms, cu, iterator, cookie)) return 1; if (list__for_all_tags(&tag__function(pos)->lexblock.tags, cu, iterator, cookie)) return 1; - } if (pos->tag == DW_TAG_subroutine_type) { + } else if (pos->tag == DW_TAG_subroutine_type) { if (list__for_all_tags(&tag__ftype(pos)->parms, cu, iterator, cookie)) return 1; + } else if (pos->tag == DW_TAG_lexical_block) { + if (list__for_all_tags(&tag__lexblock(pos)->tags, + cu, iterator, cookie)) + return 1; } + if (iterator(pos, cu, cookie)) return 1; } @@ -2626,6 +2642,21 @@ struct cus *cus__new(void) return self; } +void cus__delete(struct cus *self) +{ + struct cu *pos, *n; + + if (self == NULL) + return; + + list_for_each_entry_safe(pos, n, &self->cus, node) { + list_del_init(&pos->node); + cu__delete(pos); + } + + free(self); +} + int dwarves__init(uint16_t user_cacheline_size) { strings = strings__new(); @@ -2646,6 +2677,12 @@ int dwarves__init(uint16_t user_cacheline_size) return 0; } +void dwarves__exit(void) +{ + strings__delete(strings); + strings = NULL; +} + struct argp_state; void dwarves_print_version(FILE *fp, struct argp_state *state __unused) diff --git a/dwarves.h b/dwarves.h index fa346c6..d43c201 100644 --- a/dwarves.h +++ b/dwarves.h @@ -34,6 +34,7 @@ struct cus { }; struct cus *cus__new(void); +void cus__delete(struct cus *self); struct ptr_table { void **entries; @@ -100,6 +101,8 @@ struct cu_orig_info { const struct cu *cu); unsigned long long (*tag__orig_type)(const struct tag *self, const struct cu *cu); + void (*tag__free_orig_info)(struct tag *self, + struct cu *cu); }; struct cu { @@ -226,7 +229,12 @@ static inline unsigned long long tag__orig_type(const struct tag *self, { return cu->orig_info ? cu->orig_info->tag__orig_type(self, cu) : 0; } - + +static inline void tag__free_orig_info(struct tag *self, struct cu *cu) +{ + return cu->orig_info ? cu->orig_info->tag__free_orig_info(self, cu) : 0; +} + struct ptr_to_member_type { struct tag tag; Dwarf_Off containing_type; @@ -641,6 +649,7 @@ struct conf_fprintf { }; int dwarves__init(uint16_t user_cacheline_size); +void dwarves__exit(void); extern void class__find_holes(struct class *self, const struct cu *cu); extern int class__has_hole_ge(const struct class *self, const uint16_t size); diff --git a/pahole.c b/pahole.c index 62c8de5..b7e4c08 100644 --- a/pahole.c +++ b/pahole.c @@ -84,6 +84,11 @@ static struct structure *structure__new(struct class *class, uint16_t id, return self; } +static void structure__delete(struct structure *self) +{ + free(self); +} + static void *structures__tree; static LIST_HEAD(structures__anonymous_list); static LIST_HEAD(structures__named_list); @@ -178,6 +183,23 @@ static struct structure *structures__find(strings_t name) return s; } +void void_structure__delete(void *structure) +{ + structure__delete(structure); +} + +void structures__delete(void) +{ + struct structure *pos, *n; + + list_for_each_entry_safe(pos, n, &structures__anonymous_list, node) { + list_del_init(&pos->node); + structure__delete(pos); + } + + tdestroy(structures__tree, void_structure__delete); +} + static void nr_definitions_formatter(struct structure *self) { printf("%s%c%u\n", class__name(self->class), separator, @@ -1052,24 +1074,25 @@ static struct argp pahole__argp = { int main(int argc, char *argv[]) { - int err, remaining; - struct cus *cus = cus__new(); - - if (dwarves__init(cacheline_size) || cus == NULL) { - fputs("pahole: insufficient memory\n", stderr); - return EXIT_FAILURE; - } + int err, remaining, rc = EXIT_FAILURE; + struct cus *cus; if (argp_parse(&pahole__argp, argc, argv, 0, &remaining, NULL) || remaining == argc) { argp_help(&pahole__argp, stderr, ARGP_HELP_SEE, argv[0]); - return EXIT_FAILURE; + goto out; + } + + cus = cus__new(); + if (dwarves__init(cacheline_size) || cus == NULL) { + fputs("pahole: insufficient memory\n", stderr); + goto out; } err = cus__loadfl(cus, &conf_load, argv + remaining); if (err != 0) { fputs("pahole: No debugging information found\n", stderr); - return EXIT_FAILURE; + goto out; } if (word_size != 0) { @@ -1080,7 +1103,7 @@ int main(int argc, char *argv[]) if (long_int_str_t == 0 || long_unsigned_int_str_t == 0) { fputs("pahole: couldn't find one of \"long int\" or " "\"long unsigned int\" types", stderr); - return EXIT_FAILURE; + goto out; } cus__for_each_cu(cus, cu_fixup_word_size_iterator, NULL, NULL); @@ -1098,7 +1121,8 @@ int main(int argc, char *argv[]) tag__fprintf(tag, cu, &conf, stdout); putchar('\n'); - return EXIT_SUCCESS; + rc = EXIT_SUCCESS; + goto out; } cus__for_each_cu(cus, cu_unique_iterator, NULL, cu__filter); @@ -1106,8 +1130,10 @@ int main(int argc, char *argv[]) * Done on cu_unique_iterator, we just want to print the CUs * that have class_name defined */ - if (defined_in) - return EXIT_SUCCESS; + if (defined_in) { + rc = EXIT_SUCCESS; + goto out; + } if (formatter == nr_methods_formatter) cus__for_each_cu(cus, cu_nr_methods_iterator, NULL, cu__filter); @@ -1119,13 +1145,13 @@ int main(int argc, char *argv[]) if (!stname) { fprintf(stderr, "struct %s not found!\n", class_name); - return EXIT_FAILURE; + goto out; } s = structures__find(stname); if (s == NULL) { fprintf(stderr, "struct %s not found!\n", class_name); - return EXIT_FAILURE; + goto out; } if (reorganize) { @@ -1135,7 +1161,7 @@ int main(int argc, char *argv[]) struct class *clone = class__clone(s->class, NULL); if (clone == NULL) { fprintf(stderr, "pahole: out of memory!\n"); - return EXIT_FAILURE; + goto out; } class__reorganize(clone, s->cu, reorg_verbose, stdout); savings = class__size(s->class) - class__size(clone); @@ -1171,6 +1197,10 @@ int main(int argc, char *argv[]) } } else print_classes(formatter); - - return EXIT_SUCCESS; + rc = EXIT_SUCCESS; +out: + cus__delete(cus); + structures__delete(); + dwarves__exit(); + return rc; } diff --git a/pdwtags.c b/pdwtags.c index 753dbb2..c0a15bc 100644 --- a/pdwtags.c +++ b/pdwtags.c @@ -98,24 +98,28 @@ static struct argp pdwtags__argp = { int main(int argc, char *argv[]) { - int err, remaining; + int err, remaining, rc = EXIT_FAILURE; struct cus *cus = cus__new(); if (dwarves__init(0) || cus == NULL) { fputs("pwdtags: insufficient memory\n", stderr); - return EXIT_FAILURE; + goto out; } if (argp_parse(&pdwtags__argp, argc, argv, 0, &remaining, NULL) || remaining == argc) { argp_help(&pdwtags__argp, stderr, ARGP_HELP_SEE, argv[0]); - return EXIT_FAILURE; + goto out; } err = cus__loadfl(cus, NULL, argv + remaining); if (err != 0) - return EXIT_FAILURE; + goto out; cus__emit_tags(cus); - return EXIT_SUCCESS; + rc = EXIT_SUCCESS; +out: + cus__delete(cus); + dwarves__exit(); + return rc; } diff --git a/pfunct.c b/pfunct.c index cda0244..ee7471c 100644 --- a/pfunct.c +++ b/pfunct.c @@ -57,6 +57,11 @@ static struct fn_stats *fn_stats__new(struct tag *tag, const struct cu *cu) return self; } +static void fn_stats__delete(struct fn_stats *self) +{ + free(self); +} + static LIST_HEAD(fn_stats__list); static struct fn_stats *fn_stats__find(const char *name) @@ -70,6 +75,16 @@ static struct fn_stats *fn_stats__find(const char *name) return NULL; } +static void fn_stats__delete_list(void) +{ + struct fn_stats *pos, *n; + + list_for_each_entry_safe(pos, n, &fn_stats__list, node) { + list_del_init(&pos->node); + fn_stats__delete(pos); + } +} + static void fn_stats__add(struct tag *tag, const struct cu *cu) { struct fn_stats *fns = fn_stats__new(tag, cu); @@ -504,23 +519,24 @@ static struct argp pfunct__argp = { int main(int argc, char *argv[]) { - int err, remaining; - struct cus *cus = cus__new(); - - if (dwarves__init(0) || cus == NULL) { - fputs("pfunct: insufficient memory\n", stderr); - return EXIT_FAILURE; - } + int err, remaining, rc = EXIT_FAILURE; + struct cus *cus; if (argp_parse(&pfunct__argp, argc, argv, 0, &remaining, NULL) || remaining == argc) { argp_help(&pfunct__argp, stderr, ARGP_HELP_SEE, argv[0]); - return EXIT_FAILURE; + goto out; + } + + cus = cus__new(); + if (dwarves__init(0) || cus == NULL) { + fputs("pfunct: insufficient memory\n", stderr); + goto out; } err = cus__loadfl(cus, &conf_load, argv + remaining); if (err != 0) - return EXIT_FAILURE; + goto out; cus__for_each_cu(cus, cu_unique_iterator, NULL, NULL); @@ -534,5 +550,10 @@ int main(int argc, char *argv[]) else print_fn_stats(formatter); - return EXIT_SUCCESS; + rc = EXIT_SUCCESS; +out: + cus__delete(cus); + fn_stats__delete_list(); + dwarves__exit(); + return rc; } diff --git a/pglobal.c b/pglobal.c index 0ecd6e5..c1a6c74 100644 --- a/pglobal.c +++ b/pglobal.c @@ -316,23 +316,24 @@ static struct argp pglobal__argp = { int main(int argc, char *argv[]) { - int err, remaining; - struct cus *cus = cus__new(); - - if (dwarves__init(0) || cus == NULL) { - fputs("pglobal: insufficient memory\n", stderr); - return EXIT_FAILURE; - } + int err, remaining, rc = EXIT_FAILURE; if (argp_parse(&pglobal__argp, argc, argv, 0, &remaining, NULL) || remaining == argc) { argp_help(&pglobal__argp, stderr, ARGP_HELP_SEE, argv[0]); - return EXIT_FAILURE; + goto out; + } + + struct cus *cus = cus__new(); + + if (dwarves__init(0) || cus == NULL) { + fputs("pglobal: insufficient memory\n", stderr); + goto out; } err = cus__loadfl(cus, NULL, argv + remaining); if (err != 0) - return EXIT_FAILURE; + goto out; if (walk_var) { cus__for_each_cu(cus, cu_extvar_iterator, NULL, NULL); @@ -343,6 +344,9 @@ int main(int argc, char *argv[]) } tdestroy(tree, free_node); - - return EXIT_SUCCESS; + rc = EXIT_SUCCESS; +out: + cus__delete(cus); + dwarves__exit(); + return rc; }