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