1 //===-- sanitizer_common.cc -----------------------------------------------===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file is shared between AddressSanitizer and ThreadSanitizer
11 // run-time libraries.
12 //===----------------------------------------------------------------------===//
13
14 #include "sanitizer_common.h"
15 #include "sanitizer_libc.h"
16
17 namespace __sanitizer {
18
19 const char *SanitizerToolName = "SanitizerTool";
20 uptr SanitizerVerbosity = 0;
21
GetPageSizeCached()22 uptr GetPageSizeCached() {
23 static uptr PageSize;
24 if (!PageSize)
25 PageSize = GetPageSize();
26 return PageSize;
27 }
28
29 static bool log_to_file = false; // Set to true by __sanitizer_set_report_path
30
31 // By default, dump to stderr. If |log_to_file| is true and |report_fd_pid|
32 // isn't equal to the current PID, try to obtain file descriptor by opening
33 // file "report_path_prefix.<PID>".
34 fd_t report_fd = kStderrFd;
35 static char report_path_prefix[4096]; // Set via __sanitizer_set_report_path.
36 // PID of process that opened |report_fd|. If a fork() occurs, the PID of the
37 // child thread will be different from |report_fd_pid|.
38 static uptr report_fd_pid = 0;
39
40 static void (*DieCallback)(void);
SetDieCallback(void (* callback)(void))41 void SetDieCallback(void (*callback)(void)) {
42 DieCallback = callback;
43 }
44
Die()45 void NORETURN Die() {
46 if (DieCallback) {
47 DieCallback();
48 }
49 internal__exit(1);
50 }
51
52 static CheckFailedCallbackType CheckFailedCallback;
SetCheckFailedCallback(CheckFailedCallbackType callback)53 void SetCheckFailedCallback(CheckFailedCallbackType callback) {
54 CheckFailedCallback = callback;
55 }
56
CheckFailed(const char * file,int line,const char * cond,u64 v1,u64 v2)57 void NORETURN CheckFailed(const char *file, int line, const char *cond,
58 u64 v1, u64 v2) {
59 if (CheckFailedCallback) {
60 CheckFailedCallback(file, line, cond, v1, v2);
61 }
62 Report("Sanitizer CHECK failed: %s:%d %s (%lld, %lld)\n", file, line, cond,
63 v1, v2);
64 Die();
65 }
66
MaybeOpenReportFile()67 void MaybeOpenReportFile() {
68 if (!log_to_file || (report_fd_pid == internal_getpid())) return;
69 InternalScopedBuffer<char> report_path_full(4096);
70 internal_snprintf(report_path_full.data(), report_path_full.size(),
71 "%s.%d", report_path_prefix, internal_getpid());
72 uptr openrv = OpenFile(report_path_full.data(), true);
73 if (internal_iserror(openrv)) {
74 report_fd = kStderrFd;
75 log_to_file = false;
76 Report("ERROR: Can't open file: %s\n", report_path_full.data());
77 Die();
78 }
79 if (report_fd != kInvalidFd) {
80 // We're in the child. Close the parent's log.
81 internal_close(report_fd);
82 }
83 report_fd = openrv;
84 report_fd_pid = internal_getpid();
85 }
86
RawWrite(const char * buffer)87 void RawWrite(const char *buffer) {
88 static const char *kRawWriteError = "RawWrite can't output requested buffer!";
89 uptr length = (uptr)internal_strlen(buffer);
90 MaybeOpenReportFile();
91 if (length != internal_write(report_fd, buffer, length)) {
92 internal_write(report_fd, kRawWriteError, internal_strlen(kRawWriteError));
93 Die();
94 }
95 }
96
ReadFileToBuffer(const char * file_name,char ** buff,uptr * buff_size,uptr max_len)97 uptr ReadFileToBuffer(const char *file_name, char **buff,
98 uptr *buff_size, uptr max_len) {
99 uptr PageSize = GetPageSizeCached();
100 uptr kMinFileLen = PageSize;
101 uptr read_len = 0;
102 *buff = 0;
103 *buff_size = 0;
104 // The files we usually open are not seekable, so try different buffer sizes.
105 for (uptr size = kMinFileLen; size <= max_len; size *= 2) {
106 uptr openrv = OpenFile(file_name, /*write*/ false);
107 if (internal_iserror(openrv)) return 0;
108 fd_t fd = openrv;
109 UnmapOrDie(*buff, *buff_size);
110 *buff = (char*)MmapOrDie(size, __FUNCTION__);
111 *buff_size = size;
112 // Read up to one page at a time.
113 read_len = 0;
114 bool reached_eof = false;
115 while (read_len + PageSize <= size) {
116 uptr just_read = internal_read(fd, *buff + read_len, PageSize);
117 if (just_read == 0) {
118 reached_eof = true;
119 break;
120 }
121 read_len += just_read;
122 }
123 internal_close(fd);
124 if (reached_eof) // We've read the whole file.
125 break;
126 }
127 return read_len;
128 }
129
130 typedef bool UptrComparisonFunction(const uptr &a, const uptr &b);
131
132 template<class T>
CompareLess(const T & a,const T & b)133 static inline bool CompareLess(const T &a, const T &b) {
134 return a < b;
135 }
136
SortArray(uptr * array,uptr size)137 void SortArray(uptr *array, uptr size) {
138 InternalSort<uptr*, UptrComparisonFunction>(&array, size, CompareLess);
139 }
140
141 // We want to map a chunk of address space aligned to 'alignment'.
142 // We do it by maping a bit more and then unmaping redundant pieces.
143 // We probably can do it with fewer syscalls in some OS-dependent way.
MmapAlignedOrDie(uptr size,uptr alignment,const char * mem_type)144 void *MmapAlignedOrDie(uptr size, uptr alignment, const char *mem_type) {
145 // uptr PageSize = GetPageSizeCached();
146 CHECK(IsPowerOfTwo(size));
147 CHECK(IsPowerOfTwo(alignment));
148 uptr map_size = size + alignment;
149 uptr map_res = (uptr)MmapOrDie(map_size, mem_type);
150 uptr map_end = map_res + map_size;
151 uptr res = map_res;
152 if (res & (alignment - 1)) // Not aligned.
153 res = (map_res + alignment) & ~(alignment - 1);
154 uptr end = res + size;
155 if (res != map_res)
156 UnmapOrDie((void*)map_res, res - map_res);
157 if (end != map_end)
158 UnmapOrDie((void*)end, map_end - end);
159 return (void*)res;
160 }
161
ReportErrorSummary(const char * error_type,const char * file,int line,const char * function)162 void ReportErrorSummary(const char *error_type, const char *file,
163 int line, const char *function) {
164 const int kMaxSize = 1024; // We don't want a summary too long.
165 InternalScopedBuffer<char> buff(kMaxSize);
166 internal_snprintf(buff.data(), kMaxSize, "%s: %s %s:%d %s",
167 SanitizerToolName, error_type,
168 file ? file : "??", line, function ? function : "??");
169 __sanitizer_report_error_summary(buff.data());
170 }
171
172 } // namespace __sanitizer
173
174 using namespace __sanitizer; // NOLINT
175
176 extern "C" {
__sanitizer_set_report_path(const char * path)177 void __sanitizer_set_report_path(const char *path) {
178 if (!path) return;
179 uptr len = internal_strlen(path);
180 if (len > sizeof(report_path_prefix) - 100) {
181 Report("ERROR: Path is too long: %c%c%c%c%c%c%c%c...\n",
182 path[0], path[1], path[2], path[3],
183 path[4], path[5], path[6], path[7]);
184 Die();
185 }
186 internal_strncpy(report_path_prefix, path, sizeof(report_path_prefix));
187 report_path_prefix[len] = '\0';
188 report_fd = kInvalidFd;
189 log_to_file = true;
190 }
191
__sanitizer_set_report_fd(int fd)192 void __sanitizer_set_report_fd(int fd) {
193 if (report_fd != kStdoutFd &&
194 report_fd != kStderrFd &&
195 report_fd != kInvalidFd)
196 internal_close(report_fd);
197 report_fd = fd;
198 }
199
__sanitizer_sandbox_on_notify(void * reserved)200 void NOINLINE __sanitizer_sandbox_on_notify(void *reserved) {
201 (void)reserved;
202 PrepareForSandboxing();
203 }
204
__sanitizer_report_error_summary(const char * error_summary)205 void __sanitizer_report_error_summary(const char *error_summary) {
206 Printf("SUMMARY: %s\n", error_summary);
207 }
208 } // extern "C"
209