summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVicențiu Ciorbaru <cvicentiu@gmail.com>2015-12-11 09:16:42 +0200
committerVicențiu Ciorbaru <vicentiu@mariadb.org>2016-01-17 14:20:09 +0200
commit6d3ffd2e3a76873acb4f232f52ccca6a75bf737d (patch)
tree2a3b966736caed6436cb7c6e86fb0d8f7f1fa31b
parentdf32495c85d75b736ee8d251d07b70b3682dda4d (diff)
downloadmariadb-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.c66
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;