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/* CFRuntime.c 25 Copyright (c) 1999-2013, Apple Inc. All rights reserved. 26 Responsibility: Christopher Kane 27*/ 28 29#define ENABLE_ZOMBIES 1 30 31#include <CoreFoundation/CFRuntime.h> 32#include "CFInternal.h" 33#include "CFBasicHash.h" 34#include <string.h> 35#include <stdlib.h> 36#include <stdio.h> 37#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI 38#include <dlfcn.h> 39#include <mach-o/dyld.h> 40#include <mach/mach.h> 41#include <crt_externs.h> 42#include <unistd.h> 43#include <sys/stat.h> 44#include <CoreFoundation/CFStringDefaultEncoding.h> 45#endif 46#if DEPLOYMENT_TARGET_EMBEDDED 47// This isn't in the embedded runtime.h header 48OBJC_EXPORT void *objc_destructInstance(id obj); 49#endif 50 51 52 53#if DEPLOYMENT_TARGET_WINDOWS 54#include <Shellapi.h> 55#endif 56 57enum { 58// retain/release recording constants -- must match values 59// used by OA for now; probably will change in the future 60__kCFRetainEvent = 28, 61__kCFReleaseEvent = 29 62}; 63 64#if DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX 65#include <malloc.h> 66#else 67#include <malloc/malloc.h> 68#endif 69 70#define FAKE_INSTRUMENTS 0 71 72#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED 73CF_PRIVATE void __CFOAInitializeNSObject(void); // from NSObject.m 74 75bool __CFOASafe = false; 76 77void (*__CFObjectAllocRecordAllocationFunction)(int, void *, int64_t , uint64_t, const char *) = NULL; 78void (*__CFObjectAllocSetLastAllocEventNameFunction)(void *, const char *) = NULL; 79 80void __CFOAInitialize(void) { 81} 82 83void __CFRecordAllocationEvent(int eventnum, void *ptr, int64_t size, uint64_t data, const char *classname) { 84 if (!__CFOASafe || !__CFObjectAllocRecordAllocationFunction) return; 85 __CFObjectAllocRecordAllocationFunction(eventnum, ptr, size, data, classname); 86} 87 88void __CFSetLastAllocationEventName(void *ptr, const char *classname) { 89 if (!__CFOASafe || !__CFObjectAllocSetLastAllocEventNameFunction) return; 90 __CFObjectAllocSetLastAllocEventNameFunction(ptr, classname); 91} 92 93#elif FAKE_INSTRUMENTS 94 95CF_EXPORT bool __CFOASafe = true; 96 97void __CFOAInitialize(void) { } 98 99void __CFRecordAllocationEvent(int eventnum, void *ptr, int64_t size, uint64_t data, const char *classname) { 100 if (!__CFOASafe) return; 101 if (!classname) classname = "(no class)"; 102 const char *event = "unknown event"; 103 switch (eventnum) { 104 case 21: 105 event = "zombie"; 106 break; 107 case 13: 108 case __kCFReleaseEvent: 109 event = "release"; 110 break; 111 case 12: 112 case __kCFRetainEvent: 113 event = "retain"; 114 break; 115 } 116 fprintf(stdout, "event,%d,%s,%p,%ld,%lu,%s\n", eventnum, event, ptr, (long)size, (unsigned long)data, classname); 117} 118 119void __CFSetLastAllocationEventName(void *ptr, const char *classname) { 120 if (!__CFOASafe) return; 121 if (!classname) classname = "(no class)"; 122 fprintf(stdout, "name,%p,%s\n", ptr, classname ? classname : "(no class)"); 123} 124 125#else 126 127bool __CFOASafe = false; 128 129void __CFOAInitialize(void) { } 130void __CFRecordAllocationEvent(int eventnum, void *ptr, int64_t size, uint64_t data, const char *classname) { } 131void __CFSetLastAllocationEventName(void *ptr, const char *classname) { } 132 133#endif 134 135extern void __HALT(void); 136 137static CFTypeID __kCFNotATypeTypeID = _kCFRuntimeNotATypeID; 138 139#if !defined (__cplusplus) 140static const CFRuntimeClass __CFNotATypeClass = { 141 0, 142 "Not A Type", 143 (void *)__HALT, 144 (void *)__HALT, 145 (void *)__HALT, 146 (void *)__HALT, 147 (void *)__HALT, 148 (void *)__HALT, 149 (void *)__HALT 150}; 151 152static CFTypeID __kCFTypeTypeID = _kCFRuntimeNotATypeID; 153 154static const CFRuntimeClass __CFTypeClass = { 155 0, 156 "CFType", 157 (void *)__HALT, 158 (void *)__HALT, 159 (void *)__HALT, 160 (void *)__HALT, 161 (void *)__HALT, 162 (void *)__HALT, 163 (void *)__HALT 164}; 165#else 166void SIG1(CFTypeRef){__HALT();};; 167CFTypeRef SIG2(CFAllocatorRef,CFTypeRef){__HALT();return NULL;}; 168Boolean SIG3(CFTypeRef,CFTypeRef){__HALT();return FALSE;}; 169CFHashCode SIG4(CFTypeRef){__HALT(); return 0;}; 170CFStringRef SIG5(CFTypeRef,CFDictionaryRef){__HALT();return NULL;}; 171CFStringRef SIG6(CFTypeRef){__HALT();return NULL;}; 172 173static const CFRuntimeClass __CFNotATypeClass = { 174 0, 175 "Not A Type", 176 SIG1, 177 SIG2, 178 SIG1, 179 SIG3, 180 SIG4, 181 SIG5, 182 SIG6 183}; 184 185static CFTypeID __kCFTypeTypeID = _kCFRuntimeNotATypeID; 186 187static const CFRuntimeClass __CFTypeClass = { 188 0, 189 "CFType", 190 SIG1, 191 SIG2, 192 SIG1, 193 SIG3, 194 SIG4, 195 SIG5, 196 SIG6 197}; 198#endif //__cplusplus 199 200// the lock does not protect most reading of these; we just leak the old table to allow read-only accesses to continue to work 201static CFSpinLock_t __CFBigRuntimeFunnel = CFSpinLockInit; 202CF_PRIVATE CFRuntimeClass * __CFRuntimeClassTable[__CFRuntimeClassTableSize] = {0}; 203CF_PRIVATE int32_t __CFRuntimeClassTableCount = 0; 204 205CF_PRIVATE uintptr_t __CFRuntimeObjCClassTable[__CFRuntimeClassTableSize] = {0}; 206 207#if !defined(__CFObjCIsCollectable) 208bool (*__CFObjCIsCollectable)(void *) = NULL; 209#endif 210 211#if !__CONSTANT_CFSTRINGS__ || DEPLOYMENT_TARGET_EMBEDDED_MINI 212// Compiler uses this symbol name; must match compiler built-in decl, so we use 'int' 213#if __LP64__ 214int __CFConstantStringClassReference[24] = {0}; 215#else 216int __CFConstantStringClassReference[12] = {0}; 217#endif 218#endif 219 220#if __LP64__ 221int __CFConstantStringClassReference[24] = {0}; 222#else 223int __CFConstantStringClassReference[12] = {0}; 224#endif 225 226void *__CFConstantStringClassReferencePtr = NULL; 227 228Boolean _CFIsObjC(CFTypeID typeID, void *obj) { 229 return CF_IS_OBJC(typeID, obj); 230} 231 232CFTypeID _CFRuntimeRegisterClass(const CFRuntimeClass * const cls) { 233// className must be pure ASCII string, non-null 234 if ((cls->version & _kCFRuntimeCustomRefCount) && !cls->refcount) { 235 CFLog(kCFLogLevelWarning, CFSTR("*** _CFRuntimeRegisterClass() given inconsistent class '%s'. Program will crash soon."), cls->className); 236 return _kCFRuntimeNotATypeID; 237 } 238 __CFSpinLock(&__CFBigRuntimeFunnel); 239 if (__CFMaxRuntimeTypes <= __CFRuntimeClassTableCount) { 240 CFLog(kCFLogLevelWarning, CFSTR("*** CoreFoundation class table full; registration failing for class '%s'. Program will crash soon."), cls->className); 241 __CFSpinUnlock(&__CFBigRuntimeFunnel); 242 return _kCFRuntimeNotATypeID; 243 } 244 if (__CFRuntimeClassTableSize <= __CFRuntimeClassTableCount) { 245 CFLog(kCFLogLevelWarning, CFSTR("*** CoreFoundation class table full; registration failing for class '%s'. Program will crash soon."), cls->className); 246 __CFSpinUnlock(&__CFBigRuntimeFunnel); 247 return _kCFRuntimeNotATypeID; 248 } 249 __CFRuntimeClassTable[__CFRuntimeClassTableCount++] = (CFRuntimeClass *)cls; 250 CFTypeID typeID = __CFRuntimeClassTableCount - 1; 251 __CFSpinUnlock(&__CFBigRuntimeFunnel); 252 return typeID; 253} 254 255 256const CFRuntimeClass * _CFRuntimeGetClassWithTypeID(CFTypeID typeID) { 257 return __CFRuntimeClassTable[typeID]; // hopelessly unthreadsafe 258} 259 260void _CFRuntimeUnregisterClassWithTypeID(CFTypeID typeID) { 261 __CFSpinLock(&__CFBigRuntimeFunnel); 262 __CFRuntimeClassTable[typeID] = NULL; 263 __CFSpinUnlock(&__CFBigRuntimeFunnel); 264} 265 266 267#if defined(DEBUG) || defined(ENABLE_ZOMBIES) 268 269CF_PRIVATE uint8_t __CFZombieEnabled = 0; 270CF_PRIVATE uint8_t __CFDeallocateZombies = 0; 271 272extern void __CFZombifyNSObject(void); // from NSObject.m 273 274void _CFEnableZombies(void) { 275} 276 277#endif /* DEBUG */ 278 279// XXX_PCB: use the class version field as a bitmask, to allow classes to opt-in for GC scanning. 280 281#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED 282CF_INLINE CFOptionFlags CF_GET_COLLECTABLE_MEMORY_TYPE(const CFRuntimeClass *cls) 283{ 284 return ((cls->version & _kCFRuntimeScannedObject) ? __kCFAllocatorGCScannedMemory : 0) | __kCFAllocatorGCObjectMemory; 285} 286#else 287#define CF_GET_COLLECTABLE_MEMORY_TYPE(x) (0) 288#endif 289 290CFTypeRef _CFRuntimeCreateInstance(CFAllocatorRef allocator, CFTypeID typeID, CFIndex extraBytes, unsigned char *category) { 291 if (__CFRuntimeClassTableSize <= typeID) HALT; 292 CFAssert1(typeID != _kCFRuntimeNotATypeID, __kCFLogAssertion, "%s(): Uninitialized type id", __PRETTY_FUNCTION__); 293 CFRuntimeClass *cls = __CFRuntimeClassTable[typeID]; 294 if (NULL == cls) { 295 return NULL; 296 } 297 Boolean customRC = !!(cls->version & _kCFRuntimeCustomRefCount); 298 if (customRC && !cls->refcount) { 299 CFLog(kCFLogLevelWarning, CFSTR("*** _CFRuntimeCreateInstance() found inconsistent class '%s'."), cls->className); 300 return NULL; 301 } 302 if (customRC && kCFUseCollectableAllocator && (0 || 0)) { 303 CFLog(kCFLogLevelWarning, CFSTR("*** _CFRuntimeCreateInstance(): special zero-ref allocators cannot be used with class '%s' with custom ref counting."), cls->className); 304 return NULL; 305 } 306 CFAllocatorRef realAllocator = (NULL == allocator) ? __CFGetDefaultAllocator() : allocator; 307 if (kCFAllocatorNull == realAllocator) { 308 return NULL; 309 } 310 Boolean usesSystemDefaultAllocator = _CFAllocatorIsSystemDefault(realAllocator); 311 CFIndex size = sizeof(CFRuntimeBase) + extraBytes + (usesSystemDefaultAllocator ? 0 : sizeof(CFAllocatorRef)); 312 size = (size + 0xF) & ~0xF; // CF objects are multiples of 16 in size 313 // CFType version 0 objects are unscanned by default since they don't have write-barriers and hard retain their innards 314 // CFType version 1 objects are scanned and use hand coded write-barriers to store collectable storage within 315 CFRuntimeBase *memory = (CFRuntimeBase *)CFAllocatorAllocate(allocator, size, CF_GET_COLLECTABLE_MEMORY_TYPE(cls)); 316 if (NULL == memory) { 317 return NULL; 318 } 319 if (!kCFUseCollectableAllocator || !CF_IS_COLLECTABLE_ALLOCATOR(allocator) || !(CF_GET_COLLECTABLE_MEMORY_TYPE(cls) & __kCFAllocatorGCScannedMemory)) { 320 memset(memory, 0, size); 321 } 322 if (__CFOASafe && category) { 323 __CFSetLastAllocationEventName(memory, (char *)category); 324 } else if (__CFOASafe) { 325 __CFSetLastAllocationEventName(memory, (char *)cls->className); 326 } 327 if (!usesSystemDefaultAllocator) { 328 // add space to hold allocator ref for non-standard allocators. 329 // (this screws up 8 byte alignment but seems to work) 330 *(CFAllocatorRef *)((char *)memory) = (CFAllocatorRef)CFRetain(realAllocator); 331 memory = (CFRuntimeBase *)((char *)memory + sizeof(CFAllocatorRef)); 332 } 333 uint32_t rc = 0; 334#if __LP64__ 335 if (!kCFUseCollectableAllocator || (1 && 1)) { 336 memory->_rc = 1; 337 } 338 if (customRC) { 339 memory->_rc = 0xFFFFFFFFU; 340 rc = 0xFF; 341 } 342#else 343 if (!kCFUseCollectableAllocator || (1 && 1)) { 344 rc = 1; 345 } 346 if (customRC) { 347 rc = 0xFF; 348 } 349#endif 350 uint32_t *cfinfop = (uint32_t *)&(memory->_cfinfo); 351 *cfinfop = (uint32_t)((rc << 24) | (customRC ? 0x800000 : 0x0) | ((uint32_t)typeID << 8) | (usesSystemDefaultAllocator ? 0x80 : 0x00)); 352 memory->_cfisa = 0; 353 if (NULL != cls->init) { 354 (cls->init)(memory); 355 } 356 return memory; 357} 358 359void _CFRuntimeInitStaticInstance(void *ptr, CFTypeID typeID) { 360 CFAssert1(typeID != _kCFRuntimeNotATypeID, __kCFLogAssertion, "%s(): Uninitialized type id", __PRETTY_FUNCTION__); 361 if (__CFRuntimeClassTableSize <= typeID) HALT; 362 CFRuntimeClass *cfClass = __CFRuntimeClassTable[typeID]; 363 Boolean customRC = !!(cfClass->version & _kCFRuntimeCustomRefCount); 364 if (customRC) { 365 CFLog(kCFLogLevelError, CFSTR("*** Cannot initialize a static instance to a class (%s) with custom ref counting"), cfClass->className); 366 return; 367 } 368 CFRuntimeBase *memory = (CFRuntimeBase *)ptr; 369 uint32_t *cfinfop = (uint32_t *)&(memory->_cfinfo); 370 *cfinfop = (uint32_t)(((customRC ? 0xFF : 0) << 24) | (customRC ? 0x800000 : 0x0) | ((uint32_t)typeID << 8) | 0x80); 371#if __LP64__ 372 memory->_rc = customRC ? 0xFFFFFFFFU : 0x0; 373#endif 374 memory->_cfisa = 0; 375 if (NULL != cfClass->init) { 376 (cfClass->init)(memory); 377 } 378} 379 380void _CFRuntimeSetInstanceTypeID(CFTypeRef cf, CFTypeID newTypeID) { 381 if (__CFRuntimeClassTableSize <= newTypeID) HALT; 382 uint32_t *cfinfop = (uint32_t *)&(((CFRuntimeBase *)cf)->_cfinfo); 383 CFTypeID currTypeID = (*cfinfop >> 8) & 0x03FF; // mask up to 0x0FFF 384 CFRuntimeClass *newcfClass = __CFRuntimeClassTable[newTypeID]; 385 Boolean newCustomRC = (newcfClass->version & _kCFRuntimeCustomRefCount); 386 CFRuntimeClass *currcfClass = __CFRuntimeClassTable[currTypeID]; 387 Boolean currCustomRC = (currcfClass->version & _kCFRuntimeCustomRefCount); 388 if (currCustomRC || (0 != currTypeID && newCustomRC)) { 389 CFLog(kCFLogLevelError, CFSTR("*** Cannot change the CFTypeID of a %s to a %s due to custom ref counting"), currcfClass->className, newcfClass->className); 390 return; 391 } 392 // Going from current type ID of 0 to anything is allowed, but if 393 // the object has somehow already been retained and the transition 394 // is to a class doing custom ref counting, the ref count isn't 395 // transferred and there will probably be a crash later when the 396 // object is freed too early. 397 *cfinfop = (*cfinfop & 0xFFF000FFU) | ((uint32_t)newTypeID << 8); 398} 399 400CF_PRIVATE void _CFRuntimeSetInstanceTypeIDAndIsa(CFTypeRef cf, CFTypeID newTypeID) { 401 _CFRuntimeSetInstanceTypeID(cf, newTypeID); 402} 403 404 405enum { 406 __kCFObjectRetainedEvent = 12, 407 __kCFObjectReleasedEvent = 13 408}; 409 410#if DEPLOYMENT_TARGET_MACOSX 411#define NUM_EXTERN_TABLES 8 412#define EXTERN_TABLE_IDX(O) (((uintptr_t)(O) >> 8) & 0x7) 413#elif DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX 414#define NUM_EXTERN_TABLES 1 415#define EXTERN_TABLE_IDX(O) 0 416#else 417#error 418#endif 419 420// we disguise pointers so that programs like 'leaks' forget about these references 421#define DISGUISE(O) (~(uintptr_t)(O)) 422 423static struct { 424 CFSpinLock_t lock; 425 CFBasicHashRef table; 426 uint8_t padding[64 - sizeof(CFBasicHashRef) - sizeof(CFSpinLock_t)]; 427} __NSRetainCounters[NUM_EXTERN_TABLES]; 428 429CF_EXPORT uintptr_t __CFDoExternRefOperation(uintptr_t op, id obj) { 430 if (nil == obj) HALT; 431 uintptr_t idx = EXTERN_TABLE_IDX(obj); 432 uintptr_t disguised = DISGUISE(obj); 433 CFSpinLock_t *lock = &__NSRetainCounters[idx].lock; 434 CFBasicHashRef table = __NSRetainCounters[idx].table; 435 uintptr_t count; 436 switch (op) { 437 case 300: // increment 438 case 350: // increment, no event 439 __CFSpinLock(lock); 440 CFBasicHashAddValue(table, disguised, disguised); 441 __CFSpinUnlock(lock); 442 if (__CFOASafe && op != 350) __CFRecordAllocationEvent(__kCFObjectRetainedEvent, obj, 0, 0, NULL); 443 return (uintptr_t)obj; 444 case 400: // decrement 445 if (__CFOASafe) __CFRecordAllocationEvent(__kCFObjectReleasedEvent, obj, 0, 0, NULL); 446 case 450: // decrement, no event 447 __CFSpinLock(lock); 448 count = (uintptr_t)CFBasicHashRemoveValue(table, disguised); 449 __CFSpinUnlock(lock); 450 return 0 == count; 451 case 500: 452 __CFSpinLock(lock); 453 count = (uintptr_t)CFBasicHashGetCountOfKey(table, disguised); 454 __CFSpinUnlock(lock); 455 return count; 456 } 457 return 0; 458} 459 460CF_EXPORT CFTypeID CFNumberGetTypeID(void); 461 462CF_INLINE CFTypeID __CFGenericTypeID_inline(const void *cf) { 463 // yes, 10 bits masked off, though 12 bits are there for the type field; __CFRuntimeClassTableSize is 1024 464 uint32_t *cfinfop = (uint32_t *)&(((CFRuntimeBase *)cf)->_cfinfo); 465 CFTypeID typeID = (*cfinfop >> 8) & 0x03FF; // mask up to 0x0FFF 466 return typeID; 467} 468 469CFTypeID __CFGenericTypeID(const void *cf) { 470 return __CFGenericTypeID_inline(cf); 471} 472 473CFTypeID CFTypeGetTypeID(void) { 474 return __kCFTypeTypeID; 475} 476 477CF_PRIVATE void __CFGenericValidateType_(CFTypeRef cf, CFTypeID type, const char *func) { 478 if (cf && CF_IS_OBJC(type, cf)) return; 479 CFAssert2((cf != NULL) && (NULL != __CFRuntimeClassTable[__CFGenericTypeID_inline(cf)]) && (__kCFNotATypeTypeID != __CFGenericTypeID_inline(cf)) && (__kCFTypeTypeID != __CFGenericTypeID_inline(cf)), __kCFLogAssertion, "%s(): pointer %p is not a CF object", func, cf); \ 480 CFAssert3(__CFGenericTypeID_inline(cf) == type, __kCFLogAssertion, "%s(): pointer %p is not a %s", func, cf, __CFRuntimeClassTable[type]->className); \ 481} 482 483#define __CFGenericAssertIsCF(cf) \ 484 CFAssert2(cf != NULL && (NULL != __CFRuntimeClassTable[__CFGenericTypeID_inline(cf)]) && (__kCFNotATypeTypeID != __CFGenericTypeID_inline(cf)) && (__kCFTypeTypeID != __CFGenericTypeID_inline(cf)), __kCFLogAssertion, "%s(): pointer %p is not a CF object", __PRETTY_FUNCTION__, cf); 485 486 487#define CFTYPE_IS_OBJC(obj) (false) 488#define CFTYPE_OBJC_FUNCDISPATCH0(rettype, obj, sel) do {} while (0) 489#define CFTYPE_OBJC_FUNCDISPATCH1(rettype, obj, sel, a1) do {} while (0) 490 491 492CFTypeID CFGetTypeID(CFTypeRef cf) { 493#if defined(DEBUG) 494 if (NULL == cf) { CRSetCrashLogMessage("*** CFGetTypeID() called with NULL ***"); HALT; } 495#endif 496 CFTYPE_OBJC_FUNCDISPATCH0(CFTypeID, cf, _cfTypeID); 497 __CFGenericAssertIsCF(cf); 498 return __CFGenericTypeID_inline(cf); 499} 500 501CFStringRef CFCopyTypeIDDescription(CFTypeID type) { 502 CFAssert2((NULL != __CFRuntimeClassTable[type]) && __kCFNotATypeTypeID != type && __kCFTypeTypeID != type, __kCFLogAssertion, "%s(): type %d is not a CF type ID", __PRETTY_FUNCTION__, type); 503 return CFStringCreateWithCString(kCFAllocatorSystemDefault, __CFRuntimeClassTable[type]->className, kCFStringEncodingASCII); 504} 505 506// Bit 31 (highest bit) in second word of cf instance indicates external ref count 507 508static CFTypeRef _CFRetain(CFTypeRef cf, Boolean tryR); 509 510CFTypeRef CFRetain(CFTypeRef cf) { 511 if (NULL == cf) { CRSetCrashLogMessage("*** CFRetain() called with NULL ***"); HALT; } 512 if (cf) __CFGenericAssertIsCF(cf); 513 return _CFRetain(cf, false); 514} 515 516CFTypeRef CFAutorelease(CFTypeRef __attribute__((cf_consumed)) cf) { 517 if (NULL == cf) { CRSetCrashLogMessage("*** CFAutorelease() called with NULL ***"); HALT; } 518 return cf; 519} 520 521static void _CFRelease(CFTypeRef cf); 522 523void CFRelease(CFTypeRef cf) { 524 if (NULL == cf) { CRSetCrashLogMessage("*** CFRelease() called with NULL ***"); HALT; } 525#if 0 526 void **addrs[2] = {&&start, &&end}; 527 start:; 528 if (addrs[0] <= __builtin_return_address(0) && __builtin_return_address(0) <= addrs[1]) { 529 CFLog(3, CFSTR("*** WARNING: Recursion in CFRelease(%p) : %p '%s' : 0x%08lx 0x%08lx 0x%08lx 0x%08lx 0x%08lx 0x%08lx"), cf, object_getClass(cf), object_getClassName(cf), ((uintptr_t *)cf)[0], ((uintptr_t *)cf)[1], ((uintptr_t *)cf)[2], ((uintptr_t *)cf)[3], ((uintptr_t *)cf)[4], ((uintptr_t *)cf)[5]); 530 HALT; 531 } 532#endif 533 if (cf) __CFGenericAssertIsCF(cf); 534 _CFRelease(cf); 535#if 0 536 end:; 537#endif 538} 539 540 541CF_PRIVATE void __CFAllocatorDeallocate(CFTypeRef cf); 542 543CF_PRIVATE const void *__CFStringCollectionCopy(CFAllocatorRef allocator, const void *ptr) { 544 if (NULL == ptr) { CRSetCrashLogMessage("*** __CFStringCollectionCopy() called with NULL ***"); HALT; } 545 CFStringRef theString = (CFStringRef)ptr; 546 CFStringRef result = CFStringCreateCopy((allocator), theString); 547 if (CF_IS_COLLECTABLE_ALLOCATOR(allocator)) { 548 result = (CFStringRef)CFMakeCollectable(result); 549 } 550 return (const void *)result; 551} 552 553extern void CFCollection_non_gc_storage_error(void); 554 555CF_PRIVATE const void *__CFTypeCollectionRetain(CFAllocatorRef allocator, const void *ptr) { 556 if (NULL == ptr) { CRSetCrashLogMessage("*** __CFTypeCollectionRetain() called with NULL; likely a collection has been corrupted ***"); HALT; } 557 CFTypeRef cf = (CFTypeRef)ptr; 558 // only collections allocated in the GC zone can opt-out of reference counting. 559 if (CF_IS_COLLECTABLE_ALLOCATOR(allocator)) { 560 if (CFTYPE_IS_OBJC(cf)) return cf; // do nothing for OBJC objects. 561 if (auto_zone_is_valid_pointer(objc_collectableZone(), ptr)) { 562 CFRuntimeClass *cfClass = __CFRuntimeClassTable[__CFGenericTypeID_inline(cf)]; 563 if (cfClass->version & _kCFRuntimeResourcefulObject) { 564 // GC: If this a CF object in the GC heap that is marked resourceful, then 565 // it must be retained keep it alive in a CF collection. 566 CFRetain(cf); 567 } 568 else 569 ; // don't retain normal CF objects 570 return cf; 571 } else { 572 // support constant CFTypeRef objects. 573#if __LP64__ 574 uint32_t lowBits = ((CFRuntimeBase *)cf)->_rc; 575#else 576 uint32_t lowBits = ((CFRuntimeBase *)cf)->_cfinfo[CF_RC_BITS]; 577#endif 578 if (lowBits == 0) return cf; 579 // complain about non-GC objects in GC containers. 580 CFLog(kCFLogLevelWarning, CFSTR("storing a non-GC object %p in a GC collection, break on CFCollection_non_gc_storage_error to debug."), cf); 581 CFCollection_non_gc_storage_error(); 582 // XXX should halt, except Patrick is using this somewhere. 583 // HALT; 584 } 585 } 586 return CFRetain(cf); 587} 588 589 590CF_PRIVATE void __CFTypeCollectionRelease(CFAllocatorRef allocator, const void *ptr) { 591 if (NULL == ptr) { CRSetCrashLogMessage("*** __CFTypeCollectionRelease() called with NULL; likely a collection has been corrupted ***"); HALT; } 592 CFTypeRef cf = (CFTypeRef)ptr; 593 // only collections allocated in the GC zone can opt-out of reference counting. 594 if (CF_IS_COLLECTABLE_ALLOCATOR(allocator)) { 595 if (CFTYPE_IS_OBJC(cf)) return; // do nothing for OBJC objects. 596 if (auto_zone_is_valid_pointer(objc_collectableZone(), cf)) { 597#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED 598 // GC: If this a CF object in the GC heap that is marked uncollectable, then 599 // must balance the retain done in __CFTypeCollectionRetain(). 600 CFRuntimeClass *cfClass = __CFRuntimeClassTable[__CFGenericTypeID_inline(cf)]; 601 if (cfClass->version & _kCFRuntimeResourcefulObject) { 602 // reclaim is called by _CFRelease(), which must be called to keep the 603 // CF and GC retain counts in sync. 604 CFRelease(cf); 605 } else { 606 // avoid releasing normal CF objects. Like other collections, for example 607 } 608 return; 609#endif 610 } else { 611 // support constant CFTypeRef objects. 612#if __LP64__ 613 uint32_t lowBits = ((CFRuntimeBase *)cf)->_rc; 614#else 615 uint32_t lowBits = ((CFRuntimeBase *)cf)->_cfinfo[CF_RC_BITS]; 616#endif 617 if (lowBits == 0) return; 618 } 619 } 620 CFRelease(cf); 621} 622 623#if !__LP64__ 624static CFSpinLock_t __CFRuntimeExternRefCountTableLock = CFSpinLockInit; 625#endif 626 627static uint64_t __CFGetFullRetainCount(CFTypeRef cf) { 628 if (NULL == cf) { CRSetCrashLogMessage("*** __CFGetFullRetainCount() called with NULL ***"); HALT; } 629#if __LP64__ 630 uint32_t lowBits = ((CFRuntimeBase *)cf)->_rc; 631 if (0 == lowBits) { 632 return (uint64_t)0x0fffffffffffffffULL; 633 } 634 return lowBits; 635#else 636 uint32_t lowBits = ((CFRuntimeBase *)cf)->_cfinfo[CF_RC_BITS]; 637 if (0 == lowBits) { 638 return (uint64_t)0x0fffffffffffffffULL; 639 } 640 uint64_t highBits = 0; 641 if ((lowBits & 0x80) != 0) { 642 highBits = __CFDoExternRefOperation(500, (id)cf); 643 } 644 uint64_t compositeRC = (lowBits & 0x7f) + (highBits << 6); 645 return compositeRC; 646#endif 647} 648 649CFIndex CFGetRetainCount(CFTypeRef cf) { 650 if (NULL == cf) { CRSetCrashLogMessage("*** CFGetRetainCount() called with NULL ***"); HALT; } 651 uint32_t cfinfo = *(uint32_t *)&(((CFRuntimeBase *)cf)->_cfinfo); 652 if (cfinfo & 0x800000) { // custom ref counting for object 653 CFTypeID typeID = (cfinfo >> 8) & 0x03FF; // mask up to 0x0FFF 654 CFRuntimeClass *cfClass = __CFRuntimeClassTable[typeID]; 655 uint32_t (*refcount)(intptr_t, CFTypeRef) = cfClass->refcount; 656 if (!refcount || !(cfClass->version & _kCFRuntimeCustomRefCount) || (((CFRuntimeBase *)cf)->_cfinfo[CF_RC_BITS] != 0xFF)) { 657 HALT; // bogus object 658 } 659#if __LP64__ 660 if (((CFRuntimeBase *)cf)->_rc != 0xFFFFFFFFU) { 661 HALT; // bogus object 662 } 663#endif 664 uint32_t rc = refcount(0, cf); 665#if __LP64__ 666 return (CFIndex)rc; 667#else 668 return (rc < LONG_MAX) ? (CFIndex)rc : (CFIndex)LONG_MAX; 669#endif 670 } 671 uint64_t rc = __CFGetFullRetainCount(cf); 672 return (rc < (uint64_t)LONG_MAX) ? (CFIndex)rc : (CFIndex)LONG_MAX; 673} 674 675CFTypeRef CFMakeCollectable(CFTypeRef cf) { 676 if (NULL == cf) return NULL; 677 return cf; 678} 679 680CFTypeRef CFMakeUncollectable(CFTypeRef cf) { 681 if (NULL == cf) return NULL; 682 if (CF_IS_COLLECTABLE(cf)) { 683 CFRetain(cf); 684 } 685 return cf; 686} 687 688Boolean CFEqual(CFTypeRef cf1, CFTypeRef cf2) { 689 if (NULL == cf1) { CRSetCrashLogMessage("*** CFEqual() called with NULL first argument ***"); HALT; } 690 if (NULL == cf2) { CRSetCrashLogMessage("*** CFEqual() called with NULL second argument ***"); HALT; } 691 if (cf1 == cf2) return true; 692 CFTYPE_OBJC_FUNCDISPATCH1(Boolean, cf1, isEqual:, cf2); 693 CFTYPE_OBJC_FUNCDISPATCH1(Boolean, cf2, isEqual:, cf1); 694 __CFGenericAssertIsCF(cf1); 695 __CFGenericAssertIsCF(cf2); 696 if (__CFGenericTypeID_inline(cf1) != __CFGenericTypeID_inline(cf2)) return false; 697 if (NULL != __CFRuntimeClassTable[__CFGenericTypeID_inline(cf1)]->equal) { 698 return __CFRuntimeClassTable[__CFGenericTypeID_inline(cf1)]->equal(cf1, cf2); 699 } 700 return false; 701} 702 703CFHashCode CFHash(CFTypeRef cf) { 704 if (NULL == cf) { CRSetCrashLogMessage("*** CFHash() called with NULL ***"); HALT; } 705 CFTYPE_OBJC_FUNCDISPATCH0(CFHashCode, cf, hash); 706 __CFGenericAssertIsCF(cf); 707 CFHashCode (*hash)(CFTypeRef cf) = __CFRuntimeClassTable[__CFGenericTypeID_inline(cf)]->hash; 708 if (NULL != hash) { 709 return hash(cf); 710 } 711 if (CF_IS_COLLECTABLE(cf)) return (CFHashCode)_object_getExternalHash((id)cf); 712 return (CFHashCode)cf; 713} 714 715// definition: produces a normally non-NULL debugging description of the object 716CFStringRef CFCopyDescription(CFTypeRef cf) { 717 if (NULL == cf) return NULL; 718 // CFTYPE_OBJC_FUNCDISPATCH0(CFStringRef, cf, _copyDescription); // XXX returns 0 refcounted item under GC 719 __CFGenericAssertIsCF(cf); 720 if (NULL != __CFRuntimeClassTable[__CFGenericTypeID_inline(cf)]->copyDebugDesc) { 721 CFStringRef result = __CFRuntimeClassTable[__CFGenericTypeID_inline(cf)]->copyDebugDesc(cf); 722 if (NULL != result) return result; 723 } 724 return CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("<%s %p [%p]>"), __CFRuntimeClassTable[__CFGenericTypeID_inline(cf)]->className, cf, CFGetAllocator(cf)); 725} 726 727// Definition: if type produces a formatting description, return that string, otherwise NULL 728CF_PRIVATE CFStringRef __CFCopyFormattingDescription(CFTypeRef cf, CFDictionaryRef formatOptions) { 729 if (NULL == cf) return NULL; 730 __CFGenericAssertIsCF(cf); 731 if (NULL != __CFRuntimeClassTable[__CFGenericTypeID_inline(cf)]->copyFormattingDesc) { 732 return __CFRuntimeClassTable[__CFGenericTypeID_inline(cf)]->copyFormattingDesc(cf, formatOptions); 733 } 734 return NULL; 735} 736 737extern CFAllocatorRef __CFAllocatorGetAllocator(CFTypeRef); 738 739CFAllocatorRef CFGetAllocator(CFTypeRef cf) { 740 if (NULL == cf) return kCFAllocatorSystemDefault; 741 if (__kCFAllocatorTypeID_CONST == __CFGenericTypeID_inline(cf)) { 742 return __CFAllocatorGetAllocator(cf); 743 } 744 return __CFGetAllocator(cf); 745} 746 747extern void __CFNullInitialize(void); 748extern void __CFAllocatorInitialize(void); 749extern void __CFStringInitialize(void); 750extern void __CFArrayInitialize(void); 751extern void __CFBooleanInitialize(void); 752extern void __CFCharacterSetInitialize(void); 753extern void __CFDataInitialize(void); 754extern void __CFNumberInitialize(void); 755extern void __CFStorageInitialize(void); 756extern void __CFErrorInitialize(void); 757extern void __CFTreeInitialize(void); 758extern void __CFURLInitialize(void); 759#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI 760extern void __CFMachPortInitialize(void); 761#endif 762extern void __CFMessagePortInitialize(void); 763extern void __CFRunLoopInitialize(void); 764extern void __CFRunLoopObserverInitialize(void); 765extern void __CFRunLoopSourceInitialize(void); 766extern void __CFRunLoopTimerInitialize(void); 767extern void __CFPFactoryInitialize(void); 768extern void __CFBundleInitialize(void); 769extern void __CFPlugInInitialize(void); 770extern void __CFPlugInInstanceInitialize(void); 771extern void __CFUUIDInitialize(void); 772extern void __CFBinaryHeapInitialize(void); 773extern void __CFBitVectorInitialize(void); 774CF_PRIVATE void __CFDateInitialize(void); 775#if DEPLOYMENT_TARGET_LINUX 776CF_PRIVATE void __CFTSDLinuxInitialize(); 777#endif 778#if DEPLOYMENT_TARGET_WINDOWS 779// From CFPlatform.c 780CF_PRIVATE void __CFTSDWindowsInitialize(void); 781CF_PRIVATE void __CFTSDWindowsCleanup(void); 782CF_PRIVATE void __CFFinalizeWindowsThreadData(); 783#endif 784extern void __CFStreamInitialize(void); 785extern void __CFCalendarInitialize(); 786extern void __CFTimeZoneInitialize(); 787#if DEPLOYMENT_TARGET_LINUX 788extern void __CFCalendarInitialize(); 789extern void __CFTimeZoneInitialize(); 790#endif 791#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS 792extern void __CFXPreferencesInitialize(void); 793#endif 794 795#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI 796CF_PRIVATE uint8_t __CF120290 = false; 797CF_PRIVATE uint8_t __CF120291 = false; 798CF_PRIVATE uint8_t __CF120293 = false; 799CF_PRIVATE char * __crashreporter_info__ = NULL; // Keep this symbol, since it was exported and other things may be linking against it, like GraphicsServices.framework on iOS 800asm(".desc ___crashreporter_info__, 0x10"); 801 802static void __01121__(void) { 803 __CF120291 = pthread_is_threaded_np() ? true : false; 804} 805 806static void __01123__(void) { 807 // Ideally, child-side atfork handlers should be async-cancel-safe, as fork() 808 // is async-cancel-safe and can be called from signal handlers. See also 809 // http://standards.ieee.org/reading/ieee/interp/1003-1c-95_int/pasc-1003.1c-37.html 810 // This is not a problem for CF. 811 if (__CF120290) { 812 __CF120293 = true; 813#if DEPLOYMENT_TARGET_MACOSX 814 if (__CF120291) { 815 CRSetCrashLogMessage2("*** multi-threaded process forked ***"); 816 } else { 817 CRSetCrashLogMessage2("*** single-threaded process forked ***"); 818 } 819#endif 820 } 821} 822 823#define EXEC_WARNING_STRING_1 "The process has forked and you cannot use this CoreFoundation functionality safely. You MUST exec().\n" 824#define EXEC_WARNING_STRING_2 "Break on __THE_PROCESS_HAS_FORKED_AND_YOU_CANNOT_USE_THIS_COREFOUNDATION_FUNCTIONALITY___YOU_MUST_EXEC__() to debug.\n" 825 826CF_PRIVATE void __THE_PROCESS_HAS_FORKED_AND_YOU_CANNOT_USE_THIS_COREFOUNDATION_FUNCTIONALITY___YOU_MUST_EXEC__(void) { 827 write(2, EXEC_WARNING_STRING_1, sizeof(EXEC_WARNING_STRING_1) - 1); 828 write(2, EXEC_WARNING_STRING_2, sizeof(EXEC_WARNING_STRING_2) - 1); 829// HALT; 830} 831#endif 832 833 834CF_EXPORT const void *__CFArgStuff; 835const void *__CFArgStuff = NULL; 836CF_PRIVATE void *__CFAppleLanguages = NULL; 837 838// do not cache CFFIXED_USER_HOME or HOME, there are situations where they can change 839 840static struct { 841 const char *name; 842 const char *value; 843} __CFEnv[] = { 844 {"PATH", NULL}, 845 {"USER", NULL}, 846 {"HOMEPATH", NULL}, 847 {"HOMEDRIVE", NULL}, 848 {"USERNAME", NULL}, 849 {"TZFILE", NULL}, 850 {"TZ", NULL}, 851 {"NEXT_ROOT", NULL}, 852 {"DYLD_IMAGE_SUFFIX", NULL}, 853 {"CFProcessPath", NULL}, 854 {"CFNETWORK_LIBRARY_PATH", NULL}, 855 {"CFUUIDVersionNumber", NULL}, 856 {"CFDebugNamedDataSharing", NULL}, 857 {"CFPropertyListAllowImmutableCollections", NULL}, 858 {"CFBundleUseDYLD", NULL}, 859 {"CFBundleDisableStringsSharing", NULL}, 860 {"CFCharacterSetCheckForExpandedSet", NULL}, 861 {"__CF_DEBUG_EXPANDED_SET", NULL}, 862 {"CFStringDisableROM", NULL}, 863 {"CF_CHARSET_PATH", NULL}, 864 {"__CF_USER_TEXT_ENCODING", NULL}, 865 {"__CFPREFERENCES_AUTOSYNC_INTERVAL", NULL}, 866 {"__CFPREFERENCES_LOG_FAILURES", NULL}, 867 {"CFNumberDisableCache", NULL}, 868 {"__CFPREFERENCES_AVOID_DAEMON", NULL}, 869 {"APPLE_FRAMEWORKS_ROOT", NULL}, 870 {NULL, NULL}, // the last one is for optional "COMMAND_MODE" "legacy", do not use this slot, insert before 871}; 872 873CF_PRIVATE const char *__CFgetenv(const char *n) { 874 for (CFIndex idx = 0; idx < sizeof(__CFEnv) / sizeof(__CFEnv[0]); idx++) { 875 if (__CFEnv[idx].name && 0 == strcmp(n, __CFEnv[idx].name)) return __CFEnv[idx].value; 876 } 877 return getenv(n); 878} 879 880CF_PRIVATE Boolean __CFProcessIsRestricted() { 881 return issetugid(); 882} 883 884#if DEPLOYMENT_TARGET_WINDOWS 885#define kNilPthreadT { nil, nil } 886#else 887#define kNilPthreadT (pthread_t)0 888#endif 889 890 891#undef kCFUseCollectableAllocator 892CF_EXPORT bool kCFUseCollectableAllocator; 893bool kCFUseCollectableAllocator = false; 894 895CF_PRIVATE Boolean __CFProphylacticAutofsAccess = false; 896CF_PRIVATE Boolean __CFInitializing = 0; 897CF_PRIVATE Boolean __CFInitialized = 0; 898 899// move the next 2 lines down into the #if below, and make it static, after Foundation gets off this symbol on other platforms 900CF_EXPORT pthread_t _CFMainPThread; 901pthread_t _CFMainPThread = kNilPthreadT; 902#if DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_IPHONESIMULATOR 903 904CF_EXPORT pthread_t _CF_pthread_main_thread_np(void); 905pthread_t _CF_pthread_main_thread_np(void) { 906 return _CFMainPThread; 907} 908#define pthread_main_thread_np() _CF_pthread_main_thread_np() 909 910#endif 911 912#if DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD 913static void __CFInitialize(void) __attribute__ ((constructor)); 914static 915#endif 916#if DEPLOYMENT_TARGET_WINDOWS 917CF_EXPORT 918#endif 919void __CFInitialize(void) { 920 921 if (!__CFInitialized && !__CFInitializing) { 922 __CFInitializing = 1; 923 924#if DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_IPHONESIMULATOR 925 if (!pthread_main_np()) HALT; // CoreFoundation must be initialized on the main thread 926#endif 927 // move this next line up into the #if above after Foundation gets off this symbol 928 _CFMainPThread = pthread_self(); 929 930#if DEPLOYMENT_TARGET_WINDOWS 931 // Must not call any CF functions 932 __CFTSDWindowsInitialize(); 933#elif DEPLOYMENT_TARGET_LINUX 934 __CFTSDLinuxInitialize(); 935#endif 936 937 __CFProphylacticAutofsAccess = true; 938 939 for (CFIndex idx = 0; idx < sizeof(__CFEnv) / sizeof(__CFEnv[0]); idx++) { 940 __CFEnv[idx].value = __CFEnv[idx].name ? getenv(__CFEnv[idx].name) : NULL; 941 } 942 943#if !defined(kCFUseCollectableAllocator) 944 kCFUseCollectableAllocator = objc_collectingEnabled(); 945#endif 946 if (kCFUseCollectableAllocator) { 947#if !defined(__CFObjCIsCollectable) 948 __CFObjCIsCollectable = (bool (*)(void *))objc_isAuto; 949#endif 950 } 951#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI 952 UInt32 s, r; 953 __CFStringGetUserDefaultEncoding(&s, &r); // force the potential setenv to occur early 954 pthread_atfork(__01121__, NULL, __01123__); 955#endif 956 957 958 memset(__CFRuntimeClassTable, 0, sizeof(__CFRuntimeClassTable)); 959 memset(__CFRuntimeObjCClassTable, 0, sizeof(__CFRuntimeObjCClassTable)); 960 961 962 /* Here so that two runtime classes get indices 0, 1. */ 963 __kCFNotATypeTypeID = _CFRuntimeRegisterClass(&__CFNotATypeClass); 964 __kCFTypeTypeID = _CFRuntimeRegisterClass(&__CFTypeClass); 965 966 /* Here so that __kCFAllocatorTypeID gets index 2. */ 967 __CFAllocatorInitialize(); 968 969#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED 970 { 971 CFIndex idx, cnt; 972 char **args = *_NSGetArgv(); 973 cnt = *_NSGetArgc(); 974 for (idx = 1; idx < cnt - 1; idx++) { 975 if (NULL == args[idx]) continue; 976 if (0 == strcmp(args[idx], "-AppleLanguages") && args[idx + 1]) { 977 CFIndex length = strlen(args[idx + 1]); 978 __CFAppleLanguages = malloc(length + 1); 979 memmove(__CFAppleLanguages, args[idx + 1], length + 1); 980 break; 981 } 982 } 983 } 984#endif 985 986 987 CFBasicHashGetTypeID(); 988 CFBagGetTypeID(); 989 990 for (CFIndex idx = 0; idx < NUM_EXTERN_TABLES; idx++) { 991 CFBasicHashCallbacks callbacks = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}; 992 __NSRetainCounters[idx].table = CFBasicHashCreate(kCFAllocatorSystemDefault, kCFBasicHashHasCounts | kCFBasicHashLinearHashing | kCFBasicHashAggressiveGrowth, &callbacks); 993 CFBasicHashSetCapacity(__NSRetainCounters[idx].table, 40); 994 __NSRetainCounters[idx].lock = CFSpinLockInit; 995 } 996 997 /*** _CFRuntimeCreateInstance() can finally be called generally after this line. ***/ 998 999 __CFRuntimeClassTableCount = 7; 1000 __CFStringInitialize(); // CFString's TypeID must be 0x7, now and forever 1001 1002 __CFRuntimeClassTableCount = 16; 1003 __CFNullInitialize(); // See above for hard-coding of this position 1004 CFSetGetTypeID(); // See above for hard-coding of this position 1005 CFDictionaryGetTypeID(); // See above for hard-coding of this position 1006 __CFArrayInitialize(); // See above for hard-coding of this position 1007 __CFDataInitialize(); // See above for hard-coding of this position 1008 __CFBooleanInitialize(); // See above for hard-coding of this position 1009 __CFNumberInitialize(); // See above for hard-coding of this position 1010 1011 __CFBinaryHeapInitialize(); 1012 __CFBitVectorInitialize(); 1013 __CFCharacterSetInitialize(); 1014 __CFStorageInitialize(); 1015 __CFErrorInitialize(); 1016 __CFTreeInitialize(); 1017 __CFURLInitialize(); 1018 1019#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS 1020 __CFBundleInitialize(); 1021 __CFPFactoryInitialize(); 1022#endif 1023#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED 1024 __CFPlugInInitialize(); 1025 __CFPlugInInstanceInitialize(); 1026#endif 1027 __CFUUIDInitialize(); 1028#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI || DEPLOYMENT_TARGET_WINDOWS 1029 __CFMessagePortInitialize(); 1030#endif 1031#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI 1032 __CFMachPortInitialize(); 1033#endif 1034#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS 1035 __CFStreamInitialize(); 1036#endif 1037#if DEPLOYMENT_TARGET_WINDOWS 1038 __CFWindowsNamedPipeInitialize(); 1039#endif 1040 1041 __CFDateInitialize(); 1042 1043#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI || DEPLOYMENT_TARGET_WINDOWS 1044 __CFRunLoopInitialize(); 1045 __CFRunLoopObserverInitialize(); 1046 __CFRunLoopSourceInitialize(); 1047 __CFRunLoopTimerInitialize(); 1048#endif 1049#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX 1050 __CFTimeZoneInitialize(); 1051 __CFCalendarInitialize(); 1052#if DEPLOYMENT_TARGET_LINUX 1053 __CFTimeZoneInitialize(); 1054 __CFCalendarInitialize(); 1055#endif 1056#endif 1057 1058 { 1059 CFIndex idx, cnt = 0; 1060 char **args = NULL; 1061#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI 1062 args = *_NSGetArgv(); 1063 cnt = *_NSGetArgc(); 1064#elif DEPLOYMENT_TARGET_WINDOWS 1065 wchar_t *commandLine = GetCommandLineW(); 1066 // result is actually pointer to wchar_t *, make sure to account for that below 1067 args = (char **)CommandLineToArgvW(commandLine, (int *)&cnt); 1068#endif 1069 CFIndex count; 1070 CFStringRef *list, buffer[256]; 1071 list = (cnt <= 256) ? buffer : (CFStringRef *)malloc(cnt * sizeof(CFStringRef)); 1072 for (idx = 0, count = 0; idx < cnt; idx++) { 1073 if (NULL == args[idx]) continue; 1074#if DEPLOYMENT_TARGET_WINDOWS 1075 list[count] = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, (const UniChar *)args[idx], wcslen((wchar_t *)args[idx])); 1076#else 1077 list[count] = CFStringCreateWithCString(kCFAllocatorSystemDefault, args[idx], kCFStringEncodingUTF8); 1078 if (NULL == list[count]) { 1079 list[count] = CFStringCreateWithCString(kCFAllocatorSystemDefault, args[idx], kCFStringEncodingISOLatin1); 1080 // We CANNOT use the string SystemEncoding here; 1081 // Do not argue: it is not initialized yet, but these 1082 // arguments MUST be initialized before it is. 1083 // We should just ignore the argument if the UTF-8 1084 // conversion fails, but out of charity we try once 1085 // more with ISO Latin1, a standard unix encoding. 1086 } 1087#endif 1088 if (NULL != list[count]) count++; 1089 } 1090 __CFArgStuff = CFArrayCreate(kCFAllocatorSystemDefault, (const void **)list, count, &kCFTypeArrayCallBacks); 1091 if (list != buffer) free(list); 1092#if DEPLOYMENT_TARGET_WINDOWS 1093 LocalFree(args); 1094#endif 1095 } 1096 1097 _CFProcessPath(); // cache this early 1098 1099 __CFOAInitialize(); 1100 1101 1102 if (__CFRuntimeClassTableCount < 256) __CFRuntimeClassTableCount = 256; 1103 1104 1105#if defined(DEBUG) || defined(ENABLE_ZOMBIES) 1106 const char *value = __CFgetenv("NSZombieEnabled"); 1107 if (value && (*value == 'Y' || *value == 'y')) _CFEnableZombies(); 1108 value = __CFgetenv("NSDeallocateZombies"); 1109 if (value && (*value == 'Y' || *value == 'y')) __CFDeallocateZombies = 0xff; 1110#endif 1111 1112#if defined(DEBUG) && (DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED) 1113 CFLog(kCFLogLevelWarning, CFSTR("Assertions enabled")); 1114#endif 1115 1116 __CFProphylacticAutofsAccess = false; 1117 __CFInitializing = 0; 1118 __CFInitialized = 1; 1119 } 1120} 1121 1122 1123#if DEPLOYMENT_TARGET_WINDOWS 1124 1125CF_PRIVATE void __CFStringCleanup(void); 1126CF_PRIVATE void __CFSocketCleanup(void); 1127CF_PRIVATE void __CFUniCharCleanup(void); 1128CF_PRIVATE void __CFStreamCleanup(void); 1129 1130static CFBundleRef RegisterCoreFoundationBundle(void) { 1131#ifdef _DEBUG 1132 // might be nice to get this from the project file at some point 1133 wchar_t *DLLFileName = (wchar_t *)L"CoreFoundation_debug.dll"; 1134#else 1135 wchar_t *DLLFileName = (wchar_t *)L"CoreFoundation.dll"; 1136#endif 1137 wchar_t path[MAX_PATH+1]; 1138 path[0] = path[1] = 0; 1139 DWORD wResult; 1140 CFIndex idx; 1141 HMODULE ourModule = GetModuleHandleW(DLLFileName); 1142 1143 CFAssert(ourModule, __kCFLogAssertion, "GetModuleHandle failed"); 1144 1145 wResult = GetModuleFileNameW(ourModule, path, MAX_PATH+1); 1146 CFAssert1(wResult > 0, __kCFLogAssertion, "GetModuleFileName failed: %d", GetLastError()); 1147 CFAssert1(wResult < MAX_PATH+1, __kCFLogAssertion, "GetModuleFileName result truncated: %s", path); 1148 1149 // strip off last component, the DLL name 1150 for (idx = wResult - 1; idx; idx--) { 1151 if ('\\' == path[idx]) { 1152 path[idx] = '\0'; 1153 break; 1154 } 1155 } 1156 1157 CFStringRef fsPath = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, (UniChar*)path, idx); 1158 CFURLRef dllURL = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, fsPath, kCFURLWindowsPathStyle, TRUE); 1159 CFURLRef bundleURL = CFURLCreateCopyAppendingPathComponent(kCFAllocatorSystemDefault, dllURL, CFSTR("CoreFoundation.resources"), TRUE); 1160 CFRelease(fsPath); 1161 CFRelease(dllURL); 1162 1163 // this registers us so subsequent calls to CFBundleGetBundleWithIdentifier will succeed 1164 CFBundleRef bundle = CFBundleCreate(kCFAllocatorSystemDefault, bundleURL); 1165 CFRelease(bundleURL); 1166 1167 return bundle; 1168} 1169 1170 1171#define DLL_PROCESS_ATTACH 1 1172#define DLL_THREAD_ATTACH 2 1173#define DLL_THREAD_DETACH 3 1174#define DLL_PROCESS_DETACH 0 1175 1176int DllMain( HINSTANCE hInstance, DWORD dwReason, LPVOID pReserved ) { 1177 static CFBundleRef cfBundle = NULL; 1178 if (dwReason == DLL_PROCESS_ATTACH) { 1179 __CFInitialize(); 1180 cfBundle = RegisterCoreFoundationBundle(); 1181 } else if (dwReason == DLL_PROCESS_DETACH && pReserved == 0) { 1182 // Only cleanup if we are being unloaded dynamically (pReserved == 0) <rdar://problem/7480873> 1183 __CFStreamCleanup(); 1184 __CFSocketCleanup(); 1185 __CFUniCharCleanup(); 1186 1187#if DEPLOYMENT_TARGET_WINDOWS 1188 // No CF functions should access TSD after this is called 1189 __CFTSDWindowsCleanup(); 1190#endif 1191 1192 // do these last 1193 if (cfBundle) CFRelease(cfBundle); 1194 __CFStringCleanup(); 1195 } else if (dwReason == DLL_THREAD_DETACH) { 1196 __CFFinalizeWindowsThreadData(); 1197 } 1198 return TRUE; 1199} 1200 1201#endif 1202 1203#if __CF_BIG_ENDIAN__ 1204#define RC_INCREMENT (1ULL) 1205#define RC_MASK (0xFFFFFFFFULL) 1206#define RC_GET(V) ((V) & RC_MASK) 1207#define RC_DEALLOCATING_BIT (0x400000ULL << 32) 1208#else 1209#define RC_INCREMENT (1ULL << 32) 1210#define RC_MASK (0xFFFFFFFFULL << 32) 1211#define RC_GET(V) (((V) & RC_MASK) >> 32) 1212#define RC_DEALLOCATING_BIT (0x400000ULL) 1213#endif 1214 1215#if !DEPLOYMENT_TARGET_WINDOWS && __LP64__ 1216static bool (*CAS64)(int64_t, int64_t, volatile int64_t *) = OSAtomicCompareAndSwap64Barrier; 1217#else 1218static bool (*CAS32)(int32_t, int32_t, volatile int32_t *) = OSAtomicCompareAndSwap32Barrier; 1219#endif 1220 1221// For "tryR==true", a return of NULL means "failed". 1222static CFTypeRef _CFRetain(CFTypeRef cf, Boolean tryR) { 1223 uint32_t cfinfo = *(uint32_t *)&(((CFRuntimeBase *)cf)->_cfinfo); 1224 if (cfinfo & 0x800000) { // custom ref counting for object 1225 if (tryR) return NULL; 1226 CFTypeID typeID = (cfinfo >> 8) & 0x03FF; // mask up to 0x0FFF 1227 CFRuntimeClass *cfClass = __CFRuntimeClassTable[typeID]; 1228 uint32_t (*refcount)(intptr_t, CFTypeRef) = cfClass->refcount; 1229 if (!refcount || !(cfClass->version & _kCFRuntimeCustomRefCount) || (((CFRuntimeBase *)cf)->_cfinfo[CF_RC_BITS] != 0xFF)) { 1230 HALT; // bogus object 1231 } 1232#if __LP64__ 1233 if (((CFRuntimeBase *)cf)->_rc != 0xFFFFFFFFU) { 1234 HALT; // bogus object 1235 } 1236#endif 1237 refcount(+1, cf); 1238 return cf; 1239 } 1240 1241 Boolean didAuto = false; 1242#if __LP64__ 1243 if (0 == ((CFRuntimeBase *)cf)->_rc && !CF_IS_COLLECTABLE(cf)) return cf; // Constant CFTypeRef 1244#if !DEPLOYMENT_TARGET_WINDOWS 1245 uint64_t allBits; 1246 do { 1247 allBits = *(uint64_t *)&(((CFRuntimeBase *)cf)->_cfinfo); 1248 if (tryR && (allBits & RC_DEALLOCATING_BIT)) return NULL; 1249 } while (!CAS64(allBits, allBits + RC_INCREMENT, (int64_t *)&((CFRuntimeBase *)cf)->_cfinfo)); 1250 // GC: 0 --> 1 transition? then add a GC retain count, to root the object. we'll remove it on the 1 --> 0 transition. 1251 if (RC_GET(allBits) == 0 && CF_IS_COLLECTABLE(cf)) { 1252 auto_zone_retain(objc_collectableZone(), (void*)cf); 1253 didAuto = true; 1254 } 1255#else 1256 uint32_t lowBits; 1257 do { 1258 lowBits = ((CFRuntimeBase *)cf)->_rc; 1259 } while (!CAS32(lowBits, lowBits + 1, (int32_t *)&((CFRuntimeBase *)cf)->_rc)); 1260 // GC: 0 --> 1 transition? then add a GC retain count, to root the object. we'll remove it on the 1 --> 0 transition. 1261 if (lowBits == 0 && CF_IS_COLLECTABLE(cf)) { 1262 auto_zone_retain(objc_collectableZone(), (void*)cf); 1263 didAuto = true; 1264 } 1265#endif 1266#else 1267#define RC_START 24 1268#define RC_END 31 1269 volatile uint32_t *infoLocation = (uint32_t *)&(((CFRuntimeBase *)cf)->_cfinfo); 1270 CFIndex rcLowBits = __CFBitfieldGetValue(cfinfo, RC_END, RC_START); 1271 if (__builtin_expect(0 == rcLowBits, 0) && !CF_IS_COLLECTABLE(cf)) return cf; // Constant CFTypeRef 1272 bool success = 0; 1273 do { 1274 cfinfo = *infoLocation; 1275#if !DEPLOYMENT_TARGET_WINDOWS 1276 // if already deallocating, don't allow new retain 1277 if (tryR && (cfinfo & 0x400000)) return NULL; 1278#endif 1279 uint32_t prospectiveNewInfo = cfinfo; // don't want compiler to generate prospectiveNewInfo = *infoLocation. This is why infoLocation is declared as a pointer to volatile memory. 1280 prospectiveNewInfo += (1 << RC_START); 1281 rcLowBits = __CFBitfieldGetValue(prospectiveNewInfo, RC_END, RC_START); 1282 if (__builtin_expect((rcLowBits & 0x7f) == 0, 0)) { 1283 /* Roll over another bit to the external ref count 1284 Real ref count = low 7 bits of info[CF_RC_BITS] + external ref count << 6 1285 Bit 8 of low bits indicates that external ref count is in use. 1286 External ref count is shifted by 6 rather than 7 so that we can set the low 1287 bits to to 1100 0000 rather than 1000 0000. 1288 This prevents needing to access the external ref count for successive retains and releases 1289 when the composite retain count is right around a multiple of 1 << 7. 1290 */ 1291 prospectiveNewInfo = cfinfo; 1292 __CFBitfieldSetValue(prospectiveNewInfo, RC_END, RC_START, ((1 << 7) | (1 << 6))); 1293 __CFSpinLock(&__CFRuntimeExternRefCountTableLock); 1294 success = CAS32(*(int32_t *)& cfinfo, *(int32_t *)&prospectiveNewInfo, (int32_t *)infoLocation); 1295 if (__builtin_expect(success, 1)) { 1296 __CFDoExternRefOperation(350, (id)cf); 1297 } 1298 __CFSpinUnlock(&__CFRuntimeExternRefCountTableLock); 1299 } else { 1300 success = CAS32(*(int32_t *)& cfinfo, *(int32_t *)&prospectiveNewInfo, (int32_t *)infoLocation); 1301 // XXX_PCB: 0 --> 1 transition? then add a GC retain count, to root the object. we'll remove it on the 1 --> 0 transition. 1302 if (success && __CFBitfieldGetValue(cfinfo, RC_END, RC_START) == 0 && CF_IS_COLLECTABLE(cf)) { 1303 auto_zone_retain(objc_collectableZone(), (void*)cf); 1304 didAuto = true; 1305 } 1306 } 1307 } while (__builtin_expect(!success, 0)); 1308#endif 1309 if (!didAuto && __builtin_expect(__CFOASafe, 0)) { 1310 __CFRecordAllocationEvent(__kCFRetainEvent, (void *)cf, 0, CFGetRetainCount(cf), NULL); 1311 } 1312 return cf; 1313} 1314 1315// Never called under GC, only called via ARR weak subsystem; a return of NULL is failure 1316CFTypeRef _CFTryRetain(CFTypeRef cf) { 1317 if (NULL == cf) return NULL; 1318#if OBJC_HAVE_TAGGED_POINTERS 1319 if (_objc_isTaggedPointer(cf)) return cf; // success 1320#endif 1321 return _CFRetain(cf, true); 1322} 1323 1324Boolean _CFIsDeallocating(CFTypeRef cf) { 1325 if (NULL == cf) return false; 1326#if OBJC_HAVE_TAGGED_POINTERS 1327 if (_objc_isTaggedPointer(cf)) return false; 1328#endif 1329 uint32_t cfinfo = *(uint32_t *)&(((CFRuntimeBase *)cf)->_cfinfo); 1330 if (cfinfo & 0x800000) { // custom ref counting for object 1331 return true; // lie for now; this weak references to these objects cannot be formed 1332 } 1333 return (cfinfo & 0x400000) ? true : false; 1334} 1335 1336static void _CFRelease(CFTypeRef cf) { 1337 1338 uint32_t cfinfo = *(uint32_t *)&(((CFRuntimeBase *)cf)->_cfinfo); 1339 CFTypeID typeID = (cfinfo >> 8) & 0x03FF; // mask up to 0x0FFF 1340 if (cfinfo & 0x800000) { // custom ref counting for object 1341 CFRuntimeClass *cfClass = __CFRuntimeClassTable[typeID]; 1342 uint32_t (*refcount)(intptr_t, CFTypeRef) = cfClass->refcount; 1343 if (!refcount || !(cfClass->version & _kCFRuntimeCustomRefCount) || (((CFRuntimeBase *)cf)->_cfinfo[CF_RC_BITS] != 0xFF)) { 1344 HALT; // bogus object 1345 } 1346#if __LP64__ 1347 if (((CFRuntimeBase *)cf)->_rc != 0xFFFFFFFFU) { 1348 HALT; // bogus object 1349 } 1350#endif 1351 refcount(-1, cf); 1352 return; 1353 } 1354 1355 CFIndex start_rc = __builtin_expect(__CFOASafe, 0) ? CFGetRetainCount(cf) : 0; 1356 Boolean isAllocator = (__kCFAllocatorTypeID_CONST == typeID); 1357 Boolean didAuto = false; 1358#if __LP64__ 1359#if !DEPLOYMENT_TARGET_WINDOWS 1360 uint32_t lowBits; 1361 uint64_t allBits; 1362 again:; 1363 do { 1364 allBits = *(uint64_t *)&(((CFRuntimeBase *)cf)->_cfinfo); 1365 lowBits = RC_GET(allBits); 1366 if (0 == lowBits) { 1367 if (CF_IS_COLLECTABLE(cf)) auto_zone_release(objc_collectableZone(), (void*)cf); 1368 return; // Constant CFTypeRef 1369 } 1370 if (1 == lowBits) { 1371 CFRuntimeClass *cfClass = __CFRuntimeClassTable[typeID]; 1372 if ((cfClass->version & _kCFRuntimeResourcefulObject) && cfClass->reclaim != NULL) { 1373 cfClass->reclaim(cf); 1374 } 1375 if (!CF_IS_COLLECTABLE(cf)) { 1376 uint64_t newAllBits = allBits | RC_DEALLOCATING_BIT; 1377 if (!CAS64(allBits, newAllBits, (int64_t *)&((CFRuntimeBase *)cf)->_cfinfo)) { 1378 goto again; 1379 } 1380 allBits = newAllBits; 1381 void (*func)(CFTypeRef) = __CFRuntimeClassTable[typeID]->finalize; 1382 if (NULL != func) { 1383 func(cf); 1384 } 1385 allBits = *(uint64_t *)&(((CFRuntimeBase *)cf)->_cfinfo); 1386 lowBits = RC_GET(allBits); 1387 if (isAllocator || ((1 == lowBits) && CAS64(allBits, allBits - RC_INCREMENT, (int64_t *)&((CFRuntimeBase *)cf)->_cfinfo))) { 1388 goto really_free; 1389 } 1390 Boolean success = false; 1391 do { // drop the deallocating bit; racey, but this resurrection stuff isn't thread-safe anyway 1392 allBits = *(uint64_t *)&(((CFRuntimeBase *)cf)->_cfinfo); 1393 uint64_t newAllBits = allBits & ~RC_DEALLOCATING_BIT; 1394 success = CAS64(allBits, newAllBits, (int64_t *)&((CFRuntimeBase *)cf)->_cfinfo); 1395 } while (!success); 1396 goto again; // still need to have the effect of a CFRelease 1397 } 1398 } 1399 } while (!CAS64(allBits, allBits - RC_INCREMENT, (int64_t *)&((CFRuntimeBase *)cf)->_cfinfo)); 1400 if (lowBits == 1 && CF_IS_COLLECTABLE(cf)) { 1401 // GC: release the collector's hold over the object, which will call the finalize function later on. 1402 auto_zone_release(objc_collectableZone(), (void*)cf); 1403 didAuto = true; 1404 } 1405#else 1406 uint32_t lowBits; 1407 do { 1408 lowBits = ((CFRuntimeBase *)cf)->_rc; 1409 if (0 == lowBits) { 1410 if (CF_IS_COLLECTABLE(cf)) auto_zone_release(objc_collectableZone(), (void*)cf); 1411 return; // Constant CFTypeRef 1412 } 1413 if (1 == lowBits) { 1414 // CANNOT WRITE ANY NEW VALUE INTO [CF_RC_BITS] UNTIL AFTER FINALIZATION 1415 CFRuntimeClass *cfClass = __CFRuntimeClassTable[typeID]; 1416 if ((cfClass->version & _kCFRuntimeResourcefulObject) && cfClass->reclaim != NULL) { 1417 cfClass->reclaim(cf); 1418 } 1419 if (!CF_IS_COLLECTABLE(cf)) { 1420 void (*func)(CFTypeRef) = __CFRuntimeClassTable[typeID]->finalize; 1421 if (NULL != func) { 1422 func(cf); 1423 } 1424 if (isAllocator || CAS32(1, 0, (int32_t *)&((CFRuntimeBase *)cf)->_rc)) { 1425 goto really_free; 1426 } 1427 } 1428 } 1429 } while (!CAS32(lowBits, lowBits - 1, (int32_t *)&((CFRuntimeBase *)cf)->_rc)); 1430 if (lowBits == 1 && CF_IS_COLLECTABLE(cf)) { 1431 // GC: release the collector's hold over the object, which will call the finalize function later on. 1432 auto_zone_release(objc_collectableZone(), (void*)cf); 1433 didAuto = true; 1434 } 1435#endif 1436#else 1437#if !DEPLOYMENT_TARGET_WINDOWS 1438 again:; 1439 volatile uint32_t *infoLocation = (uint32_t *)&(((CFRuntimeBase *)cf)->_cfinfo); 1440 CFIndex rcLowBits = __CFBitfieldGetValue(cfinfo, RC_END, RC_START); 1441 if (__builtin_expect(0 == rcLowBits, 0)) { 1442 if (CF_IS_COLLECTABLE(cf)) auto_zone_release(objc_collectableZone(), (void*)cf); 1443 return; // Constant CFTypeRef 1444 } 1445 bool success = 0; 1446 Boolean whack = false; 1447 do { 1448 cfinfo = *infoLocation; 1449 rcLowBits = __CFBitfieldGetValue(cfinfo, RC_END, RC_START); 1450 if (__builtin_expect(1 == rcLowBits, 0)) { 1451 // we think cf should be deallocated 1452 uint32_t prospectiveNewInfo = cfinfo | (0x400000); 1453 if (CF_IS_COLLECTABLE(cf)) { 1454 prospectiveNewInfo -= (1 << RC_START); 1455 } 1456 success = CAS32(*(int32_t *)& cfinfo, *(int32_t *)&prospectiveNewInfo, (int32_t *)infoLocation); 1457 if (success) whack = true; 1458 } else { 1459 // not yet junk 1460 uint32_t prospectiveNewInfo = cfinfo; // don't want compiler to generate prospectiveNewInfo = *infoLocation. This is why infoLocation is declared as a pointer to volatile memory. 1461 if (__builtin_expect((1 << 7) == rcLowBits, 0)) { 1462 // Time to remove a bit from the external ref count 1463 __CFSpinLock(&__CFRuntimeExternRefCountTableLock); 1464 CFIndex rcHighBitsCnt = __CFDoExternRefOperation(500, (id)cf); 1465 if (1 == rcHighBitsCnt) { 1466 __CFBitfieldSetValue(prospectiveNewInfo, RC_END, RC_START, (1 << 6) - 1); 1467 } else { 1468 __CFBitfieldSetValue(prospectiveNewInfo, RC_END, RC_START, ((1 << 6) | (1 << 7)) - 1); 1469 } 1470 success = CAS32(*(int32_t *)& cfinfo, *(int32_t *)&prospectiveNewInfo, (int32_t *)infoLocation); 1471 if (__builtin_expect(success, 1)) { 1472 __CFDoExternRefOperation(450, (id)cf); 1473 } 1474 __CFSpinUnlock(&__CFRuntimeExternRefCountTableLock); 1475 } else { 1476 prospectiveNewInfo -= (1 << RC_START); 1477 success = CAS32(*(int32_t *)& cfinfo, *(int32_t *)&prospectiveNewInfo, (int32_t *)infoLocation); 1478 } 1479 } 1480 } while (__builtin_expect(!success, 0)); 1481 1482 if (whack) { 1483 CFRuntimeClass *cfClass = __CFRuntimeClassTable[typeID]; 1484 if ((cfClass->version & _kCFRuntimeResourcefulObject) && cfClass->reclaim != NULL) { 1485 cfClass->reclaim(cf); 1486 } 1487 if (CF_IS_COLLECTABLE(cf)) { 1488 // GC: release the collector's hold over the object, which will call the finalize function later on. 1489 auto_zone_release(objc_collectableZone(), (void*)cf); 1490 didAuto = true; 1491 } else { 1492 if (isAllocator) { 1493 goto really_free; 1494 } else { 1495 void (*func)(CFTypeRef) = __CFRuntimeClassTable[typeID]->finalize; 1496 if (NULL != func) { 1497 func(cf); 1498 } 1499 rcLowBits = __CFBitfieldGetValue(*infoLocation, RC_END, RC_START); 1500 if (1 == rcLowBits) { 1501 goto really_free; 1502 } 1503 do { // drop the deallocating bit; racey, but this resurrection stuff isn't thread-safe anyway 1504 cfinfo = *infoLocation; 1505 uint32_t prospectiveNewInfo = (cfinfo & ~(0x400000)); 1506 success = CAS32(*(int32_t *)& cfinfo, *(int32_t *)&prospectiveNewInfo, (int32_t *)infoLocation); 1507 } while (!success); 1508 goto again; 1509 } 1510 } 1511 } 1512#else 1513 volatile uint32_t *infoLocation = (uint32_t *)&(((CFRuntimeBase *)cf)->_cfinfo); 1514 CFIndex rcLowBits = __CFBitfieldGetValue(*infoLocation, RC_END, RC_START); 1515 if (__builtin_expect(0 == rcLowBits, 0)) { 1516 if (CF_IS_COLLECTABLE(cf)) auto_zone_release(objc_collectableZone(), (void*)cf); 1517 return; // Constant CFTypeRef 1518 } 1519 bool success = 0; 1520 do { 1521 uint32_t initialCheckInfo = *infoLocation; 1522 rcLowBits = __CFBitfieldGetValue(initialCheckInfo, RC_END, RC_START); 1523 if (__builtin_expect(1 == rcLowBits, 0)) { 1524 // we think cf should be deallocated 1525 // CANNOT WRITE ANY NEW VALUE INTO [CF_RC_BITS] UNTIL AFTER FINALIZATION 1526 CFRuntimeClass *cfClass = __CFRuntimeClassTable[typeID]; 1527 if ((cfClass->version & _kCFRuntimeResourcefulObject) && cfClass->reclaim != NULL) { 1528 cfClass->reclaim(cf); 1529 } 1530 if (CF_IS_COLLECTABLE(cf)) { 1531 uint32_t prospectiveNewInfo = initialCheckInfo - (1 << RC_START); 1532 success = CAS32(*(int32_t *)&initialCheckInfo, *(int32_t *)&prospectiveNewInfo, (int32_t *)infoLocation); 1533 // GC: release the collector's hold over the object, which will call the finalize function later on. 1534 if (success) { 1535 auto_zone_release(objc_collectableZone(), (void*)cf); 1536 didAuto = true; 1537 } 1538 } else { 1539 if (isAllocator) { 1540 goto really_free; 1541 } else { 1542 void (*func)(CFTypeRef) = __CFRuntimeClassTable[typeID]->finalize; 1543 if (NULL != func) { 1544 func(cf); 1545 } 1546 // We recheck rcLowBits to see if the object has been retained again during 1547 // the finalization process. This allows for the finalizer to resurrect, 1548 // but the main point is to allow finalizers to be able to manage the 1549 // removal of objects from uniquing caches, which may race with other threads 1550 // which are allocating (looking up and finding) objects from those caches, 1551 // which (that thread) would be the thing doing the extra retain in that case. 1552 rcLowBits = __CFBitfieldGetValue(*infoLocation, RC_END, RC_START); 1553 success = (1 == rcLowBits); 1554 if (__builtin_expect(success, 1)) { 1555 goto really_free; 1556 } 1557 } 1558 } 1559 } else { 1560 // not yet junk 1561 uint32_t prospectiveNewInfo = initialCheckInfo; // don't want compiler to generate prospectiveNewInfo = *infoLocation. This is why infoLocation is declared as a pointer to volatile memory. 1562 if (__builtin_expect((1 << 7) == rcLowBits, 0)) { 1563 // Time to remove a bit from the external ref count 1564 __CFSpinLock(&__CFRuntimeExternRefCountTableLock); 1565 CFIndex rcHighBitsCnt = __CFDoExternRefOperation(500, (id)cf); 1566 if (1 == rcHighBitsCnt) { 1567 __CFBitfieldSetValue(prospectiveNewInfo, RC_END, RC_START, (1 << 6) - 1); 1568 } else { 1569 __CFBitfieldSetValue(prospectiveNewInfo, RC_END, RC_START, ((1 << 6) | (1 << 7)) - 1); 1570 } 1571 success = CAS32(*(int32_t *)&initialCheckInfo, *(int32_t *)&prospectiveNewInfo, (int32_t *)infoLocation); 1572 if (__builtin_expect(success, 1)) { 1573 __CFDoExternRefOperation(450, (id)cf); 1574 } 1575 __CFSpinUnlock(&__CFRuntimeExternRefCountTableLock); 1576 } else { 1577 prospectiveNewInfo -= (1 << RC_START); 1578 success = CAS32(*(int32_t *)&initialCheckInfo, *(int32_t *)&prospectiveNewInfo, (int32_t *)infoLocation); 1579 } 1580 } 1581 } while (__builtin_expect(!success, 0)); 1582#endif 1583#endif 1584 if (!didAuto && __builtin_expect(__CFOASafe, 0)) { 1585 __CFRecordAllocationEvent(__kCFReleaseEvent, (void *)cf, 0, start_rc - 1, NULL); 1586 } 1587 return; 1588 1589 really_free:; 1590 if (!didAuto && __builtin_expect(__CFOASafe, 0)) { 1591 // do not use CFGetRetainCount() because cf has been freed if it was an allocator 1592 __CFRecordAllocationEvent(__kCFReleaseEvent, (void *)cf, 0, 0, NULL); 1593 } 1594 // cannot zombify allocators, which get deallocated by __CFAllocatorDeallocate (finalize) 1595 if (isAllocator) { 1596 __CFAllocatorDeallocate((void *)cf); 1597 } else { 1598 CFAllocatorRef allocator = kCFAllocatorSystemDefault; 1599 Boolean usesSystemDefaultAllocator = true; 1600 1601 if (!__CFBitfieldGetValue(((const CFRuntimeBase *)cf)->_cfinfo[CF_INFO_BITS], 7, 7)) { 1602 allocator = CFGetAllocator(cf); 1603 usesSystemDefaultAllocator = _CFAllocatorIsSystemDefault(allocator); 1604 } 1605 1606 { 1607 CFAllocatorDeallocate(allocator, (uint8_t *)cf - (usesSystemDefaultAllocator ? 0 : sizeof(CFAllocatorRef))); 1608 } 1609 1610 if (kCFAllocatorSystemDefault != allocator) { 1611 CFRelease(allocator); 1612 } 1613 } 1614} 1615 1616#undef __kCFAllocatorTypeID_CONST 1617#undef __CFGenericAssertIsCF 1618 1619 1620