1 //===-- sanitizer_file.cpp -----------------------------------------------===//
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-exception
7 //===---------------------------------------------------------------------===//
9 // This file is shared between AddressSanitizer and ThreadSanitizer
10 // run-time libraries. It defines filesystem-related interfaces. This
11 // is separate from sanitizer_common.cpp so that it's simpler to disable
12 // all the filesystem support code for a port that doesn't use it.
14 //===---------------------------------------------------------------------===//
16 #include "sanitizer_platform.h"
18 #if !SANITIZER_FUCHSIA
20 #include "sanitizer_common.h"
21 #include "sanitizer_file.h"
22 # include "sanitizer_interface_internal.h"
24 namespace __sanitizer
{
26 void CatastrophicErrorWrite(const char *buffer
, uptr length
) {
27 WriteToFile(kStderrFd
, buffer
, length
);
30 StaticSpinMutex report_file_mu
;
31 ReportFile report_file
= {&report_file_mu
, kStderrFd
, "", "", 0};
33 void RawWrite(const char *buffer
) {
34 report_file
.Write(buffer
, internal_strlen(buffer
));
37 void ReportFile::ReopenIfNecessary() {
39 if (fd
== kStdoutFd
|| fd
== kStderrFd
) return;
41 uptr pid
= internal_getpid();
42 // If in tracer, use the parent's file.
43 if (pid
== stoptheworld_tracer_pid
)
44 pid
= stoptheworld_tracer_ppid
;
45 if (fd
!= kInvalidFd
) {
46 // If the report file is already opened by the current process,
47 // do nothing. Otherwise the report file was opened by the parent
48 // process, close it now.
55 const char *exe_name
= GetProcessName();
56 if (common_flags()->log_exe_name
&& exe_name
) {
57 internal_snprintf(full_path
, kMaxPathLength
, "%s.%s.%zu", path_prefix
,
60 internal_snprintf(full_path
, kMaxPathLength
, "%s.%zu", path_prefix
, pid
);
62 if (common_flags()->log_suffix
) {
63 internal_strlcat(full_path
, common_flags()->log_suffix
, kMaxPathLength
);
66 fd
= OpenFile(full_path
, WrOnly
, &err
);
67 if (fd
== kInvalidFd
) {
68 const char *ErrorMsgPrefix
= "ERROR: Can't open file: ";
69 WriteToFile(kStderrFd
, ErrorMsgPrefix
, internal_strlen(ErrorMsgPrefix
));
70 WriteToFile(kStderrFd
, full_path
, internal_strlen(full_path
));
72 internal_snprintf(errmsg
, sizeof(errmsg
), " (reason: %d)\n", err
);
73 WriteToFile(kStderrFd
, errmsg
, internal_strlen(errmsg
));
79 static void RecursiveCreateParentDirs(char *path
) {
82 for (int i
= 1; path
[i
] != '\0'; ++i
) {
84 if (!IsPathSeparator(path
[i
]))
87 if (!DirExists(path
) && !CreateDir(path
)) {
88 const char *ErrorMsgPrefix
= "ERROR: Can't create directory: ";
89 WriteToFile(kStderrFd
, ErrorMsgPrefix
, internal_strlen(ErrorMsgPrefix
));
90 WriteToFile(kStderrFd
, path
, internal_strlen(path
));
91 const char *ErrorMsgSuffix
= "\n";
92 WriteToFile(kStderrFd
, ErrorMsgSuffix
, internal_strlen(ErrorMsgSuffix
));
99 void ReportFile::SetReportPath(const char *path
) {
101 uptr len
= internal_strlen(path
);
102 if (len
> sizeof(path_prefix
) - 100) {
103 Report("ERROR: Path is too long: %c%c%c%c%c%c%c%c...\n", path
[0], path
[1],
104 path
[2], path
[3], path
[4], path
[5], path
[6], path
[7]);
110 if (fd
!= kStdoutFd
&& fd
!= kStderrFd
&& fd
!= kInvalidFd
)
113 if (!path
|| internal_strcmp(path
, "stderr") == 0) {
115 } else if (internal_strcmp(path
, "stdout") == 0) {
118 internal_snprintf(path_prefix
, kMaxPathLength
, "%s", path
);
119 RecursiveCreateParentDirs(path_prefix
);
123 const char *ReportFile::GetReportPath() {
129 bool ReadFileToBuffer(const char *file_name
, char **buff
, uptr
*buff_size
,
130 uptr
*read_len
, uptr max_len
, error_t
*errno_p
) {
136 uptr PageSize
= GetPageSizeCached();
137 uptr kMinFileLen
= Min(PageSize
, max_len
);
139 // The files we usually open are not seekable, so try different buffer sizes.
140 for (uptr size
= kMinFileLen
;; size
= Min(size
* 2, max_len
)) {
141 UnmapOrDie(*buff
, *buff_size
);
142 *buff
= (char*)MmapOrDie(size
, __func__
);
144 fd_t fd
= OpenFile(file_name
, RdOnly
, errno_p
);
145 if (fd
== kInvalidFd
) {
146 UnmapOrDie(*buff
, *buff_size
);
150 // Read up to one page at a time.
151 bool reached_eof
= false;
152 while (*read_len
< size
) {
154 if (!ReadFromFile(fd
, *buff
+ *read_len
, size
- *read_len
, &just_read
,
156 UnmapOrDie(*buff
, *buff_size
);
160 *read_len
+= just_read
;
161 if (just_read
== 0 || *read_len
== max_len
) {
167 if (reached_eof
) // We've read the whole file.
173 bool ReadFileToVector(const char *file_name
,
174 InternalMmapVectorNoCtor
<char> *buff
, uptr max_len
,
179 uptr PageSize
= GetPageSizeCached();
180 fd_t fd
= OpenFile(file_name
, RdOnly
, errno_p
);
181 if (fd
== kInvalidFd
)
184 while (read_len
< max_len
) {
185 if (read_len
>= buff
->size())
186 buff
->resize(Min(Max(PageSize
, read_len
* 2), max_len
));
187 CHECK_LT(read_len
, buff
->size());
188 CHECK_LE(buff
->size(), max_len
);
190 if (!ReadFromFile(fd
, buff
->data() + read_len
, buff
->size() - read_len
,
191 &just_read
, errno_p
)) {
195 read_len
+= just_read
;
200 buff
->resize(read_len
);
204 static const char kPathSeparator
= SANITIZER_WINDOWS
? ';' : ':';
206 char *FindPathToBinary(const char *name
) {
207 if (FileExists(name
)) {
208 return internal_strdup(name
);
211 const char *path
= GetEnv("PATH");
214 uptr name_len
= internal_strlen(name
);
215 InternalMmapVector
<char> buffer(kMaxPathLength
);
216 const char *beg
= path
;
218 const char *end
= internal_strchrnul(beg
, kPathSeparator
);
219 uptr prefix_len
= end
- beg
;
220 if (prefix_len
+ name_len
+ 2 <= kMaxPathLength
) {
221 internal_memcpy(buffer
.data(), beg
, prefix_len
);
222 buffer
[prefix_len
] = '/';
223 internal_memcpy(&buffer
[prefix_len
+ 1], name
, name_len
);
224 buffer
[prefix_len
+ 1 + name_len
] = '\0';
225 if (FileExists(buffer
.data()))
226 return internal_strdup(buffer
.data());
228 if (*end
== '\0') break;
234 } // namespace __sanitizer
236 using namespace __sanitizer
;
239 void __sanitizer_set_report_path(const char *path
) {
240 report_file
.SetReportPath(path
);
243 void __sanitizer_set_report_fd(void *fd
) {
244 report_file
.fd
= (fd_t
)reinterpret_cast<uptr
>(fd
);
245 report_file
.fd_pid
= internal_getpid();
248 const char *__sanitizer_get_report_path() {
249 return report_file
.GetReportPath();
253 #endif // !SANITIZER_FUCHSIA