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