CFBase.c
  1  /*	CFBase.c
  2  	Copyright (c) 1998-2019, Apple Inc. and the Swift project authors
  3   
  4  	Portions Copyright (c) 2014-2019, Apple Inc. and the Swift project authors
  5  	Licensed under Apache License v2.0 with Runtime Library Exception
  6  	See http://swift.org/LICENSE.txt for license information
  7  	See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
  8  	Responsibility: Michael LeHew
  9  */
 10  
 11  #include <CoreFoundation/CFBase.h>
 12  #include "CFInternal.h"
 13  #include "CFRuntime_Internal.h"
 14  #if __has_include(<unistd.h>)
 15  #include <unistd.h>
 16  #endif
 17  #if _POSIX_THREADS
 18  #include <pthread.h>
 19  #endif
 20  #if TARGET_OS_MAC
 21  #include <malloc/malloc.h>
 22  #include <mach/mach.h>
 23  #include <dlfcn.h>
 24  #endif
 25  #include <stdlib.h>
 26  #include <string.h>
 27  
 28  // -------- -------- -------- -------- -------- -------- -------- --------
 29  
 30  struct __CFAllocator {
 31      CFRuntimeBase _base;
 32  #if TARGET_OS_MAC
 33      // CFAllocator structure must match struct _malloc_zone_t!
 34      // The first two reserved fields in struct _malloc_zone_t are for us with CFRuntimeBase
 35      size_t 	(*size)(struct _malloc_zone_t *zone, const void *ptr); /* returns the size of a block or 0 if not in this zone; must be fast, especially for negative answers */
 36      void 	*(*malloc)(struct _malloc_zone_t *zone, size_t size);
 37      void 	*(*calloc)(struct _malloc_zone_t *zone, size_t num_items, size_t size); /* same as malloc, but block returned is set to zero */
 38      void 	*(*valloc)(struct _malloc_zone_t *zone, size_t size); /* same as malloc, but block returned is set to zero and is guaranteed to be page aligned */
 39      void 	(*free)(struct _malloc_zone_t *zone, void *ptr);
 40      void 	*(*realloc)(struct _malloc_zone_t *zone, void *ptr, size_t size);
 41      void 	(*destroy)(struct _malloc_zone_t *zone); /* zone is destroyed and all memory reclaimed */
 42      const char	*zone_name;
 43  
 44      /* Optional batch callbacks; these may be NULL */
 45      unsigned	(*batch_malloc)(struct _malloc_zone_t *zone, size_t size, void **results, unsigned num_requested); /* given a size, returns pointers capable of holding that size; returns the number of pointers allocated (maybe 0 or less than num_requested) */
 46      void	(*batch_free)(struct _malloc_zone_t *zone, void **to_be_freed, unsigned num_to_be_freed); /* frees all the pointers in to_be_freed; note that to_be_freed may be overwritten during the process */
 47  
 48      const struct malloc_introspection_t	*introspect;
 49      unsigned	version;
 50      
 51      /* aligned memory allocation. The callback may be NULL. */
 52  	void *(*memalign)(struct _malloc_zone_t *zone, size_t alignment, size_t size);
 53      
 54      /* free a pointer known to be in zone and known to have the given size. The callback may be NULL. */
 55      void (*free_definite_size)(struct _malloc_zone_t *zone, void *ptr, size_t size);
 56  #endif
 57      CFAllocatorRef _allocator;
 58      CFAllocatorContext _context;
 59  };
 60  
 61  CF_INLINE uintptr_t __CFISAForCFAllocator(void) {
 62      return _GetCFRuntimeObjcClassAtIndex(_kCFRuntimeIDCFAllocator);
 63  }
 64  
 65  CF_INLINE CFAllocatorRetainCallBack __CFAllocatorGetRetainFunction(const CFAllocatorContext *context) {
 66      CFAllocatorRetainCallBack retval = NULL;
 67  	retval = context->retain;
 68      return retval;
 69  }
 70  
 71  CF_INLINE CFAllocatorReleaseCallBack __CFAllocatorGetReleaseFunction(const CFAllocatorContext *context) {
 72      CFAllocatorReleaseCallBack retval = NULL;
 73  	retval = context->release;
 74      return retval;
 75  }
 76  
 77  CF_INLINE CFAllocatorCopyDescriptionCallBack __CFAllocatorGetCopyDescriptionFunction(const CFAllocatorContext *context) {
 78      CFAllocatorCopyDescriptionCallBack retval = NULL;
 79  	retval = context->copyDescription;
 80      return retval;
 81  }
 82  
 83  CF_INLINE CFAllocatorAllocateCallBack __CFAllocatorGetAllocateFunction(const CFAllocatorContext *context) {
 84      CFAllocatorAllocateCallBack retval = NULL;
 85  	retval = context->allocate;
 86      return retval;
 87  }
 88  
 89  CF_INLINE CFAllocatorReallocateCallBack __CFAllocatorGetReallocateFunction(const CFAllocatorContext *context) {
 90      CFAllocatorReallocateCallBack retval = NULL;
 91  	retval = context->reallocate;
 92      return retval;
 93  }
 94  
 95  CF_INLINE CFAllocatorDeallocateCallBack __CFAllocatorGetDeallocateFunction(const CFAllocatorContext *context) {
 96      CFAllocatorDeallocateCallBack retval = NULL;
 97  	retval = context->deallocate;
 98      return retval;
 99  }
