Vitaly Buka | d4abe9e | 2017-07-22 01:46:40 +0000 | [diff] [blame] | 1 | //===-- sanitizer_file.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. It defines filesystem-related interfaces. This |
| 12 | // is separate from sanitizer_common.cc so that it's simpler to disable |
| 13 | // all the filesystem support code for a port that doesn't use it. |
| 14 | // |
| 15 | //===---------------------------------------------------------------------===// |
| 16 | |
Vitaly Buka | 51ca757 | 2017-08-01 21:28:39 +0000 | [diff] [blame] | 17 | #include "sanitizer_platform.h" |
| 18 | |
| 19 | #if !SANITIZER_FUCHSIA |
| 20 | |
Vitaly Buka | d4abe9e | 2017-07-22 01:46:40 +0000 | [diff] [blame] | 21 | #include "sanitizer_common.h" |
| 22 | #include "sanitizer_file.h" |
| 23 | |
| 24 | namespace __sanitizer { |
| 25 | |
| 26 | void CatastrophicErrorWrite(const char *buffer, uptr length) { |
| 27 | WriteToFile(kStderrFd, buffer, length); |
| 28 | } |
| 29 | |
| 30 | StaticSpinMutex report_file_mu; |
| 31 | ReportFile report_file = {&report_file_mu, kStderrFd, "", "", 0}; |
| 32 | |
| 33 | void RawWrite(const char *buffer) { |
| 34 | report_file.Write(buffer, internal_strlen(buffer)); |
| 35 | } |
| 36 | |
| 37 | void ReportFile::ReopenIfNecessary() { |
| 38 | mu->CheckLocked(); |
| 39 | if (fd == kStdoutFd || fd == kStderrFd) return; |
| 40 | |
| 41 | uptr pid = internal_getpid(); |
| 42 | // If in tracer, use the parent's file. |
| 43 | if (pid == stoptheworld_tracer_pid) |
| 44 | pid = stoptheworld_tracer_ppid; |
| 45 | if (fd != kInvalidFd) { |
| 46 | // If the report file is already opened by the current process, |
| 47 | // do nothing. Otherwise the report file was opened by the parent |
| 48 | // process, close it now. |
| 49 | if (fd_pid == pid) |
| 50 | return; |
| 51 | else |
| 52 | CloseFile(fd); |
| 53 | } |
| 54 | |
| 55 | const char *exe_name = GetProcessName(); |
| 56 | if (common_flags()->log_exe_name && exe_name) { |
| 57 | internal_snprintf(full_path, kMaxPathLength, "%s.%s.%zu", path_prefix, |
| 58 | exe_name, pid); |
| 59 | } else { |
| 60 | internal_snprintf(full_path, kMaxPathLength, "%s.%zu", path_prefix, pid); |
| 61 | } |
| 62 | fd = OpenFile(full_path, WrOnly); |
| 63 | if (fd == kInvalidFd) { |
| 64 | const char *ErrorMsgPrefix = "ERROR: Can't open file: "; |
| 65 | WriteToFile(kStderrFd, ErrorMsgPrefix, internal_strlen(ErrorMsgPrefix)); |
| 66 | WriteToFile(kStderrFd, full_path, internal_strlen(full_path)); |
| 67 | Die(); |
| 68 | } |
| 69 | fd_pid = pid; |
| 70 | } |
| 71 | |
| 72 | void ReportFile::SetReportPath(const char *path) { |
| 73 | if (!path) |
| 74 | return; |
| 75 | uptr len = internal_strlen(path); |
| 76 | if (len > sizeof(path_prefix) - 100) { |
| 77 | Report("ERROR: Path is too long: %c%c%c%c%c%c%c%c...\n", |
| 78 | path[0], path[1], path[2], path[3], |
| 79 | path[4], path[5], path[6], path[7]); |
| 80 | Die(); |
| 81 | } |
| 82 | |
| 83 | SpinMutexLock l(mu); |
| 84 | if (fd != kStdoutFd && fd != kStderrFd && fd != kInvalidFd) |
| 85 | CloseFile(fd); |
| 86 | fd = kInvalidFd; |
| 87 | if (internal_strcmp(path, "stdout") == 0) { |
| 88 | fd = kStdoutFd; |
| 89 | } else if (internal_strcmp(path, "stderr") == 0) { |
| 90 | fd = kStderrFd; |
| 91 | } else { |
| 92 | internal_snprintf(path_prefix, kMaxPathLength, "%s", path); |
| 93 | } |
| 94 | } |
| 95 | |
| 96 | bool ReadFileToBuffer(const char *file_name, char **buff, uptr *buff_size, |
| 97 | uptr *read_len, uptr max_len, error_t *errno_p) { |
Vitaly Buka | d4abe9e | 2017-07-22 01:46:40 +0000 | [diff] [blame] | 98 | *buff = nullptr; |
| 99 | *buff_size = 0; |
| 100 | *read_len = 0; |
Vitaly Buka | 4ef9117 | 2018-06-06 20:53:43 +0000 | [diff] [blame] | 101 | if (!max_len) |
| 102 | return true; |
| 103 | uptr PageSize = GetPageSizeCached(); |
| 104 | uptr kMinFileLen = Min(PageSize, max_len); |
| 105 | |
Vitaly Buka | d4abe9e | 2017-07-22 01:46:40 +0000 | [diff] [blame] | 106 | // The files we usually open are not seekable, so try different buffer sizes. |
Vitaly Buka | 4ef9117 | 2018-06-06 20:53:43 +0000 | [diff] [blame] | 107 | for (uptr size = kMinFileLen;; size = Min(size * 2, max_len)) { |
Vitaly Buka | d4abe9e | 2017-07-22 01:46:40 +0000 | [diff] [blame] | 108 | UnmapOrDie(*buff, *buff_size); |
| 109 | *buff = (char*)MmapOrDie(size, __func__); |
| 110 | *buff_size = size; |
Vitaly Buka | 6b13684 | 2018-05-08 18:32:53 +0000 | [diff] [blame] | 111 | fd_t fd = OpenFile(file_name, RdOnly, errno_p); |
Vitaly Buka | 4ef9117 | 2018-06-06 20:53:43 +0000 | [diff] [blame] | 112 | if (fd == kInvalidFd) { |
| 113 | UnmapOrDie(*buff, *buff_size); |
Vitaly Buka | 6b13684 | 2018-05-08 18:32:53 +0000 | [diff] [blame] | 114 | return false; |
Vitaly Buka | 4ef9117 | 2018-06-06 20:53:43 +0000 | [diff] [blame] | 115 | } |
Vitaly Buka | d4abe9e | 2017-07-22 01:46:40 +0000 | [diff] [blame] | 116 | *read_len = 0; |
| 117 | // Read up to one page at a time. |
| 118 | bool reached_eof = false; |
Vitaly Buka | 4ef9117 | 2018-06-06 20:53:43 +0000 | [diff] [blame] | 119 | while (*read_len < size) { |
Vitaly Buka | d4abe9e | 2017-07-22 01:46:40 +0000 | [diff] [blame] | 120 | uptr just_read; |
Vitaly Buka | 4ef9117 | 2018-06-06 20:53:43 +0000 | [diff] [blame] | 121 | if (!ReadFromFile(fd, *buff + *read_len, size - *read_len, &just_read, |
| 122 | errno_p)) { |
Vitaly Buka | d4abe9e | 2017-07-22 01:46:40 +0000 | [diff] [blame] | 123 | UnmapOrDie(*buff, *buff_size); |
Vitaly Buka | 6b13684 | 2018-05-08 18:32:53 +0000 | [diff] [blame] | 124 | CloseFile(fd); |
Vitaly Buka | d4abe9e | 2017-07-22 01:46:40 +0000 | [diff] [blame] | 125 | return false; |
| 126 | } |
Vitaly Buka | 4ef9117 | 2018-06-06 20:53:43 +0000 | [diff] [blame] | 127 | *read_len += just_read; |
| 128 | if (just_read == 0 || *read_len == max_len) { |
Vitaly Buka | d4abe9e | 2017-07-22 01:46:40 +0000 | [diff] [blame] | 129 | reached_eof = true; |
| 130 | break; |
| 131 | } |
Vitaly Buka | d4abe9e | 2017-07-22 01:46:40 +0000 | [diff] [blame] | 132 | } |
| 133 | CloseFile(fd); |
| 134 | if (reached_eof) // We've read the whole file. |
| 135 | break; |
| 136 | } |
| 137 | return true; |
| 138 | } |
| 139 | |
Vitaly Buka | 4ef9117 | 2018-06-06 20:53:43 +0000 | [diff] [blame] | 140 | bool ReadFileToVector(const char *file_name, |
Vitaly Buka | e21fbe5 | 2018-05-08 18:35:11 +0000 | [diff] [blame] | 141 | InternalMmapVectorNoCtor<char> *buff, uptr max_len, |
| 142 | error_t *errno_p) { |
Vitaly Buka | e21fbe5 | 2018-05-08 18:35:11 +0000 | [diff] [blame] | 143 | buff->clear(); |
Vitaly Buka | 4ef9117 | 2018-06-06 20:53:43 +0000 | [diff] [blame] | 144 | if (!max_len) |
| 145 | return true; |
| 146 | uptr PageSize = GetPageSizeCached(); |
| 147 | fd_t fd = OpenFile(file_name, RdOnly, errno_p); |
| 148 | if (fd == kInvalidFd) |
| 149 | return false; |
| 150 | uptr read_len = 0; |
| 151 | while (read_len < max_len) { |
| 152 | if (read_len >= buff->size()) |
| 153 | buff->resize(Min(Max(PageSize, read_len * 2), max_len)); |
| 154 | CHECK_LT(read_len, buff->size()); |
| 155 | CHECK_LE(buff->size(), max_len); |
| 156 | uptr just_read; |
| 157 | if (!ReadFromFile(fd, buff->data() + read_len, buff->size() - read_len, |
| 158 | &just_read, errno_p)) { |
| 159 | CloseFile(fd); |
Vitaly Buka | e21fbe5 | 2018-05-08 18:35:11 +0000 | [diff] [blame] | 160 | return false; |
Vitaly Buka | e21fbe5 | 2018-05-08 18:35:11 +0000 | [diff] [blame] | 161 | } |
Vitaly Buka | 4ef9117 | 2018-06-06 20:53:43 +0000 | [diff] [blame] | 162 | read_len += just_read; |
| 163 | if (!just_read) |
Vitaly Buka | e21fbe5 | 2018-05-08 18:35:11 +0000 | [diff] [blame] | 164 | break; |
Vitaly Buka | e21fbe5 | 2018-05-08 18:35:11 +0000 | [diff] [blame] | 165 | } |
Vitaly Buka | 4ef9117 | 2018-06-06 20:53:43 +0000 | [diff] [blame] | 166 | CloseFile(fd); |
| 167 | buff->resize(read_len); |
Vitaly Buka | e21fbe5 | 2018-05-08 18:35:11 +0000 | [diff] [blame] | 168 | return true; |
| 169 | } |
| 170 | |
Vitaly Buka | d4abe9e | 2017-07-22 01:46:40 +0000 | [diff] [blame] | 171 | static const char kPathSeparator = SANITIZER_WINDOWS ? ';' : ':'; |
| 172 | |
| 173 | char *FindPathToBinary(const char *name) { |
| 174 | if (FileExists(name)) { |
| 175 | return internal_strdup(name); |
| 176 | } |
| 177 | |
| 178 | const char *path = GetEnv("PATH"); |
| 179 | if (!path) |
| 180 | return nullptr; |
| 181 | uptr name_len = internal_strlen(name); |
Vitaly Buka | 2a20955 | 2018-05-07 05:56:36 +0000 | [diff] [blame] | 182 | InternalMmapVector<char> buffer(kMaxPathLength); |
Vitaly Buka | d4abe9e | 2017-07-22 01:46:40 +0000 | [diff] [blame] | 183 | const char *beg = path; |
| 184 | while (true) { |
| 185 | const char *end = internal_strchrnul(beg, kPathSeparator); |
| 186 | uptr prefix_len = end - beg; |
| 187 | if (prefix_len + name_len + 2 <= kMaxPathLength) { |
| 188 | internal_memcpy(buffer.data(), beg, prefix_len); |
| 189 | buffer[prefix_len] = '/'; |
| 190 | internal_memcpy(&buffer[prefix_len + 1], name, name_len); |
| 191 | buffer[prefix_len + 1 + name_len] = '\0'; |
| 192 | if (FileExists(buffer.data())) |
| 193 | return internal_strdup(buffer.data()); |
| 194 | } |
| 195 | if (*end == '\0') break; |
| 196 | beg = end + 1; |
| 197 | } |
| 198 | return nullptr; |
| 199 | } |
| 200 | |
| 201 | } // namespace __sanitizer |
| 202 | |
| 203 | using namespace __sanitizer; // NOLINT |
| 204 | |
| 205 | extern "C" { |
| 206 | void __sanitizer_set_report_path(const char *path) { |
| 207 | report_file.SetReportPath(path); |
| 208 | } |
| 209 | |
| 210 | void __sanitizer_set_report_fd(void *fd) { |
| 211 | report_file.fd = (fd_t)reinterpret_cast<uptr>(fd); |
| 212 | report_file.fd_pid = internal_getpid(); |
| 213 | } |
| 214 | } // extern "C" |
Vitaly Buka | 51ca757 | 2017-08-01 21:28:39 +0000 | [diff] [blame] | 215 | |
| 216 | #endif // !SANITIZER_FUCHSIA |