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