sanitizer_common.cc revision dedba5d6b0664218b1b1109f024a1ab151642776
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
17namespace __sanitizer {
18
19uptr GetPageSizeCached() {
20  static uptr PageSize;
21  if (!PageSize)
22    PageSize = GetPageSize();
23  return PageSize;
24}
25
26static bool log_to_file = false;  // Set to true by __sanitizer_set_report_path
27
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>".
31static fd_t report_fd = kStderrFd;
32static 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|.
35static int report_fd_pid = 0;
36
37static void (*DieCallback)(void);
38void SetDieCallback(void (*callback)(void)) {
39  DieCallback = callback;
40}
41
42void NORETURN Die() {
43  if (DieCallback) {
44    DieCallback();
45  }
46  Exit(1);
47}
48
49static CheckFailedCallbackType CheckFailedCallback;
50void SetCheckFailedCallback(CheckFailedCallbackType callback) {
51  CheckFailedCallback = callback;
52}
53
54void 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);
58  }
59  Report("Sanitizer CHECK failed: %s:%d %s (%lld, %lld)\n", file, line, cond,
60                                                            v1, v2);
61  Die();
62}
63
64static void MaybeOpenReportFile() {
65  if (!log_to_file || (report_fd_pid == GetPid())) return;
66  char report_path_full[4096];
67  internal_snprintf(report_path_full, sizeof(report_path_full),
68                    "%s.%d", report_path_prefix, GetPid());
69  fd_t fd = internal_open(report_path_full, 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);
74    Die();
75  }
76  if (report_fd != kInvalidFd) {
77    // We're in the child. Close the parent's log.
78    internal_close(report_fd);
79  }
80  report_fd = fd;
81  report_fd_pid = GetPid();
82}
83
84bool PrintsToTty() {
85  MaybeOpenReportFile();
86  return internal_isatty(report_fd);
87}
88
89void 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();
96  }
97}
98
99uptr 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 = internal_open(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;
121      }
122      read_len += just_read;
123    }
124    internal_close(fd);
125    if (reached_eof)  // We've read the whole file.
126      break;
127  }
128  return read_len;
129}
130
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.
137void 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;
149    }
150  }
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;
168    }
169  }
170}
171
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.
175void *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;
191}
192
193}  // namespace __sanitizer
194
195using namespace __sanitizer;  // NOLINT
196
197extern "C" {
198void __sanitizer_set_report_path(const char *path) {
199  if (!path) return;
200  uptr len = internal_strlen(path);
201  if (len > sizeof(report_path_prefix) - 100) {
202    Report("ERROR: Path is too long: %c%c%c%c%c%c%c%c...\n",
203           path[0], path[1], path[2], path[3],
204           path[4], path[5], path[6], path[7]);
205    Die();
206  }
207  internal_strncpy(report_path_prefix, path, sizeof(report_path_prefix));
208  report_path_prefix[len] = '\0';
209  report_fd = kInvalidFd;
210  log_to_file = true;
211}
212
213void __sanitizer_set_report_fd(int fd) {
214  if (report_fd != kStdoutFd &&
215      report_fd != kStderrFd &&
216      report_fd != kInvalidFd)
217    internal_close(report_fd);
218  report_fd = fd;
219}
220
221void NOINLINE __sanitizer_sandbox_on_notify(void *reserved) {
222  (void)reserved;
223  PrepareForSandboxing();
224}
225}  // extern "C"
226