/ 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