diff options
author | Vicențiu Ciorbaru <cvicentiu@gmail.com> | 2015-12-11 09:16:42 +0200 |
---|---|---|
committer | Vicențiu Ciorbaru <vicentiu@mariadb.org> | 2016-01-17 14:20:09 +0200 |
commit | 6d3ffd2e3a76873acb4f232f52ccca6a75bf737d (patch) | |
tree | 2a3b966736caed6436cb7c6e86fb0d8f7f1fa31b | |
parent | df32495c85d75b736ee8d251d07b70b3682dda4d (diff) | |
download | mariadb-git-6d3ffd2e3a76873acb4f232f52ccca6a75bf737d.tar.gz |
Fixed a crash during stacktrace printing if addr2line failed to start.
In order to get all the input from addr2line we must read in a loop,
until the response is complete. Also, in case that the response is
malformed, we must not end up reading invalid memory.
-rw-r--r-- | mysys/my_addr_resolve.c | 66 |
1 files changed, 52 insertions, 14 deletions
diff --git a/mysys/my_addr_resolve.c b/mysys/my_addr_resolve.c index 9c9a7d9b97c..f9f40bc6ba5 100644 --- a/mysys/my_addr_resolve.c +++ b/mysys/my_addr_resolve.c @@ -145,30 +145,68 @@ static int initialized= 0; static char output[1024]; int my_addr_resolve(void *ptr, my_addr_loc *loc) { - char input[32], *s; + char input[32]; size_t len; len= my_snprintf(input, sizeof(input), "%p\n", ptr - offset); if (write(in[1], input, len) <= 0) return 1; - if (read(out[0], output, sizeof(output)) <= 0) + + ssize_t total_bytes_read = 0; + ssize_t extra_bytes_read = 0; + + fd_set set; + struct timeval timeout; + FD_ZERO(&set); + FD_SET(out[0], &set); + + /* 10 ms should be plenty of time for addr2line to issue a response. */ + timeout.tv_sec = 0; + timeout.tv_usec = 10000; + /* Read in a loop till all the output from addr2line is complete. */ + while (select(out[0] + 1, &set, NULL, NULL, &timeout) > 0) + { + extra_bytes_read= read(out[0], output + total_bytes_read, + sizeof(output) - total_bytes_read); + if (extra_bytes_read < 0) + return 1; + total_bytes_read += extra_bytes_read; + } + + /* Failed starting addr2line. */ + if (total_bytes_read == 0) return 1; - loc->func= s= output; - while (*s != '\n') - s++; - *s++= 0; - loc->file= s; - while (*s != ':') - s++; - *s++= 0; + int filename_start = -1; + int line_number_start = -1; + /* Go through the addr2line response and get the required data. + The response is structured in 2 lnes. The first line contains the function + name, while the second one contains <filename>:<line number> */ + for (ssize_t i = 0; i < total_bytes_read; i++) { + if (output[i] == '\n') { + filename_start = i + 1; + output[i] = '\0'; + } + if (filename_start != -1 && output[i] == ':') { + line_number_start = i + 1; + output[i] = '\0'; + } + if (line_number_start != -1) { + loc->line= atoi(output + line_number_start); + break; + } + } + /* Response is malformed. */ + if (filename_start == -1 || line_number_start == -1) + return 1; + + loc->func= output; + loc->file= output + filename_start; + + /* Addr2line was unable to extract any meaningful information. */ if (strcmp(loc->file, "??") == 0) return 1; - loc->line= 0; - while (isdigit(*s)) - loc->line = loc->line * 10 + (*s++ - '0'); - *s = 0; loc->file= strip_path(loc->file); return 0; |