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