blob: 4f5a0befe2f0107e68f1a474c8493b2ed24957f8 [file] [log] [blame]
mistergc2e75482017-09-19 16:54:40 -04001// Copyright 2017 The Abseil Authors.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#include "absl/base/config.h"
16
17#if ABSL_HAVE_MMAP
18// Disable the glibc prototype of mremap(), as older versions of the
19// system headers define this function with only four arguments,
20// whereas newer versions allow an optional fifth argument:
21#define mremap glibc_mremap
22#include <sys/mman.h>
23#undef mremap
24#endif
25
Abseil Team53c239d2017-09-19 17:15:26 -070026#include "absl/base/internal/malloc_hook.h"
27
28#include <algorithm>
mistergc2e75482017-09-19 16:54:40 -040029#include <cstddef>
30#include <cstdint>
mistergc2e75482017-09-19 16:54:40 -040031
32#include "absl/base/call_once.h"
mistergc2e75482017-09-19 16:54:40 -040033#include "absl/base/internal/malloc_hook_invoke.h"
34#include "absl/base/internal/raw_logging.h"
35#include "absl/base/internal/spinlock.h"
Abseil Team53c239d2017-09-19 17:15:26 -070036#include "absl/base/macros.h"
mistergc2e75482017-09-19 16:54:40 -040037
38// __THROW is defined in glibc systems. It means, counter-intuitively,
39// "This function will never throw an exception." It's an optional
40// optimization tool, but we may need to use it to match glibc prototypes.
41#ifndef __THROW // I guess we're not on a glibc system
42# define __THROW // __THROW is just an optimization, so ok to make it ""
43#endif
44
45namespace absl {
46namespace base_internal {
47namespace {
48
49void RemoveInitialHooksAndCallInitializers(); // below.
50
51absl::once_flag once;
52
53// These hooks are installed in MallocHook as the only initial hooks. The first
54// hook that is called will run RemoveInitialHooksAndCallInitializers (see the
55// definition below) and then redispatch to any malloc hooks installed by
56// RemoveInitialHooksAndCallInitializers.
57//
58// Note(llib): there is a possibility of a race in the event that there are
59// multiple threads running before the first allocation. This is pretty
60// difficult to achieve, but if it is then multiple threads may concurrently do
61// allocations. The first caller will call
62// RemoveInitialHooksAndCallInitializers via one of the initial hooks. A
63// concurrent allocation may, depending on timing either:
64// * still have its initial malloc hook installed, run that and block on waiting
65// for the first caller to finish its call to
66// RemoveInitialHooksAndCallInitializers, and proceed normally.
67// * occur some time during the RemoveInitialHooksAndCallInitializers call, at
68// which point there could be no initial hooks and the subsequent hooks that
69// are about to be set up by RemoveInitialHooksAndCallInitializers haven't
70// been installed yet. I think the worst we can get is that some allocations
71// will not get reported to some hooks set by the initializers called from
72// RemoveInitialHooksAndCallInitializers.
73
74void InitialNewHook(const void* ptr, size_t size) {
75 absl::call_once(once, RemoveInitialHooksAndCallInitializers);
76 MallocHook::InvokeNewHook(ptr, size);
77}
78
79void InitialPreMMapHook(const void* start,
80 size_t size,
81 int protection,
82 int flags,
83 int fd,
84 off_t offset) {
85 absl::call_once(once, RemoveInitialHooksAndCallInitializers);
86 MallocHook::InvokePreMmapHook(start, size, protection, flags, fd, offset);
87}
88
89void InitialPreSbrkHook(ptrdiff_t increment) {
90 absl::call_once(once, RemoveInitialHooksAndCallInitializers);
91 MallocHook::InvokePreSbrkHook(increment);
92}
93
94// This function is called at most once by one of the above initial malloc
95// hooks. It removes all initial hooks and initializes all other clients that
96// want to get control at the very first memory allocation. The initializers
97// may assume that the initial malloc hooks have been removed. The initializers
98// may set up malloc hooks and allocate memory.
99void RemoveInitialHooksAndCallInitializers() {
100 ABSL_RAW_CHECK(MallocHook::RemoveNewHook(&InitialNewHook), "");
101 ABSL_RAW_CHECK(MallocHook::RemovePreMmapHook(&InitialPreMMapHook), "");
102 ABSL_RAW_CHECK(MallocHook::RemovePreSbrkHook(&InitialPreSbrkHook), "");
103}
104
105} // namespace
106} // namespace base_internal
107} // namespace absl
108
109namespace absl {
110namespace base_internal {
111
112// This lock is shared between all implementations of HookList::Add & Remove.
113// The potential for contention is very small. This needs to be a SpinLock and
114// not a Mutex since it's possible for Mutex locking to allocate memory (e.g.,
115// per-thread allocation in debug builds), which could cause infinite recursion.
116static absl::base_internal::SpinLock hooklist_spinlock(
117 absl::base_internal::kLinkerInitialized);
118
119template <typename T>
120bool HookList<T>::Add(T value_as_t) {
121 if (value_as_t == T()) {
122 return false;
123 }
124 absl::base_internal::SpinLockHolder l(&hooklist_spinlock);
125 // Find the first slot in data that is 0.
126 int index = 0;
127 while ((index < kHookListMaxValues) &&
128 (priv_data[index].load(std::memory_order_relaxed) != 0)) {
129 ++index;
130 }
131 if (index == kHookListMaxValues) {
132 return false;
133 }
134 int prev_num_hooks = priv_end.load(std::memory_order_acquire);
135 priv_data[index].store(reinterpret_cast<intptr_t>(value_as_t),
136 std::memory_order_release);
137 if (prev_num_hooks <= index) {
138 priv_end.store(index + 1, std::memory_order_release);
139 }
140 return true;
141}
142
143template <typename T>
144bool HookList<T>::Remove(T value_as_t) {
145 if (value_as_t == T()) {
146 return false;
147 }
148 absl::base_internal::SpinLockHolder l(&hooklist_spinlock);
149 int hooks_end = priv_end.load(std::memory_order_acquire);
150 int index = 0;
151 while (index < hooks_end &&
152 value_as_t != reinterpret_cast<T>(
153 priv_data[index].load(std::memory_order_acquire))) {
154 ++index;
155 }
156 if (index == hooks_end) {
157 return false;
158 }
159 priv_data[index].store(0, std::memory_order_release);
160 if (hooks_end == index + 1) {
161 // Adjust hooks_end down to the lowest possible value.
162 hooks_end = index;
163 while ((hooks_end > 0) &&
164 (priv_data[hooks_end - 1].load(std::memory_order_acquire) == 0)) {
165 --hooks_end;
166 }
167 priv_end.store(hooks_end, std::memory_order_release);
168 }
169 return true;
170}
171
172template <typename T>
173int HookList<T>::Traverse(T* output_array, int n) const {
174 int hooks_end = priv_end.load(std::memory_order_acquire);
175 int actual_hooks_end = 0;
176 for (int i = 0; i < hooks_end && n > 0; ++i) {
177 T data = reinterpret_cast<T>(priv_data[i].load(std::memory_order_acquire));
178 if (data != T()) {
179 *output_array++ = data;
180 ++actual_hooks_end;
181 --n;
182 }
183 }
184 return actual_hooks_end;
185}
186
187// Initialize a HookList (optionally with the given initial_value in index 0).
188#define INIT_HOOK_LIST { {0}, {{}} }
189#define INIT_HOOK_LIST_WITH_VALUE(initial_value) \
190 { {1}, { {reinterpret_cast<intptr_t>(initial_value)} } }
191
192// Explicit instantiation for malloc_hook_test.cc. This ensures all the methods
193// are instantiated.
194template struct HookList<MallocHook::NewHook>;
195
196HookList<MallocHook::NewHook> new_hooks_ =
197 INIT_HOOK_LIST_WITH_VALUE(&InitialNewHook);
198HookList<MallocHook::DeleteHook> delete_hooks_ = INIT_HOOK_LIST;
199HookList<MallocHook::SampledNewHook> sampled_new_hooks_ = INIT_HOOK_LIST;
200HookList<MallocHook::SampledDeleteHook> sampled_delete_hooks_ = INIT_HOOK_LIST;
201HookList<MallocHook::PreMmapHook> premmap_hooks_ =
202 INIT_HOOK_LIST_WITH_VALUE(&InitialPreMMapHook);
203HookList<MallocHook::MmapHook> mmap_hooks_ = INIT_HOOK_LIST;
204HookList<MallocHook::MunmapHook> munmap_hooks_ = INIT_HOOK_LIST;
205HookList<MallocHook::MremapHook> mremap_hooks_ = INIT_HOOK_LIST;
206HookList<MallocHook::PreSbrkHook> presbrk_hooks_ =
207 INIT_HOOK_LIST_WITH_VALUE(InitialPreSbrkHook);
208HookList<MallocHook::SbrkHook> sbrk_hooks_ = INIT_HOOK_LIST;
209
210// These lists contain either 0 or 1 hooks.
211HookList<MallocHook::MmapReplacement> mmap_replacement_ = INIT_HOOK_LIST;
212HookList<MallocHook::MunmapReplacement> munmap_replacement_ = INIT_HOOK_LIST;
213
214#undef INIT_HOOK_LIST_WITH_VALUE
215#undef INIT_HOOK_LIST
216
217} // namespace base_internal
218} // namespace absl
219
220// These are available as C bindings as well as C++, hence their
221// definition outside the MallocHook class.
222extern "C"
223int MallocHook_AddNewHook(MallocHook_NewHook hook) {
224 return absl::base_internal::new_hooks_.Add(hook);
225}
226
227extern "C"
228int MallocHook_RemoveNewHook(MallocHook_NewHook hook) {
229 return absl::base_internal::new_hooks_.Remove(hook);
230}
231
232extern "C"
233int MallocHook_AddDeleteHook(MallocHook_DeleteHook hook) {
234 return absl::base_internal::delete_hooks_.Add(hook);
235}
236
237extern "C"
238int MallocHook_RemoveDeleteHook(MallocHook_DeleteHook hook) {
239 return absl::base_internal::delete_hooks_.Remove(hook);
240}
241
242extern "C" int MallocHook_AddSampledNewHook(MallocHook_SampledNewHook hook) {
243 return absl::base_internal::sampled_new_hooks_.Add(hook);
244}
245
246extern "C" int MallocHook_RemoveSampledNewHook(MallocHook_SampledNewHook hook) {
247 return absl::base_internal::sampled_new_hooks_.Remove(hook);
248}
249
250extern "C" int MallocHook_AddSampledDeleteHook(
251 MallocHook_SampledDeleteHook hook) {
252 return absl::base_internal::sampled_delete_hooks_.Add(hook);
253}
254
255extern "C" int MallocHook_RemoveSampledDeleteHook(
256 MallocHook_SampledDeleteHook hook) {
257 return absl::base_internal::sampled_delete_hooks_.Remove(hook);
258}
259
260extern "C"
261int MallocHook_AddPreMmapHook(MallocHook_PreMmapHook hook) {
262 return absl::base_internal::premmap_hooks_.Add(hook);
263}
264
265extern "C"
266int MallocHook_RemovePreMmapHook(MallocHook_PreMmapHook hook) {
267 return absl::base_internal::premmap_hooks_.Remove(hook);
268}
269
270extern "C"
271int MallocHook_SetMmapReplacement(MallocHook_MmapReplacement hook) {
272 // NOTE this is a best effort CHECK. Concurrent sets could succeed since
273 // this test is outside of the Add spin lock.
274 ABSL_RAW_CHECK(absl::base_internal::mmap_replacement_.empty(),
275 "Only one MMapReplacement is allowed.");
276 return absl::base_internal::mmap_replacement_.Add(hook);
277}
278
279extern "C"
280int MallocHook_RemoveMmapReplacement(MallocHook_MmapReplacement hook) {
281 return absl::base_internal::mmap_replacement_.Remove(hook);
282}
283
284extern "C"
285int MallocHook_AddMmapHook(MallocHook_MmapHook hook) {
286 return absl::base_internal::mmap_hooks_.Add(hook);
287}
288
289extern "C"
290int MallocHook_RemoveMmapHook(MallocHook_MmapHook hook) {
291 return absl::base_internal::mmap_hooks_.Remove(hook);
292}
293
294extern "C"
295int MallocHook_AddMunmapHook(MallocHook_MunmapHook hook) {
296 return absl::base_internal::munmap_hooks_.Add(hook);
297}
298
299extern "C"
300int MallocHook_RemoveMunmapHook(MallocHook_MunmapHook hook) {
301 return absl::base_internal::munmap_hooks_.Remove(hook);
302}
303
304extern "C"
305int MallocHook_SetMunmapReplacement(MallocHook_MunmapReplacement hook) {
306 // NOTE this is a best effort CHECK. Concurrent sets could succeed since
307 // this test is outside of the Add spin lock.
308 ABSL_RAW_CHECK(absl::base_internal::munmap_replacement_.empty(),
309 "Only one MunmapReplacement is allowed.");
310 return absl::base_internal::munmap_replacement_.Add(hook);
311}
312
313extern "C"
314int MallocHook_RemoveMunmapReplacement(MallocHook_MunmapReplacement hook) {
315 return absl::base_internal::munmap_replacement_.Remove(hook);
316}
317
318extern "C"
319int MallocHook_AddMremapHook(MallocHook_MremapHook hook) {
320 return absl::base_internal::mremap_hooks_.Add(hook);
321}
322
323extern "C"
324int MallocHook_RemoveMremapHook(MallocHook_MremapHook hook) {
325 return absl::base_internal::mremap_hooks_.Remove(hook);
326}
327
328extern "C"
329int MallocHook_AddPreSbrkHook(MallocHook_PreSbrkHook hook) {
330 return absl::base_internal::presbrk_hooks_.Add(hook);
331}
332
333extern "C"
334int MallocHook_RemovePreSbrkHook(MallocHook_PreSbrkHook hook) {
335 return absl::base_internal::presbrk_hooks_.Remove(hook);
336}
337
338extern "C"
339int MallocHook_AddSbrkHook(MallocHook_SbrkHook hook) {
340 return absl::base_internal::sbrk_hooks_.Add(hook);
341}
342
343extern "C"
344int MallocHook_RemoveSbrkHook(MallocHook_SbrkHook hook) {
345 return absl::base_internal::sbrk_hooks_.Remove(hook);
346}
347
348namespace absl {
349namespace base_internal {
350
351// Note: embedding the function calls inside the traversal of HookList would be
352// very confusing, as it is legal for a hook to remove itself and add other
353// hooks. Doing traversal first, and then calling the hooks ensures we only
354// call the hooks registered at the start.
355#define INVOKE_HOOKS(HookType, hook_list, args) \
356 do { \
357 HookType hooks[kHookListMaxValues]; \
358 int num_hooks = hook_list.Traverse(hooks, kHookListMaxValues); \
359 for (int i = 0; i < num_hooks; ++i) { \
360 (*hooks[i]) args; \
361 } \
362 } while (0)
363
364// There should only be one replacement. Return the result of the first
365// one, or false if there is none.
366#define INVOKE_REPLACEMENT(HookType, hook_list, args) \
367 do { \
368 HookType hooks[kHookListMaxValues]; \
369 int num_hooks = hook_list.Traverse(hooks, kHookListMaxValues); \
370 return (num_hooks > 0 && (*hooks[0])args); \
371 } while (0)
372
373void MallocHook::InvokeNewHookSlow(const void* ptr, size_t size) {
374 INVOKE_HOOKS(NewHook, new_hooks_, (ptr, size));
375}
376
377void MallocHook::InvokeDeleteHookSlow(const void* ptr) {
378 INVOKE_HOOKS(DeleteHook, delete_hooks_, (ptr));
379}
380
381void MallocHook::InvokeSampledNewHookSlow(const SampledAlloc* sampled_alloc) {
382 INVOKE_HOOKS(SampledNewHook, sampled_new_hooks_, (sampled_alloc));
383}
384
385void MallocHook::InvokeSampledDeleteHookSlow(AllocHandle handle) {
386 INVOKE_HOOKS(SampledDeleteHook, sampled_delete_hooks_, (handle));
387}
388
389void MallocHook::InvokePreMmapHookSlow(const void* start,
390 size_t size,
391 int protection,
392 int flags,
393 int fd,
394 off_t offset) {
395 INVOKE_HOOKS(PreMmapHook, premmap_hooks_, (start, size, protection, flags, fd,
396 offset));
397}
398
399void MallocHook::InvokeMmapHookSlow(const void* result,
400 const void* start,
401 size_t size,
402 int protection,
403 int flags,
404 int fd,
405 off_t offset) {
406 INVOKE_HOOKS(MmapHook, mmap_hooks_, (result, start, size, protection, flags,
407 fd, offset));
408}
409
410bool MallocHook::InvokeMmapReplacementSlow(const void* start,
411 size_t size,
412 int protection,
413 int flags,
414 int fd,
415 off_t offset,
416 void** result) {
417 INVOKE_REPLACEMENT(MmapReplacement, mmap_replacement_,
418 (start, size, protection, flags, fd, offset, result));
419}
420
421void MallocHook::InvokeMunmapHookSlow(const void* start, size_t size) {
422 INVOKE_HOOKS(MunmapHook, munmap_hooks_, (start, size));
423}
424
425bool MallocHook::InvokeMunmapReplacementSlow(const void* start,
426 size_t size,
427 int* result) {
428 INVOKE_REPLACEMENT(MunmapReplacement, munmap_replacement_,
429 (start, size, result));
430}
431
432void MallocHook::InvokeMremapHookSlow(const void* result,
433 const void* old_addr,
434 size_t old_size,
435 size_t new_size,
436 int flags,
437 const void* new_addr) {
438 INVOKE_HOOKS(MremapHook, mremap_hooks_, (result, old_addr, old_size, new_size,
439 flags, new_addr));
440}
441
442void MallocHook::InvokePreSbrkHookSlow(ptrdiff_t increment) {
443 INVOKE_HOOKS(PreSbrkHook, presbrk_hooks_, (increment));
444}
445
446void MallocHook::InvokeSbrkHookSlow(const void* result, ptrdiff_t increment) {
447 INVOKE_HOOKS(SbrkHook, sbrk_hooks_, (result, increment));
448}
449
450#undef INVOKE_HOOKS
451#undef INVOKE_REPLACEMENT
452
453} // namespace base_internal
454} // namespace absl
455
456ABSL_DEFINE_ATTRIBUTE_SECTION_VARS(google_malloc);
457ABSL_DECLARE_ATTRIBUTE_SECTION_VARS(google_malloc);
458// actual functions are in debugallocation.cc or tcmalloc.cc
459ABSL_DEFINE_ATTRIBUTE_SECTION_VARS(malloc_hook);
460ABSL_DECLARE_ATTRIBUTE_SECTION_VARS(malloc_hook);
461// actual functions are in this file, malloc_hook.cc, and low_level_alloc.cc
462ABSL_DEFINE_ATTRIBUTE_SECTION_VARS(blink_malloc);
463ABSL_DECLARE_ATTRIBUTE_SECTION_VARS(blink_malloc);
464// actual functions are in third_party/blink_headless/.../{PartitionAlloc,
465// FastMalloc}.cpp.
466
467#define ADDR_IN_ATTRIBUTE_SECTION(addr, name) \
468 (reinterpret_cast<uintptr_t>(ABSL_ATTRIBUTE_SECTION_START(name)) <= \
469 reinterpret_cast<uintptr_t>(addr) && \
470 reinterpret_cast<uintptr_t>(addr) < \
471 reinterpret_cast<uintptr_t>(ABSL_ATTRIBUTE_SECTION_STOP(name)))
472
473// Return true iff 'caller' is a return address within a function
474// that calls one of our hooks via MallocHook:Invoke*.
475// A helper for GetCallerStackTrace.
476static inline bool InHookCaller(const void* caller) {
477 return ADDR_IN_ATTRIBUTE_SECTION(caller, google_malloc) ||
478 ADDR_IN_ATTRIBUTE_SECTION(caller, malloc_hook) ||
479 ADDR_IN_ATTRIBUTE_SECTION(caller, blink_malloc);
480 // We can use one section for everything except tcmalloc_or_debug
481 // due to its special linkage mode, which prevents merging of the sections.
482}
483
484#undef ADDR_IN_ATTRIBUTE_SECTION
485
486static absl::once_flag in_hook_caller_once;
487
488static void InitializeInHookCaller() {
489 ABSL_INIT_ATTRIBUTE_SECTION_VARS(google_malloc);
490 if (ABSL_ATTRIBUTE_SECTION_START(google_malloc) ==
491 ABSL_ATTRIBUTE_SECTION_STOP(google_malloc)) {
492 ABSL_RAW_LOG(ERROR,
493 "google_malloc section is missing, "
494 "thus InHookCaller is broken!");
495 }
496 ABSL_INIT_ATTRIBUTE_SECTION_VARS(malloc_hook);
497 if (ABSL_ATTRIBUTE_SECTION_START(malloc_hook) ==
498 ABSL_ATTRIBUTE_SECTION_STOP(malloc_hook)) {
499 ABSL_RAW_LOG(ERROR,
500 "malloc_hook section is missing, "
501 "thus InHookCaller is broken!");
502 }
503 ABSL_INIT_ATTRIBUTE_SECTION_VARS(blink_malloc);
504 // The blink_malloc section is only expected to be present in binaries
505 // linking against the blink rendering engine in third_party/blink_headless.
506}
507
508// We can improve behavior/compactness of this function
509// if we pass a generic test function (with a generic arg)
510// into the implementations for get_stack_trace_fn instead of the skip_count.
511extern "C" int MallocHook_GetCallerStackTrace(
512 void** result, int max_depth, int skip_count,
513 MallocHook_GetStackTraceFn get_stack_trace_fn) {
514 if (!ABSL_HAVE_ATTRIBUTE_SECTION) {
515 // Fall back to get_stack_trace_fn and good old but fragile frame skip
516 // counts.
517 // Note: this path is inaccurate when a hook is not called directly by an
518 // allocation function but is daisy-chained through another hook,
519 // search for MallocHook::(Get|Set|Invoke)* to find such cases.
520#ifdef NDEBUG
521 return get_stack_trace_fn(result, max_depth, skip_count);
522#else
523 return get_stack_trace_fn(result, max_depth, skip_count + 1);
524#endif
525 // due to -foptimize-sibling-calls in opt mode
526 // there's no need for extra frame skip here then
527 }
528 absl::call_once(in_hook_caller_once, InitializeInHookCaller);
529 // MallocHook caller determination via InHookCaller works, use it:
530 static const int kMaxSkip = 32 + 6 + 3;
531 // Constant tuned to do just one get_stack_trace_fn call below in practice
532 // and not get many frames that we don't actually need:
533 // currently max passed max_depth is 32,
534 // max passed/needed skip_count is 6
535 // and 3 is to account for some hook daisy chaining.
536 static const int kStackSize = kMaxSkip + 1;
537 void* stack[kStackSize];
538 int depth =
539 get_stack_trace_fn(stack, kStackSize, 1); // skip this function frame
540 if (depth == 0)
541 // silently propagate cases when get_stack_trace_fn does not work
542 return 0;
543 for (int i = depth - 1; i >= 0; --i) { // stack[0] is our immediate caller
544 if (InHookCaller(stack[i])) {
545 i += 1; // skip hook caller frame
546 depth -= i; // correct depth
547 if (depth > max_depth) depth = max_depth;
548 std::copy(stack + i, stack + i + depth, result);
549 if (depth < max_depth && depth + i == kStackSize) {
550 // get frames for the missing depth
551 depth += get_stack_trace_fn(result + depth, max_depth - depth,
552 1 + kStackSize);
553 }
554 return depth;
555 }
556 }
557 ABSL_RAW_LOG(WARNING,
558 "Hooked allocator frame not found, returning empty trace");
559 // If this happens try increasing kMaxSkip
560 // or else something must be wrong with InHookCaller,
561 // e.g. for every section used in InHookCaller
562 // all functions in that section must be inside the same library.
563 return 0;
564}
565
566// On systems where we know how, we override mmap/munmap/mremap/sbrk
567// to provide support for calling the related hooks (in addition,
568// of course, to doing what these functions normally do).
569
570// The ABSL_MALLOC_HOOK_MMAP_DISABLE macro disables mmap/munmap interceptors.
571// Dynamic tools that intercept mmap/munmap can't be linked together with
572// malloc_hook interceptors. We disable the malloc_hook interceptors for the
573// widely-used dynamic tools, i.e. ThreadSanitizer and MemorySanitizer, but
574// still allow users to disable this in special cases that can't be easily
575// detected during compilation, via -DABSL_MALLOC_HOOK_MMAP_DISABLE or #define
576// ABSL_MALLOC_HOOK_MMAP_DISABLE.
577// TODO(b/62370839): Remove MALLOC_HOOK_MMAP_DISABLE in CROSSTOOL for tsan and
578// msan config; Replace MALLOC_HOOK_MMAP_DISABLE with
579// ABSL_MALLOC_HOOK_MMAP_DISABLE for other special cases.
580#if !defined(THREAD_SANITIZER) && !defined(MEMORY_SANITIZER) && \
581 !defined(ABSL_MALLOC_HOOK_MMAP_DISABLE) && defined(__linux__)
582#include "absl/base/internal/malloc_hook_mmap_linux.inc"
583
584#elif ABSL_HAVE_MMAP
585
586namespace absl {
587namespace base_internal {
588
589// static
590void* MallocHook::UnhookedMMap(void* start, size_t size, int protection,
591 int flags, int fd, off_t offset) {
592 void* result;
593 if (!MallocHook::InvokeMmapReplacement(
594 start, size, protection, flags, fd, offset, &result)) {
595 result = mmap(start, size, protection, flags, fd, offset);
596 }
597 return result;
598}
599
600// static
601int MallocHook::UnhookedMUnmap(void* start, size_t size) {
602 int result;
603 if (!MallocHook::InvokeMunmapReplacement(start, size, &result)) {
604 result = munmap(start, size);
605 }
606 return result;
607}
608
609} // namespace base_internal
610} // namespace absl
611
612#endif