1/*
2 * Copyright (c) 2014 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-2013, 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
44struct __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
75CF_INLINE CFAllocatorRetainCallBack __CFAllocatorGetRetainFunction(const CFAllocatorContext *context) {
76    CFAllocatorRetainCallBack retval = NULL;
77	retval = context->retain;
78    return retval;
79}
80
81CF_INLINE CFAllocatorReleaseCallBack __CFAllocatorGetReleaseFunction(const CFAllocatorContext *context) {
82    CFAllocatorReleaseCallBack retval = NULL;
83	retval = context->release;
84    return retval;
85}
86
87CF_INLINE CFAllocatorCopyDescriptionCallBack __CFAllocatorGetCopyDescriptionFunction(const CFAllocatorContext *context) {
88    CFAllocatorCopyDescriptionCallBack retval = NULL;
89	retval = context->copyDescription;
90    return retval;
91}
92
93CF_INLINE CFAllocatorAllocateCallBack __CFAllocatorGetAllocateFunction(const CFAllocatorContext *context) {
94    CFAllocatorAllocateCallBack retval = NULL;
95	retval = context->allocate;
96    return retval;
97}
98
99CF_INLINE CFAllocatorReallocateCallBack __CFAllocatorGetReallocateFunction(const CFAllocatorContext *context) {
100    CFAllocatorReallocateCallBack retval = NULL;
101	retval = context->reallocate;
102    return retval;
103}
104
105CF_INLINE CFAllocatorDeallocateCallBack __CFAllocatorGetDeallocateFunction(const CFAllocatorContext *context) {
106    CFAllocatorDeallocateCallBack retval = NULL;
107	retval = context->deallocate;
108    return retval;
109}
110
111CF_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
119CF_PRIVATE void __CFAllocatorDeallocate(CFTypeRef cf);
120
121static kern_return_t __CFAllocatorZoneIntrospectNoOp(void) {
122    return 0;
123}
124
125static boolean_t __CFAllocatorZoneIntrospectTrue(void) {
126    return 1;
127}
128
129static 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
140static void *__CFAllocatorCustomMalloc(malloc_zone_t *zone, size_t size) {
141    CFAllocatorRef allocator = (CFAllocatorRef)zone;
142    return CFAllocatorAllocate(allocator, size, 0);
143}
144
145static 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
152static 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
160static void __CFAllocatorCustomFree(malloc_zone_t *zone, void *ptr) {
161    CFAllocatorRef allocator = (CFAllocatorRef)zone;
162    CFAllocatorDeallocate(allocator, ptr);
163}
164
165static 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
170static 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
181static size_t __CFAllocatorCustomGoodSize(malloc_zone_t *zone, size_t size) {
182    CFAllocatorRef allocator = (CFAllocatorRef)zone;
183    return CFAllocatorGetPreferredSizeForSize(allocator, size, 0);
184}
185
186static 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
197static size_t __CFAllocatorNullSize(malloc_zone_t *zone, const void *ptr) {
198    return 0;
199}
200
201static void * __CFAllocatorNullMalloc(malloc_zone_t *zone, size_t size) {
202    return NULL;
203}
204
205static void * __CFAllocatorNullCalloc(malloc_zone_t *zone, size_t num_items, size_t size) {
206    return NULL;
207}
208
209static void * __CFAllocatorNullValloc(malloc_zone_t *zone, size_t size) {
210    return NULL;
211}
212
213static void __CFAllocatorNullFree(malloc_zone_t *zone, void *ptr) {
214}
215
216static void * __CFAllocatorNullRealloc(malloc_zone_t *zone, void *ptr, size_t size) {
217    return NULL;
218}
219
220static void __CFAllocatorNullDestroy(malloc_zone_t *zone) {
221}
222
223static size_t __CFAllocatorNullGoodSize(malloc_zone_t *zone, size_t size) {
224    return size;
225}
226
227static 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
238static void *__CFAllocatorSystemAllocate(CFIndex size, CFOptionFlags hint, void *info) {
239    return malloc_zone_malloc(info, size);
240}
241
242static void *__CFAllocatorSystemReallocate(void *ptr, CFIndex newsize, CFOptionFlags hint, void *info) {
243    return malloc_zone_realloc(info, ptr, newsize);
244}
245
246static 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
256static void *__CFAllocatorSystemAllocate(CFIndex size, CFOptionFlags hint, void *info) {
257    return malloc(size);
258}
259
260static void *__CFAllocatorSystemReallocate(void *ptr, CFIndex newsize, CFOptionFlags hint, void *info) {
261    return realloc(ptr, newsize);
262}
263
264static void __CFAllocatorSystemDeallocate(void *ptr, void *info) {
265    free(ptr);
266}
267#endif
268
269static void *__CFAllocatorNullAllocate(CFIndex size, CFOptionFlags hint, void *info) {
270    return NULL;
271}
272
273static void *__CFAllocatorNullReallocate(void *ptr, CFIndex newsize, CFOptionFlags hint, void *info) {
274    return NULL;
275}
276
277#if defined (__cplusplus)
278static void * __CFAllocatorCPPMalloc(CFIndex allocSize, CFOptionFlags hint, void *info)
279{
280	return malloc(allocSize);
281}
282static void * __CFAllocatorCPPReAlloc(void *ptr, CFIndex newsize, CFOptionFlags hint, void *info)
283{
284	return realloc(ptr, newsize);
285}
286static void __CFAllocatorCPPFree(void *ptr, void *info)
287{
288	free(ptr);
289}
290#endif // C++
291
292
293static 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
322static 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
344static 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
366static 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
388const CFAllocatorRef kCFAllocatorDefault = NULL;
389const CFAllocatorRef kCFAllocatorSystemDefault = &__kCFAllocatorSystemDefault;
390const CFAllocatorRef kCFAllocatorMalloc = &__kCFAllocatorMalloc;
391const CFAllocatorRef kCFAllocatorMallocZone = &__kCFAllocatorMallocZone;
392const CFAllocatorRef kCFAllocatorNull = &__kCFAllocatorNull;
393const CFAllocatorRef kCFAllocatorUseContext = (CFAllocatorRef)0x03ab;
394#undef kCFAllocatorSystemDefaultGCRefZero
395#undef kCFAllocatorDefaultGCRefZero
396const CFAllocatorRef kCFAllocatorSystemDefaultGCRefZero = (CFAllocatorRef)0x03ad;
397const CFAllocatorRef kCFAllocatorDefaultGCRefZero = (CFAllocatorRef)0x03af;
398
399static 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
407CF_PRIVATE CFAllocatorRef __CFAllocatorGetAllocator(CFTypeRef cf) {
408    CFAllocatorRef allocator = (CFAllocatorRef)cf;
409    return (kCFAllocatorUseContext == allocator->_allocator) ? allocator : allocator->_allocator;
410}
411
412CF_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
435static CFTypeID __kCFAllocatorTypeID = _kCFRuntimeNotATypeID;
436
437static 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
449static void _CFAllocatorSetInstanceTypeIDAndIsa(struct __CFAllocator *memory) {
450    _CFRuntimeSetInstanceTypeID(memory, __kCFAllocatorTypeID);
451    memory->_base._cfisa = __CFISAForTypeID(__kCFAllocatorTypeID);
452}
453
454CF_PRIVATE void __CFAllocatorInitialize(void) {
455    __kCFAllocatorTypeID = _CFRuntimeRegisterClass(&__CFAllocatorClass);
456
457    _CFAllocatorSetInstanceTypeIDAndIsa(&__kCFAllocatorSystemDefault);
458#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
459    __kCFAllocatorSystemDefault._context.info = (kCFUseCollectableAllocator ? objc_collectableZone() : malloc_default_zone());
460#endif
461    __kCFAllocatorSystemDefault._allocator = kCFAllocatorSystemDefault;
462
463    _CFAllocatorSetInstanceTypeIDAndIsa(&__kCFAllocatorMalloc);
464    __kCFAllocatorMalloc._allocator = kCFAllocatorSystemDefault;
465
466#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
467    _CFAllocatorSetInstanceTypeIDAndIsa(&__kCFAllocatorMallocZone);
468    __kCFAllocatorMallocZone._allocator = kCFAllocatorSystemDefault;
469    __kCFAllocatorMallocZone._context.info = malloc_default_zone();
470#endif
471
472    _CFAllocatorSetInstanceTypeIDAndIsa(&__kCFAllocatorNull);
473    __kCFAllocatorNull._allocator = kCFAllocatorSystemDefault;
474}
475
476CFTypeID CFAllocatorGetTypeID(void) {
477    return __kCFAllocatorTypeID;
478}
479
480CFAllocatorRef CFAllocatorGetDefault(void) {
481    return __CFGetDefaultAllocator();
482}
483
484void CFAllocatorSetDefault(CFAllocatorRef allocator) {
485    CFAllocatorRef current = __CFGetDefaultAllocator();
486#if defined(DEBUG)
487    if (NULL != allocator) {
488	__CFGenericValidateType(allocator, __kCFAllocatorTypeID);
489    }
490#endif
491#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
492    if (allocator && allocator->_base._cfisa != __CFISAForTypeID(__kCFAllocatorTypeID)) {	// malloc_zone_t *
493	return;		// require allocator to this function to be an allocator
494    }
495#endif
496    if (NULL != allocator && allocator != current) {
497	if (current) CFRelease(current);
498	CFRetain(allocator);
499	// We retain an extra time so that anything set as the default
500	// allocator never goes away.
501	CFRetain(allocator);
502        _CFSetTSD(__CFTSDKeyAllocator, (void *)allocator, NULL);
503    }
504}
505
506static CFAllocatorRef __CFAllocatorCreate(CFAllocatorRef allocator, CFAllocatorContext *context) {
507    struct __CFAllocator *memory = NULL;
508    CFAllocatorRetainCallBack retainFunc;
509    CFAllocatorAllocateCallBack allocateFunc;
510    void *retainedInfo;
511#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
512    if (allocator && kCFAllocatorUseContext != allocator && allocator->_base._cfisa != __CFISAForTypeID(__kCFAllocatorTypeID)) {	// malloc_zone_t *
513	return NULL;	// require allocator to this function to be an allocator
514    }
515#endif
516    retainFunc = context->retain;
517    FAULT_CALLBACK((void **)&retainFunc);
518    allocateFunc = context->allocate;
519    FAULT_CALLBACK((void **)&allocateFunc);
520    if (NULL != retainFunc) {
521	retainedInfo = (void *)INVOKE_CALLBACK1(retainFunc, context->info);
522    } else {
523	retainedInfo = context->info;
524    }
525    // We don't use _CFRuntimeCreateInstance()
526    if (kCFAllocatorUseContext == allocator) {
527	memory = NULL;
528	if (allocateFunc) {
529		memory = (struct __CFAllocator *)INVOKE_CALLBACK3(allocateFunc, sizeof(struct __CFAllocator), 0, retainedInfo);
530	}
531	if (NULL == memory) {
532	    return NULL;
533	}
534    } else {
535	allocator = (NULL == allocator) ? __CFGetDefaultAllocator() : allocator;
536	memory = (struct __CFAllocator *)CFAllocatorAllocate(allocator, sizeof(struct __CFAllocator), __kCFAllocatorGCObjectMemory);
537	if (NULL == memory) {
538	    return NULL;
539	}
540	if (__CFOASafe) __CFSetLastAllocationEventName(memory, "CFAllocator");
541    }
542    memset(memory, 0, sizeof(CFRuntimeBase));
543#if __LP64__
544    memory->_base._rc = 1;
545#else
546    memory->_base._cfinfo[CF_RC_BITS] = 1;
547#endif
548    memory->_base._cfinfo[CF_INFO_BITS] = 0;
549    _CFAllocatorSetInstanceTypeIDAndIsa(memory);
550#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
551    memory->size = __CFAllocatorCustomSize;
552    memory->malloc = __CFAllocatorCustomMalloc;
553    memory->calloc = __CFAllocatorCustomCalloc;
554    memory->valloc = __CFAllocatorCustomValloc;
555    memory->free = __CFAllocatorCustomFree;
556    memory->realloc = __CFAllocatorCustomRealloc;
557    memory->destroy = __CFAllocatorCustomDestroy;
558    memory->zone_name = "Custom CFAllocator";
559    memory->batch_malloc = NULL;
560    memory->batch_free = NULL;
561    memory->introspect = &__CFAllocatorZoneIntrospect;
562    memory->version = 6;
563    memory->memalign = NULL;
564    memory->free_definite_size = NULL;
565#endif
566    memory->_allocator = allocator;
567    memory->_context.version = context->version;
568    memory->_context.info = retainedInfo;
569    memory->_context.retain = retainFunc;
570    memory->_context.release = context->release;
571    FAULT_CALLBACK((void **)&(memory->_context.release));
572    memory->_context.copyDescription = context->copyDescription;
573    FAULT_CALLBACK((void **)&(memory->_context.copyDescription));
574    memory->_context.allocate = allocateFunc;
575    memory->_context.reallocate = context->reallocate;
576    FAULT_CALLBACK((void **)&(memory->_context.reallocate));
577    memory->_context.deallocate = context->deallocate;
578    FAULT_CALLBACK((void **)&(memory->_context.deallocate));
579    memory->_context.preferredSize = context->preferredSize;
580    FAULT_CALLBACK((void **)&(memory->_context.preferredSize));
581
582    return memory;
583}
584
585CFAllocatorRef CFAllocatorCreate(CFAllocatorRef allocator, CFAllocatorContext *context) {
586    return __CFAllocatorCreate(allocator, context);
587}
588
589void *CFAllocatorAllocate(CFAllocatorRef allocator, CFIndex size, CFOptionFlags hint) {
590    CFAllocatorAllocateCallBack allocateFunc;
591    void *newptr = NULL;
592
593    Boolean initialRefcountOne = true;
594    if (NULL == allocator) {
595	allocator = __CFGetDefaultAllocator();
596    }
597
598#if defined(DEBUG) && (DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI)
599    if (allocator->_base._cfisa == __CFISAForTypeID(__kCFAllocatorTypeID)) {
600	__CFGenericValidateType(allocator, __kCFAllocatorTypeID);
601    }
602#else
603    __CFGenericValidateType(allocator, __kCFAllocatorTypeID);
604#endif
605    if (0 == size) return NULL;
606#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
607    if (allocator->_base._cfisa != __CFISAForTypeID(__kCFAllocatorTypeID)) {	// malloc_zone_t *
608	return malloc_zone_malloc((malloc_zone_t *)allocator, size);
609    }
610#endif
611    if (CF_IS_COLLECTABLE_ALLOCATOR(allocator)) {
612	newptr = auto_zone_allocate_object((auto_zone_t*)allocator->_context.info, size, CF_GET_GC_MEMORY_TYPE(hint), initialRefcountOne, false);
613    } else {
614	newptr = NULL;
615	allocateFunc = __CFAllocatorGetAllocateFunction(&allocator->_context);
616	if (allocateFunc) {
617		newptr = (void *)INVOKE_CALLBACK3(allocateFunc, size, hint, allocator->_context.info);
618	}
619    }
620    return newptr;
621}
622
623void *CFAllocatorReallocate(CFAllocatorRef allocator, void *ptr, CFIndex newsize, CFOptionFlags hint) {
624    CFAllocatorAllocateCallBack allocateFunc;
625    CFAllocatorReallocateCallBack reallocateFunc;
626    CFAllocatorDeallocateCallBack deallocateFunc;
627    void *newptr;
628
629    if (0) {
630        allocator = kCFAllocatorSystemDefault;
631    } else if (0) {
632	allocator = kCFUseCollectableAllocator ? kCFAllocatorSystemDefault : __CFGetDefaultAllocator();
633    } else if (NULL == allocator) {
634        allocator = __CFGetDefaultAllocator();
635    }
636
637#if defined(DEBUG) && (DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI)
638    if (allocator->_base._cfisa == __CFISAForTypeID(__kCFAllocatorTypeID)) {
639	__CFGenericValidateType(allocator, __kCFAllocatorTypeID);
640    }
641#else
642    __CFGenericValidateType(allocator, __kCFAllocatorTypeID);
643#endif
644    if (NULL == ptr && 0 < newsize) {
645#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
646	if (allocator->_base._cfisa != __CFISAForTypeID(__kCFAllocatorTypeID)) {	// malloc_zone_t *
647	    return malloc_zone_malloc((malloc_zone_t *)allocator, newsize);
648	}
649#endif
650	newptr = NULL;
651	allocateFunc = __CFAllocatorGetAllocateFunction(&allocator->_context);
652	if (allocateFunc) {
653		newptr = (void *)INVOKE_CALLBACK3(allocateFunc, newsize, hint, allocator->_context.info);
654	}
655	return newptr;
656    }
657    if (NULL != ptr && 0 == newsize) {
658#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
659	if (allocator->_base._cfisa != __CFISAForTypeID(__kCFAllocatorTypeID)) {	// malloc_zone_t *
660#if defined(DEBUG)
661	    size_t size = malloc_size(ptr);
662	    if (size) memset(ptr, 0xCC, size);
663#endif
664	    malloc_zone_free((malloc_zone_t *)allocator, ptr);
665	    return NULL;
666	}
667#endif
668	deallocateFunc = __CFAllocatorGetDeallocateFunction(&allocator->_context);
669	if (NULL != deallocateFunc) {
670	    INVOKE_CALLBACK2(deallocateFunc, ptr, allocator->_context.info);
671	}
672	return NULL;
673    }
674    if (NULL == ptr && 0 == newsize) return NULL;
675#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
676    if (allocator->_base._cfisa != __CFISAForTypeID(__kCFAllocatorTypeID)) {	// malloc_zone_t *
677	return malloc_zone_realloc((malloc_zone_t *)allocator, ptr, newsize);
678    }
679#endif
680    reallocateFunc = __CFAllocatorGetReallocateFunction(&allocator->_context);
681    if (NULL == reallocateFunc) return NULL;
682    newptr = (void *)INVOKE_CALLBACK4(reallocateFunc, ptr, newsize, hint, allocator->_context.info);
683    return newptr;
684}
685
686void CFAllocatorDeallocate(CFAllocatorRef allocator, void *ptr) {
687    CFAllocatorDeallocateCallBack deallocateFunc;
688
689    if (0) {
690        allocator = kCFAllocatorSystemDefault;
691    } else if (0) {
692	allocator = kCFUseCollectableAllocator ? kCFAllocatorSystemDefault : __CFGetDefaultAllocator();
693	if (CF_IS_COLLECTABLE_ALLOCATOR(allocator)) return;
694    } else if (NULL == allocator) {
695        allocator = __CFGetDefaultAllocator();
696    }
697
698#if defined(DEBUG) && (DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI)
699    if (allocator->_base._cfisa == __CFISAForTypeID(__kCFAllocatorTypeID)) {
700	__CFGenericValidateType(allocator, __kCFAllocatorTypeID);
701    }
702#else
703    __CFGenericValidateType(allocator, __kCFAllocatorTypeID);
704#endif
705#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
706    if (allocator->_base._cfisa != __CFISAForTypeID(__kCFAllocatorTypeID)) {	// malloc_zone_t *
707#if defined(DEBUG)
708	size_t size = malloc_size(ptr);
709	if (size) memset(ptr, 0xCC, size);
710#endif
711	return malloc_zone_free((malloc_zone_t *)allocator, ptr);
712    }
713#endif
714    deallocateFunc = __CFAllocatorGetDeallocateFunction(&allocator->_context);
715    if (NULL != ptr && NULL != deallocateFunc) {
716	INVOKE_CALLBACK2(deallocateFunc, ptr, allocator->_context.info);
717    }
718}
719
720CFIndex CFAllocatorGetPreferredSizeForSize(CFAllocatorRef allocator, CFIndex size, CFOptionFlags hint) {
721    CFAllocatorPreferredSizeCallBack prefFunc;
722    CFIndex newsize = 0;
723
724    if (0) {
725        allocator = kCFAllocatorSystemDefault;
726    } else if (0) {
727	allocator = kCFUseCollectableAllocator ? kCFAllocatorSystemDefault : __CFGetDefaultAllocator();
728    } else if (NULL == allocator) {
729        allocator = __CFGetDefaultAllocator();
730    }
731
732#if defined(DEBUG) && (DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI)
733    if (allocator->_base._cfisa == __CFISAForTypeID(__kCFAllocatorTypeID)) {
734	__CFGenericValidateType(allocator, __kCFAllocatorTypeID);
735    }
736#else
737    __CFGenericValidateType(allocator, __kCFAllocatorTypeID);
738#endif
739#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
740    if (allocator->_base._cfisa != __CFISAForTypeID(__kCFAllocatorTypeID)) {	// malloc_zone_t *
741	return malloc_good_size(size);
742    }
743#endif
744    prefFunc = __CFAllocatorGetPreferredSizeFunction(&allocator->_context);
745    if (0 < size && NULL != prefFunc) {
746	newsize = (CFIndex)(INVOKE_CALLBACK3(prefFunc, size, hint, allocator->_context.info));
747    }
748    if (newsize < size) newsize = size;
749    return newsize;
750}
751
752void CFAllocatorGetContext(CFAllocatorRef allocator, CFAllocatorContext *context) {
753    if (0) {
754        allocator = kCFAllocatorSystemDefault;
755    } else if (0) {
756	allocator = kCFUseCollectableAllocator ? kCFAllocatorSystemDefault : __CFGetDefaultAllocator();
757    } else if (NULL == allocator) {
758        allocator = __CFGetDefaultAllocator();
759    }
760
761#if defined(DEBUG) && (DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI)
762    if (allocator->_base._cfisa == __CFISAForTypeID(__kCFAllocatorTypeID)) {
763	__CFGenericValidateType(allocator, __kCFAllocatorTypeID);
764    }
765#else
766    __CFGenericValidateType(allocator, __kCFAllocatorTypeID);
767#endif
768    CFAssert1(0 == context->version, __kCFLogAssertion, "%s(): context version not initialized to 0", __PRETTY_FUNCTION__);
769#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
770    if (allocator->_base._cfisa != __CFISAForTypeID(__kCFAllocatorTypeID)) {	// malloc_zone_t *
771	return;
772    }
773#endif
774    context->version = 0;
775    context->info = allocator->_context.info;
776    context->retain = __CFAllocatorGetRetainFunction(&allocator->_context);
777    context->release = __CFAllocatorGetReleaseFunction(&allocator->_context);
778    context->copyDescription = __CFAllocatorGetCopyDescriptionFunction(&allocator->_context);
779    context->allocate = __CFAllocatorGetAllocateFunction(&allocator->_context);
780    context->reallocate = __CFAllocatorGetReallocateFunction(&allocator->_context);
781    context->deallocate = __CFAllocatorGetDeallocateFunction(&allocator->_context);
782    context->preferredSize = __CFAllocatorGetPreferredSizeFunction(&allocator->_context);
783}
784
785CF_PRIVATE void *_CFAllocatorAllocateGC(CFAllocatorRef allocator, CFIndex size, CFOptionFlags hint)
786{
787    if (CF_IS_COLLECTABLE_ALLOCATOR(allocator))
788        return auto_zone_allocate_object((auto_zone_t*)kCFAllocatorSystemDefault->_context.info, size, CF_GET_GC_MEMORY_TYPE(hint), false, false);
789    else
790        return CFAllocatorAllocate(allocator, size, hint);
791}
792
793CF_PRIVATE void *_CFAllocatorReallocateGC(CFAllocatorRef allocator, void *ptr, CFIndex newsize, CFOptionFlags hint)
794{
795    if (CF_IS_COLLECTABLE_ALLOCATOR(allocator)) {
796	if (ptr && (newsize == 0)) {
797	    return NULL; // equivalent to _CFAllocatorDeallocateGC.
798	}
799	if (ptr == NULL) {
800	    return auto_zone_allocate_object((auto_zone_t*)kCFAllocatorSystemDefault->_context.info, newsize, CF_GET_GC_MEMORY_TYPE(hint), false, false); // eq. to _CFAllocator
801	}
802    }
803    // otherwise, auto_realloc() now preserves layout type and refCount.
804    return CFAllocatorReallocate(allocator, ptr, newsize, hint);
805}
806
807CF_PRIVATE void _CFAllocatorDeallocateGC(CFAllocatorRef allocator, void *ptr)
808{
809    // when running GC, don't deallocate.
810    if (!CF_IS_COLLECTABLE_ALLOCATOR(allocator)) CFAllocatorDeallocate(allocator, ptr);
811}
812
813// -------- -------- -------- -------- -------- -------- -------- --------
814
815
816CFRange __CFRangeMake(CFIndex loc, CFIndex len) {
817    CFRange range;
818    range.location = loc;
819    range.length = len;
820    return range;
821}
822
823
824struct __CFNull {
825    CFRuntimeBase _base;
826};
827
828static struct __CFNull __kCFNull = {
829    INIT_CFRUNTIME_BASE()
830};
831const CFNullRef kCFNull = &__kCFNull;
832
833static CFStringRef __CFNullCopyDescription(CFTypeRef cf) {
834    return CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("<CFNull %p [%p]>"), cf, CFGetAllocator(cf));
835}
836
837static CFStringRef __CFNullCopyFormattingDescription(CFTypeRef cf, CFDictionaryRef formatOptions) {
838    return (CFStringRef)CFRetain(CFSTR("null"));
839}
840
841static void __CFNullDeallocate(CFTypeRef cf) {
842    CFAssert(false, __kCFLogAssertion, "Deallocated CFNull!");
843}
844
845static CFTypeID __kCFNullTypeID = _kCFRuntimeNotATypeID;
846
847static const CFRuntimeClass __CFNullClass = {
848    0,
849    "CFNull",
850    NULL,      // init
851    NULL,      // copy
852    __CFNullDeallocate,
853    NULL,
854    NULL,
855    __CFNullCopyFormattingDescription,
856    __CFNullCopyDescription
857};
858
859CF_PRIVATE void __CFNullInitialize(void) {
860    __kCFNullTypeID = _CFRuntimeRegisterClass(&__CFNullClass);
861    _CFRuntimeSetInstanceTypeIDAndIsa(&__kCFNull, __kCFNullTypeID);
862}
863
864CFTypeID CFNullGetTypeID(void) {
865    return __kCFNullTypeID;
866}
867
868void CFCollection_non_gc_storage_error(void) { }
869
870
871void _CFRuntimeSetCFMPresent(void *addr) {
872}
873
874
875// void __HALT(void);
876
877/* Keep this assembly at the bottom of the source file! */
878
879
880extern void __HALT() {
881#if defined(__ppc__)
882    __asm__("trap");
883#elif defined(__i386__) || defined(__x86_64__)
884#if defined(_MSC_VER)
885    __asm int 3;
886#else
887    __asm__("int3");
888#endif
889#endif
890}
891
892
893