brintos

brintos / llvm-project-archived public Read only

0
0
Text · 10.8 KiB · e8f219b Raw
346 lines · cpp
1//===-- sanitizer_file.cpp -----------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===---------------------------------------------------------------------===//8//9// This file is shared between AddressSanitizer and ThreadSanitizer10// run-time libraries.  It defines filesystem-related interfaces.  This11// is separate from sanitizer_common.cpp so that it's simpler to disable12// all the filesystem support code for a port that doesn't use it.13//14//===---------------------------------------------------------------------===//15 16#include "sanitizer_platform.h"17 18#if !SANITIZER_FUCHSIA19 20#include "sanitizer_common.h"21#include "sanitizer_file.h"22#  include "sanitizer_interface_internal.h"23 24namespace __sanitizer {25 26void CatastrophicErrorWrite(const char *buffer, uptr length) {27  WriteToFile(kStderrFd, buffer, length);28}29 30StaticSpinMutex report_file_mu;31ReportFile report_file = {&report_file_mu, kStderrFd, "", "", 0};32 33void RawWrite(const char *buffer) {34  report_file.Write(buffer, internal_strlen(buffer));35}36 37void ReportFile::ReopenIfNecessary() {38  mu->CheckLocked();39  uptr pid = internal_getpid();40  if (fallbackToStderrActive && fd_pid != pid) {41    // If fallbackToStderrActive is set then we fellback to stderr. If this is a42    // new process, mark fd as invalid so we attempt to open again.43    CHECK_EQ(fd, kStderrFd);44    fd = kInvalidFd;45    fallbackToStderrActive = false;46  }47  if (fd == kStdoutFd || fd == kStderrFd)48    return;49 50  // If in tracer, use the parent's file.51  if (pid == stoptheworld_tracer_pid)52    pid = stoptheworld_tracer_ppid;53  if (fd != kInvalidFd) {54    // If the report file is already opened by the current process,55    // do nothing. Otherwise the report file was opened by the parent56    // process, close it now.57    if (fd_pid == pid)58      return;59    CloseFile(fd);60  }61 62  const char *exe_name = GetProcessName();63  if (common_flags()->log_exe_name && exe_name) {64    internal_snprintf(full_path, kMaxPathLength, "%s.%s.%zu", path_prefix,65                      exe_name, pid);66  } else {67    internal_snprintf(full_path, kMaxPathLength, "%s.%zu", path_prefix, pid);68  }69  if (common_flags()->log_suffix) {70    internal_strlcat(full_path, common_flags()->log_suffix, kMaxPathLength);71  }72  error_t err;73  fd = OpenFile(full_path, WrOnly, &err);74  if (fd == kInvalidFd) {75    bool fallback = common_flags()->log_fallback_to_stderr;76    const char *ErrorMsgPrefix =77        fallback ? "WARNING: Can't open file, falling back to stderr: "78                 : "ERROR: Can't open file: ";79    WriteToFile(kStderrFd, ErrorMsgPrefix, internal_strlen(ErrorMsgPrefix));80    WriteToFile(kStderrFd, full_path, internal_strlen(full_path));81    char errmsg[100];82    internal_snprintf(errmsg, sizeof(errmsg), " (reason: %d)\n", err);83    WriteToFile(kStderrFd, errmsg, internal_strlen(errmsg));84    if (!fallback)85      Die();86    fallbackToStderrActive = true;87    fd = kStderrFd;88  }89  fd_pid = pid;90}91 92static void RecursiveCreateParentDirs(char *path, fd_t &fd) {93  if (path[0] == '\0')94    return;95  for (int i = 1; path[i] != '\0'; ++i) {96    char save = path[i];97    if (!IsPathSeparator(path[i]))98      continue;99    path[i] = '\0';100    if (!DirExists(path) && !CreateDir(path)) {101      bool fallback = common_flags()->log_fallback_to_stderr;102      const char *ErrorMsgPrefix =103          fallback ? "WARNING: Can't create directory, falling back to stderr: "104                   : "ERROR: Can't create directory: ";105      WriteToFile(kStderrFd, ErrorMsgPrefix, internal_strlen(ErrorMsgPrefix));106      WriteToFile(kStderrFd, path, internal_strlen(path));107      const char *ErrorMsgSuffix = "\n";108      WriteToFile(kStderrFd, ErrorMsgSuffix, internal_strlen(ErrorMsgSuffix));109      if (!fallback)110        Die();111      path[i] = save;112      fd = kStderrFd;113      return;114    }115    path[i] = save;116  }117}118 119/// Parse the report path \p pattern and copy the parsed path to \p dest.120///121/// * `%%` becomes `%`122/// * `%H` expands to the environment variable `HOME`123/// * `%t` expands to the environment variable `TMPDIR`124/// * `%p` expands to the process ID (PID)125static void ParseAndSetPath(const char *pattern, char *dest,126                            const uptr dest_size) {127  CHECK(pattern);128  CHECK(dest);129  CHECK_GE(dest_size, 1);130  dest[0] = '\0';131  // Return empty string if empty string was passed132  if (internal_strlen(pattern) == 0)133    return;134  uptr next_substr_start_idx = 0;135  for (uptr i = 0; i < internal_strlen(pattern) - 1; i++) {136    if (pattern[i] != '%')137      continue;138    int bytes_to_copy = i - next_substr_start_idx;139    // Copy over previous substring.140    CHECK_LT(internal_strlcat(dest, pattern + next_substr_start_idx,141                              internal_strlen(dest) + bytes_to_copy + 1),142             dest_size);143    const char *str_to_concat;144    switch (pattern[++i]) {145      case '%':146        str_to_concat = "%";147        break;148      case 'H':149        str_to_concat = GetEnv("HOME");150        break;151      case 't':152        str_to_concat = GetEnv("TMPDIR");153        break;154      case 'p': {155        // Use printf directly to write the PID since it's not a static string.156        int remaining_capacity = dest_size - internal_strlen(dest);157        int bytes_copied =158            internal_snprintf(dest + internal_strlen(dest), remaining_capacity,159                              "%ld", internal_getpid());160        CHECK_GT(bytes_copied, 0);161        CHECK_LT(bytes_copied, remaining_capacity);162        str_to_concat = "";163        break;164      }165      default: {166        // Invalid pattern: fallback to original pattern.167        const char *message = "ERROR: Unexpected pattern: ";168        WriteToFile(kStderrFd, message, internal_strlen(message));169        WriteToFile(kStderrFd, pattern, internal_strlen(pattern));170        WriteToFile(kStderrFd, "\n", internal_strlen("\n"));171        CHECK_LT(internal_strlcpy(dest, pattern, dest_size), dest_size);172        return;173      }174    }175    CHECK(str_to_concat);176    CHECK_LT(internal_strlcat(dest, str_to_concat, dest_size), dest_size);177    next_substr_start_idx = i + 1;178  }179  CHECK_LT(internal_strlcat(dest, pattern + next_substr_start_idx, dest_size),180           dest_size);181}182 183void ReportFile::SetReportPath(const char *path) {184  if (path) {185    uptr len = internal_strlen(path);186    if (len > sizeof(path_prefix) - 100) {187      bool fallback = common_flags()->log_fallback_to_stderr;188      const char *message =189          fallback ? "WARNING: Path is too long, falling back to stderr: "190                   : "ERROR: Path is too long: ";191      WriteToFile(kStderrFd, message, internal_strlen(message));192      WriteToFile(kStderrFd, path, 8);193      message = "...\n";194      WriteToFile(kStderrFd, message, internal_strlen(message));195      if (!fallback)196        Die();197      path = "stderr";198    }199  }200 201  SpinMutexLock l(mu);202  if (fd != kStdoutFd && fd != kStderrFd && fd != kInvalidFd)203    CloseFile(fd);204  fd = kInvalidFd;205  if (!path || internal_strcmp(path, "stderr") == 0) {206    fd = kStderrFd;207  } else if (internal_strcmp(path, "stdout") == 0) {208    fd = kStdoutFd;209  } else {210    ParseAndSetPath(path, path_prefix, kMaxPathLength);211    RecursiveCreateParentDirs(path_prefix, fd);212  }213}214 215const char *ReportFile::GetReportPath() {216  SpinMutexLock l(mu);217  ReopenIfNecessary();218  return full_path;219}220 221bool ReadFileToBuffer(const char *file_name, char **buff, uptr *buff_size,222                      uptr *read_len, uptr max_len, error_t *errno_p) {223  *buff = nullptr;224  *buff_size = 0;225  *read_len = 0;226  if (!max_len)227    return true;228  uptr PageSize = GetPageSizeCached();229  uptr kMinFileLen = Min(PageSize, max_len);230 231  // The files we usually open are not seekable, so try different buffer sizes.232  for (uptr size = kMinFileLen;; size = Min(size * 2, max_len)) {233    UnmapOrDie(*buff, *buff_size);234    *buff = (char*)MmapOrDie(size, __func__);235    *buff_size = size;236    fd_t fd = OpenFile(file_name, RdOnly, errno_p);237    if (fd == kInvalidFd) {238      UnmapOrDie(*buff, *buff_size);239      return false;240    }241    *read_len = 0;242    // Read up to one page at a time.243    bool reached_eof = false;244    while (*read_len < size) {245      uptr just_read;246      if (!ReadFromFile(fd, *buff + *read_len, size - *read_len, &just_read,247                        errno_p)) {248        UnmapOrDie(*buff, *buff_size);249        CloseFile(fd);250        return false;251      }252      *read_len += just_read;253      if (just_read == 0 || *read_len == max_len) {254        reached_eof = true;255        break;256      }257    }258    CloseFile(fd);259    if (reached_eof)  // We've read the whole file.260      break;261  }262  return true;263}264 265bool ReadFileToVector(const char *file_name,266                      InternalMmapVectorNoCtor<char> *buff, uptr max_len,267                      error_t *errno_p) {268  buff->clear();269  if (!max_len)270    return true;271  uptr PageSize = GetPageSizeCached();272  fd_t fd = OpenFile(file_name, RdOnly, errno_p);273  if (fd == kInvalidFd)274    return false;275  uptr read_len = 0;276  while (read_len < max_len) {277    if (read_len >= buff->size())278      buff->resize(Min(Max(PageSize, read_len * 2), max_len));279    CHECK_LT(read_len, buff->size());280    CHECK_LE(buff->size(), max_len);281    uptr just_read;282    if (!ReadFromFile(fd, buff->data() + read_len, buff->size() - read_len,283                      &just_read, errno_p)) {284      CloseFile(fd);285      return false;286    }287    read_len += just_read;288    if (!just_read)289      break;290  }291  CloseFile(fd);292  buff->resize(read_len);293  return true;294}295 296static const char kPathSeparator = SANITIZER_WINDOWS ? ';' : ':';297 298char *FindPathToBinary(const char *name) {299  if (FileExists(name)) {300    return internal_strdup(name);301  }302 303  const char *path = GetEnv("PATH");304  if (!path)305    return nullptr;306  uptr name_len = internal_strlen(name);307  InternalMmapVector<char> buffer(kMaxPathLength);308  const char *beg = path;309  while (true) {310    const char *end = internal_strchrnul(beg, kPathSeparator);311    uptr prefix_len = end - beg;312    if (prefix_len + name_len + 2 <= kMaxPathLength) {313      internal_memcpy(buffer.data(), beg, prefix_len);314      buffer[prefix_len] = '/';315      internal_memcpy(&buffer[prefix_len + 1], name, name_len);316      buffer[prefix_len + 1 + name_len] = '\0';317      if (FileExists(buffer.data()))318        return internal_strdup(buffer.data());319    }320    if (*end == '\0') break;321    beg = end + 1;322  }323  return nullptr;324}325 326} // namespace __sanitizer327 328using namespace __sanitizer;329 330extern "C" {331void __sanitizer_set_report_path(const char *path) {332  report_file.SetReportPath(path);333}334 335void __sanitizer_set_report_fd(void *fd) {336  report_file.fd = (fd_t)reinterpret_cast<uptr>(fd);337  report_file.fd_pid = internal_getpid();338}339 340const char *__sanitizer_get_report_path() {341  return report_file.GetReportPath();342}343} // extern "C"344 345#endif  // !SANITIZER_FUCHSIA346