sanitizer_symbolizer_posix_libcdep.cc revision 7aaaee4cab08096d46e9886c5fea8564732ad2ff
1//===-- sanitizer_symbolizer_posix_libcdep.cc -----------------------------===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file is shared between AddressSanitizer and ThreadSanitizer
11// run-time libraries.
12// POSIX-specific implementation of symbolizer parts.
13//===----------------------------------------------------------------------===//
14
15#include "sanitizer_platform.h"
16#if SANITIZER_POSIX
17#include "sanitizer_common.h"
18#include "sanitizer_internal_defs.h"
19#include "sanitizer_symbolizer.h"
20
21#include <errno.h>
22#include <sys/wait.h>
23#include <unistd.h>
24
25namespace __sanitizer {
26
27#if defined(__x86_64__)
28static const char* const kSymbolizerArch = "--default-arch=x86_64";
29#elif defined(__i386__)
30static const char* const kSymbolizerArch = "--default-arch=i386";
31#elif defined(__powerpc64__)
32static const char* const kSymbolizerArch = "--default-arch=powerpc64";
33#else
34static const char* const kSymbolizerArch = "--default-arch=unknown";
35#endif
36
37bool StartSymbolizerSubprocess(const char *path_to_symbolizer,
38                               int *input_fd, int *output_fd) {
39  if (!FileExists(path_to_symbolizer)) {
40    Report("WARNING: invalid path to external symbolizer!\n");
41    return false;
42  }
43
44  int *infd = NULL;
45  int *outfd = NULL;
46  // The client program may close its stdin and/or stdout and/or stderr
47  // thus allowing socketpair to reuse file descriptors 0, 1 or 2.
48  // In this case the communication between the forked processes may be
49  // broken if either the parent or the child tries to close or duplicate
50  // these descriptors. The loop below produces two pairs of file
51  // descriptors, each greater than 2 (stderr).
52  int sock_pair[5][2];
53  for (int i = 0; i < 5; i++) {
54    if (pipe(sock_pair[i]) == -1) {
55      for (int j = 0; j < i; j++) {
56        internal_close(sock_pair[j][0]);
57        internal_close(sock_pair[j][1]);
58      }
59      Report("WARNING: Can't create a socket pair to start "
60             "external symbolizer (errno: %d)\n", errno);
61      return false;
62    } else if (sock_pair[i][0] > 2 && sock_pair[i][1] > 2) {
63      if (infd == NULL) {
64        infd = sock_pair[i];
65      } else {
66        outfd = sock_pair[i];
67        for (int j = 0; j < i; j++) {
68          if (sock_pair[j] == infd) continue;
69          internal_close(sock_pair[j][0]);
70          internal_close(sock_pair[j][1]);
71        }
72        break;
73      }
74    }
75  }
76  CHECK(infd);
77  CHECK(outfd);
78
79  int pid = fork();
80  if (pid == -1) {
81    // Fork() failed.
82    internal_close(infd[0]);
83    internal_close(infd[1]);
84    internal_close(outfd[0]);
85    internal_close(outfd[1]);
86    Report("WARNING: failed to fork external symbolizer "
87           " (errno: %d)\n", errno);
88    return false;
89  } else if (pid == 0) {
90    // Child subprocess.
91    internal_close(STDOUT_FILENO);
92    internal_close(STDIN_FILENO);
93    internal_dup2(outfd[0], STDIN_FILENO);
94    internal_dup2(infd[1], STDOUT_FILENO);
95    internal_close(outfd[0]);
96    internal_close(outfd[1]);
97    internal_close(infd[0]);
98    internal_close(infd[1]);
99    for (int fd = getdtablesize(); fd > 2; fd--)
100      internal_close(fd);
101    execl(path_to_symbolizer, path_to_symbolizer, kSymbolizerArch, (char*)0);
102    internal__exit(1);
103  }
104
105  // Continue execution in parent process.
106  internal_close(outfd[0]);
107  internal_close(infd[1]);
108  *input_fd = infd[0];
109  *output_fd = outfd[1];
110
111  // Check that symbolizer subprocess started successfully.
112  int pid_status;
113  SleepForMillis(kSymbolizerStartupTimeMillis);
114  int exited_pid = waitpid(pid, &pid_status, WNOHANG);
115  if (exited_pid != 0) {
116    // Either waitpid failed, or child has already exited.
117    Report("WARNING: external symbolizer didn't start up correctly!\n");
118    return false;
119  }
120
121  return true;
122}
123
124
125}  // namespace __sanitizer
126
127#endif  // SANITIZER_POSIX
128