1353944Sdim//===-- sanitizer_file.cpp -----------------------------------------------===//
2353944Sdim//
3353944Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4353944Sdim// See https://llvm.org/LICENSE.txt for license information.
5353944Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6353944Sdim//
7353944Sdim//===---------------------------------------------------------------------===//
8353944Sdim//
9353944Sdim// This file is shared between AddressSanitizer and ThreadSanitizer
10353944Sdim// run-time libraries.  It defines filesystem-related interfaces.  This
11353944Sdim// is separate from sanitizer_common.cpp so that it's simpler to disable
12353944Sdim// all the filesystem support code for a port that doesn't use it.
13353944Sdim//
14353944Sdim//===---------------------------------------------------------------------===//
15353944Sdim
16353944Sdim#include "sanitizer_platform.h"
17353944Sdim
18353944Sdim#if !SANITIZER_FUCHSIA
19353944Sdim
20353944Sdim#include "sanitizer_common.h"
21353944Sdim#include "sanitizer_file.h"
22353944Sdim
23353944Sdimnamespace __sanitizer {
24353944Sdim
25353944Sdimvoid CatastrophicErrorWrite(const char *buffer, uptr length) {
26353944Sdim  WriteToFile(kStderrFd, buffer, length);
27353944Sdim}
28353944Sdim
29353944SdimStaticSpinMutex report_file_mu;
30353944SdimReportFile report_file = {&report_file_mu, kStderrFd, "", "", 0};
31353944Sdim
32353944Sdimvoid RawWrite(const char *buffer) {
33353944Sdim  report_file.Write(buffer, internal_strlen(buffer));
34353944Sdim}
35353944Sdim
36353944Sdimvoid ReportFile::ReopenIfNecessary() {
37353944Sdim  mu->CheckLocked();
38353944Sdim  if (fd == kStdoutFd || fd == kStderrFd) return;
39353944Sdim
40353944Sdim  uptr pid = internal_getpid();
41353944Sdim  // If in tracer, use the parent's file.
42353944Sdim  if (pid == stoptheworld_tracer_pid)
43353944Sdim    pid = stoptheworld_tracer_ppid;
44353944Sdim  if (fd != kInvalidFd) {
45353944Sdim    // If the report file is already opened by the current process,
46353944Sdim    // do nothing. Otherwise the report file was opened by the parent
47353944Sdim    // process, close it now.
48353944Sdim    if (fd_pid == pid)
49353944Sdim      return;
50353944Sdim    else
51353944Sdim      CloseFile(fd);
52353944Sdim  }
53353944Sdim
54353944Sdim  const char *exe_name = GetProcessName();
55353944Sdim  if (common_flags()->log_exe_name && exe_name) {
56353944Sdim    internal_snprintf(full_path, kMaxPathLength, "%s.%s.%zu", path_prefix,
57353944Sdim                      exe_name, pid);
58353944Sdim  } else {
59353944Sdim    internal_snprintf(full_path, kMaxPathLength, "%s.%zu", path_prefix, pid);
60353944Sdim  }
61353944Sdim  fd = OpenFile(full_path, WrOnly);
62353944Sdim  if (fd == kInvalidFd) {
63353944Sdim    const char *ErrorMsgPrefix = "ERROR: Can't open file: ";
64353944Sdim    WriteToFile(kStderrFd, ErrorMsgPrefix, internal_strlen(ErrorMsgPrefix));
65353944Sdim    WriteToFile(kStderrFd, full_path, internal_strlen(full_path));
66353944Sdim    Die();
67353944Sdim  }
68353944Sdim  fd_pid = pid;
69353944Sdim}
70353944Sdim
71353944Sdimvoid ReportFile::SetReportPath(const char *path) {
72353944Sdim  if (!path)
73353944Sdim    return;
74353944Sdim  uptr len = internal_strlen(path);
75353944Sdim  if (len > sizeof(path_prefix) - 100) {
76353944Sdim    Report("ERROR: Path is too long: %c%c%c%c%c%c%c%c...\n",
77353944Sdim           path[0], path[1], path[2], path[3],
78353944Sdim           path[4], path[5], path[6], path[7]);
79353944Sdim    Die();
80353944Sdim  }
81353944Sdim
82353944Sdim  SpinMutexLock l(mu);
83353944Sdim  if (fd != kStdoutFd && fd != kStderrFd && fd != kInvalidFd)
84353944Sdim    CloseFile(fd);
85353944Sdim  fd = kInvalidFd;
86353944Sdim  if (internal_strcmp(path, "stdout") == 0) {
87353944Sdim    fd = kStdoutFd;
88353944Sdim  } else if (internal_strcmp(path, "stderr") == 0) {
89353944Sdim    fd = kStderrFd;
90353944Sdim  } else {
91353944Sdim    internal_snprintf(path_prefix, kMaxPathLength, "%s", path);
92353944Sdim  }
93353944Sdim}
94353944Sdim
95353944Sdimbool ReadFileToBuffer(const char *file_name, char **buff, uptr *buff_size,
96353944Sdim                      uptr *read_len, uptr max_len, error_t *errno_p) {
97353944Sdim  *buff = nullptr;
98353944Sdim  *buff_size = 0;
99353944Sdim  *read_len = 0;
100353944Sdim  if (!max_len)
101353944Sdim    return true;
102353944Sdim  uptr PageSize = GetPageSizeCached();
103353944Sdim  uptr kMinFileLen = Min(PageSize, max_len);
104353944Sdim
105353944Sdim  // The files we usually open are not seekable, so try different buffer sizes.
106353944Sdim  for (uptr size = kMinFileLen;; size = Min(size * 2, max_len)) {
107353944Sdim    UnmapOrDie(*buff, *buff_size);
108353944Sdim    *buff = (char*)MmapOrDie(size, __func__);
109353944Sdim    *buff_size = size;
110353944Sdim    fd_t fd = OpenFile(file_name, RdOnly, errno_p);
111353944Sdim    if (fd == kInvalidFd) {
112353944Sdim      UnmapOrDie(*buff, *buff_size);
113353944Sdim      return false;
114353944Sdim    }
115353944Sdim    *read_len = 0;
116353944Sdim    // Read up to one page at a time.
117353944Sdim    bool reached_eof = false;
118353944Sdim    while (*read_len < size) {
119353944Sdim      uptr just_read;
120353944Sdim      if (!ReadFromFile(fd, *buff + *read_len, size - *read_len, &just_read,
121353944Sdim                        errno_p)) {
122353944Sdim        UnmapOrDie(*buff, *buff_size);
123353944Sdim        CloseFile(fd);
124353944Sdim        return false;
125353944Sdim      }
126353944Sdim      *read_len += just_read;
127353944Sdim      if (just_read == 0 || *read_len == max_len) {
128353944Sdim        reached_eof = true;
129353944Sdim        break;
130353944Sdim      }
131353944Sdim    }
132353944Sdim    CloseFile(fd);
133353944Sdim    if (reached_eof)  // We've read the whole file.
134353944Sdim      break;
135353944Sdim  }
136353944Sdim  return true;
137353944Sdim}
138353944Sdim
139353944Sdimbool ReadFileToVector(const char *file_name,
140353944Sdim                      InternalMmapVectorNoCtor<char> *buff, uptr max_len,
141353944Sdim                      error_t *errno_p) {
142353944Sdim  buff->clear();
143353944Sdim  if (!max_len)
144353944Sdim    return true;
145353944Sdim  uptr PageSize = GetPageSizeCached();
146353944Sdim  fd_t fd = OpenFile(file_name, RdOnly, errno_p);
147353944Sdim  if (fd == kInvalidFd)
148353944Sdim    return false;
149353944Sdim  uptr read_len = 0;
150353944Sdim  while (read_len < max_len) {
151353944Sdim    if (read_len >= buff->size())
152353944Sdim      buff->resize(Min(Max(PageSize, read_len * 2), max_len));
153353944Sdim    CHECK_LT(read_len, buff->size());
154353944Sdim    CHECK_LE(buff->size(), max_len);
155353944Sdim    uptr just_read;
156353944Sdim    if (!ReadFromFile(fd, buff->data() + read_len, buff->size() - read_len,
157353944Sdim                      &just_read, errno_p)) {
158353944Sdim      CloseFile(fd);
159353944Sdim      return false;
160353944Sdim    }
161353944Sdim    read_len += just_read;
162353944Sdim    if (!just_read)
163353944Sdim      break;
164353944Sdim  }
165353944Sdim  CloseFile(fd);
166353944Sdim  buff->resize(read_len);
167353944Sdim  return true;
168353944Sdim}
169353944Sdim
170353944Sdimstatic const char kPathSeparator = SANITIZER_WINDOWS ? ';' : ':';
171353944Sdim
172353944Sdimchar *FindPathToBinary(const char *name) {
173353944Sdim  if (FileExists(name)) {
174353944Sdim    return internal_strdup(name);
175353944Sdim  }
176353944Sdim
177353944Sdim  const char *path = GetEnv("PATH");
178353944Sdim  if (!path)
179353944Sdim    return nullptr;
180353944Sdim  uptr name_len = internal_strlen(name);
181353944Sdim  InternalMmapVector<char> buffer(kMaxPathLength);
182353944Sdim  const char *beg = path;
183353944Sdim  while (true) {
184353944Sdim    const char *end = internal_strchrnul(beg, kPathSeparator);
185353944Sdim    uptr prefix_len = end - beg;
186353944Sdim    if (prefix_len + name_len + 2 <= kMaxPathLength) {
187353944Sdim      internal_memcpy(buffer.data(), beg, prefix_len);
188353944Sdim      buffer[prefix_len] = '/';
189353944Sdim      internal_memcpy(&buffer[prefix_len + 1], name, name_len);
190353944Sdim      buffer[prefix_len + 1 + name_len] = '\0';
191353944Sdim      if (FileExists(buffer.data()))
192353944Sdim        return internal_strdup(buffer.data());
193353944Sdim    }
194353944Sdim    if (*end == '\0') break;
195353944Sdim    beg = end + 1;
196353944Sdim  }
197353944Sdim  return nullptr;
198353944Sdim}
199353944Sdim
200353944Sdim} // namespace __sanitizer
201353944Sdim
202353944Sdimusing namespace __sanitizer;
203353944Sdim
204353944Sdimextern "C" {
205353944Sdimvoid __sanitizer_set_report_path(const char *path) {
206353944Sdim  report_file.SetReportPath(path);
207353944Sdim}
208353944Sdim
209353944Sdimvoid __sanitizer_set_report_fd(void *fd) {
210353944Sdim  report_file.fd = (fd_t)reinterpret_cast<uptr>(fd);
211353944Sdim  report_file.fd_pid = internal_getpid();
212353944Sdim}
213353944Sdim} // extern "C"
214353944Sdim
215353944Sdim#endif  // !SANITIZER_FUCHSIA
216