Home | History | Annotate | Download | only in gperftools
      1 // Copyright (c) 2005, Google Inc.
      2 // All rights reserved.
      3 //
      4 // Redistribution and use in source and binary forms, with or without
      5 // modification, are permitted provided that the following conditions are
      6 // met:
      7 //
      8 //     * Redistributions of source code must retain the above copyright
      9 // notice, this list of conditions and the following disclaimer.
     10 //     * Redistributions in binary form must reproduce the above
     11 // copyright notice, this list of conditions and the following disclaimer
     12 // in the documentation and/or other materials provided with the
     13 // distribution.
     14 //     * Neither the name of Google Inc. nor the names of its
     15 // contributors may be used to endorse or promote products derived from
     16 // this software without specific prior written permission.
     17 //
     18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29 
     30 // ---
     31 // Author: Sanjay Ghemawat
     32 //
     33 // Some of our malloc implementations can invoke the following hooks whenever
     34 // memory is allocated or deallocated.  MallocHook is thread-safe, and things
     35 // you do before calling AddFooHook(MyHook) are visible to any resulting calls
     36 // to MyHook.  Hooks must be thread-safe.  If you write:
     37 //
     38 //   CHECK(MallocHook::AddNewHook(&MyNewHook));
     39 //
     40 // MyNewHook will be invoked in subsequent calls in the current thread, but
     41 // there are no guarantees on when it might be invoked in other threads.
     42 //
     43 // There are a limited number of slots available for each hook type.  Add*Hook
     44 // will return false if there are no slots available.  Remove*Hook will return
     45 // false if the given hook was not already installed.
     46 //
     47 // The order in which individual hooks are called in Invoke*Hook is undefined.
     48 //
     49 // It is safe for a hook to remove itself within Invoke*Hook and add other
     50 // hooks.  Any hooks added inside a hook invocation (for the same hook type)
     51 // will not be invoked for the current invocation.
     52 //
     53 // One important user of these hooks is the heap profiler.
     54 //
     55 // CAVEAT: If you add new MallocHook::Invoke* calls then those calls must be
     56 // directly in the code of the (de)allocation function that is provided to the
     57 // user and that function must have an ATTRIBUTE_SECTION(malloc_hook) attribute.
     58 //
     59 // Note: the Invoke*Hook() functions are defined in malloc_hook-inl.h.  If you
     60 // need to invoke a hook (which you shouldn't unless you're part of tcmalloc),
     61 // be sure to #include malloc_hook-inl.h in addition to malloc_hook.h.
     62 //
     63 // NOTE FOR C USERS: If you want to use malloc_hook functionality from
     64 // a C program, #include malloc_hook_c.h instead of this file.
     65 
     66 #ifndef _MALLOC_HOOK_H_
     67 #define _MALLOC_HOOK_H_
     68 
     69 #include <stddef.h>
     70 #include <sys/types.h>
     71 extern "C" {
     72 #include <gperftools/malloc_hook_c.h>  // a C version of the malloc_hook interface
     73 }
     74 
     75 // Annoying stuff for windows -- makes sure clients can import these functions
     76 #ifndef PERFTOOLS_DLL_DECL
     77 # ifdef _WIN32
     78 #   define PERFTOOLS_DLL_DECL  __declspec(dllimport)
     79 # else
     80 #   define PERFTOOLS_DLL_DECL
     81 # endif
     82 #endif
     83 
     84 // The C++ methods below call the C version (MallocHook_*), and thus
     85 // convert between an int and a bool.  Windows complains about this
     86 // (a "performance warning") which we don't care about, so we suppress.
     87 #ifdef _MSC_VER
     88 #pragma warning(push)
     89 #pragma warning(disable:4800)
     90 #endif
     91 
     92 // Note: malloc_hook_c.h defines MallocHook_*Hook and
     93 // MallocHook_{Add,Remove}*Hook.  The version of these inside the MallocHook
     94 // class are defined in terms of the malloc_hook_c version.  See malloc_hook_c.h
     95 // for details of these types/functions.
     96 
     97 class PERFTOOLS_DLL_DECL MallocHook {
     98  public:
     99   // The NewHook is invoked whenever an object is allocated.
    100   // It may be passed NULL if the allocator returned NULL.
    101   typedef MallocHook_NewHook NewHook;
    102   inline static bool AddNewHook(NewHook hook) {
    103     return MallocHook_AddNewHook(hook);
    104   }
    105   inline static bool RemoveNewHook(NewHook hook) {
    106     return MallocHook_RemoveNewHook(hook);
    107   }
    108   inline static void InvokeNewHook(const void* p, size_t s);
    109 
    110   // The DeleteHook is invoked whenever an object is deallocated.
    111   // It may be passed NULL if the caller is trying to delete NULL.
    112   typedef MallocHook_DeleteHook DeleteHook;
    113   inline static bool AddDeleteHook(DeleteHook hook) {
    114     return MallocHook_AddDeleteHook(hook);
    115   }
    116   inline static bool RemoveDeleteHook(DeleteHook hook) {
    117     return MallocHook_RemoveDeleteHook(hook);
    118   }
    119   inline static void InvokeDeleteHook(const void* p);
    120 
    121   // The PreMmapHook is invoked with mmap or mmap64 arguments just
    122   // before the call is actually made.  Such a hook may be useful
    123   // in memory limited contexts, to catch allocations that will exceed
    124   // a memory limit, and take outside actions to increase that limit.
    125   typedef MallocHook_PreMmapHook PreMmapHook;
    126   inline static bool AddPreMmapHook(PreMmapHook hook) {
    127     return MallocHook_AddPreMmapHook(hook);
    128   }
    129   inline static bool RemovePreMmapHook(PreMmapHook hook) {
    130     return MallocHook_RemovePreMmapHook(hook);
    131   }
    132   inline static void InvokePreMmapHook(const void* start,
    133                                        size_t size,
    134                                        int protection,
    135                                        int flags,
    136                                        int fd,
    137                                        off_t offset);
    138 
    139   // The MmapReplacement is invoked after the PreMmapHook but before
    140   // the call is actually made. The MmapReplacement should return true
    141   // if it handled the call, or false if it is still necessary to
    142   // call mmap/mmap64.
    143   // This should be used only by experts, and users must be be
    144   // extremely careful to avoid recursive calls to mmap. The replacement
    145   // should be async signal safe.
    146   // Only one MmapReplacement is supported. After setting an MmapReplacement
    147   // you must call RemoveMmapReplacement before calling SetMmapReplacement
    148   // again.
    149   typedef MallocHook_MmapReplacement MmapReplacement;
    150   inline static bool SetMmapReplacement(MmapReplacement hook) {
    151     return MallocHook_SetMmapReplacement(hook);
    152   }
    153   inline static bool RemoveMmapReplacement(MmapReplacement hook) {
    154     return MallocHook_RemoveMmapReplacement(hook);
    155   }
    156   inline static bool InvokeMmapReplacement(const void* start,
    157                                            size_t size,
    158                                            int protection,
    159                                            int flags,
    160                                            int fd,
    161                                            off_t offset,
    162                                            void** result);
    163 
    164 
    165   // The MmapHook is invoked whenever a region of memory is mapped.
    166   // It may be passed MAP_FAILED if the mmap failed.
    167   typedef MallocHook_MmapHook MmapHook;
    168   inline static bool AddMmapHook(MmapHook hook) {
    169     return MallocHook_AddMmapHook(hook);
    170   }
    171   inline static bool RemoveMmapHook(MmapHook hook) {
    172     return MallocHook_RemoveMmapHook(hook);
    173   }
    174   inline static void InvokeMmapHook(const void* result,
    175                                     const void* start,
    176                                     size_t size,
    177                                     int protection,
    178                                     int flags,
    179                                     int fd,
    180                                     off_t offset);
    181 
    182   // The MunmapReplacement is invoked with munmap arguments just before
    183   // the call is actually made. The MunmapReplacement should return true
    184   // if it handled the call, or false if it is still necessary to
    185   // call munmap.
    186   // This should be used only by experts. The replacement should be
    187   // async signal safe.
    188   // Only one MunmapReplacement is supported. After setting an
    189   // MunmapReplacement you must call RemoveMunmapReplacement before
    190   // calling SetMunmapReplacement again.
    191   typedef MallocHook_MunmapReplacement MunmapReplacement;
    192   inline static bool SetMunmapReplacement(MunmapReplacement hook) {
    193     return MallocHook_SetMunmapReplacement(hook);
    194   }
    195   inline static bool RemoveMunmapReplacement(MunmapReplacement hook) {
    196     return MallocHook_RemoveMunmapReplacement(hook);
    197   }
    198   inline static bool InvokeMunmapReplacement(const void* p,
    199                                              size_t size,
    200                                              int* result);
    201 
    202   // The MunmapHook is invoked whenever a region of memory is unmapped.
    203   typedef MallocHook_MunmapHook MunmapHook;
    204   inline static bool AddMunmapHook(MunmapHook hook) {
    205     return MallocHook_AddMunmapHook(hook);
    206   }
    207   inline static bool RemoveMunmapHook(MunmapHook hook) {
    208     return MallocHook_RemoveMunmapHook(hook);
    209   }
    210   inline static void InvokeMunmapHook(const void* p, size_t size);
    211 
    212   // The MremapHook is invoked whenever a region of memory is remapped.
    213   typedef MallocHook_MremapHook MremapHook;
    214   inline static bool AddMremapHook(MremapHook hook) {
    215     return MallocHook_AddMremapHook(hook);
    216   }
    217   inline static bool RemoveMremapHook(MremapHook hook) {
    218     return MallocHook_RemoveMremapHook(hook);
    219   }
    220   inline static void InvokeMremapHook(const void* result,
    221                                       const void* old_addr,
    222                                       size_t old_size,
    223                                       size_t new_size,
    224                                       int flags,
    225                                       const void* new_addr);
    226 
    227   // The PreSbrkHook is invoked just before sbrk is called -- except when
    228   // the increment is 0.  This is because sbrk(0) is often called
    229   // to get the top of the memory stack, and is not actually a
    230   // memory-allocation call.  It may be useful in memory-limited contexts,
    231   // to catch allocations that will exceed the limit and take outside
    232   // actions to increase such a limit.
    233   typedef MallocHook_PreSbrkHook PreSbrkHook;
    234   inline static bool AddPreSbrkHook(PreSbrkHook hook) {
    235     return MallocHook_AddPreSbrkHook(hook);
    236   }
    237   inline static bool RemovePreSbrkHook(PreSbrkHook hook) {
    238     return MallocHook_RemovePreSbrkHook(hook);
    239   }
    240   inline static void InvokePreSbrkHook(ptrdiff_t increment);
    241 
    242   // The SbrkHook is invoked whenever sbrk is called -- except when
    243   // the increment is 0.  This is because sbrk(0) is often called
    244   // to get the top of the memory stack, and is not actually a
    245   // memory-allocation call.
    246   typedef MallocHook_SbrkHook SbrkHook;
    247   inline static bool AddSbrkHook(SbrkHook hook) {
    248     return MallocHook_AddSbrkHook(hook);
    249   }
    250   inline static bool RemoveSbrkHook(SbrkHook hook) {
    251     return MallocHook_RemoveSbrkHook(hook);
    252   }
    253   inline static void InvokeSbrkHook(const void* result, ptrdiff_t increment);
    254 
    255   // Get the current stack trace.  Try to skip all routines up to and
    256   // and including the caller of MallocHook::Invoke*.
    257   // Use "skip_count" (similarly to GetStackTrace from stacktrace.h)
    258   // as a hint about how many routines to skip if better information
    259   // is not available.
    260   inline static int GetCallerStackTrace(void** result, int max_depth,
    261                                         int skip_count) {
    262     return MallocHook_GetCallerStackTrace(result, max_depth, skip_count);
    263   }
    264 
    265   // Unhooked versions of mmap() and munmap().   These should be used
    266   // only by experts, since they bypass heapchecking, etc.
    267   // Note: These do not run hooks, but they still use the MmapReplacement
    268   // and MunmapReplacement.
    269   static void* UnhookedMMap(void *start, size_t length, int prot, int flags,
    270                             int fd, off_t offset);
    271   static int UnhookedMUnmap(void *start, size_t length);
    272 
    273   // The following are DEPRECATED.
    274   inline static NewHook GetNewHook();
    275   inline static NewHook SetNewHook(NewHook hook) {
    276     return MallocHook_SetNewHook(hook);
    277   }
    278 
    279   inline static DeleteHook GetDeleteHook();
    280   inline static DeleteHook SetDeleteHook(DeleteHook hook) {
    281     return MallocHook_SetDeleteHook(hook);
    282   }
    283 
    284   inline static PreMmapHook GetPreMmapHook();
    285   inline static PreMmapHook SetPreMmapHook(PreMmapHook hook) {
    286     return MallocHook_SetPreMmapHook(hook);
    287   }
    288 
    289   inline static MmapHook GetMmapHook();
    290   inline static MmapHook SetMmapHook(MmapHook hook) {
    291     return MallocHook_SetMmapHook(hook);
    292   }
    293 
    294   inline static MunmapHook GetMunmapHook();
    295   inline static MunmapHook SetMunmapHook(MunmapHook hook) {
    296     return MallocHook_SetMunmapHook(hook);
    297   }
    298 
    299   inline static MremapHook GetMremapHook();
    300   inline static MremapHook SetMremapHook(MremapHook hook) {
    301     return MallocHook_SetMremapHook(hook);
    302   }
    303 
    304   inline static PreSbrkHook GetPreSbrkHook();
    305   inline static PreSbrkHook SetPreSbrkHook(PreSbrkHook hook) {
    306     return MallocHook_SetPreSbrkHook(hook);
    307   }
    308 
    309   inline static SbrkHook GetSbrkHook();
    310   inline static SbrkHook SetSbrkHook(SbrkHook hook) {
    311     return MallocHook_SetSbrkHook(hook);
    312   }
    313   // End of DEPRECATED methods.
    314 
    315  private:
    316   // Slow path versions of Invoke*Hook.
    317   static void InvokeNewHookSlow(const void* p, size_t s);
    318   static void InvokeDeleteHookSlow(const void* p);
    319   static void InvokePreMmapHookSlow(const void* start,
    320                                     size_t size,
    321                                     int protection,
    322                                     int flags,
    323                                     int fd,
    324                                     off_t offset);
    325   static void InvokeMmapHookSlow(const void* result,
    326                                  const void* start,
    327                                  size_t size,
    328                                  int protection,
    329                                  int flags,
    330                                  int fd,
    331                                  off_t offset);
    332   static bool InvokeMmapReplacementSlow(const void* start,
    333                                         size_t size,
    334                                         int protection,
    335                                         int flags,
    336                                         int fd,
    337                                         off_t offset,
    338                                         void** result);
    339   static void InvokeMunmapHookSlow(const void* p, size_t size);
    340   static bool InvokeMunmapReplacementSlow(const void* p,
    341                                           size_t size,
    342                                           int* result);
    343   static void InvokeMremapHookSlow(const void* result,
    344                                    const void* old_addr,
    345                                    size_t old_size,
    346                                    size_t new_size,
    347                                    int flags,
    348                                    const void* new_addr);
    349   static void InvokePreSbrkHookSlow(ptrdiff_t increment);
    350   static void InvokeSbrkHookSlow(const void* result, ptrdiff_t increment);
    351 };
    352 
    353 #ifdef _MSC_VER
    354 #pragma warning(pop)
    355 #endif
    356 
    357 
    358 #endif /* _MALLOC_HOOK_H_ */
    359