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" 2281ad6265SDimitry Andric # include "sanitizer_interface_internal.h" 2368d75effSDimitry Andric 2468d75effSDimitry Andric namespace __sanitizer { 2568d75effSDimitry Andric 2668d75effSDimitry Andric void CatastrophicErrorWrite(const char *buffer, uptr length) { 2768d75effSDimitry Andric WriteToFile(kStderrFd, buffer, length); 2868d75effSDimitry Andric } 2968d75effSDimitry Andric 3068d75effSDimitry Andric StaticSpinMutex report_file_mu; 3168d75effSDimitry Andric ReportFile report_file = {&report_file_mu, kStderrFd, "", "", 0}; 3268d75effSDimitry Andric 3368d75effSDimitry Andric void RawWrite(const char *buffer) { 3468d75effSDimitry Andric report_file.Write(buffer, internal_strlen(buffer)); 3568d75effSDimitry Andric } 3668d75effSDimitry Andric 3768d75effSDimitry Andric void ReportFile::ReopenIfNecessary() { 3868d75effSDimitry Andric mu->CheckLocked(); 3968d75effSDimitry Andric if (fd == kStdoutFd || fd == kStderrFd) return; 4068d75effSDimitry Andric 4168d75effSDimitry Andric uptr pid = internal_getpid(); 4268d75effSDimitry Andric // If in tracer, use the parent's file. 4368d75effSDimitry Andric if (pid == stoptheworld_tracer_pid) 4468d75effSDimitry Andric pid = stoptheworld_tracer_ppid; 4568d75effSDimitry Andric if (fd != kInvalidFd) { 4668d75effSDimitry Andric // If the report file is already opened by the current process, 4768d75effSDimitry Andric // do nothing. Otherwise the report file was opened by the parent 4868d75effSDimitry Andric // process, close it now. 4968d75effSDimitry Andric if (fd_pid == pid) 5068d75effSDimitry Andric return; 5168d75effSDimitry Andric else 5268d75effSDimitry Andric CloseFile(fd); 5368d75effSDimitry Andric } 5468d75effSDimitry Andric 5568d75effSDimitry Andric const char *exe_name = GetProcessName(); 5668d75effSDimitry Andric if (common_flags()->log_exe_name && exe_name) { 5768d75effSDimitry Andric internal_snprintf(full_path, kMaxPathLength, "%s.%s.%zu", path_prefix, 5868d75effSDimitry Andric exe_name, pid); 5968d75effSDimitry Andric } else { 6068d75effSDimitry Andric internal_snprintf(full_path, kMaxPathLength, "%s.%zu", path_prefix, pid); 6168d75effSDimitry Andric } 62fe6060f1SDimitry Andric if (common_flags()->log_suffix) { 63fe6060f1SDimitry Andric internal_strlcat(full_path, common_flags()->log_suffix, kMaxPathLength); 64fe6060f1SDimitry Andric } 65e8d8bef9SDimitry Andric error_t err; 66e8d8bef9SDimitry Andric fd = OpenFile(full_path, WrOnly, &err); 6768d75effSDimitry Andric if (fd == kInvalidFd) { 6868d75effSDimitry Andric const char *ErrorMsgPrefix = "ERROR: Can't open file: "; 6968d75effSDimitry Andric WriteToFile(kStderrFd, ErrorMsgPrefix, internal_strlen(ErrorMsgPrefix)); 7068d75effSDimitry Andric WriteToFile(kStderrFd, full_path, internal_strlen(full_path)); 71e8d8bef9SDimitry Andric char errmsg[100]; 72*0fca6ea1SDimitry Andric internal_snprintf(errmsg, sizeof(errmsg), " (reason: %d)\n", err); 73e8d8bef9SDimitry Andric WriteToFile(kStderrFd, errmsg, internal_strlen(errmsg)); 7468d75effSDimitry Andric Die(); 7568d75effSDimitry Andric } 7668d75effSDimitry Andric fd_pid = pid; 7768d75effSDimitry Andric } 7868d75effSDimitry Andric 79349cc55cSDimitry Andric static void RecursiveCreateParentDirs(char *path) { 80349cc55cSDimitry Andric if (path[0] == '\0') 81349cc55cSDimitry Andric return; 82349cc55cSDimitry Andric for (int i = 1; path[i] != '\0'; ++i) { 83349cc55cSDimitry Andric char save = path[i]; 84349cc55cSDimitry Andric if (!IsPathSeparator(path[i])) 85349cc55cSDimitry Andric continue; 86349cc55cSDimitry Andric path[i] = '\0'; 8781ad6265SDimitry Andric if (!DirExists(path) && !CreateDir(path)) { 8881ad6265SDimitry Andric const char *ErrorMsgPrefix = "ERROR: Can't create directory: "; 8981ad6265SDimitry Andric WriteToFile(kStderrFd, ErrorMsgPrefix, internal_strlen(ErrorMsgPrefix)); 9081ad6265SDimitry Andric WriteToFile(kStderrFd, path, internal_strlen(path)); 91*0fca6ea1SDimitry Andric const char *ErrorMsgSuffix = "\n"; 92*0fca6ea1SDimitry Andric WriteToFile(kStderrFd, ErrorMsgSuffix, internal_strlen(ErrorMsgSuffix)); 9381ad6265SDimitry Andric Die(); 9481ad6265SDimitry Andric } 95349cc55cSDimitry Andric path[i] = save; 96349cc55cSDimitry Andric } 97349cc55cSDimitry Andric } 98349cc55cSDimitry Andric 9968d75effSDimitry Andric void ReportFile::SetReportPath(const char *path) { 100e8d8bef9SDimitry Andric if (path) { 10168d75effSDimitry Andric uptr len = internal_strlen(path); 10268d75effSDimitry Andric if (len > sizeof(path_prefix) - 100) { 103e8d8bef9SDimitry Andric Report("ERROR: Path is too long: %c%c%c%c%c%c%c%c...\n", path[0], path[1], 104e8d8bef9SDimitry Andric path[2], path[3], path[4], path[5], path[6], path[7]); 10568d75effSDimitry Andric Die(); 10668d75effSDimitry Andric } 107e8d8bef9SDimitry Andric } 10868d75effSDimitry Andric 10968d75effSDimitry Andric SpinMutexLock l(mu); 11068d75effSDimitry Andric if (fd != kStdoutFd && fd != kStderrFd && fd != kInvalidFd) 11168d75effSDimitry Andric CloseFile(fd); 11268d75effSDimitry Andric fd = kInvalidFd; 113e8d8bef9SDimitry Andric if (!path || internal_strcmp(path, "stderr") == 0) { 11468d75effSDimitry Andric fd = kStderrFd; 115e8d8bef9SDimitry Andric } else if (internal_strcmp(path, "stdout") == 0) { 116e8d8bef9SDimitry Andric fd = kStdoutFd; 11768d75effSDimitry Andric } else { 11868d75effSDimitry Andric internal_snprintf(path_prefix, kMaxPathLength, "%s", path); 119349cc55cSDimitry Andric RecursiveCreateParentDirs(path_prefix); 12068d75effSDimitry Andric } 12168d75effSDimitry Andric } 12268d75effSDimitry Andric 123e8d8bef9SDimitry Andric const char *ReportFile::GetReportPath() { 124e8d8bef9SDimitry Andric SpinMutexLock l(mu); 125e8d8bef9SDimitry Andric ReopenIfNecessary(); 126e8d8bef9SDimitry Andric return full_path; 127e8d8bef9SDimitry Andric } 128e8d8bef9SDimitry Andric 12968d75effSDimitry Andric bool ReadFileToBuffer(const char *file_name, char **buff, uptr *buff_size, 13068d75effSDimitry Andric uptr *read_len, uptr max_len, error_t *errno_p) { 13168d75effSDimitry Andric *buff = nullptr; 13268d75effSDimitry Andric *buff_size = 0; 13368d75effSDimitry Andric *read_len = 0; 13468d75effSDimitry Andric if (!max_len) 13568d75effSDimitry Andric return true; 13668d75effSDimitry Andric uptr PageSize = GetPageSizeCached(); 13768d75effSDimitry Andric uptr kMinFileLen = Min(PageSize, max_len); 13868d75effSDimitry Andric 13968d75effSDimitry Andric // The files we usually open are not seekable, so try different buffer sizes. 14068d75effSDimitry Andric for (uptr size = kMinFileLen;; size = Min(size * 2, max_len)) { 14168d75effSDimitry Andric UnmapOrDie(*buff, *buff_size); 14268d75effSDimitry Andric *buff = (char*)MmapOrDie(size, __func__); 14368d75effSDimitry Andric *buff_size = size; 14468d75effSDimitry Andric fd_t fd = OpenFile(file_name, RdOnly, errno_p); 14568d75effSDimitry Andric if (fd == kInvalidFd) { 14668d75effSDimitry Andric UnmapOrDie(*buff, *buff_size); 14768d75effSDimitry Andric return false; 14868d75effSDimitry Andric } 14968d75effSDimitry Andric *read_len = 0; 15068d75effSDimitry Andric // Read up to one page at a time. 15168d75effSDimitry Andric bool reached_eof = false; 15268d75effSDimitry Andric while (*read_len < size) { 15368d75effSDimitry Andric uptr just_read; 15468d75effSDimitry Andric if (!ReadFromFile(fd, *buff + *read_len, size - *read_len, &just_read, 15568d75effSDimitry Andric errno_p)) { 15668d75effSDimitry Andric UnmapOrDie(*buff, *buff_size); 15768d75effSDimitry Andric CloseFile(fd); 15868d75effSDimitry Andric return false; 15968d75effSDimitry Andric } 16068d75effSDimitry Andric *read_len += just_read; 16168d75effSDimitry Andric if (just_read == 0 || *read_len == max_len) { 16268d75effSDimitry Andric reached_eof = true; 16368d75effSDimitry Andric break; 16468d75effSDimitry Andric } 16568d75effSDimitry Andric } 16668d75effSDimitry Andric CloseFile(fd); 16768d75effSDimitry Andric if (reached_eof) // We've read the whole file. 16868d75effSDimitry Andric break; 16968d75effSDimitry Andric } 17068d75effSDimitry Andric return true; 17168d75effSDimitry Andric } 17268d75effSDimitry Andric 17368d75effSDimitry Andric bool ReadFileToVector(const char *file_name, 17468d75effSDimitry Andric InternalMmapVectorNoCtor<char> *buff, uptr max_len, 17568d75effSDimitry Andric error_t *errno_p) { 17668d75effSDimitry Andric buff->clear(); 17768d75effSDimitry Andric if (!max_len) 17868d75effSDimitry Andric return true; 17968d75effSDimitry Andric uptr PageSize = GetPageSizeCached(); 18068d75effSDimitry Andric fd_t fd = OpenFile(file_name, RdOnly, errno_p); 18168d75effSDimitry Andric if (fd == kInvalidFd) 18268d75effSDimitry Andric return false; 18368d75effSDimitry Andric uptr read_len = 0; 18468d75effSDimitry Andric while (read_len < max_len) { 18568d75effSDimitry Andric if (read_len >= buff->size()) 18668d75effSDimitry Andric buff->resize(Min(Max(PageSize, read_len * 2), max_len)); 18768d75effSDimitry Andric CHECK_LT(read_len, buff->size()); 18868d75effSDimitry Andric CHECK_LE(buff->size(), max_len); 18968d75effSDimitry Andric uptr just_read; 19068d75effSDimitry Andric if (!ReadFromFile(fd, buff->data() + read_len, buff->size() - read_len, 19168d75effSDimitry Andric &just_read, errno_p)) { 19268d75effSDimitry Andric CloseFile(fd); 19368d75effSDimitry Andric return false; 19468d75effSDimitry Andric } 19568d75effSDimitry Andric read_len += just_read; 19668d75effSDimitry Andric if (!just_read) 19768d75effSDimitry Andric break; 19868d75effSDimitry Andric } 19968d75effSDimitry Andric CloseFile(fd); 20068d75effSDimitry Andric buff->resize(read_len); 20168d75effSDimitry Andric return true; 20268d75effSDimitry Andric } 20368d75effSDimitry Andric 20468d75effSDimitry Andric static const char kPathSeparator = SANITIZER_WINDOWS ? ';' : ':'; 20568d75effSDimitry Andric 20668d75effSDimitry Andric char *FindPathToBinary(const char *name) { 20768d75effSDimitry Andric if (FileExists(name)) { 20868d75effSDimitry Andric return internal_strdup(name); 20968d75effSDimitry Andric } 21068d75effSDimitry Andric 21168d75effSDimitry Andric const char *path = GetEnv("PATH"); 21268d75effSDimitry Andric if (!path) 21368d75effSDimitry Andric return nullptr; 21468d75effSDimitry Andric uptr name_len = internal_strlen(name); 21568d75effSDimitry Andric InternalMmapVector<char> buffer(kMaxPathLength); 21668d75effSDimitry Andric const char *beg = path; 21768d75effSDimitry Andric while (true) { 21868d75effSDimitry Andric const char *end = internal_strchrnul(beg, kPathSeparator); 21968d75effSDimitry Andric uptr prefix_len = end - beg; 22068d75effSDimitry Andric if (prefix_len + name_len + 2 <= kMaxPathLength) { 22168d75effSDimitry Andric internal_memcpy(buffer.data(), beg, prefix_len); 22268d75effSDimitry Andric buffer[prefix_len] = '/'; 22368d75effSDimitry Andric internal_memcpy(&buffer[prefix_len + 1], name, name_len); 22468d75effSDimitry Andric buffer[prefix_len + 1 + name_len] = '\0'; 22568d75effSDimitry Andric if (FileExists(buffer.data())) 22668d75effSDimitry Andric return internal_strdup(buffer.data()); 22768d75effSDimitry Andric } 22868d75effSDimitry Andric if (*end == '\0') break; 22968d75effSDimitry Andric beg = end + 1; 23068d75effSDimitry Andric } 23168d75effSDimitry Andric return nullptr; 23268d75effSDimitry Andric } 23368d75effSDimitry Andric 23468d75effSDimitry Andric } // namespace __sanitizer 23568d75effSDimitry Andric 23668d75effSDimitry Andric using namespace __sanitizer; 23768d75effSDimitry Andric 23868d75effSDimitry Andric extern "C" { 23968d75effSDimitry Andric void __sanitizer_set_report_path(const char *path) { 24068d75effSDimitry Andric report_file.SetReportPath(path); 24168d75effSDimitry Andric } 24268d75effSDimitry Andric 24368d75effSDimitry Andric void __sanitizer_set_report_fd(void *fd) { 24468d75effSDimitry Andric report_file.fd = (fd_t)reinterpret_cast<uptr>(fd); 24568d75effSDimitry Andric report_file.fd_pid = internal_getpid(); 24668d75effSDimitry Andric } 247e8d8bef9SDimitry Andric 248e8d8bef9SDimitry Andric const char *__sanitizer_get_report_path() { 249e8d8bef9SDimitry Andric return report_file.GetReportPath(); 250e8d8bef9SDimitry Andric } 25168d75effSDimitry Andric } // extern "C" 25268d75effSDimitry Andric 25368d75effSDimitry Andric #endif // !SANITIZER_FUCHSIA 254