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