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