mirror of
https://github.com/gperftools/gperftools
synced 2024-12-24 00:02:12 +00:00
8be84e4a5c
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.
129 lines
4.5 KiB
C++
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
|