111
|
1 //===-- sanitizer_file.cc ------------------------------------------------===//
|
|
2 //
|
|
3 // This file is distributed under the University of Illinois Open Source
|
|
4 // License. See LICENSE.TXT for details.
|
|
5 //
|
|
6 //===---------------------------------------------------------------------===//
|
|
7 //
|
|
8 // This file is shared between AddressSanitizer and ThreadSanitizer
|
|
9 // run-time libraries. It defines filesystem-related interfaces. This
|
|
10 // is separate from sanitizer_common.cc so that it's simpler to disable
|
|
11 // all the filesystem support code for a port that doesn't use it.
|
|
12 //
|
|
13 //===---------------------------------------------------------------------===//
|
|
14
|
|
15 #include "sanitizer_platform.h"
|
|
16
|
|
17 #if !SANITIZER_FUCHSIA
|
|
18
|
|
19 #include "sanitizer_common.h"
|
|
20 #include "sanitizer_file.h"
|
|
21
|
|
22 namespace __sanitizer {
|
|
23
|
|
24 void CatastrophicErrorWrite(const char *buffer, uptr length) {
|
|
25 WriteToFile(kStderrFd, buffer, length);
|
|
26 }
|
|
27
|
|
28 StaticSpinMutex report_file_mu;
|
|
29 ReportFile report_file = {&report_file_mu, kStderrFd, "", "", 0};
|
|
30
|
|
31 void RawWrite(const char *buffer) {
|
|
32 report_file.Write(buffer, internal_strlen(buffer));
|
|
33 }
|
|
34
|
|
35 void ReportFile::ReopenIfNecessary() {
|
|
36 mu->CheckLocked();
|
|
37 if (fd == kStdoutFd || fd == kStderrFd) return;
|
|
38
|
|
39 uptr pid = internal_getpid();
|
|
40 // If in tracer, use the parent's file.
|
|
41 if (pid == stoptheworld_tracer_pid)
|
|
42 pid = stoptheworld_tracer_ppid;
|
|
43 if (fd != kInvalidFd) {
|
|
44 // If the report file is already opened by the current process,
|
|
45 // do nothing. Otherwise the report file was opened by the parent
|
|
46 // process, close it now.
|
|
47 if (fd_pid == pid)
|
|
48 return;
|
|
49 else
|
|
50 CloseFile(fd);
|
|
51 }
|
|
52
|
|
53 const char *exe_name = GetProcessName();
|
|
54 if (common_flags()->log_exe_name && exe_name) {
|
|
55 internal_snprintf(full_path, kMaxPathLength, "%s.%s.%zu", path_prefix,
|
|
56 exe_name, pid);
|
|
57 } else {
|
|
58 internal_snprintf(full_path, kMaxPathLength, "%s.%zu", path_prefix, pid);
|
|
59 }
|
|
60 fd = OpenFile(full_path, WrOnly);
|
|
61 if (fd == kInvalidFd) {
|
|
62 const char *ErrorMsgPrefix = "ERROR: Can't open file: ";
|
|
63 WriteToFile(kStderrFd, ErrorMsgPrefix, internal_strlen(ErrorMsgPrefix));
|
|
64 WriteToFile(kStderrFd, full_path, internal_strlen(full_path));
|
|
65 Die();
|
|
66 }
|
|
67 fd_pid = pid;
|
|
68 }
|
|
69
|
|
70 void ReportFile::SetReportPath(const char *path) {
|
|
71 if (!path)
|
|
72 return;
|
|
73 uptr len = internal_strlen(path);
|
|
74 if (len > sizeof(path_prefix) - 100) {
|
|
75 Report("ERROR: Path is too long: %c%c%c%c%c%c%c%c...\n",
|
|
76 path[0], path[1], path[2], path[3],
|
|
77 path[4], path[5], path[6], path[7]);
|
|
78 Die();
|
|
79 }
|
|
80
|
|
81 SpinMutexLock l(mu);
|
|
82 if (fd != kStdoutFd && fd != kStderrFd && fd != kInvalidFd)
|
|
83 CloseFile(fd);
|
|
84 fd = kInvalidFd;
|
|
85 if (internal_strcmp(path, "stdout") == 0) {
|
|
86 fd = kStdoutFd;
|
|
87 } else if (internal_strcmp(path, "stderr") == 0) {
|
|
88 fd = kStderrFd;
|
|
89 } else {
|
|
90 internal_snprintf(path_prefix, kMaxPathLength, "%s", path);
|
|
91 }
|
|
92 }
|
|
93
|
|
94 bool ReadFileToBuffer(const char *file_name, char **buff, uptr *buff_size,
|
|
95 uptr *read_len, uptr max_len, error_t *errno_p) {
|
|
96 uptr PageSize = GetPageSizeCached();
|
|
97 uptr kMinFileLen = PageSize;
|
|
98 *buff = nullptr;
|
|
99 *buff_size = 0;
|
|
100 *read_len = 0;
|
|
101 // The files we usually open are not seekable, so try different buffer sizes.
|
|
102 for (uptr size = kMinFileLen; size <= max_len; size *= 2) {
|
|
103 fd_t fd = OpenFile(file_name, RdOnly, errno_p);
|
|
104 if (fd == kInvalidFd) return false;
|
|
105 UnmapOrDie(*buff, *buff_size);
|
|
106 *buff = (char*)MmapOrDie(size, __func__);
|
|
107 *buff_size = size;
|
|
108 *read_len = 0;
|
|
109 // Read up to one page at a time.
|
|
110 bool reached_eof = false;
|
|
111 while (*read_len + PageSize <= size) {
|
|
112 uptr just_read;
|
|
113 if (!ReadFromFile(fd, *buff + *read_len, PageSize, &just_read, errno_p)) {
|
|
114 UnmapOrDie(*buff, *buff_size);
|
|
115 return false;
|
|
116 }
|
|
117 if (just_read == 0) {
|
|
118 reached_eof = true;
|
|
119 break;
|
|
120 }
|
|
121 *read_len += just_read;
|
|
122 }
|
|
123 CloseFile(fd);
|
|
124 if (reached_eof) // We've read the whole file.
|
|
125 break;
|
|
126 }
|
|
127 return true;
|
|
128 }
|
|
129
|
|
130 static const char kPathSeparator = SANITIZER_WINDOWS ? ';' : ':';
|
|
131
|
|
132 char *FindPathToBinary(const char *name) {
|
|
133 if (FileExists(name)) {
|
|
134 return internal_strdup(name);
|
|
135 }
|
|
136
|
|
137 const char *path = GetEnv("PATH");
|
|
138 if (!path)
|
|
139 return nullptr;
|
|
140 uptr name_len = internal_strlen(name);
|
|
141 InternalScopedBuffer<char> buffer(kMaxPathLength);
|
|
142 const char *beg = path;
|
|
143 while (true) {
|
|
144 const char *end = internal_strchrnul(beg, kPathSeparator);
|
|
145 uptr prefix_len = end - beg;
|
|
146 if (prefix_len + name_len + 2 <= kMaxPathLength) {
|
|
147 internal_memcpy(buffer.data(), beg, prefix_len);
|
|
148 buffer[prefix_len] = '/';
|
|
149 internal_memcpy(&buffer[prefix_len + 1], name, name_len);
|
|
150 buffer[prefix_len + 1 + name_len] = '\0';
|
|
151 if (FileExists(buffer.data()))
|
|
152 return internal_strdup(buffer.data());
|
|
153 }
|
|
154 if (*end == '\0') break;
|
|
155 beg = end + 1;
|
|
156 }
|
|
157 return nullptr;
|
|
158 }
|
|
159
|
|
160 } // namespace __sanitizer
|
|
161
|
|
162 using namespace __sanitizer; // NOLINT
|
|
163
|
|
164 extern "C" {
|
|
165 void __sanitizer_set_report_path(const char *path) {
|
|
166 report_file.SetReportPath(path);
|
|
167 }
|
|
168
|
|
169 void __sanitizer_set_report_fd(void *fd) {
|
|
170 report_file.fd = (fd_t)reinterpret_cast<uptr>(fd);
|
|
171 report_file.fd_pid = internal_getpid();
|
|
172 }
|
|
173 } // extern "C"
|
|
174
|
|
175 #endif // !SANITIZER_FUCHSIA
|