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