]> git.saurik.com Git - apple/cf.git/blob - CFBase.c
CF-1153.18.tar.gz
[apple/cf.git] / 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