100  
101  CF_INLINE CFAllocatorPreferredSizeCallBack __CFAllocatorGetPreferredSizeFunction(const CFAllocatorContext *context) {
102      CFAllocatorPreferredSizeCallBack retval = NULL;
103  	retval = context->preferredSize;
104      return retval;
105  }
106  
107  static const void * const __MallocDefaultZoneInfoPlaceholder = NULL;
108  
109  #if TARGET_OS_MAC
110  
111  CF_PRIVATE void __CFAllocatorDeallocate(CFTypeRef cf);
112  
113  static kern_return_t __CFAllocatorZoneIntrospectNoOp(void) {
114      return 0;
115  }
116  
117  static boolean_t __CFAllocatorZoneIntrospectTrue(void) {
118      return 1;
119  }
120  
121  static size_t __CFAllocatorCustomSize(malloc_zone_t *zone, const void *ptr) {
122      return 0;
123  
124      // The only way to implement this with a version 0 allocator would be
125      // for CFAllocator to keep track of all blocks allocated itself, which
126      // could be done, but would be bad for performance, so we don't do it.
127      //    size_t (*size)(struct _malloc_zone_t *zone, const void *ptr);
128      /* returns the size of a block or 0 if not in this zone;
129       * must be fast, especially for negative answers */
130  }
131  
132  static void *__CFAllocatorCustomMalloc(malloc_zone_t *zone, size_t size) {
133      CFAllocatorRef allocator = (CFAllocatorRef)zone;
134      return CFAllocatorAllocate(allocator, size, 0);
135  }
136  
137  static void *__CFAllocatorCustomCalloc(malloc_zone_t *zone, size_t num_items, size_t size) {
138      CFAllocatorRef allocator = (CFAllocatorRef)zone;
139      void *newptr = CFAllocatorAllocate(allocator, size, 0);
140      if (newptr) memset(newptr, 0, size);
141      return newptr;
142  }
143  
144  static void *__CFAllocatorCustomValloc(malloc_zone_t *zone, size_t size) {
145      CFAllocatorRef allocator = (CFAllocatorRef)zone;
146      if (size >= ULONG_MAX - 2 * vm_page_size) return NULL; // avoid integer overflow plus don't allow all pages to be allocated either
147      void *newptr = CFAllocatorAllocate(allocator, size + vm_page_size, 0);
148      newptr = (void *)round_page((uintptr_t)newptr);
149      return newptr;
150  }
151  
152  static void __CFAllocatorCustomFree(malloc_zone_t *zone, void *ptr) {
153      CFAllocatorRef allocator = (CFAllocatorRef)zone;
154      CFAllocatorDeallocate(allocator, ptr);
155  }
156  
157  static void *__CFAllocatorCustomRealloc(malloc_zone_t *zone, void *ptr, size_t size) {
158      CFAllocatorRef allocator = (CFAllocatorRef)zone;
159      return CFAllocatorReallocate(allocator, ptr, size, 0);
160  }
161  
162  static void __CFAllocatorCustomDestroy(malloc_zone_t *zone) {
163      CFAllocatorRef allocator = (CFAllocatorRef)zone;
164      // !!! we do it, and caller of malloc_destroy_zone() assumes
165      // COMPLETE responsibility for the result; NO Apple library
166      // code should be modified as a result of discovering that
167      // some activity results in inconveniences to developers
168      // trying to use malloc_destroy_zone() with a CFAllocatorRef;
169      // that's just too bad for them.
170      __CFAllocatorDeallocate(allocator);
171  }
172  
173  static size_t __CFAllocatorCustomGoodSize(malloc_zone_t *zone, size_t size) {
174      CFAllocatorRef allocator = (CFAllocatorRef)zone;
175      return CFAllocatorGetPreferredSizeForSize(allocator, size, 0);
176  }
177  
178  static const struct malloc_introspection_t __CFAllocatorZoneIntrospect = {
179      (void *)__CFAllocatorZoneIntrospectNoOp,
180      (void *)__CFAllocatorCustomGoodSize,
181      (void *)__CFAllocatorZoneIntrospectTrue,
182      (void *)__CFAllocatorZoneIntrospectNoOp,
183      (void *)__CFAllocatorZoneIntrospectNoOp,
184      (void *)__CFAllocatorZoneIntrospectNoOp,
185      (void *)__CFAllocatorZoneIntrospectNoOp,
186      (void *)__CFAllocatorZoneIntrospectNoOp
187  };
188  
189  static size_t __CFAllocatorNullSize(malloc_zone_t *zone, const void *ptr) {
190      return 0;
191  }
192  
193  static void * __CFAllocatorNullMalloc(malloc_zone_t *zone, size_t size) {
194      return NULL;
195  }
196  
197  static void * __CFAllocatorNullCalloc(malloc_zone_t *zone, size_t num_items, size_t size) {
198      return NULL;
199  }
200  
201  static void * __CFAllocatorNullValloc(malloc_zone_t *zone, size_t size) {
202      return NULL;
203  }
204  
205  static void __CFAllocatorNullFree(malloc_zone_t *zone, void *ptr) {
206  }
207  
208  static void * __CFAllocatorNullRealloc(malloc_zone_t *zone, void *ptr, size_t size) {
209      return NULL;
210  }
211  
212  static void __CFAllocatorNullDestroy(malloc_zone_t *zone) {
213  }
214  
215  static size_t __CFAllocatorNullGoodSize(malloc_zone_t *zone, size_t size) {
216      return size;
217  }
218  
219  static const struct malloc_introspection_t __CFAllocatorNullZoneIntrospect = {
220      (void *)__CFAllocatorZoneIntrospectNoOp,
221      (void *)__CFAllocatorNullGoodSize,
222      (void *)__CFAllocatorZoneIntrospectTrue,
223      (void *)__CFAllocatorZoneIntrospectNoOp,
224      (void *)__CFAllocatorZoneIntrospectNoOp,
225      (void *)__CFAllocatorZoneIntrospectNoOp,
226      (void *)__CFAllocatorZoneIntrospectNoOp,
227      (void *)__CFAllocatorZoneIntrospectNoOp
228  };
229  
230  static void *__CFAllocatorSystemAllocate(CFIndex size, CFOptionFlags hint, void *info) {
231      malloc_zone_t * const zone = (info == &__MallocDefaultZoneInfoPlaceholder) ? malloc_default_zone() : (malloc_zone_t *)info;
232      void *result = NULL;
233      if (hint == _CFAllocatorHintZeroWhenAllocating) {
234          result = malloc_zone_calloc(zone, 1, size);
235      } else {
236          result = malloc_zone_malloc(zone, size);
237      }
238      return result;
239  }
240  
241  static void *__CFAllocatorSystemReallocate(void *ptr, CFIndex newsize, CFOptionFlags hint, void *info) {
242      malloc_zone_t * const zone = (info == &__MallocDefaultZoneInfoPlaceholder) ? malloc_default_zone() : (malloc_zone_t *)info;
243      return malloc_zone_realloc(zone, ptr, newsize);
244  }
245  
246  static void __CFAllocatorSystemDeallocate(void *ptr, void *info) {
247      malloc_zone_t * const zone = (info == &__MallocDefaultZoneInfoPlaceholder) ? malloc_default_zone() : (malloc_zone_t *)info;
248  #if defined(DEBUG)
249      size_t size = malloc_size(ptr);
250      if (size) memset(ptr, 0xCC, size);
251  #endif
252      malloc_zone_free(zone, ptr);
253  }
254  
255  #else
256  
257  static void *__CFAllocatorSystemAllocate(CFIndex size, CFOptionFlags hint, void *info) {
258      if (hint == _CFAllocatorHintZeroWhenAllocating) {
259          return calloc(1, size);
260      } else {
261          return malloc(size);
262      }
263  }
264  
265  static void *__CFAllocatorSystemReallocate(void *ptr, CFIndex newsize, CFOptionFlags hint, void *info) {
266      return realloc(ptr, newsize);
267  }
268  
269  static void __CFAllocatorSystemDeallocate(void *ptr, void *info) {
270      free(ptr);
271  }
272  #endif
273  
274  static void *__CFAllocatorNullAllocate(CFIndex size, CFOptionFlags hint, void *info) {
275      return NULL;
276  }
277  
278  static void *__CFAllocatorNullReallocate(void *ptr, CFIndex newsize, CFOptionFlags hint, void *info) {
279      return NULL;
280  }
281  
282  #if defined (__cplusplus)
283  static void * __CFAllocatorCPPMalloc(CFIndex allocSize, CFOptionFlags hint, void *info)
284  {
285  	return malloc(allocSize);	
286  }
287  static void * __CFAllocatorCPPReAlloc(void *ptr, CFIndex newsize, CFOptionFlags hint, void *info)
288  {
289  	return realloc(ptr, newsize);
290  }
291  static void __CFAllocatorCPPFree(void *ptr, void *info)
292  {
293  	free(ptr);
294  }
295  #endif // C++
296  
297  
298  static _CF_CONSTANT_OBJECT_BACKING struct __CFAllocator __kCFAllocatorSystemDefault;
299  
300  DECLARE_STATIC_CLASS_REF(__NSCFType);
301  
302  static _CF_CONSTANT_OBJECT_BACKING struct __CFAllocator __kCFAllocatorMalloc = {
303      INIT_CFRUNTIME_BASE_WITH_CLASS(__NSCFType, _kCFRuntimeIDCFAllocator),
304  #if TARGET_OS_MAC
305      __CFAllocatorCustomSize,
306      __CFAllocatorCustomMalloc,
307      __CFAllocatorCustomCalloc,
308      __CFAllocatorCustomValloc,
309      __CFAllocatorCustomFree,
310      __CFAllocatorCustomRealloc,
311      __CFAllocatorNullDestroy,
312      "kCFAllocatorMalloc",
313      NULL,
314      NULL,
315      &__CFAllocatorZoneIntrospect,
316      6,
317      NULL,
318      NULL,
319  #endif
320      &__kCFAllocatorSystemDefault,	// _allocator
321      // Using the malloc functions directly is a total cheat, but works (in C)
322      // because the function signatures match in their common prefix of arguments.
323      // This saves us one hop through an adaptor function.
324  #if !defined (__cplusplus)
325  	{0, NULL, NULL, NULL, NULL, (void *)malloc, (void *)realloc, (void *)free, NULL}
326  #else
327  	{0, NULL, NULL, NULL, NULL, __CFAllocatorCPPMalloc,__CFAllocatorCPPReAlloc, __CFAllocatorCPPFree, NULL}
328  #endif // __cplusplus
329  };
330  
331  static _CF_CONSTANT_OBJECT_BACKING struct __CFAllocator __kCFAllocatorMallocZone = {
332      INIT_CFRUNTIME_BASE_WITH_CLASS(__NSCFType, _kCFRuntimeIDCFAllocator),
333  #if TARGET_OS_MAC 
334      __CFAllocatorCustomSize,
335      __CFAllocatorCustomMalloc,
336      __CFAllocatorCustomCalloc,
337      __CFAllocatorCustomValloc,
338      __CFAllocatorCustomFree,
339      __CFAllocatorCustomRealloc,
340      __CFAllocatorNullDestroy,
341      "kCFAllocatorMallocZone",
342      NULL,
343      NULL,
344      &__CFAllocatorZoneIntrospect,
345      6,
346      NULL,
347      NULL,
348  #endif
349      &__kCFAllocatorSystemDefault,	// _allocator
350      {0, (void *)&__MallocDefaultZoneInfoPlaceholder, NULL, NULL, NULL, __CFAllocatorSystemAllocate, __CFAllocatorSystemReallocate, __CFAllocatorSystemDeallocate, NULL}
351  };
352  
353  static _CF_CONSTANT_OBJECT_BACKING struct __CFAllocator __kCFAllocatorSystemDefault = {
354      INIT_CFRUNTIME_BASE_WITH_CLASS(__NSCFType, _kCFRuntimeIDCFAllocator),
355  #if TARGET_OS_MAC 
356      __CFAllocatorCustomSize,
357      __CFAllocatorCustomMalloc,
358      __CFAllocatorCustomCalloc,
359      __CFAllocatorCustomValloc,
360      __CFAllocatorCustomFree,
361      __CFAllocatorCustomRealloc,
362      __CFAllocatorNullDestroy,
363      "kCFAllocatorSystemDefault",
364      NULL,
365      NULL,
366      &__CFAllocatorZoneIntrospect,
367      6,
368      NULL,
369      NULL,
370  #endif
371      &__kCFAllocatorSystemDefault,	// _allocator
372      {0, (void *)&__MallocDefaultZoneInfoPlaceholder, NULL, NULL, NULL, __CFAllocatorSystemAllocate, __CFAllocatorSystemReallocate, __CFAllocatorSystemDeallocate, NULL}
373  };
374  
375  static _CF_CONSTANT_OBJECT_BACKING struct __CFAllocator __kCFAllocatorNull = {
376      INIT_CFRUNTIME_BASE_WITH_CLASS(__NSCFType, _kCFRuntimeIDCFAllocator),
377  #if TARGET_OS_MAC 
378      __CFAllocatorNullSize,
379      __CFAllocatorNullMalloc,
380      __CFAllocatorNullCalloc,
381      __CFAllocatorNullValloc,
382      __CFAllocatorNullFree,
383      __CFAllocatorNullRealloc,
384      __CFAllocatorNullDestroy,
385      "kCFAllocatorNull",
386      NULL,
387      NULL,
388      &__CFAllocatorNullZoneIntrospect,
389      6,
390      NULL,
391      NULL,
392  #endif
393      &__kCFAllocatorSystemDefault,	// _allocator
394      {0, NULL, NULL, NULL, NULL, __CFAllocatorNullAllocate, __CFAllocatorNullReallocate, NULL, NULL}
395  };
396  
397  const CFAllocatorRef kCFAllocatorDefault = NULL;
398  const CFAllocatorRef kCFAllocatorSystemDefault = &__kCFAllocatorSystemDefault;
399  const CFAllocatorRef kCFAllocatorMalloc = &__kCFAllocatorMalloc;
400  const CFAllocatorRef kCFAllocatorMallocZone = &__kCFAllocatorMallocZone;
401  const CFAllocatorRef kCFAllocatorNull = &__kCFAllocatorNull;
402  const CFAllocatorRef kCFAllocatorUseContext = (CFAllocatorRef)0x03ab;
403  
404  // Even though we no longer support GC, leave in the definitions for exported symbols.
405  #undef kCFAllocatorSystemDefaultGCRefZero
406  #undef kCFAllocatorDefaultGCRefZero
407  const CFAllocatorRef kCFAllocatorSystemDefaultGCRefZero = (CFAllocatorRef)0x03ad;
408  const CFAllocatorRef kCFAllocatorDefaultGCRefZero = (CFAllocatorRef)0x03af;
409  
410  static CFStringRef __CFAllocatorCopyDescription(CFTypeRef cf) {
411      CFAllocatorRef self = (CFAllocatorRef)cf;
412      CFAllocatorRef allocator = (kCFAllocatorUseContext == self->_allocator) ? self : self->_allocator;
413      return CFStringCreateWithFormat(allocator, NULL, CFSTR("<CFAllocator %p [%p]>{info = %p}"), cf, allocator, self->_context.info);
414  // CF: should use copyDescription function here to describe info field
415  // remember to release value returned from copydescr function when this happens
416  }
417  
418  CF_PRIVATE CFAllocatorRef __CFAllocatorGetAllocator(CFTypeRef cf) {
419      CFAllocatorRef allocator = (CFAllocatorRef)cf;
420      return (kCFAllocatorUseContext == allocator->_allocator) ? allocator : allocator->_allocator;
421  }
422  
423  CF_PRIVATE void __CFAllocatorDeallocate(CFTypeRef cf) {
424      CFAllocatorRef self = (CFAllocatorRef)cf;
425      CFAllocatorRef allocator = self->_allocator;
426      CFAllocatorReleaseCallBack releaseFunc = __CFAllocatorGetReleaseFunction(&self->_context);
427      if (kCFAllocatorUseContext == allocator) {
428  	/* Rather a chicken and egg problem here, so we do things
429  	   in the reverse order from what was done at create time. */
430  	CFAllocatorDeallocateCallBack deallocateFunc = __CFAllocatorGetDeallocateFunction(&self->_context);
431  	void *info = self->_context.info;
432  	if (NULL != deallocateFunc) {
433  	    INVOKE_CALLBACK2(deallocateFunc, (void *)self, info);
434  	}
435  	if (NULL != releaseFunc) {
436  	    INVOKE_CALLBACK1(releaseFunc, info);
437  	}
438      } else {
439  	if (NULL != releaseFunc) {
440  	    INVOKE_CALLBACK1(releaseFunc, self->_context.info);
441  	}
442          CFAllocatorDeallocate(allocator, (void *)self);
443      }
444  }
445  
446  const CFRuntimeClass __CFAllocatorClass = {
447      0,
448      "CFAllocator",
449      NULL,	// init
450      NULL,	// copy
451      NULL,
452      NULL,	// equal
453      NULL,	// hash
454      NULL,	// 
455      __CFAllocatorCopyDescription
456  };
457  
458  static void _CFAllocatorSetInstanceTypeIDAndIsa(struct __CFAllocator *memory) {
459      _CFRuntimeSetInstanceTypeID(memory, _kCFRuntimeIDCFAllocator);
460      memory->_base._cfisa = __CFISAForCFAllocator();
461  }
462  
463  CFTypeID CFAllocatorGetTypeID(void) {
464      return _kCFRuntimeIDCFAllocator;
465  }
466  
467  CFAllocatorRef CFAllocatorGetDefault(void) {
468      return __CFGetDefaultAllocator();
469  }
470  
471  void CFAllocatorSetDefault(CFAllocatorRef allocator) {
472  #ifndef __clang_analyzer__
473      // clang doesn't like complexity of staticly laid out instances like the black magic we do here and  __CFGetDefaultAllocator
474      CFAllocatorRef current = __CFGetDefaultAllocator();
475  #if defined(DEBUG) 
476      if (NULL != allocator) {
477  	__CFGenericValidateType(allocator, _kCFRuntimeIDCFAllocator);
478      }
479  #endif
480  #if TARGET_OS_MAC
481      if (allocator && _CFTypeGetClass(allocator) != __CFISAForCFAllocator()) {	// malloc_zone_t *
482  	return;		// require allocator to this function to be an allocator
483      }
484  #endif
485      if (NULL != allocator && allocator != current) {
486  	if (current) CFRelease(current);
487  	CFRetain(allocator);
488  	// We retain an extra time so that anything set as the default
489  	// allocator never goes away.
490  	CFRetain(allocator);
491          _CFSetTSD(__CFTSDKeyAllocator, (void *)allocator, NULL);
492      }
493  #endif
494  }
495  
496  #if DEPLOYMENT_RUNTIME_SWIFT
497  // Custom allocators are unsupported for swift-corelibs-foundation
498  CFAllocatorRef CFAllocatorCreate(CFAllocatorRef allocator, CFAllocatorContext *context) {
499      HALT;
500  }
501  #else
502  static CFAllocatorRef __CFAllocatorCreate(CFAllocatorRef allocator, CFAllocatorContext *context) {
503      struct __CFAllocator *memory = NULL;
504      CFAllocatorRetainCallBack retainFunc;
505      CFAllocatorAllocateCallBack allocateFunc;
506      void *retainedInfo;
507  #if TARGET_OS_MAC
508      if (allocator && kCFAllocatorUseContext != allocator && _CFTypeGetClass(allocator) != __CFISAForCFAllocator()) {	// malloc_zone_t *
509  	return NULL;	// require allocator to this function to be an allocator
510      }
511  #endif
512      retainFunc = context->retain;
513      FAULT_CALLBACK((void **)&retainFunc);
514      allocateFunc = context->allocate;
515      FAULT_CALLBACK((void **)&allocateFunc);
516      if (NULL != retainFunc) {
517  	retainedInfo = (void *)INVOKE_CALLBACK1(retainFunc, context->info);
518      } else {
519  	retainedInfo = context->info;
520      }
521      // We don't use _CFRuntimeCreateInstance()
522      if (kCFAllocatorUseContext == allocator) {
523  	memory = NULL;
524  	if (allocateFunc) {
525  		memory = (struct __CFAllocator *)INVOKE_CALLBACK3(allocateFunc, sizeof(struct __CFAllocator), 0, retainedInfo);
526  	}
527  	if (NULL == memory) {
528  	    return NULL;
529  	}
530      } else {
531  	allocator = (NULL == allocator) ? __CFGetDefaultAllocator() : allocator;
532  	memory = (struct __CFAllocator *)CFAllocatorAllocate(allocator, sizeof(struct __CFAllocator), 0);
533  	if (NULL == memory) {
534  	    return NULL;
535  	}
536  	if (__CFOASafe) __CFSetLastAllocationEventName(memory, "CFAllocator");
537      }
538      memset(memory, 0, sizeof(CFRuntimeBase));
539      __CFRuntimeSetRC(memory, 1);
540      _CFAllocatorSetInstanceTypeIDAndIsa(memory);
541  #if TARGET_OS_MAC
542      memory->size = __CFAllocatorCustomSize;
543      memory->malloc = __CFAllocatorCustomMalloc;
544      memory->calloc = __CFAllocatorCustomCalloc;
545      memory->valloc = __CFAllocatorCustomValloc;
546      memory->free = __CFAllocatorCustomFree;
547      memory->realloc = __CFAllocatorCustomRealloc;
548      memory->destroy = __CFAllocatorCustomDestroy;
549      memory->zone_name = "Custom CFAllocator";
550      memory->batch_malloc = NULL;
551      memory->batch_free = NULL;
552      memory->introspect = &__CFAllocatorZoneIntrospect;
553      memory->version = 6;
554      memory->memalign = NULL;
555      memory->free_definite_size = NULL;
556  #endif
557      memory->_allocator = allocator;
558      memory->_context.version = context->version;
559      memory->_context.info = retainedInfo;
560      memory->_context.retain = retainFunc;
561      memory->_context.release = context->release;
562      FAULT_CALLBACK((void **)&(memory->_context.release));
563      memory->_context.copyDescription = context->copyDescription;
564      FAULT_CALLBACK((void **)&(memory->_context.copyDescription));
565      memory->_context.allocate = allocateFunc;
566      memory->_context.reallocate = context->reallocate;
567      FAULT_CALLBACK((void **)&(memory->_context.reallocate));
568      memory->_context.deallocate = context->deallocate;
569      FAULT_CALLBACK((void **)&(memory->_context.deallocate));
570      memory->_context.preferredSize = context->preferredSize;
571      FAULT_CALLBACK((void **)&(memory->_context.preferredSize));
572  
573      return memory;
574  }
575  
576  
577  CFAllocatorRef CFAllocatorCreate(CFAllocatorRef allocator, CFAllocatorContext *context) {
578      return __CFAllocatorCreate(allocator, context);
579  }
580  #endif
581  
582  void *CFAllocatorAllocate(CFAllocatorRef allocator, CFIndex size, CFOptionFlags hint) {
583      CFAllocatorAllocateCallBack allocateFunc;
584      void *newptr = NULL;
585  
586      if (NULL == allocator) {
587  	allocator = __CFGetDefaultAllocator();
588      }
589  
590  #if defined(DEBUG) && TARGET_OS_MAC
591      if (_CFTypeGetClass(allocator) == __CFISAForCFAllocator()) {
592  	__CFGenericValidateType(allocator, _kCFRuntimeIDCFAllocator);
593      }
594  #else
595      __CFGenericValidateType(allocator, _kCFRuntimeIDCFAllocator);
596  #endif
597      if (0 == size) return NULL;
598  #if TARGET_OS_MAC
599      if (_CFTypeGetClass(allocator) != __CFISAForCFAllocator()) {	// malloc_zone_t *
600  	return malloc_zone_malloc((malloc_zone_t *)allocator, size);
601      }
602  #endif
603      newptr = NULL;
604      allocateFunc = __CFAllocatorGetAllocateFunction(&allocator->_context);
605      if (allocateFunc) {
606          newptr = (void *)INVOKE_CALLBACK3(allocateFunc, size, hint, allocator->_context.info);
607      }
608      return newptr;
609  }
610  
611  void *CFAllocatorReallocate(CFAllocatorRef allocator, void *ptr, CFIndex newsize, CFOptionFlags hint) {
612      CFAllocatorAllocateCallBack allocateFunc;
613      CFAllocatorReallocateCallBack reallocateFunc;
614      CFAllocatorDeallocateCallBack deallocateFunc;
615      void *newptr;
616  
617      if (NULL == allocator) {
618          allocator = __CFGetDefaultAllocator();
619      }
620  
621  #if defined(DEBUG) && TARGET_OS_MAC
622      if (_CFTypeGetClass(allocator) == __CFISAForCFAllocator()) {
623  	__CFGenericValidateType(allocator, _kCFRuntimeIDCFAllocator);
624      }
625  #else
626      __CFGenericValidateType(allocator, _kCFRuntimeIDCFAllocator);
627  #endif
628      if (NULL == ptr && 0 < newsize) {
629  #if TARGET_OS_MAC
630  	if (_CFTypeGetClass(allocator) != __CFISAForCFAllocator()) {	// malloc_zone_t *
631  	    return malloc_zone_malloc((malloc_zone_t *)allocator, newsize);
632  	}
633  #endif
634  	newptr = NULL;
635  	allocateFunc = __CFAllocatorGetAllocateFunction(&allocator->_context);
636  	if (allocateFunc) {
637  		newptr = (void *)INVOKE_CALLBACK3(allocateFunc, newsize, hint, allocator->_context.info);
638  	}
639  	return newptr;
640      }
641      if (NULL != ptr && 0 == newsize) {
642  #if TARGET_OS_MAC
643  	if (_CFTypeGetClass(allocator) != __CFISAForCFAllocator()) {	// malloc_zone_t *
644  #if defined(DEBUG)
645  	    size_t size = malloc_size(ptr);
646  	    if (size) memset(ptr, 0xCC, size);
647  #endif
648  	    malloc_zone_free((malloc_zone_t *)allocator, ptr);
649  	    return NULL;
650  	}
651  #endif
652  	deallocateFunc = __CFAllocatorGetDeallocateFunction(&allocator->_context);
653  	if (NULL != deallocateFunc) {
654  	    INVOKE_CALLBACK2(deallocateFunc, ptr, allocator->_context.info);
655  	}
656  	return NULL;
657      }
658      if (NULL == ptr && 0 == newsize) return NULL;
659  #if TARGET_OS_MAC
660      if (_CFTypeGetClass(allocator) != __CFISAForCFAllocator()) {	// malloc_zone_t *
661  	return malloc_zone_realloc((malloc_zone_t *)allocator, ptr, newsize);
662      }
663  #endif
664      reallocateFunc = __CFAllocatorGetReallocateFunction(&allocator->_context);
665      if (NULL == reallocateFunc) return NULL;
666      newptr = (void *)INVOKE_CALLBACK4(reallocateFunc, ptr, newsize, hint, allocator->_context.info);
667      return newptr;
668  }
669  
670  void CFAllocatorDeallocate(CFAllocatorRef allocator, void *ptr) {
671      CFAllocatorDeallocateCallBack deallocateFunc;
672  
673      if (NULL == allocator) {
674          allocator = __CFGetDefaultAllocator();
675      }
676  
677  #if defined(DEBUG) && TARGET_OS_MAC
678      if (_CFTypeGetClass(allocator) == __CFISAForCFAllocator()) {
679  	__CFGenericValidateType(allocator, _kCFRuntimeIDCFAllocator);
680      }
681  #else
682      __CFGenericValidateType(allocator, _kCFRuntimeIDCFAllocator);
683  #endif
684  #if TARGET_OS_MAC
685      if (_CFTypeGetClass(allocator) != __CFISAForCFAllocator()) {	// malloc_zone_t *
686  #if defined(DEBUG)
687  	size_t size = malloc_size(ptr);
688  	if (size) memset(ptr, 0xCC, size);
689  #endif
690  	return malloc_zone_free((malloc_zone_t *)allocator, ptr);
691      }
692  #endif
693      deallocateFunc = __CFAllocatorGetDeallocateFunction(&allocator->_context);
694      if (NULL != ptr && NULL != deallocateFunc) {
695  	INVOKE_CALLBACK2(deallocateFunc, ptr, allocator->_context.info);
696      }
697  }
698  
699  CFIndex CFAllocatorGetPreferredSizeForSize(CFAllocatorRef allocator, CFIndex size, CFOptionFlags hint) {
700      CFAllocatorPreferredSizeCallBack prefFunc;
701      CFIndex newsize = 0;
702  
703      if (NULL == allocator) {
704          allocator = __CFGetDefaultAllocator();
705      }
706  
707  #if TARGET_OS_MAC
708      if (_CFTypeGetClass(allocator) == __CFISAForCFAllocator()) {
709  	__CFGenericValidateType(allocator, _kCFRuntimeIDCFAllocator);
710      }
711  #else
712      __CFGenericValidateType(allocator, _kCFRuntimeIDCFAllocator);
713  #endif
714  #if TARGET_OS_MAC
715      if (_CFTypeGetClass(allocator) != __CFISAForCFAllocator()) {	// malloc_zone_t *
716  	return malloc_good_size(size);
717      }
718  #endif
719      prefFunc = __CFAllocatorGetPreferredSizeFunction(&allocator->_context);
720      if (0 < size && NULL != prefFunc) {
721  	newsize = (CFIndex)(INVOKE_CALLBACK3(prefFunc, size, hint, allocator->_context.info));
722      }
723      if (newsize < size) newsize = size;
724      return newsize;
725  }
726  
727  void CFAllocatorGetContext(CFAllocatorRef allocator, CFAllocatorContext *context) {
728      if (NULL == allocator) {
729          allocator = __CFGetDefaultAllocator();
730      }
731  
732  #if TARGET_OS_MAC
733      if (_CFTypeGetClass(allocator) == __CFISAForCFAllocator()) {
734  	__CFGenericValidateType(allocator, _kCFRuntimeIDCFAllocator);
735      }
736  #else
737      __CFGenericValidateType(allocator, _kCFRuntimeIDCFAllocator);
738  #endif
739      CFAssert1(0 == context->version, __kCFLogAssertion, "%s(): context version not initialized to 0", __PRETTY_FUNCTION__);
740  #if TARGET_OS_MAC
741      if (_CFTypeGetClass(allocator) != __CFISAForCFAllocator()) {	// malloc_zone_t *
742  	return;
743      }
744  #endif
745      context->version = 0;
746      context->info = (allocator->_context.info == &__MallocDefaultZoneInfoPlaceholder) ? (void *)malloc_default_zone() : allocator->_context.info;
747      context->retain = __CFAllocatorGetRetainFunction(&allocator->_context);
748      context->release = __CFAllocatorGetReleaseFunction(&allocator->_context);
749      context->copyDescription = __CFAllocatorGetCopyDescriptionFunction(&allocator->_context);
750      context->allocate = __CFAllocatorGetAllocateFunction(&allocator->_context);
751      context->reallocate = __CFAllocatorGetReallocateFunction(&allocator->_context);
752      context->deallocate = __CFAllocatorGetDeallocateFunction(&allocator->_context);
753      context->preferredSize = __CFAllocatorGetPreferredSizeFunction(&allocator->_context);
754  }
755  
756  // -------- -------- -------- -------- -------- -------- -------- --------
757  
758  
759  // Technically this function can return, but for analyzer purposes it's enough to claim it doesn't.
760  __attribute__((cold))
761  static void __CFReallocationFailed(void *ptr, CFStringRef reason, void (^reallocationFailureHandler)(void *original, bool *outRecovered)) CLANG_ANALYZER_NORETURN {
762      bool recovered = false;
763      if (reallocationFailureHandler) {
764          reallocationFailureHandler(ptr, &recovered);
765      }
766      
767      if (!recovered) {
768          CRSetCrashLogMessage("Failed to grow buffer");
769          HALT;
770      }
771  }
772  
773  
774  void *__CFSafelyReallocate(void *destination, size_t newCapacity, void (^reallocationFailureHandler)(void *original, bool *outRecovered)) {
775      void *const reallocated = realloc(destination, newCapacity);
776      if (__builtin_expect(reallocated == NULL, false)) {
777          __CFReallocationFailed(destination,  CFSTR("realloc"), reallocationFailureHandler);
778      }
779      return reallocated;
780  }
781  
782  
783  void *__CFSafelyReallocateWithAllocator(CFAllocatorRef allocator, void *destination, size_t newCapacity, CFOptionFlags options, void (^reallocationFailureHandler)(void *original, bool *outRecovered)) {
784      void *reallocated = CFAllocatorReallocate(allocator, destination, newCapacity, options);
785      // NOTE: important difference in behavior between realloc vs CFAllocateReallocate NULL+0 -> NULL for allocators!
786      if (__builtin_expect(reallocated == NULL, false) && !(destination == NULL && newCapacity == 0)) {
787          __CFReallocationFailed(destination,  CFSTR("realloc"), reallocationFailureHandler);
788      }
789      return _CLANG_ANALYZER_IGNORE_NONNULL(reallocated);;
790  }
791  
792  Boolean __CFAllocatorRespectsHintZeroWhenAllocating(CFAllocatorRef allocator) {
793      return allocator == kCFAllocatorSystemDefault || allocator == kCFAllocatorMallocZone;
794  }
795  
796  
797  CFRange __CFRangeMake(CFIndex loc, CFIndex len) {
798      CFRange range;
799      range.location = loc;
800      range.length = len;
801      return range;
802  }
803  
804  
805  struct __CFNull {
806      CFRuntimeBase _base;
807  };
808  
809  DECLARE_STATIC_CLASS_REF(NSNull);
810  
811  struct __CFNull _CF_CONSTANT_OBJECT_BACKING __kCFNull = {
812      INIT_CFRUNTIME_BASE_WITH_CLASS(NSNull, _kCFRuntimeIDCFNull)
813  };
814  const CFNullRef kCFNull = &__kCFNull;
815  
816  static CFStringRef __CFNullCopyDescription(CFTypeRef cf) {
817      return CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("<CFNull %p [%p]>"), cf, CFGetAllocator(cf));
818  }
819  
820  static CFStringRef __CFNullCopyFormattingDescription(CFTypeRef cf, CFDictionaryRef formatOptions) {
821      return (CFStringRef)CFRetain(CFSTR("null"));
822  }
823  
824  static void __CFNullDeallocate(CFTypeRef cf) {
825      CFAssert(false, __kCFLogAssertion, "Deallocated CFNull!");
826  }
827  
828  const CFRuntimeClass __CFNullClass = {
829      0,
830      "CFNull",
831      NULL,      // init
832      NULL,      // copy
833      __CFNullDeallocate,
834      NULL,
835      NULL,
836      __CFNullCopyFormattingDescription,
837      __CFNullCopyDescription
838  };
839  
840  CFTypeID CFNullGetTypeID(void) {
841      return _kCFRuntimeIDCFNull;
842  }
843  
844  void CFCollection_non_gc_storage_error(void) { }
845  
846  
847  void _CFRuntimeSetCFMPresent(void *addr) {
848  }
849  
850  
851  // void __HALT(void);
852  
853  /* Keep this assembly at the bottom of the source file! */
854  
855  
856  extern void __HALT(void);
857  void __HALT() {
858      __builtin_trap();
859  }
860  
861