diff options
author | Rex <rex.johnston@mariadb.com> | 2023-03-09 13:41:07 +1200 |
---|---|---|
committer | Rex <rex.johnston@mariadb.com> | 2023-03-09 14:52:22 +1200 |
commit | f367047033f2096dbbee7f67f5931b9faf49d483 (patch) | |
tree | 1db2f1be7039a880cf03217cfc92f1e37697f98e | |
parent | 231c0eb7a68570da6b5b3741b2f1431c2f43c475 (diff) | |
download | mariadb-git-bb-10.5-MDEV-30815.tar.gz |
MDEV-30815 Printing a stack trace leaks file descriptors.bb-10.5-MDEV-30815
In situations where mariadbd emits a lot of stack traces it can
run out of file descriptors. Each time the pipe to the external
utility addr2line is opened, those file descriptor are never closed.
-rw-r--r-- | include/my_stacktrace.h | 3 | ||||
-rw-r--r-- | mysys/my_addr_resolve.c | 95 | ||||
-rw-r--r-- | mysys/safemalloc.c | 3 | ||||
-rw-r--r-- | mysys/stacktrace.c | 3 |
4 files changed, 58 insertions, 46 deletions
diff --git a/include/my_stacktrace.h b/include/my_stacktrace.h index 20b86f45232..924f198be3e 100644 --- a/include/my_stacktrace.h +++ b/include/my_stacktrace.h @@ -75,7 +75,8 @@ typedef struct { #ifdef HAVE_MY_ADDR_RESOLVE int my_addr_resolve(void *ptr, my_addr_loc *loc); -const char *my_addr_resolve_init(); +const char *my_addr_resolve_init(void *ptr); +void my_addr_resolve_close(); #else #define my_addr_resolve_init() (0) #define my_addr_resolve(A,B) (1) diff --git a/mysys/my_addr_resolve.c b/mysys/my_addr_resolve.c index 336e419806d..e4d3fd1fff6 100644 --- a/mysys/my_addr_resolve.c +++ b/mysys/my_addr_resolve.c @@ -115,7 +115,7 @@ int my_addr_resolve(void *ptr, my_addr_loc *loc) return 1; } -const char *my_addr_resolve_init() +const char *my_addr_resolve_init(void *ptr) { if (!bfdh) { @@ -145,6 +145,11 @@ const char *my_addr_resolve_init() err: return bfd_errmsg(bfd_get_error()); } + + +void my_addr_resolve_close() +{ +} #elif defined(HAVE_LIBELF_H) /* another possible implementation. @@ -171,19 +176,11 @@ static char addr2line_binary[1024]; static char output[1024]; static struct pollfd poll_fds; static void *addr_offset; +Dl_info info; + int start_addr2line_fork(const char *binary_path) { - - if (pid > 0) - { - /* Don't leak FDs */ - close(in[1]); - close(out[0]); - /* Don't create zombie processes. */ - waitpid(pid, NULL, 0); - } - if (pipe(in) < 0) return 1; if (pipe(out) < 0) @@ -211,6 +208,16 @@ int start_addr2line_fork(const char *binary_path) return 0; } + +void my_addr_resolve_close() +{ + /* Don't leak FDs */ + close(in[1]); + close(out[0]); + /* Don't create zombie processes. */ + waitpid(pid, NULL, 0); +} + static int first_error= 0; static int addr_resolve(void *ptr, my_addr_loc *loc) @@ -297,48 +304,50 @@ static int addr_resolve(void *ptr, my_addr_loc *loc) int my_addr_resolve(void *ptr, my_addr_loc *loc) { - Dl_info info; +#ifndef __PIE__ + addr_offset= (void*) info.dli_fbase; + if (strcmp(info.dli_fname, my_progname) == 0 && + addr_resolve((void*) my_addr_resolve, loc) == 0 && + strcmp(loc->func, "my_addr_resolve") == 0) + addr_offset= 0; +#endif + return addr_resolve((void*) (ptr - addr_offset), loc); +} + + +const char *my_addr_resolve_init(void *ptr) +{ if (!dladdr(ptr, &info)) - return 1; + return "dladdr() error"; - if (strcmp(addr2line_binary, info.dli_fname)) - { - /* - We use dli_fname in case the path is longer than the length of - our static string. We don't want to allocate anything - dynamically here as we are in a "crashed" state. + /* + We use dli_fname in case the path is longer than the length of + our static string. We don't want to allocate anything + dynamically here as we are in a "crashed" state. */ - if (start_addr2line_fork(info.dli_fname)) + + if (start_addr2line_fork(info.dli_fname)) + { + if (!first_error++) { - if (!first_error++) - fputs("Can't start addr2line\n", stderr); - addr2line_binary[0] = '\0'; - return 2; + fputs("Can't start addr2line\n", stderr); + my_addr_resolve_close(); } - /* Save result for future comparisons. */ - strnmov(addr2line_binary, info.dli_fname, sizeof(addr2line_binary)); - - /* - Check if we should use info.dli_fbase as an offset or not - for the base program. This is depending on if the compilation is - done with PIE or not. - */ - addr_offset= (void*) info.dli_fbase; -#ifndef __PIE__ - if (strcmp(info.dli_fname, my_progname) == 0 && - addr_resolve((void*) my_addr_resolve, loc) == 0 && - strcmp(loc->func, "my_addr_resolve") == 0) - addr_offset= 0; -#endif + addr2line_binary[0] = '\0'; + return "fork() error"; } - return addr_resolve((void*) (ptr - addr_offset), loc); -} + /* Save result for future comparisons. */ + strnmov(addr2line_binary, info.dli_fname, sizeof(addr2line_binary)); + /* + Check if we should use info.dli_fbase as an offset or not + for the base program. This is depending on if the compilation is + done with PIE or not. + */ + addr_offset= (void*) info.dli_fbase; -const char *my_addr_resolve_init() -{ return 0; } #endif diff --git a/mysys/safemalloc.c b/mysys/safemalloc.c index 8ccc49bbb23..ba22d629dae 100644 --- a/mysys/safemalloc.c +++ b/mysys/safemalloc.c @@ -225,7 +225,7 @@ static void print_stack(void **frame) const char *err; int i; - if ((err= my_addr_resolve_init())) + if ((err= my_addr_resolve_init(frame[0]))) { fprintf(stderr, "(my_addr_resolve failure: %s)\n", err); return; @@ -243,6 +243,7 @@ static void print_stack(void **frame) fprintf(stderr, "%s:%u", loc.file, loc.line); } fprintf(stderr, "\n"); + my_addr_resolve_close(); } #else #define print_stack(X) fprintf(stderr, "???\n") diff --git a/mysys/stacktrace.c b/mysys/stacktrace.c index 5718b2e762d..6a9161460a0 100644 --- a/mysys/stacktrace.c +++ b/mysys/stacktrace.c @@ -185,7 +185,7 @@ static int print_with_addr_resolve(void **addrs, int n) int i; const char *err; - if ((err= my_addr_resolve_init())) + if ((err= my_addr_resolve_init(addrs[0]))) { my_safe_printf_stderr("(my_addr_resolve failure: %s)\n", err); return 0; @@ -200,6 +200,7 @@ static int print_with_addr_resolve(void **addrs, int n) my_safe_printf_stderr("%s:%u(%s)[%p]\n", loc.file, loc.line, loc.func, addrs[i]); } + my_addr_resolve_close(); return 1; } #endif |