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