1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "base/allocator/allocator_shim.h"
6 #include "base/compiler_specific.h"
7 
8 #include <dlfcn.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <malloc_np.h>
12 
13 // This translation unit defines a default dispatch for the allocator shim which
14 // routes allocations to libc functions.
15 // The code here is strongly inspired from tcmalloc's override_glibc.h.
16 
17 extern "C" {
18 void* __malloc(size_t size);
19 void* __calloc(size_t n, size_t size);
20 void* __realloc(void* address, size_t len);
__memalign(size_t alignment,size_t size)21 void* __memalign(size_t alignment, size_t size) {
22   void *ret;
23   if (__posix_memalign(&ret, alignment, size) != 0) {
24     return nullptr;
25   } else {
26     return ret;
27   }
28 }
29 int __posix_memalign(void **ptr, size_t alignment, size_t size);
30 void __free(void* ptr);
31 }  // extern "C"
32 
33 namespace {
34 
35 using base::allocator::AllocatorDispatch;
36 
GlibcMalloc(const AllocatorDispatch *,size_t size,void * context)37 void* GlibcMalloc(const AllocatorDispatch*, size_t size, void* context) {
38   return __malloc(size);
39 }
40 
GlibcCalloc(const AllocatorDispatch *,size_t n,size_t size,void * context)41 void* GlibcCalloc(const AllocatorDispatch*,
42                   size_t n,
43                   size_t size,
44                   void* context) {
45   return __calloc(n, size);
46 }
47 
GlibcRealloc(const AllocatorDispatch *,void * address,size_t size,void * context)48 void* GlibcRealloc(const AllocatorDispatch*,
49                    void* address,
50                    size_t size,
51                    void* context) {
52   return __realloc(address, size);
53 }
54 
GlibcMemalign(const AllocatorDispatch *,size_t alignment,size_t size,void * context)55 void* GlibcMemalign(const AllocatorDispatch*,
56                     size_t alignment,
57                     size_t size,
58                     void* context) {
59   return __memalign(alignment, size);
60 }
61 
GlibcFree(const AllocatorDispatch *,void * address,void * context)62 void GlibcFree(const AllocatorDispatch*, void* address, void* context) {
63   __free(address);
64 }
65 
66 NO_SANITIZE("cfi-icall")
GlibcGetSizeEstimate(const AllocatorDispatch *,void * address,void * context)67 size_t GlibcGetSizeEstimate(const AllocatorDispatch*,
68                             void* address,
69                             void* context) {
70   // glibc does not expose an alias to resolve malloc_usable_size. Dynamically
71   // resolve it instead. This should be safe because glibc (and hence dlfcn)
72   // does not use malloc_size internally and so there should not be a risk of
73   // recursion.
74   using MallocUsableSizeFunction = decltype(malloc_usable_size)*;
75   static MallocUsableSizeFunction fn_ptr =
76       reinterpret_cast<MallocUsableSizeFunction>(
77           dlsym(RTLD_NEXT, "malloc_usable_size"));
78 
79   return fn_ptr(address);
80 }
81 
82 }  // namespace
83 
84 const AllocatorDispatch AllocatorDispatch::default_dispatch = {
85     &GlibcMalloc,          /* alloc_function */
86     &GlibcMalloc,          /* alloc_unchecked_function */
87     &GlibcCalloc,          /* alloc_zero_initialized_function */
88     &GlibcMemalign,        /* alloc_aligned_function */
89     &GlibcRealloc,         /* realloc_function */
90     &GlibcFree,            /* free_function */
91     &GlibcGetSizeEstimate, /* get_size_estimate_function */
92     nullptr,               /* batch_malloc_function */
93     nullptr,               /* batch_free_function */
94     nullptr,               /* free_definite_size_function */
95     nullptr,               /* aligned_malloc_function */
96     nullptr,               /* aligned_realloc_function */
97     nullptr,               /* aligned_free_function */
98     nullptr,               /* next */
99 };
100