xref: /freebsd-src/contrib/llvm-project/compiler-rt/lib/sanitizer_common/sanitizer_file.cpp (revision 349cc55c9796c4596a5b9904cd3281af295f878f)
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