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