diff --git a/helpers/inspect-library.c b/helpers/inspect-library.c index 8a8ece5da2b4d220e96634ffcae0e08ec13cc230..22c8c9e974c831a2b8ab69f4fab61d89cc7e08d3 100644 --- a/helpers/inspect-library.c +++ b/helpers/inspect-library.c @@ -46,7 +46,6 @@ #define BASE "Base" static void print_json_string_content (const char *s); -static void clean_exit (void *handle); static bool has_symbol (void *handle, const char *symbol); static bool has_versioned_symbol (void *handle, const char *symbol, @@ -72,6 +71,44 @@ do { \ oom (); \ } while (0) +static inline void * +steal_pointer (void *pp) +{ + typedef void *__attribute__((may_alias)) voidp_alias; + voidp_alias *pointer_to_pointer = pp; + void *ret = *pointer_to_pointer; + *pointer_to_pointer = NULL; + return ret; +} + +static void +clear_with_free (void *pp) +{ + free (steal_pointer (pp)); +} + +static void +clear_with_dlclose (void *pp) +{ + void *handle = steal_pointer (pp); + + if (handle != NULL) + dlclose (handle); +} + +static void +clear_with_fclose (void *pp) +{ + FILE *fh = steal_pointer (pp); + + if (fh != NULL) + fclose (fh); +} + +#define autodlclose __attribute__((__cleanup__(clear_with_dlclose))) +#define autofclose __attribute__((__cleanup__(clear_with_fclose))) +#define autofree __attribute__((__cleanup__(clear_with_free))) + enum { OPTION_HELP = 1, @@ -152,28 +189,30 @@ main (int argc, const char *soname; const char *version; const char *symbol; - void *handle = NULL; + autodlclose void *handle = NULL; struct link_map *dep_map = NULL; struct link_map *the_library = NULL; - FILE *fp; - char *missing_symbols = NULL; - char *misversioned_symbols = NULL; + autofclose FILE *fp = NULL; + autofree char *missing_symbols = NULL; + autofree char *misversioned_symbols = NULL; size_t missing_n = 0; size_t misversioned_n = 0; - char *line = NULL; + autofree char *line = NULL; size_t len = 0; ssize_t chars; bool first; bool deb_symbols = false; - size_t dependency_counter = 0; int opt; + autofree char *hidden_deps = NULL; + size_t hidden_deps_len = 0; + const char *hidden_dep; while ((opt = getopt_long (argc, argv, "", long_options, NULL)) != -1) { switch (opt) { case OPTION_HIDDEN_DEPENDENCY: - dependency_counter++; + argz_add_or_die (&hidden_deps, &hidden_deps_len, optarg); break; case OPTION_DEB_SYMBOLS: @@ -206,43 +245,21 @@ main (int argc, usage (1); } - const char *hidden_deps[dependency_counter + 1]; - - if (dependency_counter > 0) - { - /* Reset getopt */ - optind = 1; - - size_t i = 0; - while ((opt = getopt_long (argc, argv, "", long_options, NULL)) != -1) - { - switch (opt) - { - case OPTION_HIDDEN_DEPENDENCY: - hidden_deps[i] = optarg; - i++; - break; - - default: - break; - } - } - } - soname = argv[optind]; printf ("{\n"); printf (" \""); print_json_string_content (soname); printf ("\": {"); - for (size_t i = 0; i < dependency_counter; i++) + for (hidden_dep = argz_next (hidden_deps, hidden_deps_len, NULL); + hidden_dep != NULL; + hidden_dep = argz_next (hidden_deps, hidden_deps_len, hidden_dep)) { /* We don't call "dlclose" on global hidden dependencies, otherwise ubsan * will report an indirect memory leak */ - if (dlopen (hidden_deps[i], RTLD_NOW|RTLD_GLOBAL) == NULL) + if (dlopen (hidden_dep, RTLD_NOW|RTLD_GLOBAL) == NULL) { fprintf (stderr, "Unable to find the dependency library: %s\n", dlerror ()); - clean_exit (handle); return 1; } } @@ -251,7 +268,6 @@ main (int argc, if (handle == NULL) { fprintf (stderr, "Unable to find the library: %s\n", dlerror ()); - clean_exit (handle); return 1; } /* Using RTLD_DI_LINKMAP insted of RTLD_DI_ORIGIN we don't need to worry @@ -259,7 +275,6 @@ main (int argc, if (dlinfo (handle, RTLD_DI_LINKMAP, &the_library) != 0 || the_library == NULL) { fprintf (stderr, "Unable to obtain the path: %s\n", dlerror ()); - clean_exit (handle); return 1; } @@ -301,7 +316,6 @@ main (int argc, fprintf (stderr, "Error reading \"%s\": %s\n", argv[optind + 1], strerror (saved_errno)); - clean_exit (handle); return 1; } @@ -368,10 +382,6 @@ main (int argc, if (symbol == NULL) { fprintf (stderr, "Probably the symbol@version pair is mispelled."); - free (line); - free (missing_symbols); - free (misversioned_symbols); - clean_exit (handle); return 1; } @@ -390,20 +400,17 @@ main (int argc, } else if (!has_versioned_symbol (handle, symbol, version)) { - char * merged_string; + autofree char * merged_string = NULL; + asprintf_or_die (&merged_string, "%s@%s", symbol, version); if (has_symbol (handle, symbol)) argz_add_or_die (&misversioned_symbols, &misversioned_n, merged_string); else argz_add_or_die (&missing_symbols, &missing_n, merged_string); - - free (merged_string); } } } } - free (line); - fclose (fp); if (deb_symbols && !found_our_soname) { @@ -442,9 +449,6 @@ main (int argc, printf ("\""); } printf ("\n ]"); - - free (missing_symbols); - free (misversioned_symbols); } dep_map = the_library; @@ -473,7 +477,7 @@ main (int argc, } printf ("\n ]\n }"); - clean_exit (handle); + printf ("\n}\n"); return 0; } @@ -492,15 +496,6 @@ print_json_string_content (const char *s) } } -static void -clean_exit (void *handle) -{ - if (handle != NULL) - dlclose (handle); - - printf ("\n}\n"); -} - static bool has_symbol (void *handle, const char *symbol)