sanitizer_symbolizer_posix_libcdep.cc revision ff0ce7fbdba7d02dd06bbb1ba1003c50355513df
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
27bool StartSymbolizerSubprocess(const char *path_to_symbolizer,
28                               int *input_fd, int *output_fd) {
29  if (!FileExists(path_to_symbolizer)) {
30    Report("WARNING: invalid path to external symbolizer!\n");
31    return false;
32  }
33
34  int *infd = NULL;
35  int *outfd = NULL;
36  // The client program may close its stdin and/or stdout and/or stderr
37  // thus allowing socketpair to reuse file descriptors 0, 1 or 2.
38  // In this case the communication between the forked processes may be
39  // broken if either the parent or the child tries to close or duplicate
40  // these descriptors. The loop below produces two pairs of file
41  // descriptors, each greater than 2 (stderr).
42  int sock_pair[5][2];
43  for (int i = 0; i < 5; i++) {
44    if (pipe(sock_pair[i]) == -1) {
45      for (int j = 0; j < i; j++) {
46        internal_close(sock_pair[j][0]);
47        internal_close(sock_pair[j][1]);
48      }
49      Report("WARNING: Can't create a socket pair to start "
50             "external symbolizer (errno: %d)\n", errno);
51      return false;
52    } else if (sock_pair[i][0] > 2 && sock_pair[i][1] > 2) {
53      if (infd == NULL) {
54        infd = sock_pair[i];
55      } else {
56        outfd = sock_pair[i];
57        for (int j = 0; j < i; j++) {
58          if (sock_pair[j] == infd) continue;
59          internal_close(sock_pair[j][0]);
60          internal_close(sock_pair[j][1]);
61        }
62        break;
63      }
64    }
65  }
66  CHECK(infd);
67  CHECK(outfd);
68
69  int pid = fork();
70  if (pid == -1) {
71    // Fork() failed.
72    internal_close(infd[0]);
73    internal_close(infd[1]);
74    internal_close(outfd[0]);
75    internal_close(outfd[1]);
76    Report("WARNING: failed to fork external symbolizer "
77           " (errno: %d)\n", errno);
78    return false;
79  } else if (pid == 0) {
80    // Child subprocess.
81    internal_close(STDOUT_FILENO);
82    internal_close(STDIN_FILENO);
83    internal_dup2(outfd[0], STDIN_FILENO);
84    internal_dup2(infd[1], STDOUT_FILENO);
85    internal_close(outfd[0]);
86    internal_close(outfd[1]);
87    internal_close(infd[0]);
88    internal_close(infd[1]);
89    for (int fd = getdtablesize(); fd > 2; fd--)
90      internal_close(fd);
91    execl(path_to_symbolizer, path_to_symbolizer, (char*)0);
92    internal__exit(1);
93  }
94
95  // Continue execution in parent process.
96  internal_close(outfd[0]);
97  internal_close(infd[1]);
98  *input_fd = infd[0];
99  *output_fd = outfd[1];
100
101  // Check that symbolizer subprocess started successfully.
102  int pid_status;
103  SleepForMillis(kSymbolizerStartupTimeMillis);
104  int exited_pid = waitpid(pid, &pid_status, WNOHANG);
105  if (exited_pid != 0) {
106    // Either waitpid failed, or child has already exited.
107    Report("WARNING: external symbolizer didn't start up correctly!\n");
108    return false;
109  }
110
111  return true;
112}
113
114
115}  // namespace __sanitizer
116
117#endif  // SANITIZER_POSIX
118