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