]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/compiler-rt/lib/sanitizer_common/sanitizer_malloc_mac.inc
MFV r308265: Update tzdata to 2016i.
[FreeBSD/FreeBSD.git] / contrib / compiler-rt / lib / sanitizer_common / sanitizer_malloc_mac.inc
1 //===-- sanitizer_malloc_mac.inc --------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file contains Mac-specific malloc interceptors and a custom zone
11 // implementation, which together replace the system allocator.
12 //
13 //===----------------------------------------------------------------------===//
14
15 #include "sanitizer_common/sanitizer_platform.h"
16 #if !SANITIZER_MAC
17 #error "This file should only be compiled on Darwin."
18 #endif
19
20 #include <AvailabilityMacros.h>
21 #include <CoreFoundation/CFBase.h>
22 #include <dlfcn.h>
23 #include <malloc/malloc.h>
24 #include <sys/mman.h>
25
26 #include "interception/interception.h"
27 #include "sanitizer_common/sanitizer_mac.h"
28
29 // Similar code is used in Google Perftools,
30 // https://github.com/gperftools/gperftools.
31
32 static malloc_zone_t sanitizer_zone;
33
34 INTERCEPTOR(malloc_zone_t *, malloc_create_zone,
35                              vm_size_t start_size, unsigned zone_flags) {
36   COMMON_MALLOC_ENTER();
37   uptr page_size = GetPageSizeCached();
38   uptr allocated_size = RoundUpTo(sizeof(sanitizer_zone), page_size);
39   COMMON_MALLOC_MEMALIGN(page_size, allocated_size);
40   malloc_zone_t *new_zone = (malloc_zone_t *)p;
41   internal_memcpy(new_zone, &sanitizer_zone, sizeof(sanitizer_zone));
42   new_zone->zone_name = NULL;  // The name will be changed anyway.
43   if (GetMacosVersion() >= MACOS_VERSION_LION) {
44     // Prevent the client app from overwriting the zone contents.
45     // Library functions that need to modify the zone will set PROT_WRITE on it.
46     // This matches the behavior of malloc_create_zone() on OSX 10.7 and higher.
47     mprotect(new_zone, allocated_size, PROT_READ);
48   }
49   return new_zone;
50 }
51
52 INTERCEPTOR(malloc_zone_t *, malloc_default_zone, void) {
53   COMMON_MALLOC_ENTER();
54   return &sanitizer_zone;
55 }
56
57 INTERCEPTOR(malloc_zone_t *, malloc_default_purgeable_zone, void) {
58   // FIXME: ASan should support purgeable allocations.
59   // https://github.com/google/sanitizers/issues/139
60   COMMON_MALLOC_ENTER();
61   return &sanitizer_zone;
62 }
63
64 INTERCEPTOR(void, malloc_make_purgeable, void *ptr) {
65   // FIXME: ASan should support purgeable allocations. Ignoring them is fine
66   // for now.
67   COMMON_MALLOC_ENTER();
68 }
69
70 INTERCEPTOR(int, malloc_make_nonpurgeable, void *ptr) {
71   // FIXME: ASan should support purgeable allocations. Ignoring them is fine
72   // for now.
73   COMMON_MALLOC_ENTER();
74   // Must return 0 if the contents were not purged since the last call to
75   // malloc_make_purgeable().
76   return 0;
77 }
78
79 INTERCEPTOR(void, malloc_set_zone_name, malloc_zone_t *zone, const char *name) {
80   COMMON_MALLOC_ENTER();
81   // Allocate |sizeof(COMMON_MALLOC_ZONE_NAME "-") + internal_strlen(name)|
82   // bytes.
83   size_t buflen =
84       sizeof(COMMON_MALLOC_ZONE_NAME "-") + (name ? internal_strlen(name) : 0);
85   InternalScopedString new_name(buflen);
86   if (name && zone->introspect == sanitizer_zone.introspect) {
87     new_name.append(COMMON_MALLOC_ZONE_NAME "-%s", name);
88     name = new_name.data();
89   }
90
91   // Call the system malloc's implementation for both external and our zones,
92   // since that appropriately changes VM region protections on the zone.
93   REAL(malloc_set_zone_name)(zone, name);
94 }
95
96 INTERCEPTOR(void *, malloc, size_t size) {
97   COMMON_MALLOC_ENTER();
98   COMMON_MALLOC_MALLOC(size);
99   return p;
100 }
101
102 INTERCEPTOR(void, free, void *ptr) {
103   COMMON_MALLOC_ENTER();
104   if (!ptr) return;
105   COMMON_MALLOC_FREE(ptr);
106 }
107
108 INTERCEPTOR(void *, realloc, void *ptr, size_t size) {
109   COMMON_MALLOC_ENTER();
110   COMMON_MALLOC_REALLOC(ptr, size);
111   return p;
112 }
113
114 INTERCEPTOR(void *, calloc, size_t nmemb, size_t size) {
115   COMMON_MALLOC_ENTER();
116   COMMON_MALLOC_CALLOC(nmemb, size);
117   return p;
118 }
119
120 INTERCEPTOR(void *, valloc, size_t size) {
121   COMMON_MALLOC_ENTER();
122   COMMON_MALLOC_VALLOC(size);
123   return p;
124 }
125
126 INTERCEPTOR(size_t, malloc_good_size, size_t size) {
127   COMMON_MALLOC_ENTER();
128   return sanitizer_zone.introspect->good_size(&sanitizer_zone, size);
129 }
130
131 INTERCEPTOR(int, posix_memalign, void **memptr, size_t alignment, size_t size) {
132   COMMON_MALLOC_ENTER();
133   CHECK(memptr);
134   COMMON_MALLOC_MEMALIGN(alignment, size);
135   if (p) {
136     *memptr = p;
137     return 0;
138   }
139   return -1;
140 }
141
142 namespace {
143
144 // TODO(glider): the __sanitizer_mz_* functions should be united with the Linux
145 // wrappers, as they are basically copied from there.
146 extern "C"
147 SANITIZER_INTERFACE_ATTRIBUTE
148 size_t __sanitizer_mz_size(malloc_zone_t* zone, const void* ptr) {
149   COMMON_MALLOC_SIZE(ptr);
150   return size;
151 }
152
153 extern "C"
154 SANITIZER_INTERFACE_ATTRIBUTE
155 void *__sanitizer_mz_malloc(malloc_zone_t *zone, uptr size) {
156   COMMON_MALLOC_ENTER();
157   COMMON_MALLOC_MALLOC(size);
158   return p;
159 }
160
161 extern "C"
162 SANITIZER_INTERFACE_ATTRIBUTE
163 void *__sanitizer_mz_calloc(malloc_zone_t *zone, size_t nmemb, size_t size) {
164   if (UNLIKELY(!COMMON_MALLOC_SANITIZER_INITIALIZED)) {
165     // Hack: dlsym calls calloc before REAL(calloc) is retrieved from dlsym.
166     const size_t kCallocPoolSize = 1024;
167     static uptr calloc_memory_for_dlsym[kCallocPoolSize];
168     static size_t allocated;
169     size_t size_in_words = ((nmemb * size) + kWordSize - 1) / kWordSize;
170     void *mem = (void*)&calloc_memory_for_dlsym[allocated];
171     allocated += size_in_words;
172     CHECK(allocated < kCallocPoolSize);
173     return mem;
174   }
175   COMMON_MALLOC_CALLOC(nmemb, size);
176   return p;
177 }
178
179 extern "C"
180 SANITIZER_INTERFACE_ATTRIBUTE
181 void *__sanitizer_mz_valloc(malloc_zone_t *zone, size_t size) {
182   COMMON_MALLOC_ENTER();
183   COMMON_MALLOC_VALLOC(size);
184   return p;
185 }
186
187 // TODO(glider): the allocation callbacks need to be refactored.
188 extern "C"
189 SANITIZER_INTERFACE_ATTRIBUTE
190 void __sanitizer_mz_free(malloc_zone_t *zone, void *ptr) {
191   if (!ptr) return;
192   COMMON_MALLOC_FREE(ptr);
193 }
194
195 #define GET_ZONE_FOR_PTR(ptr) \
196   malloc_zone_t *zone_ptr = malloc_zone_from_ptr(ptr); \
197   const char *zone_name = (zone_ptr == 0) ? 0 : zone_ptr->zone_name
198
199 extern "C"
200 SANITIZER_INTERFACE_ATTRIBUTE
201 void *__sanitizer_mz_realloc(malloc_zone_t *zone, void *ptr, size_t new_size) {
202   if (!ptr) {
203     COMMON_MALLOC_MALLOC(new_size);
204     return p;
205   } else {
206     COMMON_MALLOC_SIZE(ptr);
207     if (size) {
208       COMMON_MALLOC_REALLOC(ptr, new_size);
209       return p;
210     } else {
211       // We can't recover from reallocating an unknown address, because
212       // this would require reading at most |new_size| bytes from
213       // potentially unaccessible memory.
214       GET_ZONE_FOR_PTR(ptr);
215       COMMON_MALLOC_REPORT_UNKNOWN_REALLOC(ptr, zone_ptr, zone_name);
216       return nullptr;
217     }
218   }
219 }
220
221 extern "C"
222 SANITIZER_INTERFACE_ATTRIBUTE
223 void __sanitizer_mz_destroy(malloc_zone_t* zone) {
224   // A no-op -- we will not be destroyed!
225   Report("__sanitizer_mz_destroy() called -- ignoring\n");
226 }
227
228 extern "C"
229 SANITIZER_INTERFACE_ATTRIBUTE
230 void *__sanitizer_mz_memalign(malloc_zone_t *zone, size_t align, size_t size) {
231   COMMON_MALLOC_ENTER();
232   COMMON_MALLOC_MEMALIGN(align, size);
233   return p;
234 }
235
236 // This function is currently unused, and we build with -Werror.
237 #if 0
238 void __sanitizer_mz_free_definite_size(
239     malloc_zone_t* zone, void *ptr, size_t size) {
240   // TODO(glider): check that |size| is valid.
241   UNIMPLEMENTED();
242 }
243 #endif
244
245 kern_return_t mi_enumerator(task_t task, void *,
246                             unsigned type_mask, vm_address_t zone_address,
247                             memory_reader_t reader,
248                             vm_range_recorder_t recorder) {
249   // Should enumerate all the pointers we have.  Seems like a lot of work.
250   return KERN_FAILURE;
251 }
252
253 size_t mi_good_size(malloc_zone_t *zone, size_t size) {
254   // I think it's always safe to return size, but we maybe could do better.
255   return size;
256 }
257
258 boolean_t mi_check(malloc_zone_t *zone) {
259   UNIMPLEMENTED();
260 }
261
262 void mi_print(malloc_zone_t *zone, boolean_t verbose) {
263   UNIMPLEMENTED();
264 }
265
266 void mi_log(malloc_zone_t *zone, void *address) {
267   // I don't think we support anything like this
268 }
269
270 void mi_force_lock(malloc_zone_t *zone) {
271   COMMON_MALLOC_FORCE_LOCK();
272 }
273
274 void mi_force_unlock(malloc_zone_t *zone) {
275   COMMON_MALLOC_FORCE_UNLOCK();
276 }
277
278 void mi_statistics(malloc_zone_t *zone, malloc_statistics_t *stats) {
279   COMMON_MALLOC_FILL_STATS(zone, stats);
280 }
281
282 boolean_t mi_zone_locked(malloc_zone_t *zone) {
283   // UNIMPLEMENTED();
284   return false;
285 }
286
287 }  // unnamed namespace
288
289 namespace COMMON_MALLOC_NAMESPACE {
290
291 void ReplaceSystemMalloc() {
292   static malloc_introspection_t sanitizer_zone_introspection;
293   // Ok to use internal_memset, these places are not performance-critical.
294   internal_memset(&sanitizer_zone_introspection, 0,
295                   sizeof(sanitizer_zone_introspection));
296
297   sanitizer_zone_introspection.enumerator = &mi_enumerator;
298   sanitizer_zone_introspection.good_size = &mi_good_size;
299   sanitizer_zone_introspection.check = &mi_check;
300   sanitizer_zone_introspection.print = &mi_print;
301   sanitizer_zone_introspection.log = &mi_log;
302   sanitizer_zone_introspection.force_lock = &mi_force_lock;
303   sanitizer_zone_introspection.force_unlock = &mi_force_unlock;
304   sanitizer_zone_introspection.statistics = &mi_statistics;
305   sanitizer_zone_introspection.zone_locked = &mi_zone_locked;
306
307   internal_memset(&sanitizer_zone, 0, sizeof(malloc_zone_t));
308
309   // Use version 6 for OSX >= 10.6.
310   sanitizer_zone.version = 6;
311   sanitizer_zone.zone_name = COMMON_MALLOC_ZONE_NAME;
312   sanitizer_zone.size = &__sanitizer_mz_size;
313   sanitizer_zone.malloc = &__sanitizer_mz_malloc;
314   sanitizer_zone.calloc = &__sanitizer_mz_calloc;
315   sanitizer_zone.valloc = &__sanitizer_mz_valloc;
316   sanitizer_zone.free = &__sanitizer_mz_free;
317   sanitizer_zone.realloc = &__sanitizer_mz_realloc;
318   sanitizer_zone.destroy = &__sanitizer_mz_destroy;
319   sanitizer_zone.batch_malloc = 0;
320   sanitizer_zone.batch_free = 0;
321   sanitizer_zone.free_definite_size = 0;
322   sanitizer_zone.memalign = &__sanitizer_mz_memalign;
323   sanitizer_zone.introspect = &sanitizer_zone_introspection;
324
325   // Register the zone.
326   malloc_zone_register(&sanitizer_zone);
327 }
328
329 }  // namespace COMMON_MALLOC_NAMESPACE