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_flags.h"
14 #include "sanitizer_libc.h"
15 #include "sanitizer_stacktrace.h"
16 #include "sanitizer_symbolizer.h"
18 namespace __sanitizer
{
20 const char *SanitizerToolName
= "SanitizerTool";
22 uptr
GetPageSizeCached() {
25 PageSize
= GetPageSize();
30 // By default, dump to stderr. If |log_to_file| is true and |report_fd_pid|
31 // isn't equal to the current PID, try to obtain file descriptor by opening
32 // file "report_path_prefix.<PID>".
33 fd_t report_fd
= kStderrFd
;
35 // Set via __sanitizer_set_report_path.
36 bool log_to_file
= false;
37 char report_path_prefix
[sizeof(report_path_prefix
)];
39 // PID of process that opened |report_fd|. If a fork() occurs, the PID of the
40 // child thread will be different from |report_fd_pid|.
41 uptr report_fd_pid
= 0;
43 // PID of the tracer task in StopTheWorld. It shares the address space with the
44 // main process, but has a different PID and thus requires special handling.
45 uptr stoptheworld_tracer_pid
= 0;
46 // Cached pid of parent process - if the parent process dies, we want to keep
47 // writing to the same log file.
48 uptr stoptheworld_tracer_ppid
= 0;
50 static DieCallbackType DieCallback
;
51 void SetDieCallback(DieCallbackType callback
) {
52 DieCallback
= callback
;
55 DieCallbackType
GetDieCallback() {
66 static CheckFailedCallbackType CheckFailedCallback
;
67 void SetCheckFailedCallback(CheckFailedCallbackType callback
) {
68 CheckFailedCallback
= callback
;
71 void NORETURN
CheckFailed(const char *file
, int line
, const char *cond
,
73 if (CheckFailedCallback
) {
74 CheckFailedCallback(file
, line
, cond
, v1
, v2
);
76 Report("Sanitizer CHECK failed: %s:%d %s (%lld, %lld)\n", file
, line
, cond
,
81 uptr
ReadFileToBuffer(const char *file_name
, char **buff
,
82 uptr
*buff_size
, uptr max_len
) {
83 uptr PageSize
= GetPageSizeCached();
84 uptr kMinFileLen
= PageSize
;
88 // The files we usually open are not seekable, so try different buffer sizes.
89 for (uptr size
= kMinFileLen
; size
<= max_len
; size
*= 2) {
90 uptr openrv
= OpenFile(file_name
, /*write*/ false);
91 if (internal_iserror(openrv
)) return 0;
93 UnmapOrDie(*buff
, *buff_size
);
94 *buff
= (char*)MmapOrDie(size
, __func__
);
96 // Read up to one page at a time.
98 bool reached_eof
= false;
99 while (read_len
+ PageSize
<= size
) {
100 uptr just_read
= internal_read(fd
, *buff
+ read_len
, PageSize
);
101 if (just_read
== 0) {
105 read_len
+= just_read
;
108 if (reached_eof
) // We've read the whole file.
114 typedef bool UptrComparisonFunction(const uptr
&a
, const uptr
&b
);
117 static inline bool CompareLess(const T
&a
, const T
&b
) {
121 void SortArray(uptr
*array
, uptr size
) {
122 InternalSort
<uptr
*, UptrComparisonFunction
>(&array
, size
, CompareLess
);
125 // We want to map a chunk of address space aligned to 'alignment'.
126 // We do it by maping a bit more and then unmaping redundant pieces.
127 // We probably can do it with fewer syscalls in some OS-dependent way.
128 void *MmapAlignedOrDie(uptr size
, uptr alignment
, const char *mem_type
) {
129 // uptr PageSize = GetPageSizeCached();
130 CHECK(IsPowerOfTwo(size
));
131 CHECK(IsPowerOfTwo(alignment
));
132 uptr map_size
= size
+ alignment
;
133 uptr map_res
= (uptr
)MmapOrDie(map_size
, mem_type
);
134 uptr map_end
= map_res
+ map_size
;
136 if (res
& (alignment
- 1)) // Not aligned.
137 res
= (map_res
+ alignment
) & ~(alignment
- 1);
138 uptr end
= res
+ size
;
140 UnmapOrDie((void*)map_res
, res
- map_res
);
142 UnmapOrDie((void*)end
, map_end
- end
);
146 const char *StripPathPrefix(const char *filepath
,
147 const char *strip_path_prefix
) {
148 if (filepath
== 0) return 0;
149 if (strip_path_prefix
== 0) return filepath
;
150 const char *pos
= internal_strstr(filepath
, strip_path_prefix
);
151 if (pos
== 0) return filepath
;
152 pos
+= internal_strlen(strip_path_prefix
);
153 if (pos
[0] == '.' && pos
[1] == '/')
158 void PrintSourceLocation(InternalScopedString
*buffer
, const char *file
,
159 int line
, int column
) {
162 StripPathPrefix(file
, common_flags()->strip_path_prefix
));
164 buffer
->append(":%d", line
);
166 buffer
->append(":%d", column
);
170 void PrintModuleAndOffset(InternalScopedString
*buffer
, const char *module
,
172 buffer
->append("(%s+0x%zx)",
173 StripPathPrefix(module
, common_flags()->strip_path_prefix
),
177 void ReportErrorSummary(const char *error_message
) {
178 if (!common_flags()->print_summary
)
180 InternalScopedBuffer
<char> buff(kMaxSummaryLength
);
181 internal_snprintf(buff
.data(), buff
.size(),
182 "SUMMARY: %s: %s", SanitizerToolName
, error_message
);
183 __sanitizer_report_error_summary(buff
.data());
186 void ReportErrorSummary(const char *error_type
, const char *file
,
187 int line
, const char *function
) {
188 if (!common_flags()->print_summary
)
190 InternalScopedBuffer
<char> buff(kMaxSummaryLength
);
192 buff
.data(), buff
.size(), "%s %s:%d %s", error_type
,
193 file
? StripPathPrefix(file
, common_flags()->strip_path_prefix
) : "??",
194 line
, function
? function
: "??");
195 ReportErrorSummary(buff
.data());
198 void ReportErrorSummary(const char *error_type
, StackTrace
*stack
) {
199 if (!common_flags()->print_summary
)
203 if (stack
->size
> 0 && Symbolizer::Get()->CanReturnFileLineInfo()) {
204 // Currently, we include the first stack frame into the report summary.
205 // Maybe sometimes we need to choose another frame (e.g. skip memcpy/etc).
206 uptr pc
= StackTrace::GetPreviousInstructionPc(stack
->trace
[0]);
207 Symbolizer::Get()->SymbolizePC(pc
, &ai
, 1);
210 ReportErrorSummary(error_type
, ai
.file
, ai
.line
, ai
.function
);
213 LoadedModule::LoadedModule(const char *module_name
, uptr base_address
) {
214 full_name_
= internal_strdup(module_name
);
215 base_address_
= base_address
;
219 void LoadedModule::addAddressRange(uptr beg
, uptr end
) {
220 CHECK_LT(n_ranges_
, kMaxNumberOfAddressRanges
);
221 ranges_
[n_ranges_
].beg
= beg
;
222 ranges_
[n_ranges_
].end
= end
;
226 bool LoadedModule::containsAddress(uptr address
) const {
227 for (uptr i
= 0; i
< n_ranges_
; i
++) {
228 if (ranges_
[i
].beg
<= address
&& address
< ranges_
[i
].end
)
234 char *StripModuleName(const char *module
) {
237 const char *short_module_name
= internal_strrchr(module
, '/');
238 if (short_module_name
)
239 short_module_name
+= 1;
241 short_module_name
= module
;
242 return internal_strdup(short_module_name
);
245 static atomic_uintptr_t g_total_mmaped
;
247 void IncreaseTotalMmap(uptr size
) {
248 if (!common_flags()->mmap_limit_mb
) return;
250 atomic_fetch_add(&g_total_mmaped
, size
, memory_order_relaxed
) + size
;
251 if ((total_mmaped
>> 20) > common_flags()->mmap_limit_mb
) {
252 // Since for now mmap_limit_mb is not a user-facing flag, just CHECK.
253 uptr mmap_limit_mb
= common_flags()->mmap_limit_mb
;
254 common_flags()->mmap_limit_mb
= 0; // Allow mmap in CHECK.
255 RAW_CHECK(total_mmaped
>> 20 < mmap_limit_mb
);
259 void DecreaseTotalMmap(uptr size
) {
260 if (!common_flags()->mmap_limit_mb
) return;
261 atomic_fetch_sub(&g_total_mmaped
, size
, memory_order_relaxed
);
264 static void (*sandboxing_callback
)();
265 void SetSandboxingCallback(void (*f
)()) {
266 sandboxing_callback
= f
;
269 } // namespace __sanitizer
271 using namespace __sanitizer
; // NOLINT
274 void __sanitizer_set_report_path(const char *path
) {
277 uptr len
= internal_strlen(path
);
278 if (len
> sizeof(report_path_prefix
) - 100) {
279 Report("ERROR: Path is too long: %c%c%c%c%c%c%c%c...\n",
280 path
[0], path
[1], path
[2], path
[3],
281 path
[4], path
[5], path
[6], path
[7]);
284 if (report_fd
!= kStdoutFd
&&
285 report_fd
!= kStderrFd
&&
286 report_fd
!= kInvalidFd
)
287 internal_close(report_fd
);
288 report_fd
= kInvalidFd
;
290 if (internal_strcmp(path
, "stdout") == 0) {
291 report_fd
= kStdoutFd
;
292 } else if (internal_strcmp(path
, "stderr") == 0) {
293 report_fd
= kStderrFd
;
295 internal_strncpy(report_path_prefix
, path
, sizeof(report_path_prefix
));
296 report_path_prefix
[len
] = '\0';
302 __sanitizer_sandbox_on_notify(__sanitizer_sandbox_arguments
*args
) {
303 PrepareForSandboxing(args
);
304 if (sandboxing_callback
)
305 sandboxing_callback();
308 void __sanitizer_report_error_summary(const char *error_summary
) {
309 Printf("%s\n", error_summary
);