LCOV - code coverage report
Current view: top level - memory/build - replace_malloc.c (source / functions) Hit Total Coverage
Test: output.info Lines: 14 39 35.9 %
Date: 2017-07-14 16:53:18 Functions: 3 7 42.9 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* This Source Code Form is subject to the terms of the Mozilla Public
       2             :  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
       3             :  * You can obtain one at http://mozilla.org/MPL/2.0/. */
       4             : 
       5             : #ifndef MOZ_MEMORY
       6             : #  error Should not compile this file when MOZ_MEMORY is not set
       7             : #endif
       8             : 
       9             : #ifndef MOZ_REPLACE_MALLOC
      10             : #  error Should not compile this file when replace-malloc is disabled
      11             : #endif
      12             : 
      13             : #include "mozmemory_wrap.h"
      14             : 
      15             : /* Declare all je_* functions */
      16             : #define MALLOC_DECL(name, return_type, ...) \
      17             :   return_type je_ ## name(__VA_ARGS__);
      18             : #include "malloc_decls.h"
      19             : 
      20             : #include "mozilla/Likely.h"
      21             : #include "mozilla/MacroArgs.h"
      22             : #include <errno.h>
      23             : #ifndef XP_WIN
      24             : #include <unistd.h>
      25             : #endif
      26             : 
      27             : /*
      28             :  * Windows doesn't come with weak imports as they are possible with
      29             :  * LD_PRELOAD or DYLD_INSERT_LIBRARIES on Linux/OSX. On this platform,
      30             :  * the replacement functions are defined as variable pointers to the
      31             :  * function resolved with GetProcAddress() instead of weak definitions
      32             :  * of functions. On Android, the same needs to happen as well, because
      33             :  * the Android linker doesn't handle weak linking with non LD_PRELOADed
      34             :  * libraries, but LD_PRELOADing is not very convenient on Android, with
      35             :  * the zygote.
      36             :  */
      37             : #ifdef XP_DARWIN
      38             : #  define MOZ_REPLACE_WEAK __attribute__((weak_import))
      39             : #elif defined(XP_WIN) || defined(MOZ_WIDGET_ANDROID)
      40             : #  define MOZ_NO_REPLACE_FUNC_DECL
      41             : #elif defined(__GNUC__)
      42             : #  define MOZ_REPLACE_WEAK __attribute__((weak))
      43             : #endif
      44             : 
      45             : #include "replace_malloc.h"
      46             : 
      47             : #define MALLOC_DECL(name, return_type, ...) \
      48             :     je_ ## name,
      49             : 
      50             : static const malloc_table_t malloc_table = {
      51             : #include "malloc_decls.h"
      52             : };
      53             : 
      54             : static malloc_table_t replace_malloc_table;
      55             : 
      56             : #ifdef MOZ_NO_REPLACE_FUNC_DECL
      57             : #  define MALLOC_DECL(name, return_type, ...) \
      58             :     typedef return_type (name ## _impl_t)(__VA_ARGS__); \
      59             :     name ## _impl_t* replace_ ## name = NULL;
      60             : #  define MALLOC_FUNCS (MALLOC_FUNCS_INIT | MALLOC_FUNCS_BRIDGE)
      61             : #  include "malloc_decls.h"
      62             : #endif
      63             : 
      64             : #ifdef XP_WIN
      65             : #  include <windows.h>
      66             : 
      67             : typedef HMODULE replace_malloc_handle_t;
      68             : 
      69             : static replace_malloc_handle_t
      70             : replace_malloc_handle()
      71             : {
      72             :   char replace_malloc_lib[1024];
      73             :   if (GetEnvironmentVariableA("MOZ_REPLACE_MALLOC_LIB", (LPSTR)&replace_malloc_lib,
      74             :                               sizeof(replace_malloc_lib)) > 0) {
      75             :     return LoadLibraryA(replace_malloc_lib);
      76             :   }
      77             :   return NULL;
      78             : }
      79             : 
      80             : #    define REPLACE_MALLOC_GET_FUNC(handle, name) \
      81             :       (name ## _impl_t*) GetProcAddress(handle, "replace_" # name)
      82             : 
      83             : #elif defined(MOZ_WIDGET_ANDROID)
      84             : #  include <dlfcn.h>
      85             : #  include <stdlib.h>
      86             : 
      87             : typedef void* replace_malloc_handle_t;
      88             : 
      89             : static replace_malloc_handle_t
      90             : replace_malloc_handle()
      91             : {
      92             :   const char *replace_malloc_lib = getenv("MOZ_REPLACE_MALLOC_LIB");
      93             :   if (replace_malloc_lib && *replace_malloc_lib) {
      94             :     return dlopen(replace_malloc_lib, RTLD_LAZY);
      95             :   }
      96             :   return NULL;
      97             : }
      98             : 
      99             : #  define REPLACE_MALLOC_GET_FUNC(handle, name) \
     100             :     (name ## _impl_t*) dlsym(handle, "replace_" # name)
     101             : 
     102             : #else
     103             : 
     104             : #  include <stdbool.h>
     105             : 
     106             : typedef bool replace_malloc_handle_t;
     107             : 
     108             : static replace_malloc_handle_t
     109           3 : replace_malloc_handle()
     110             : {
     111           3 :   return true;
     112             : }
     113             : 
     114             : #  define REPLACE_MALLOC_GET_FUNC(handle, name) \
     115             :     replace_ ## name
     116             : 
     117             : #endif
     118             : 
     119             : static void replace_malloc_init_funcs();
     120             : 
     121             : /*
     122             :  * Below is the malloc implementation overriding jemalloc and calling the
     123             :  * replacement functions if they exist.
     124             :  */
     125             : 
     126             : static int replace_malloc_initialized = 0;
     127             : static void
     128           3 : init()
     129             : {
     130           3 :   replace_malloc_init_funcs();
     131             :   // Set this *before* calling replace_init, otherwise if replace_init calls
     132             :   // malloc() we'll get an infinite loop.
     133           3 :   replace_malloc_initialized = 1;
     134           3 :   if (replace_init)
     135           0 :     replace_init(&malloc_table);
     136           3 : }
     137             : 
     138             : /*
     139             :  * Malloc implementation functions are MOZ_MEMORY_API, and jemalloc
     140             :  * specific functions MOZ_JEMALLOC_API; see mozmemory_wrap.h
     141             :  */
     142             : #define MACRO_CALL(a, b) a b
     143             : /* Can't use macros recursively, so we need another one doing the same as above. */
     144             : #define MACRO_CALL2(a, b) a b
     145             : 
     146             : #define ARGS_HELPER(name, ...) MACRO_CALL2( \
     147             :   MOZ_PASTE_PREFIX_AND_ARG_COUNT(name, ##__VA_ARGS__), \
     148             :   (__VA_ARGS__))
     149             : #define TYPED_ARGS0()
     150             : #define TYPED_ARGS1(t1) t1 arg1
     151             : #define TYPED_ARGS2(t1, t2) TYPED_ARGS1(t1), t2 arg2
     152             : #define TYPED_ARGS3(t1, t2, t3) TYPED_ARGS2(t1, t2), t3 arg3
     153             : 
     154             : #define ARGS0()
     155             : #define ARGS1(t1) arg1
     156             : #define ARGS2(t1, t2) ARGS1(t1), arg2
     157             : #define ARGS3(t1, t2, t3) ARGS2(t1, t2), arg3
     158             : 
     159             : #define GENERIC_MALLOC_DECL_HELPER(name, return, return_type, ...) \
     160             :   return_type name ## _impl(ARGS_HELPER(TYPED_ARGS, ##__VA_ARGS__)) \
     161             :   { \
     162             :     if (MOZ_UNLIKELY(!replace_malloc_initialized)) \
     163             :       init(); \
     164             :     return replace_malloc_table.name(ARGS_HELPER(ARGS, ##__VA_ARGS__)); \
     165             :   }
     166             : 
     167             : #define GENERIC_MALLOC_DECL(name, return_type, ...) \
     168             :   GENERIC_MALLOC_DECL_HELPER(name, return, return_type, ##__VA_ARGS__)
     169             : #define GENERIC_MALLOC_DECL_VOID(name, ...) \
     170             :   GENERIC_MALLOC_DECL_HELPER(name, , void, ##__VA_ARGS__)
     171             : 
     172             : #define MALLOC_DECL(...) MOZ_MEMORY_API MACRO_CALL(GENERIC_MALLOC_DECL, (__VA_ARGS__))
     173             : #define MALLOC_DECL_VOID(...) MOZ_MEMORY_API MACRO_CALL(GENERIC_MALLOC_DECL_VOID, (__VA_ARGS__))
     174             : #define MALLOC_FUNCS MALLOC_FUNCS_MALLOC
     175             : #include "malloc_decls.h"
     176             : 
     177             : #define MALLOC_DECL(...) MOZ_JEMALLOC_API MACRO_CALL(GENERIC_MALLOC_DECL, (__VA_ARGS__))
     178             : #define MALLOC_DECL_VOID(...) MOZ_JEMALLOC_API MACRO_CALL(GENERIC_MALLOC_DECL_VOID, (__VA_ARGS__))
     179             : #define MALLOC_FUNCS MALLOC_FUNCS_JEMALLOC
     180             : #include "malloc_decls.h"
     181             : 
     182             : MFBT_API struct ReplaceMallocBridge*
     183           0 : get_bridge(void)
     184             : {
     185           0 :   if (MOZ_UNLIKELY(!replace_malloc_initialized))
     186           0 :     init();
     187           0 :   if (MOZ_LIKELY(!replace_get_bridge))
     188           0 :     return NULL;
     189           0 :   return replace_get_bridge();
     190             : }
     191             : 
     192             : /* The following comment and definitions are from jemalloc.c: */
     193             : #if defined(__GLIBC__) && !defined(__UCLIBC__)
     194             : 
     195             : /*
     196             :  * glibc provides the RTLD_DEEPBIND flag for dlopen which can make it possible
     197             :  * to inconsistently reference libc's malloc(3)-compatible functions
     198             :  * (https://bugzilla.mozilla.org/show_bug.cgi?id=493541).
     199             :  *
     200             :  * These definitions interpose hooks in glibc.  The functions are actually
     201             :  * passed an extra argument for the caller return address, which will be
     202             :  * ignored.
     203             :  */
     204             : 
     205             : typedef void (* __free_hook_type)(void *ptr);
     206             : typedef void *(* __malloc_hook_type)(size_t size);
     207             : typedef void *(* __realloc_hook_type)(void *ptr, size_t size);
     208             : typedef void *(* __memalign_hook_type)(size_t alignment, size_t size);
     209             : 
     210             : MOZ_MEMORY_API __free_hook_type __free_hook = free_impl;
     211             : MOZ_MEMORY_API __malloc_hook_type __malloc_hook = malloc_impl;
     212             : MOZ_MEMORY_API __realloc_hook_type __realloc_hook = realloc_impl;
     213             : MOZ_MEMORY_API __memalign_hook_type __memalign_hook = memalign_impl;
     214             : 
     215             : #endif
     216             : 
     217             : /*
     218             :  * posix_memalign, aligned_alloc, memalign and valloc all implement some kind
     219             :  * of aligned memory allocation. For convenience, a replace-malloc library can
     220             :  * skip defining replace_posix_memalign, replace_aligned_alloc and
     221             :  * replace_valloc, and default implementations will be automatically derived
     222             :  * from replace_memalign.
     223             :  */
     224             : static int
     225           0 : default_posix_memalign(void** ptr, size_t alignment, size_t size)
     226             : {
     227           0 :   if (size == 0) {
     228           0 :     *ptr = NULL;
     229           0 :     return 0;
     230             :   }
     231             :   /* alignment must be a power of two and a multiple of sizeof(void *) */
     232           0 :   if (((alignment - 1) & alignment) != 0 || (alignment % sizeof(void *)))
     233           0 :     return EINVAL;
     234           0 :   *ptr = replace_malloc_table.memalign(alignment, size);
     235           0 :   return *ptr ? 0 : ENOMEM;
     236             : }
     237             : 
     238             : static void*
     239           0 : default_aligned_alloc(size_t alignment, size_t size)
     240             : {
     241             :   /* size should be a multiple of alignment */
     242           0 :   if (size % alignment)
     243           0 :     return NULL;
     244           0 :   return replace_malloc_table.memalign(alignment, size);
     245             : }
     246             : 
     247             : // Nb: sysconf() is expensive, but valloc is obsolete and rarely used.
     248             : static void*
     249           0 : default_valloc(size_t size)
     250             : {
     251             : #ifdef XP_WIN
     252             :   SYSTEM_INFO si;
     253             :   GetSystemInfo(&si);
     254             :   size_t page_size = si.dwPageSize;
     255             : #else
     256           0 :   size_t page_size = sysconf(_SC_PAGE_SIZE);
     257             : #endif
     258           0 :   return replace_malloc_table.memalign(page_size, size);
     259             : }
     260             : 
     261             : static void
     262           3 : replace_malloc_init_funcs()
     263             : {
     264           3 :   replace_malloc_handle_t handle = replace_malloc_handle();
     265           3 :   if (handle) {
     266             : #ifdef MOZ_NO_REPLACE_FUNC_DECL
     267             : #  define MALLOC_DECL(name, ...) \
     268             :     replace_ ## name = REPLACE_MALLOC_GET_FUNC(handle, name);
     269             : 
     270             : #  define MALLOC_FUNCS (MALLOC_FUNCS_INIT | MALLOC_FUNCS_BRIDGE)
     271             : #  include "malloc_decls.h"
     272             : #endif
     273             : 
     274             : #define MALLOC_DECL(name, ...) \
     275             :   replace_malloc_table.name = REPLACE_MALLOC_GET_FUNC(handle, name);
     276             : #include "malloc_decls.h"
     277             :   }
     278             : 
     279           3 :   if (!replace_malloc_table.posix_memalign && replace_malloc_table.memalign)
     280           0 :     replace_malloc_table.posix_memalign = default_posix_memalign;
     281             : 
     282           3 :   if (!replace_malloc_table.aligned_alloc && replace_malloc_table.memalign)
     283           0 :     replace_malloc_table.aligned_alloc = default_aligned_alloc;
     284             : 
     285           3 :   if (!replace_malloc_table.valloc && replace_malloc_table.memalign)
     286           0 :     replace_malloc_table.valloc = default_valloc;
     287             : 
     288             : #define MALLOC_DECL(name, ...) \
     289             :   if (!replace_malloc_table.name) { \
     290             :     replace_malloc_table.name = je_ ## name; \
     291             :   }
     292             : #include "malloc_decls.h"
     293           3 : }

Generated by: LCOV version 1.13