2013-06-12 Richard Biener <rguenther@suse.de>
[official-gcc.git] / libsanitizer / sanitizer_common / sanitizer_common.cc
blobf8d2d0e3fe5cff068868f4be089761d15aceadbb
1 //===-- sanitizer_common.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.
10 //===----------------------------------------------------------------------===//
12 #include "sanitizer_common.h"
13 #include "sanitizer_libc.h"
15 namespace __sanitizer {
17 const char *SanitizerToolName = "SanitizerTool";
19 uptr GetPageSizeCached() {
20 static uptr PageSize;
21 if (!PageSize)
22 PageSize = GetPageSize();
23 return PageSize;
26 static bool log_to_file = false; // Set to true by __sanitizer_set_report_path
28 // By default, dump to stderr. If |log_to_file| is true and |report_fd_pid|
29 // isn't equal to the current PID, try to obtain file descriptor by opening
30 // file "report_path_prefix.<PID>".
31 static fd_t report_fd = kStderrFd;
32 static char report_path_prefix[4096]; // Set via __sanitizer_set_report_path.
33 // PID of process that opened |report_fd|. If a fork() occurs, the PID of the
34 // child thread will be different from |report_fd_pid|.
35 static int report_fd_pid = 0;
37 static void (*DieCallback)(void);
38 void SetDieCallback(void (*callback)(void)) {
39 DieCallback = callback;
42 void NORETURN Die() {
43 if (DieCallback) {
44 DieCallback();
46 internal__exit(1);
49 static CheckFailedCallbackType CheckFailedCallback;
50 void SetCheckFailedCallback(CheckFailedCallbackType callback) {
51 CheckFailedCallback = callback;
54 void NORETURN CheckFailed(const char *file, int line, const char *cond,
55 u64 v1, u64 v2) {
56 if (CheckFailedCallback) {
57 CheckFailedCallback(file, line, cond, v1, v2);
59 Report("Sanitizer CHECK failed: %s:%d %s (%lld, %lld)\n", file, line, cond,
60 v1, v2);
61 Die();
64 static void MaybeOpenReportFile() {
65 if (!log_to_file || (report_fd_pid == GetPid())) return;
66 InternalScopedBuffer<char> report_path_full(4096);
67 internal_snprintf(report_path_full.data(), report_path_full.size(),
68 "%s.%d", report_path_prefix, GetPid());
69 fd_t fd = OpenFile(report_path_full.data(), true);
70 if (fd == kInvalidFd) {
71 report_fd = kStderrFd;
72 log_to_file = false;
73 Report("ERROR: Can't open file: %s\n", report_path_full.data());
74 Die();
76 if (report_fd != kInvalidFd) {
77 // We're in the child. Close the parent's log.
78 internal_close(report_fd);
80 report_fd = fd;
81 report_fd_pid = GetPid();
84 bool PrintsToTty() {
85 MaybeOpenReportFile();
86 return internal_isatty(report_fd);
89 void RawWrite(const char *buffer) {
90 static const char *kRawWriteError = "RawWrite can't output requested buffer!";
91 uptr length = (uptr)internal_strlen(buffer);
92 MaybeOpenReportFile();
93 if (length != internal_write(report_fd, buffer, length)) {
94 internal_write(report_fd, kRawWriteError, internal_strlen(kRawWriteError));
95 Die();
99 uptr ReadFileToBuffer(const char *file_name, char **buff,
100 uptr *buff_size, uptr max_len) {
101 uptr PageSize = GetPageSizeCached();
102 uptr kMinFileLen = PageSize;
103 uptr read_len = 0;
104 *buff = 0;
105 *buff_size = 0;
106 // The files we usually open are not seekable, so try different buffer sizes.
107 for (uptr size = kMinFileLen; size <= max_len; size *= 2) {
108 fd_t fd = OpenFile(file_name, /*write*/ false);
109 if (fd == kInvalidFd) return 0;
110 UnmapOrDie(*buff, *buff_size);
111 *buff = (char*)MmapOrDie(size, __FUNCTION__);
112 *buff_size = size;
113 // Read up to one page at a time.
114 read_len = 0;
115 bool reached_eof = false;
116 while (read_len + PageSize <= size) {
117 uptr just_read = internal_read(fd, *buff + read_len, PageSize);
118 if (just_read == 0) {
119 reached_eof = true;
120 break;
122 read_len += just_read;
124 internal_close(fd);
125 if (reached_eof) // We've read the whole file.
126 break;
128 return read_len;
131 // We don't want to use std::sort to avoid including <algorithm>, as
132 // we may end up with two implementation of std::sort - one in instrumented
133 // code, and the other in runtime.
134 // qsort() from stdlib won't work as it calls malloc(), which results
135 // in deadlock in ASan allocator.
136 // We re-implement in-place sorting w/o recursion as straightforward heapsort.
137 void SortArray(uptr *array, uptr size) {
138 if (size < 2)
139 return;
140 // Stage 1: insert elements to the heap.
141 for (uptr i = 1; i < size; i++) {
142 uptr j, p;
143 for (j = i; j > 0; j = p) {
144 p = (j - 1) / 2;
145 if (array[j] > array[p])
146 Swap(array[j], array[p]);
147 else
148 break;
151 // Stage 2: swap largest element with the last one,
152 // and sink the new top.
153 for (uptr i = size - 1; i > 0; i--) {
154 Swap(array[0], array[i]);
155 uptr j, max_ind;
156 for (j = 0; j < i; j = max_ind) {
157 uptr left = 2 * j + 1;
158 uptr right = 2 * j + 2;
159 max_ind = j;
160 if (left < i && array[left] > array[max_ind])
161 max_ind = left;
162 if (right < i && array[right] > array[max_ind])
163 max_ind = right;
164 if (max_ind != j)
165 Swap(array[j], array[max_ind]);
166 else
167 break;
172 // We want to map a chunk of address space aligned to 'alignment'.
173 // We do it by maping a bit more and then unmaping redundant pieces.
174 // We probably can do it with fewer syscalls in some OS-dependent way.
175 void *MmapAlignedOrDie(uptr size, uptr alignment, const char *mem_type) {
176 // uptr PageSize = GetPageSizeCached();
177 CHECK(IsPowerOfTwo(size));
178 CHECK(IsPowerOfTwo(alignment));
179 uptr map_size = size + alignment;
180 uptr map_res = (uptr)MmapOrDie(map_size, mem_type);
181 uptr map_end = map_res + map_size;
182 uptr res = map_res;
183 if (res & (alignment - 1)) // Not aligned.
184 res = (map_res + alignment) & ~(alignment - 1);
185 uptr end = res + size;
186 if (res != map_res)
187 UnmapOrDie((void*)map_res, res - map_res);
188 if (end != map_end)
189 UnmapOrDie((void*)end, map_end - end);
190 return (void*)res;
193 void ReportErrorSummary(const char *error_type, const char *file,
194 int line, const char *function) {
195 const int kMaxSize = 1024; // We don't want a summary too long.
196 InternalScopedBuffer<char> buff(kMaxSize);
197 internal_snprintf(buff.data(), kMaxSize, "%s: %s %s:%d %s",
198 SanitizerToolName, error_type,
199 file ? file : "??", line, function ? function : "??");
200 __sanitizer_report_error_summary(buff.data());
203 } // namespace __sanitizer
205 using namespace __sanitizer; // NOLINT
207 extern "C" {
208 void __sanitizer_set_report_path(const char *path) {
209 if (!path) return;
210 uptr len = internal_strlen(path);
211 if (len > sizeof(report_path_prefix) - 100) {
212 Report("ERROR: Path is too long: %c%c%c%c%c%c%c%c...\n",
213 path[0], path[1], path[2], path[3],
214 path[4], path[5], path[6], path[7]);
215 Die();
217 internal_strncpy(report_path_prefix, path, sizeof(report_path_prefix));
218 report_path_prefix[len] = '\0';
219 report_fd = kInvalidFd;
220 log_to_file = true;
223 void __sanitizer_set_report_fd(int fd) {
224 if (report_fd != kStdoutFd &&
225 report_fd != kStderrFd &&
226 report_fd != kInvalidFd)
227 internal_close(report_fd);
228 report_fd = fd;
231 void NOINLINE __sanitizer_sandbox_on_notify(void *reserved) {
232 (void)reserved;
233 PrepareForSandboxing();
236 void __sanitizer_report_error_summary(const char *error_summary) {
237 Printf("SUMMARY: %s\n", error_summary);
239 } // extern "C"