gperftools/src/mmap_hook.h
Aliaksey Kandratsenka 8be84e4a5c drop old mmap hooks and introduce internal & simpler mmap_hook.h
Previous implementation wasn't entirely safe w.r.t. 32-bit off_t
systems. Specifically around mmap replacement hook. Also, API was a
lot more general and broad than we actually need.

Sadly, old mmap hooks API was shipped with our public headers. But
thankfully it appears to be unused externally (checked via github
search). So we keep this old API and ABI for the sake of formal API
and ABI compatibility. But this old API is now empty and always
fails (some OS/hardware combinations didn't have functional
implementations of those hooks anyways).

New API is 64-bit clean and only provides us with what we need. Namely
being able to react to virtual address space mapping changes for
logging, heap profiling and heap leak checker. I.e. no pre hooks or
mmap-replacement hooks. We also explicitly not ship this API
externally to give us freedom to change it.

New code is also hopefully tidier and slightly more portable. At least
there are fewer arch-specific ifdef-s.

Another somewhat notable change is, since mmap hook isn't needed in
"minimal" configuration, we now don't override system's
mmap/munmap/etc functions in this configuration. No big deal, but it
reduces risk of damage if we somehow mess those up. I.e. musl's mmap
does few things that our mmap replacement doesn't, such as very fancy
vm_lock thingy. Which doesn't look critical, but is good thing for us
not to interfere with when not necessary.

Fixes issue #1406 and issue #1407. Lets also mention issue #1010 which
is somewhat relevant.
2023-07-21 16:13:19 -04:00

129 lines
4.5 KiB
C++

/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
* Copyright (c) 2023, gperftools Contributors
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
// mmap_hook.h holds strictly non-public API for hooking mmap/sbrk
// events as well invoking mmap/munmap with ability to bypass hooks
// (i.e. for low_level_alloc).
#ifndef MMAP_HOOK_H
#define MMAP_HOOK_H
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include "base/basictypes.h"
namespace tcmalloc {
struct DirectAnonMMapResult {
void* addr;
bool success;
};
// DirectAnonMMap does mmap of r+w anonymous memory. Optionally
// bypassing or not mmap hooks.
ATTRIBUTE_VISIBILITY_HIDDEN DirectAnonMMapResult DirectAnonMMap(bool invoke_hooks, size_t length);
// DirectMUnMap does munmap of given region optionally bypassing mmap hooks.
ATTRIBUTE_VISIBILITY_HIDDEN int DirectMUnMap(bool invoke_hooks, void* start, size_t length);
// We use those by tests to see what parts we think should work.
extern ATTRIBUTE_VISIBILITY_HIDDEN const bool mmap_hook_works;
extern ATTRIBUTE_VISIBILITY_HIDDEN const bool sbrk_hook_works;
// MMapEventFn gets this struct with all the details of
// mmap/munmap/mremap/sbrk event.
struct MappingEvent {
MappingEvent() {
memset(this, 0, sizeof(*this));
}
// before_XXX fields describe address space chunk that was removed
// from address space (say via munmap or mremap)
void* before_address;
size_t before_length;
// after_XXX fields describe address space chunk that was added to
// address space.
void* after_address;
size_t after_length;
// This group of fields gets populated from mmap file, flags, prot
// fields.
int prot;
int flags;
int file_fd;
int64_t file_off;
unsigned after_valid:1;
unsigned before_valid:1;
unsigned file_valid:1;
unsigned is_sbrk:1;
};
// Pass this to Hook/Unhook function below. Note, nature of
// implementation requires that this chunk of memory must be valid
// even after unhook. So typical use-case is to use global variable
// storage.
//
// All fields are private.
class MappingHookSpace {
public:
constexpr MappingHookSpace() = default;
bool initialized = false;
static constexpr size_t kSize = sizeof(void*) * 3;
alignas(alignof(void*)) char storage[kSize] = {};
};
using MMapEventFn = void (*)(const MappingEvent& evt);
// HookMMapEvents address hook for mmap events, using given place to
// store relevant metadata (linked list membership etc).
//
// It does no memory allocation and is safe to be called from hooks of all kinds.
ATTRIBUTE_VISIBILITY_HIDDEN void HookMMapEvents(MappingHookSpace* place, MMapEventFn callback);
// UnHookMMapEvents undoes effect of HookMMapEvents. This one is also
// entirely safe to be called from out of anywhere. Including from
// inside MMapEventFn invokations.
//
// As noted on MappingHookSpace the place ***must not** be deallocated or
// reused for anything even after unhook. This requirement makes
// implementation simple enough and fits our internal usage use-case
// fine.
ATTRIBUTE_VISIBILITY_HIDDEN void UnHookMMapEvents(MappingHookSpace* place);
} // namespace tcmalloc
#endif // MMAP_HOOK_H