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