1 //===-- sanitizer_common.cc -----------------------------------------------===//
3 // This file is distributed under the University of Illinois Open Source
4 // License. See LICENSE.TXT for details.
6 //===----------------------------------------------------------------------===//
8 // This file is shared between AddressSanitizer and ThreadSanitizer
10 //===----------------------------------------------------------------------===//
12 #include "sanitizer_common.h"
13 #include "sanitizer_libc.h"
15 namespace __sanitizer
{
17 const char *SanitizerToolName
= "SanitizerTool";
19 uptr
GetPageSizeCached() {
22 PageSize
= GetPageSize();
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
;
49 static CheckFailedCallbackType CheckFailedCallback
;
50 void SetCheckFailedCallback(CheckFailedCallbackType callback
) {
51 CheckFailedCallback
= callback
;
54 void NORETURN
CheckFailed(const char *file
, int line
, const char *cond
,
56 if (CheckFailedCallback
) {
57 CheckFailedCallback(file
, line
, cond
, v1
, v2
);
59 Report("Sanitizer CHECK failed: %s:%d %s (%lld, %lld)\n", file
, line
, cond
,
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
;
73 Report("ERROR: Can't open file: %s\n", report_path_full
.data());
76 if (report_fd
!= kInvalidFd
) {
77 // We're in the child. Close the parent's log.
78 internal_close(report_fd
);
81 report_fd_pid
= GetPid();
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
));
99 uptr
ReadFileToBuffer(const char *file_name
, char **buff
,
100 uptr
*buff_size
, uptr max_len
) {
101 uptr PageSize
= GetPageSizeCached();
102 uptr kMinFileLen
= PageSize
;
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__
);
113 // Read up to one page at a time.
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) {
122 read_len
+= just_read
;
125 if (reached_eof
) // We've read the whole file.
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
) {
140 // Stage 1: insert elements to the heap.
141 for (uptr i
= 1; i
< size
; i
++) {
143 for (j
= i
; j
> 0; j
= p
) {
145 if (array
[j
] > array
[p
])
146 Swap(array
[j
], array
[p
]);
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
]);
156 for (j
= 0; j
< i
; j
= max_ind
) {
157 uptr left
= 2 * j
+ 1;
158 uptr right
= 2 * j
+ 2;
160 if (left
< i
&& array
[left
] > array
[max_ind
])
162 if (right
< i
&& array
[right
] > array
[max_ind
])
165 Swap(array
[j
], array
[max_ind
]);
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
;
183 if (res
& (alignment
- 1)) // Not aligned.
184 res
= (map_res
+ alignment
) & ~(alignment
- 1);
185 uptr end
= res
+ size
;
187 UnmapOrDie((void*)map_res
, res
- map_res
);
189 UnmapOrDie((void*)end
, map_end
- end
);
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
208 void __sanitizer_set_report_path(const char *path
) {
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]);
217 internal_strncpy(report_path_prefix
, path
, sizeof(report_path_prefix
));
218 report_path_prefix
[len
] = '\0';
219 report_fd
= kInvalidFd
;
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
);
231 void NOINLINE
__sanitizer_sandbox_on_notify(void *reserved
) {
233 PrepareForSandboxing();
236 void __sanitizer_report_error_summary(const char *error_summary
) {
237 Printf("SUMMARY: %s\n", error_summary
);