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 } 61*e8d8bef9SDimitry Andric error_t err; 62*e8d8bef9SDimitry Andric fd = OpenFile(full_path, WrOnly, &err); 6368d75effSDimitry Andric if (fd == kInvalidFd) { 6468d75effSDimitry Andric const char *ErrorMsgPrefix = "ERROR: Can't open file: "; 6568d75effSDimitry Andric WriteToFile(kStderrFd, ErrorMsgPrefix, internal_strlen(ErrorMsgPrefix)); 6668d75effSDimitry Andric WriteToFile(kStderrFd, full_path, internal_strlen(full_path)); 67*e8d8bef9SDimitry Andric char errmsg[100]; 68*e8d8bef9SDimitry Andric internal_snprintf(errmsg, sizeof(errmsg), " (reason: %d)", err); 69*e8d8bef9SDimitry Andric WriteToFile(kStderrFd, errmsg, internal_strlen(errmsg)); 7068d75effSDimitry Andric Die(); 7168d75effSDimitry Andric } 7268d75effSDimitry Andric fd_pid = pid; 7368d75effSDimitry Andric } 7468d75effSDimitry Andric 7568d75effSDimitry Andric void ReportFile::SetReportPath(const char *path) { 76*e8d8bef9SDimitry Andric if (path) { 7768d75effSDimitry Andric uptr len = internal_strlen(path); 7868d75effSDimitry Andric if (len > sizeof(path_prefix) - 100) { 79*e8d8bef9SDimitry Andric Report("ERROR: Path is too long: %c%c%c%c%c%c%c%c...\n", path[0], path[1], 80*e8d8bef9SDimitry Andric path[2], path[3], path[4], path[5], path[6], path[7]); 8168d75effSDimitry Andric Die(); 8268d75effSDimitry Andric } 83*e8d8bef9SDimitry Andric } 8468d75effSDimitry Andric 8568d75effSDimitry Andric SpinMutexLock l(mu); 8668d75effSDimitry Andric if (fd != kStdoutFd && fd != kStderrFd && fd != kInvalidFd) 8768d75effSDimitry Andric CloseFile(fd); 8868d75effSDimitry Andric fd = kInvalidFd; 89*e8d8bef9SDimitry Andric if (!path || internal_strcmp(path, "stderr") == 0) { 9068d75effSDimitry Andric fd = kStderrFd; 91*e8d8bef9SDimitry Andric } else if (internal_strcmp(path, "stdout") == 0) { 92*e8d8bef9SDimitry Andric fd = kStdoutFd; 9368d75effSDimitry Andric } else { 9468d75effSDimitry Andric internal_snprintf(path_prefix, kMaxPathLength, "%s", path); 9568d75effSDimitry Andric } 9668d75effSDimitry Andric } 9768d75effSDimitry Andric 98*e8d8bef9SDimitry Andric const char *ReportFile::GetReportPath() { 99*e8d8bef9SDimitry Andric SpinMutexLock l(mu); 100*e8d8bef9SDimitry Andric ReopenIfNecessary(); 101*e8d8bef9SDimitry Andric return full_path; 102*e8d8bef9SDimitry Andric } 103*e8d8bef9SDimitry Andric 10468d75effSDimitry Andric bool ReadFileToBuffer(const char *file_name, char **buff, uptr *buff_size, 10568d75effSDimitry Andric uptr *read_len, uptr max_len, error_t *errno_p) { 10668d75effSDimitry Andric *buff = nullptr; 10768d75effSDimitry Andric *buff_size = 0; 10868d75effSDimitry Andric *read_len = 0; 10968d75effSDimitry Andric if (!max_len) 11068d75effSDimitry Andric return true; 11168d75effSDimitry Andric uptr PageSize = GetPageSizeCached(); 11268d75effSDimitry Andric uptr kMinFileLen = Min(PageSize, max_len); 11368d75effSDimitry Andric 11468d75effSDimitry Andric // The files we usually open are not seekable, so try different buffer sizes. 11568d75effSDimitry Andric for (uptr size = kMinFileLen;; size = Min(size * 2, max_len)) { 11668d75effSDimitry Andric UnmapOrDie(*buff, *buff_size); 11768d75effSDimitry Andric *buff = (char*)MmapOrDie(size, __func__); 11868d75effSDimitry Andric *buff_size = size; 11968d75effSDimitry Andric fd_t fd = OpenFile(file_name, RdOnly, errno_p); 12068d75effSDimitry Andric if (fd == kInvalidFd) { 12168d75effSDimitry Andric UnmapOrDie(*buff, *buff_size); 12268d75effSDimitry Andric return false; 12368d75effSDimitry Andric } 12468d75effSDimitry Andric *read_len = 0; 12568d75effSDimitry Andric // Read up to one page at a time. 12668d75effSDimitry Andric bool reached_eof = false; 12768d75effSDimitry Andric while (*read_len < size) { 12868d75effSDimitry Andric uptr just_read; 12968d75effSDimitry Andric if (!ReadFromFile(fd, *buff + *read_len, size - *read_len, &just_read, 13068d75effSDimitry Andric errno_p)) { 13168d75effSDimitry Andric UnmapOrDie(*buff, *buff_size); 13268d75effSDimitry Andric CloseFile(fd); 13368d75effSDimitry Andric return false; 13468d75effSDimitry Andric } 13568d75effSDimitry Andric *read_len += just_read; 13668d75effSDimitry Andric if (just_read == 0 || *read_len == max_len) { 13768d75effSDimitry Andric reached_eof = true; 13868d75effSDimitry Andric break; 13968d75effSDimitry Andric } 14068d75effSDimitry Andric } 14168d75effSDimitry Andric CloseFile(fd); 14268d75effSDimitry Andric if (reached_eof) // We've read the whole file. 14368d75effSDimitry Andric break; 14468d75effSDimitry Andric } 14568d75effSDimitry Andric return true; 14668d75effSDimitry Andric } 14768d75effSDimitry Andric 14868d75effSDimitry Andric bool ReadFileToVector(const char *file_name, 14968d75effSDimitry Andric InternalMmapVectorNoCtor<char> *buff, uptr max_len, 15068d75effSDimitry Andric error_t *errno_p) { 15168d75effSDimitry Andric buff->clear(); 15268d75effSDimitry Andric if (!max_len) 15368d75effSDimitry Andric return true; 15468d75effSDimitry Andric uptr PageSize = GetPageSizeCached(); 15568d75effSDimitry Andric fd_t fd = OpenFile(file_name, RdOnly, errno_p); 15668d75effSDimitry Andric if (fd == kInvalidFd) 15768d75effSDimitry Andric return false; 15868d75effSDimitry Andric uptr read_len = 0; 15968d75effSDimitry Andric while (read_len < max_len) { 16068d75effSDimitry Andric if (read_len >= buff->size()) 16168d75effSDimitry Andric buff->resize(Min(Max(PageSize, read_len * 2), max_len)); 16268d75effSDimitry Andric CHECK_LT(read_len, buff->size()); 16368d75effSDimitry Andric CHECK_LE(buff->size(), max_len); 16468d75effSDimitry Andric uptr just_read; 16568d75effSDimitry Andric if (!ReadFromFile(fd, buff->data() + read_len, buff->size() - read_len, 16668d75effSDimitry Andric &just_read, errno_p)) { 16768d75effSDimitry Andric CloseFile(fd); 16868d75effSDimitry Andric return false; 16968d75effSDimitry Andric } 17068d75effSDimitry Andric read_len += just_read; 17168d75effSDimitry Andric if (!just_read) 17268d75effSDimitry Andric break; 17368d75effSDimitry Andric } 17468d75effSDimitry Andric CloseFile(fd); 17568d75effSDimitry Andric buff->resize(read_len); 17668d75effSDimitry Andric return true; 17768d75effSDimitry Andric } 17868d75effSDimitry Andric 17968d75effSDimitry Andric static const char kPathSeparator = SANITIZER_WINDOWS ? ';' : ':'; 18068d75effSDimitry Andric 18168d75effSDimitry Andric char *FindPathToBinary(const char *name) { 18268d75effSDimitry Andric if (FileExists(name)) { 18368d75effSDimitry Andric return internal_strdup(name); 18468d75effSDimitry Andric } 18568d75effSDimitry Andric 18668d75effSDimitry Andric const char *path = GetEnv("PATH"); 18768d75effSDimitry Andric if (!path) 18868d75effSDimitry Andric return nullptr; 18968d75effSDimitry Andric uptr name_len = internal_strlen(name); 19068d75effSDimitry Andric InternalMmapVector<char> buffer(kMaxPathLength); 19168d75effSDimitry Andric const char *beg = path; 19268d75effSDimitry Andric while (true) { 19368d75effSDimitry Andric const char *end = internal_strchrnul(beg, kPathSeparator); 19468d75effSDimitry Andric uptr prefix_len = end - beg; 19568d75effSDimitry Andric if (prefix_len + name_len + 2 <= kMaxPathLength) { 19668d75effSDimitry Andric internal_memcpy(buffer.data(), beg, prefix_len); 19768d75effSDimitry Andric buffer[prefix_len] = '/'; 19868d75effSDimitry Andric internal_memcpy(&buffer[prefix_len + 1], name, name_len); 19968d75effSDimitry Andric buffer[prefix_len + 1 + name_len] = '\0'; 20068d75effSDimitry Andric if (FileExists(buffer.data())) 20168d75effSDimitry Andric return internal_strdup(buffer.data()); 20268d75effSDimitry Andric } 20368d75effSDimitry Andric if (*end == '\0') break; 20468d75effSDimitry Andric beg = end + 1; 20568d75effSDimitry Andric } 20668d75effSDimitry Andric return nullptr; 20768d75effSDimitry Andric } 20868d75effSDimitry Andric 20968d75effSDimitry Andric } // namespace __sanitizer 21068d75effSDimitry Andric 21168d75effSDimitry Andric using namespace __sanitizer; 21268d75effSDimitry Andric 21368d75effSDimitry Andric extern "C" { 21468d75effSDimitry Andric void __sanitizer_set_report_path(const char *path) { 21568d75effSDimitry Andric report_file.SetReportPath(path); 21668d75effSDimitry Andric } 21768d75effSDimitry Andric 21868d75effSDimitry Andric void __sanitizer_set_report_fd(void *fd) { 21968d75effSDimitry Andric report_file.fd = (fd_t)reinterpret_cast<uptr>(fd); 22068d75effSDimitry Andric report_file.fd_pid = internal_getpid(); 22168d75effSDimitry Andric } 222*e8d8bef9SDimitry Andric 223*e8d8bef9SDimitry Andric const char *__sanitizer_get_report_path() { 224*e8d8bef9SDimitry Andric return report_file.GetReportPath(); 225*e8d8bef9SDimitry Andric } 22668d75effSDimitry Andric } // extern "C" 22768d75effSDimitry Andric 22868d75effSDimitry Andric #endif // !SANITIZER_FUCHSIA 229