1 //===-- sanitizer_common_libcdep.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_allocator_interface.h"
15 #include "sanitizer_common.h"
16 #include "sanitizer_flags.h"
17 #include "sanitizer_procmaps.h"
18
19
20 namespace __sanitizer {
21
22 static void (*SoftRssLimitExceededCallback)(bool exceeded);
SetSoftRssLimitExceededCallback(void (* Callback)(bool exceeded))23 void SetSoftRssLimitExceededCallback(void (*Callback)(bool exceeded)) {
24 CHECK_EQ(SoftRssLimitExceededCallback, nullptr);
25 SoftRssLimitExceededCallback = Callback;
26 }
27
28 #if (SANITIZER_LINUX || SANITIZER_NETBSD) && !SANITIZER_GO
29 // Weak default implementation for when sanitizer_stackdepot is not linked in.
StackDepotGetStats()30 SANITIZER_WEAK_ATTRIBUTE StackDepotStats *StackDepotGetStats() {
31 return nullptr;
32 }
33
BackgroundThread(void * arg)34 void BackgroundThread(void *arg) {
35 const uptr hard_rss_limit_mb = common_flags()->hard_rss_limit_mb;
36 const uptr soft_rss_limit_mb = common_flags()->soft_rss_limit_mb;
37 const bool heap_profile = common_flags()->heap_profile;
38 uptr prev_reported_rss = 0;
39 uptr prev_reported_stack_depot_size = 0;
40 bool reached_soft_rss_limit = false;
41 uptr rss_during_last_reported_profile = 0;
42 while (true) {
43 SleepForMillis(100);
44 const uptr current_rss_mb = GetRSS() >> 20;
45 if (Verbosity()) {
46 // If RSS has grown 10% since last time, print some information.
47 if (prev_reported_rss * 11 / 10 < current_rss_mb) {
48 Printf("%s: RSS: %zdMb\n", SanitizerToolName, current_rss_mb);
49 prev_reported_rss = current_rss_mb;
50 }
51 // If stack depot has grown 10% since last time, print it too.
52 StackDepotStats *stack_depot_stats = StackDepotGetStats();
53 if (stack_depot_stats) {
54 if (prev_reported_stack_depot_size * 11 / 10 <
55 stack_depot_stats->allocated) {
56 Printf("%s: StackDepot: %zd ids; %zdM allocated\n",
57 SanitizerToolName,
58 stack_depot_stats->n_uniq_ids,
59 stack_depot_stats->allocated >> 20);
60 prev_reported_stack_depot_size = stack_depot_stats->allocated;
61 }
62 }
63 }
64 // Check RSS against the limit.
65 if (hard_rss_limit_mb && hard_rss_limit_mb < current_rss_mb) {
66 Report("%s: hard rss limit exhausted (%zdMb vs %zdMb)\n",
67 SanitizerToolName, hard_rss_limit_mb, current_rss_mb);
68 DumpProcessMap();
69 Die();
70 }
71 if (soft_rss_limit_mb) {
72 if (soft_rss_limit_mb < current_rss_mb && !reached_soft_rss_limit) {
73 reached_soft_rss_limit = true;
74 Report("%s: soft rss limit exhausted (%zdMb vs %zdMb)\n",
75 SanitizerToolName, soft_rss_limit_mb, current_rss_mb);
76 if (SoftRssLimitExceededCallback)
77 SoftRssLimitExceededCallback(true);
78 } else if (soft_rss_limit_mb >= current_rss_mb &&
79 reached_soft_rss_limit) {
80 reached_soft_rss_limit = false;
81 if (SoftRssLimitExceededCallback)
82 SoftRssLimitExceededCallback(false);
83 }
84 }
85 if (heap_profile &&
86 current_rss_mb > rss_during_last_reported_profile * 1.1) {
87 Printf("\n\nHEAP PROFILE at RSS %zdMb\n", current_rss_mb);
88 __sanitizer_print_memory_profile(90, 20);
89 rss_during_last_reported_profile = current_rss_mb;
90 }
91 }
92 }
93 #endif
94
WriteToSyslog(const char * msg)95 void WriteToSyslog(const char *msg) {
96 InternalScopedString msg_copy(kErrorMessageBufferSize);
97 msg_copy.append("%s", msg);
98 char *p = msg_copy.data();
99 char *q;
100
101 // Print one line at a time.
102 // syslog, at least on Android, has an implicit message length limit.
103 while ((q = internal_strchr(p, '\n'))) {
104 *q = '\0';
105 WriteOneLineToSyslog(p);
106 p = q + 1;
107 }
108 // Print remaining characters, if there are any.
109 // Note that this will add an extra newline at the end.
110 // FIXME: buffer extra output. This would need a thread-local buffer, which
111 // on Android requires plugging into the tools (ex. ASan's) Thread class.
112 if (*p)
113 WriteOneLineToSyslog(p);
114 }
115
MaybeStartBackgroudThread()116 void MaybeStartBackgroudThread() {
117 #if (SANITIZER_LINUX || SANITIZER_NETBSD) && \
118 !SANITIZER_GO // Need to implement/test on other platforms.
119 // Start the background thread if one of the rss limits is given.
120 if (!common_flags()->hard_rss_limit_mb &&
121 !common_flags()->soft_rss_limit_mb &&
122 !common_flags()->heap_profile) return;
123 if (!&real_pthread_create) return; // Can't spawn the thread anyway.
124 internal_start_thread(BackgroundThread, nullptr);
125 #endif
126 }
127
128 static void (*sandboxing_callback)();
SetSandboxingCallback(void (* f)())129 void SetSandboxingCallback(void (*f)()) {
130 sandboxing_callback = f;
131 }
132
133 } // namespace __sanitizer
134
SANITIZER_INTERFACE_WEAK_DEF(void,__sanitizer_sandbox_on_notify,__sanitizer_sandbox_arguments * args)135 SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_sandbox_on_notify,
136 __sanitizer_sandbox_arguments *args) {
137 __sanitizer::PlatformPrepareForSandboxing(args);
138 if (__sanitizer::sandboxing_callback)
139 __sanitizer::sandboxing_callback();
140 }
141