1 //===-- sanitizer_common_libcdep.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"
14 #include "sanitizer_allocator_interface.h"
15 #include "sanitizer_flags.h"
16 #include "sanitizer_stackdepot.h"
17 #include "sanitizer_stacktrace.h"
18 #include "sanitizer_symbolizer.h"
21 #include "sanitizer_posix.h"
24 namespace __sanitizer
{
26 bool ReportFile::SupportsColors() {
29 return SupportsColoredOutput(fd
);
32 bool ColorizeReports() {
33 // FIXME: Add proper Windows support to AnsiColorDecorator and re-enable color
34 // printing on Windows.
35 if (SANITIZER_WINDOWS
)
38 const char *flag
= common_flags()->color
;
39 return internal_strcmp(flag
, "always") == 0 ||
40 (internal_strcmp(flag
, "auto") == 0 && report_file
.SupportsColors());
43 static void (*sandboxing_callback
)();
44 void SetSandboxingCallback(void (*f
)()) {
45 sandboxing_callback
= f
;
48 void ReportErrorSummary(const char *error_type
, const StackTrace
*stack
) {
50 if (!common_flags()->print_summary
)
52 if (stack
->size
== 0) {
53 ReportErrorSummary(error_type
);
56 // Currently, we include the first stack frame into the report summary.
57 // Maybe sometimes we need to choose another frame (e.g. skip memcpy/etc).
58 uptr pc
= StackTrace::GetPreviousInstructionPc(stack
->trace
[0]);
59 SymbolizedStack
*frame
= Symbolizer::GetOrInit()->SymbolizePC(pc
);
60 ReportErrorSummary(error_type
, frame
->info
);
65 static void (*SoftRssLimitExceededCallback
)(bool exceeded
);
66 void SetSoftRssLimitExceededCallback(void (*Callback
)(bool exceeded
)) {
67 CHECK_EQ(SoftRssLimitExceededCallback
, nullptr);
68 SoftRssLimitExceededCallback
= Callback
;
71 static AllocatorReleaseToOSCallback ReleseCallback
;
72 void SetAllocatorReleaseToOSCallback(AllocatorReleaseToOSCallback Callback
) {
73 CHECK_EQ(ReleseCallback
, nullptr);
74 ReleseCallback
= Callback
;
77 #if SANITIZER_LINUX && !SANITIZER_GO
78 void BackgroundThread(void *arg
) {
79 uptr hard_rss_limit_mb
= common_flags()->hard_rss_limit_mb
;
80 uptr soft_rss_limit_mb
= common_flags()->soft_rss_limit_mb
;
81 bool heap_profile
= common_flags()->heap_profile
;
82 bool allocator_release_to_os
= common_flags()->allocator_release_to_os
;
83 uptr prev_reported_rss
= 0;
84 uptr prev_reported_stack_depot_size
= 0;
85 bool reached_soft_rss_limit
= false;
86 uptr rss_during_last_reported_profile
= 0;
89 uptr current_rss_mb
= GetRSS() >> 20;
91 // If RSS has grown 10% since last time, print some information.
92 if (prev_reported_rss
* 11 / 10 < current_rss_mb
) {
93 Printf("%s: RSS: %zdMb\n", SanitizerToolName
, current_rss_mb
);
94 prev_reported_rss
= current_rss_mb
;
96 // If stack depot has grown 10% since last time, print it too.
97 StackDepotStats
*stack_depot_stats
= StackDepotGetStats();
98 if (prev_reported_stack_depot_size
* 11 / 10 <
99 stack_depot_stats
->allocated
) {
100 Printf("%s: StackDepot: %zd ids; %zdM allocated\n",
102 stack_depot_stats
->n_uniq_ids
,
103 stack_depot_stats
->allocated
>> 20);
104 prev_reported_stack_depot_size
= stack_depot_stats
->allocated
;
107 // Check RSS against the limit.
108 if (hard_rss_limit_mb
&& hard_rss_limit_mb
< current_rss_mb
) {
109 Report("%s: hard rss limit exhausted (%zdMb vs %zdMb)\n",
110 SanitizerToolName
, hard_rss_limit_mb
, current_rss_mb
);
114 if (soft_rss_limit_mb
) {
115 if (soft_rss_limit_mb
< current_rss_mb
&& !reached_soft_rss_limit
) {
116 reached_soft_rss_limit
= true;
117 Report("%s: soft rss limit exhausted (%zdMb vs %zdMb)\n",
118 SanitizerToolName
, soft_rss_limit_mb
, current_rss_mb
);
119 if (SoftRssLimitExceededCallback
)
120 SoftRssLimitExceededCallback(true);
121 } else if (soft_rss_limit_mb
>= current_rss_mb
&&
122 reached_soft_rss_limit
) {
123 reached_soft_rss_limit
= false;
124 if (SoftRssLimitExceededCallback
)
125 SoftRssLimitExceededCallback(false);
128 if (allocator_release_to_os
&& ReleseCallback
) ReleseCallback();
130 current_rss_mb
> rss_during_last_reported_profile
* 1.1) {
131 Printf("\n\nHEAP PROFILE at RSS %zdMb\n", current_rss_mb
);
132 __sanitizer_print_memory_profile(90);
133 rss_during_last_reported_profile
= current_rss_mb
;
139 void WriteToSyslog(const char *msg
) {
140 InternalScopedString
msg_copy(kErrorMessageBufferSize
);
141 msg_copy
.append("%s", msg
);
142 char *p
= msg_copy
.data();
145 // Print one line at a time.
146 // syslog, at least on Android, has an implicit message length limit.
148 q
= internal_strchr(p
, '\n');
151 WriteOneLineToSyslog(p
);
157 void MaybeStartBackgroudThread() {
158 #if SANITIZER_LINUX && \
159 !SANITIZER_GO // Need to implement/test on other platforms.
160 // Start the background thread if one of the rss limits is given.
161 if (!common_flags()->hard_rss_limit_mb
&&
162 !common_flags()->soft_rss_limit_mb
&&
163 !common_flags()->allocator_release_to_os
&&
164 !common_flags()->heap_profile
) return;
165 if (!&real_pthread_create
) return; // Can't spawn the thread anyway.
166 internal_start_thread(BackgroundThread
, nullptr);
170 } // namespace __sanitizer
173 __sanitizer_sandbox_on_notify(__sanitizer_sandbox_arguments
*args
) {
174 __sanitizer::PrepareForSandboxing(args
);
175 if (__sanitizer::sandboxing_callback
)
176 __sanitizer::sandboxing_callback();