168d75effSDimitry Andric //===-- sanitizer_file.cpp -----------------------------------------------===// 268d75effSDimitry Andric // 368d75effSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 468d75effSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 568d75effSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 668d75effSDimitry Andric // 768d75effSDimitry Andric //===---------------------------------------------------------------------===// 868d75effSDimitry Andric // 968d75effSDimitry Andric // This file is shared between AddressSanitizer and ThreadSanitizer 1068d75effSDimitry Andric // run-time libraries. It defines filesystem-related interfaces. This 1168d75effSDimitry Andric // is separate from sanitizer_common.cpp so that it's simpler to disable 1268d75effSDimitry Andric // all the filesystem support code for a port that doesn't use it. 1368d75effSDimitry Andric // 1468d75effSDimitry Andric //===---------------------------------------------------------------------===// 1568d75effSDimitry Andric 1668d75effSDimitry Andric #include "sanitizer_platform.h" 1768d75effSDimitry Andric 1868d75effSDimitry Andric #if !SANITIZER_FUCHSIA 1968d75effSDimitry Andric 2068d75effSDimitry Andric #include "sanitizer_common.h" 2168d75effSDimitry Andric #include "sanitizer_file.h" 2268d75effSDimitry Andric 2368d75effSDimitry Andric namespace __sanitizer { 2468d75effSDimitry Andric 2568d75effSDimitry Andric void CatastrophicErrorWrite(const char *buffer, uptr length) { 2668d75effSDimitry Andric WriteToFile(kStderrFd, buffer, length); 2768d75effSDimitry Andric } 2868d75effSDimitry Andric 2968d75effSDimitry Andric StaticSpinMutex report_file_mu; 3068d75effSDimitry Andric ReportFile report_file = {&report_file_mu, kStderrFd, "", "", 0}; 3168d75effSDimitry Andric 3268d75effSDimitry Andric void RawWrite(const char *buffer) { 3368d75effSDimitry Andric report_file.Write(buffer, internal_strlen(buffer)); 3468d75effSDimitry Andric } 3568d75effSDimitry Andric 3668d75effSDimitry Andric void ReportFile::ReopenIfNecessary() { 3768d75effSDimitry Andric mu->CheckLocked(); 3868d75effSDimitry Andric if (fd == kStdoutFd || fd == kStderrFd) return; 3968d75effSDimitry Andric 4068d75effSDimitry Andric uptr pid = internal_getpid(); 4168d75effSDimitry Andric // If in tracer, use the parent's file. 4268d75effSDimitry Andric if (pid == stoptheworld_tracer_pid) 4368d75effSDimitry Andric pid = stoptheworld_tracer_ppid; 4468d75effSDimitry Andric if (fd != kInvalidFd) { 4568d75effSDimitry Andric // If the report file is already opened by the current process, 4668d75effSDimitry Andric // do nothing. Otherwise the report file was opened by the parent 4768d75effSDimitry Andric // process, close it now. 4868d75effSDimitry Andric if (fd_pid == pid) 4968d75effSDimitry Andric return; 5068d75effSDimitry Andric else 5168d75effSDimitry Andric CloseFile(fd); 5268d75effSDimitry Andric } 5368d75effSDimitry Andric 5468d75effSDimitry Andric const char *exe_name = GetProcessName(); 5568d75effSDimitry Andric if (common_flags()->log_exe_name && exe_name) { 5668d75effSDimitry Andric internal_snprintf(full_path, kMaxPathLength, "%s.%s.%zu", path_prefix, 5768d75effSDimitry Andric exe_name, pid); 5868d75effSDimitry Andric } else { 5968d75effSDimitry Andric internal_snprintf(full_path, kMaxPathLength, "%s.%zu", path_prefix, pid); 6068d75effSDimitry Andric } 61fe6060f1SDimitry Andric if (common_flags()->log_suffix) { 62fe6060f1SDimitry Andric internal_strlcat(full_path, common_flags()->log_suffix, kMaxPathLength); 63fe6060f1SDimitry Andric } 64e8d8bef9SDimitry Andric error_t err; 65e8d8bef9SDimitry Andric fd = OpenFile(full_path, WrOnly, &err); 6668d75effSDimitry Andric if (fd == kInvalidFd) { 6768d75effSDimitry Andric const char *ErrorMsgPrefix = "ERROR: Can't open file: "; 6868d75effSDimitry Andric WriteToFile(kStderrFd, ErrorMsgPrefix, internal_strlen(ErrorMsgPrefix)); 6968d75effSDimitry Andric WriteToFile(kStderrFd, full_path, internal_strlen(full_path)); 70e8d8bef9SDimitry Andric char errmsg[100]; 71e8d8bef9SDimitry Andric internal_snprintf(errmsg, sizeof(errmsg), " (reason: %d)", err); 72e8d8bef9SDimitry Andric WriteToFile(kStderrFd, errmsg, internal_strlen(errmsg)); 7368d75effSDimitry Andric Die(); 7468d75effSDimitry Andric } 7568d75effSDimitry Andric fd_pid = pid; 7668d75effSDimitry Andric } 7768d75effSDimitry Andric 78*349cc55cSDimitry Andric static void RecursiveCreateParentDirs(char *path) { 79*349cc55cSDimitry Andric if (path[0] == '\0') 80*349cc55cSDimitry Andric return; 81*349cc55cSDimitry Andric for (int i = 1; path[i] != '\0'; ++i) { 82*349cc55cSDimitry Andric char save = path[i]; 83*349cc55cSDimitry Andric if (!IsPathSeparator(path[i])) 84*349cc55cSDimitry Andric continue; 85*349cc55cSDimitry Andric path[i] = '\0'; 86*349cc55cSDimitry Andric /* Some of these will fail, because the directory exists, ignore it. */ 87*349cc55cSDimitry Andric CreateDir(path); 88*349cc55cSDimitry Andric path[i] = save; 89*349cc55cSDimitry Andric } 90*349cc55cSDimitry Andric } 91*349cc55cSDimitry Andric 9268d75effSDimitry Andric void ReportFile::SetReportPath(const char *path) { 93e8d8bef9SDimitry Andric if (path) { 9468d75effSDimitry Andric uptr len = internal_strlen(path); 9568d75effSDimitry Andric if (len > sizeof(path_prefix) - 100) { 96e8d8bef9SDimitry Andric Report("ERROR: Path is too long: %c%c%c%c%c%c%c%c...\n", path[0], path[1], 97e8d8bef9SDimitry Andric path[2], path[3], path[4], path[5], path[6], path[7]); 9868d75effSDimitry Andric Die(); 9968d75effSDimitry Andric } 100e8d8bef9SDimitry Andric } 10168d75effSDimitry Andric 10268d75effSDimitry Andric SpinMutexLock l(mu); 10368d75effSDimitry Andric if (fd != kStdoutFd && fd != kStderrFd && fd != kInvalidFd) 10468d75effSDimitry Andric CloseFile(fd); 10568d75effSDimitry Andric fd = kInvalidFd; 106e8d8bef9SDimitry Andric if (!path || internal_strcmp(path, "stderr") == 0) { 10768d75effSDimitry Andric fd = kStderrFd; 108e8d8bef9SDimitry Andric } else if (internal_strcmp(path, "stdout") == 0) { 109e8d8bef9SDimitry Andric fd = kStdoutFd; 11068d75effSDimitry Andric } else { 11168d75effSDimitry Andric internal_snprintf(path_prefix, kMaxPathLength, "%s", path); 112*349cc55cSDimitry Andric RecursiveCreateParentDirs(path_prefix); 11368d75effSDimitry Andric } 11468d75effSDimitry Andric } 11568d75effSDimitry Andric 116e8d8bef9SDimitry Andric const char *ReportFile::GetReportPath() { 117e8d8bef9SDimitry Andric SpinMutexLock l(mu); 118e8d8bef9SDimitry Andric ReopenIfNecessary(); 119e8d8bef9SDimitry Andric return full_path; 120e8d8bef9SDimitry Andric } 121e8d8bef9SDimitry Andric 12268d75effSDimitry Andric bool ReadFileToBuffer(const char *file_name, char **buff, uptr *buff_size, 12368d75effSDimitry Andric uptr *read_len, uptr max_len, error_t *errno_p) { 12468d75effSDimitry Andric *buff = nullptr; 12568d75effSDimitry Andric *buff_size = 0; 12668d75effSDimitry Andric *read_len = 0; 12768d75effSDimitry Andric if (!max_len) 12868d75effSDimitry Andric return true; 12968d75effSDimitry Andric uptr PageSize = GetPageSizeCached(); 13068d75effSDimitry Andric uptr kMinFileLen = Min(PageSize, max_len); 13168d75effSDimitry Andric 13268d75effSDimitry Andric // The files we usually open are not seekable, so try different buffer sizes. 13368d75effSDimitry Andric for (uptr size = kMinFileLen;; size = Min(size * 2, max_len)) { 13468d75effSDimitry Andric UnmapOrDie(*buff, *buff_size); 13568d75effSDimitry Andric *buff = (char*)MmapOrDie(size, __func__); 13668d75effSDimitry Andric *buff_size = size; 13768d75effSDimitry Andric fd_t fd = OpenFile(file_name, RdOnly, errno_p); 13868d75effSDimitry Andric if (fd == kInvalidFd) { 13968d75effSDimitry Andric UnmapOrDie(*buff, *buff_size); 14068d75effSDimitry Andric return false; 14168d75effSDimitry Andric } 14268d75effSDimitry Andric *read_len = 0; 14368d75effSDimitry Andric // Read up to one page at a time. 14468d75effSDimitry Andric bool reached_eof = false; 14568d75effSDimitry Andric while (*read_len < size) { 14668d75effSDimitry Andric uptr just_read; 14768d75effSDimitry Andric if (!ReadFromFile(fd, *buff + *read_len, size - *read_len, &just_read, 14868d75effSDimitry Andric errno_p)) { 14968d75effSDimitry Andric UnmapOrDie(*buff, *buff_size); 15068d75effSDimitry Andric CloseFile(fd); 15168d75effSDimitry Andric return false; 15268d75effSDimitry Andric } 15368d75effSDimitry Andric *read_len += just_read; 15468d75effSDimitry Andric if (just_read == 0 || *read_len == max_len) { 15568d75effSDimitry Andric reached_eof = true; 15668d75effSDimitry Andric break; 15768d75effSDimitry Andric } 15868d75effSDimitry Andric } 15968d75effSDimitry Andric CloseFile(fd); 16068d75effSDimitry Andric if (reached_eof) // We've read the whole file. 16168d75effSDimitry Andric break; 16268d75effSDimitry Andric } 16368d75effSDimitry Andric return true; 16468d75effSDimitry Andric } 16568d75effSDimitry Andric 16668d75effSDimitry Andric bool ReadFileToVector(const char *file_name, 16768d75effSDimitry Andric InternalMmapVectorNoCtor<char> *buff, uptr max_len, 16868d75effSDimitry Andric error_t *errno_p) { 16968d75effSDimitry Andric buff->clear(); 17068d75effSDimitry Andric if (!max_len) 17168d75effSDimitry Andric return true; 17268d75effSDimitry Andric uptr PageSize = GetPageSizeCached(); 17368d75effSDimitry Andric fd_t fd = OpenFile(file_name, RdOnly, errno_p); 17468d75effSDimitry Andric if (fd == kInvalidFd) 17568d75effSDimitry Andric return false; 17668d75effSDimitry Andric uptr read_len = 0; 17768d75effSDimitry Andric while (read_len < max_len) { 17868d75effSDimitry Andric if (read_len >= buff->size()) 17968d75effSDimitry Andric buff->resize(Min(Max(PageSize, read_len * 2), max_len)); 18068d75effSDimitry Andric CHECK_LT(read_len, buff->size()); 18168d75effSDimitry Andric CHECK_LE(buff->size(), max_len); 18268d75effSDimitry Andric uptr just_read; 18368d75effSDimitry Andric if (!ReadFromFile(fd, buff->data() + read_len, buff->size() - read_len, 18468d75effSDimitry Andric &just_read, errno_p)) { 18568d75effSDimitry Andric CloseFile(fd); 18668d75effSDimitry Andric return false; 18768d75effSDimitry Andric } 18868d75effSDimitry Andric read_len += just_read; 18968d75effSDimitry Andric if (!just_read) 19068d75effSDimitry Andric break; 19168d75effSDimitry Andric } 19268d75effSDimitry Andric CloseFile(fd); 19368d75effSDimitry Andric buff->resize(read_len); 19468d75effSDimitry Andric return true; 19568d75effSDimitry Andric } 19668d75effSDimitry Andric 19768d75effSDimitry Andric static const char kPathSeparator = SANITIZER_WINDOWS ? ';' : ':'; 19868d75effSDimitry Andric 19968d75effSDimitry Andric char *FindPathToBinary(const char *name) { 20068d75effSDimitry Andric if (FileExists(name)) { 20168d75effSDimitry Andric return internal_strdup(name); 20268d75effSDimitry Andric } 20368d75effSDimitry Andric 20468d75effSDimitry Andric const char *path = GetEnv("PATH"); 20568d75effSDimitry Andric if (!path) 20668d75effSDimitry Andric return nullptr; 20768d75effSDimitry Andric uptr name_len = internal_strlen(name); 20868d75effSDimitry Andric InternalMmapVector<char> buffer(kMaxPathLength); 20968d75effSDimitry Andric const char *beg = path; 21068d75effSDimitry Andric while (true) { 21168d75effSDimitry Andric const char *end = internal_strchrnul(beg, kPathSeparator); 21268d75effSDimitry Andric uptr prefix_len = end - beg; 21368d75effSDimitry Andric if (prefix_len + name_len + 2 <= kMaxPathLength) { 21468d75effSDimitry Andric internal_memcpy(buffer.data(), beg, prefix_len); 21568d75effSDimitry Andric buffer[prefix_len] = '/'; 21668d75effSDimitry Andric internal_memcpy(&buffer[prefix_len + 1], name, name_len); 21768d75effSDimitry Andric buffer[prefix_len + 1 + name_len] = '\0'; 21868d75effSDimitry Andric if (FileExists(buffer.data())) 21968d75effSDimitry Andric return internal_strdup(buffer.data()); 22068d75effSDimitry Andric } 22168d75effSDimitry Andric if (*end == '\0') break; 22268d75effSDimitry Andric beg = end + 1; 22368d75effSDimitry Andric } 22468d75effSDimitry Andric return nullptr; 22568d75effSDimitry Andric } 22668d75effSDimitry Andric 22768d75effSDimitry Andric } // namespace __sanitizer 22868d75effSDimitry Andric 22968d75effSDimitry Andric using namespace __sanitizer; 23068d75effSDimitry Andric 23168d75effSDimitry Andric extern "C" { 23268d75effSDimitry Andric void __sanitizer_set_report_path(const char *path) { 23368d75effSDimitry Andric report_file.SetReportPath(path); 23468d75effSDimitry Andric } 23568d75effSDimitry Andric 23668d75effSDimitry Andric void __sanitizer_set_report_fd(void *fd) { 23768d75effSDimitry Andric report_file.fd = (fd_t)reinterpret_cast<uptr>(fd); 23868d75effSDimitry Andric report_file.fd_pid = internal_getpid(); 23968d75effSDimitry Andric } 240e8d8bef9SDimitry Andric 241e8d8bef9SDimitry Andric const char *__sanitizer_get_report_path() { 242e8d8bef9SDimitry Andric return report_file.GetReportPath(); 243e8d8bef9SDimitry Andric } 24468d75effSDimitry Andric } // extern "C" 24568d75effSDimitry Andric 24668d75effSDimitry Andric #endif // !SANITIZER_FUCHSIA 247