2 * Copyright (c) 2015 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
25 Copyright (c) 1999-2014, Apple Inc. All rights reserved.
26 Responsibility: Christopher Kane
29 #define ENABLE_ZOMBIES 1
31 #include <CoreFoundation/CFRuntime.h>
32 #include "CFInternal.h"
33 #include "CFBasicHash.h"
37 #include <CoreFoundation/CFUUID.h>
38 #include <CoreFoundation/CFCalendar.h>
39 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
41 #include <mach-o/dyld.h>
42 #include <mach/mach.h>
43 #include <crt_externs.h>
46 #include <CoreFoundation/CFStringDefaultEncoding.h>
48 #if DEPLOYMENT_TARGET_EMBEDDED
49 // This isn't in the embedded runtime.h header
50 OBJC_EXPORT
void *objc_destructInstance(id obj
);
54 #if DEPLOYMENT_TARGET_WINDOWS
59 // retain/release recording constants -- must match values
60 // used by OA for now; probably will change in the future
61 __kCFRetainEvent
= 28,
62 __kCFReleaseEvent
= 29
65 #if DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX
68 #include <malloc/malloc.h>
71 #define FAKE_INSTRUMENTS 0
73 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
74 CF_PRIVATE
void __CFOAInitializeNSObject(void); // from NSObject.m
76 bool __CFOASafe
= false;
78 void (*__CFObjectAllocRecordAllocationFunction
)(int, void *, int64_t , uint64_t, const char *) = NULL
;
79 void (*__CFObjectAllocSetLastAllocEventNameFunction
)(void *, const char *) = NULL
;
81 void __CFOAInitialize(void) {
84 void __CFRecordAllocationEvent(int eventnum
, void *ptr
, int64_t size
, uint64_t data
, const char *classname
) {
85 if (!__CFOASafe
|| !__CFObjectAllocRecordAllocationFunction
) return;
86 __CFObjectAllocRecordAllocationFunction(eventnum
, ptr
, size
, data
, classname
);
89 void __CFSetLastAllocationEventName(void *ptr
, const char *classname
) {
90 if (!__CFOASafe
|| !__CFObjectAllocSetLastAllocEventNameFunction
) return;
91 __CFObjectAllocSetLastAllocEventNameFunction(ptr
, classname
);
94 #elif FAKE_INSTRUMENTS
96 CF_EXPORT
bool __CFOASafe
= true;
98 void __CFOAInitialize(void) { }
100 void __CFRecordAllocationEvent(int eventnum
, void *ptr
, int64_t size
, uint64_t data
, const char *classname
) {
101 if (!__CFOASafe
) return;
102 if (!classname
) classname
= "(no class)";
103 const char *event
= "unknown event";
109 case __kCFReleaseEvent
:
113 case __kCFRetainEvent
:
117 fprintf(stdout
, "event,%d,%s,%p,%ld,%lu,%s\n", eventnum
, event
, ptr
, (long)size
, (unsigned long)data
, classname
);
120 void __CFSetLastAllocationEventName(void *ptr
, const char *classname
) {
121 if (!__CFOASafe
) return;
122 if (!classname
) classname
= "(no class)";
123 fprintf(stdout
, "name,%p,%s\n", ptr
, classname
? classname
: "(no class)");
128 bool __CFOASafe
= false;
130 void __CFOAInitialize(void) { }
131 void __CFRecordAllocationEvent(int eventnum
, void *ptr
, int64_t size
, uint64_t data
, const char *classname
) { }
132 void __CFSetLastAllocationEventName(void *ptr
, const char *classname
) { }
136 extern void __HALT(void);
138 static CFTypeID __kCFNotATypeTypeID
= _kCFRuntimeNotATypeID
;
140 #if !defined (__cplusplus)
141 static const CFRuntimeClass __CFNotATypeClass
= {
153 static CFTypeID __kCFTypeTypeID
= _kCFRuntimeNotATypeID
;
155 static const CFRuntimeClass __CFTypeClass
= {
167 void SIG1(CFTypeRef
){__HALT();};;
168 CFTypeRef
SIG2(CFAllocatorRef
,CFTypeRef
){__HALT();return NULL
;};
169 Boolean
SIG3(CFTypeRef
,CFTypeRef
){__HALT();return FALSE
;};
170 CFHashCode
SIG4(CFTypeRef
){__HALT(); return 0;};
171 CFStringRef
SIG5(CFTypeRef
,CFDictionaryRef
){__HALT();return NULL
;};
172 CFStringRef
SIG6(CFTypeRef
){__HALT();return NULL
;};
174 static const CFRuntimeClass __CFNotATypeClass
= {
186 static CFTypeID __kCFTypeTypeID
= _kCFRuntimeNotATypeID
;
188 static const CFRuntimeClass __CFTypeClass
= {
201 // the lock does not protect most reading of these; we just leak the old table to allow read-only accesses to continue to work
202 static CFLock_t __CFBigRuntimeFunnel
= CFLockInit
;
203 CF_PRIVATE CFRuntimeClass
* __CFRuntimeClassTable
[__CFRuntimeClassTableSize
] = {0};
204 CF_PRIVATE
int32_t __CFRuntimeClassTableCount
= 0;
206 CF_PRIVATE
uintptr_t __CFRuntimeObjCClassTable
[__CFRuntimeClassTableSize
] = {0};
208 #if !defined(__CFObjCIsCollectable)
209 bool (*__CFObjCIsCollectable
)(void *) = NULL
;
212 #if !__CONSTANT_CFSTRINGS__ || DEPLOYMENT_TARGET_EMBEDDED_MINI
213 // Compiler uses this symbol name; must match compiler built-in decl, so we use 'int'
215 int __CFConstantStringClassReference
[24] = {0};
217 int __CFConstantStringClassReference
[12] = {0};
222 int __CFConstantStringClassReference
[24] = {0};
224 int __CFConstantStringClassReference
[12] = {0};
227 void *__CFConstantStringClassReferencePtr
= NULL
;
229 Boolean
_CFIsObjC(CFTypeID typeID
, void *obj
) {
230 return CF_IS_OBJC(typeID
, obj
);
233 CFTypeID
_CFRuntimeRegisterClass(const CFRuntimeClass
* const cls
) {
234 // className must be pure ASCII string, non-null
235 if ((cls
->version
& _kCFRuntimeCustomRefCount
) && !cls
->refcount
) {
236 CFLog(kCFLogLevelWarning
, CFSTR("*** _CFRuntimeRegisterClass() given inconsistent class '%s'. Program will crash soon."), cls
->className
);
237 return _kCFRuntimeNotATypeID
;
239 __CFLock(&__CFBigRuntimeFunnel
);
240 if (__CFMaxRuntimeTypes
<= __CFRuntimeClassTableCount
) {
241 CFLog(kCFLogLevelWarning
, CFSTR("*** CoreFoundation class table full; registration failing for class '%s'. Program will crash soon."), cls
->className
);
242 __CFUnlock(&__CFBigRuntimeFunnel
);
243 return _kCFRuntimeNotATypeID
;
245 if (__CFRuntimeClassTableSize
<= __CFRuntimeClassTableCount
) {
246 CFLog(kCFLogLevelWarning
, CFSTR("*** CoreFoundation class table full; registration failing for class '%s'. Program will crash soon."), cls
->className
);
247 __CFUnlock(&__CFBigRuntimeFunnel
);
248 return _kCFRuntimeNotATypeID
;
250 __CFRuntimeClassTable
[__CFRuntimeClassTableCount
++] = (CFRuntimeClass
*)cls
;
251 CFTypeID typeID
= __CFRuntimeClassTableCount
- 1;
252 __CFUnlock(&__CFBigRuntimeFunnel
);
257 const CFRuntimeClass
* _CFRuntimeGetClassWithTypeID(CFTypeID typeID
) {
258 return __CFRuntimeClassTable
[typeID
]; // hopelessly unthreadsafe
261 void _CFRuntimeUnregisterClassWithTypeID(CFTypeID typeID
) {
262 __CFLock(&__CFBigRuntimeFunnel
);
263 __CFRuntimeClassTable
[typeID
] = NULL
;
264 __CFUnlock(&__CFBigRuntimeFunnel
);
268 #if defined(DEBUG) || defined(ENABLE_ZOMBIES)
270 CF_PRIVATE
uint8_t __CFZombieEnabled
= 0;
271 CF_PRIVATE
uint8_t __CFDeallocateZombies
= 0;
273 extern void __CFZombifyNSObject(void); // from NSObject.m
275 void _CFEnableZombies(void) {
280 // XXX_PCB: use the class version field as a bitmask, to allow classes to opt-in for GC scanning.
282 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
283 CF_INLINE CFOptionFlags
CF_GET_COLLECTABLE_MEMORY_TYPE(const CFRuntimeClass
*cls
)
285 return ((cls
->version
& _kCFRuntimeScannedObject
) ? __kCFAllocatorGCScannedMemory
: 0) | __kCFAllocatorGCObjectMemory
;
288 #define CF_GET_COLLECTABLE_MEMORY_TYPE(x) (0)
291 CFTypeRef
_CFRuntimeCreateInstance(CFAllocatorRef allocator
, CFTypeID typeID
, CFIndex extraBytes
, unsigned char *category
) {
292 if (__CFRuntimeClassTableSize
<= typeID
) HALT
;
293 CFAssert1(typeID
!= _kCFRuntimeNotATypeID
, __kCFLogAssertion
, "%s(): Uninitialized type id", __PRETTY_FUNCTION__
);
294 CFRuntimeClass
*cls
= __CFRuntimeClassTable
[typeID
];
298 if (cls
->version
& _kCFRuntimeRequiresAlignment
) {
299 allocator
= kCFAllocatorSystemDefault
;
301 Boolean customRC
= !!(cls
->version
& _kCFRuntimeCustomRefCount
);
302 if (customRC
&& !cls
->refcount
) {
303 CFLog(kCFLogLevelWarning
, CFSTR("*** _CFRuntimeCreateInstance() found inconsistent class '%s'."), cls
->className
);
306 CFAllocatorRef realAllocator
= (NULL
== allocator
) ? __CFGetDefaultAllocator() : allocator
;
307 if (kCFAllocatorNull
== realAllocator
) {
310 Boolean usesSystemDefaultAllocator
= _CFAllocatorIsSystemDefault(realAllocator
);
311 size_t align
= (cls
->version
& _kCFRuntimeRequiresAlignment
) ? cls
->requiredAlignment
: 16;
312 CFIndex size
= sizeof(CFRuntimeBase
) + extraBytes
+ (usesSystemDefaultAllocator
? 0 : sizeof(CFAllocatorRef
));
313 size
= (size
+ 0xF) & ~0xF; // CF objects are multiples of 16 in size
314 // CFType version 0 objects are unscanned by default since they don't have write-barriers and hard retain their innards
315 // CFType version 1 objects are scanned and use hand coded write-barriers to store collectable storage within
316 CFRuntimeBase
*memory
= NULL
;
317 if (cls
->version
& _kCFRuntimeRequiresAlignment
) {
318 memory
= malloc_zone_memalign(malloc_default_zone(), align
, size
);
320 memory
= (CFRuntimeBase
*)CFAllocatorAllocate(allocator
, size
, CF_GET_COLLECTABLE_MEMORY_TYPE(cls
));
322 if (NULL
== memory
) {
325 if (!kCFUseCollectableAllocator
|| !CF_IS_COLLECTABLE_ALLOCATOR(allocator
) || !(CF_GET_COLLECTABLE_MEMORY_TYPE(cls
) & __kCFAllocatorGCScannedMemory
)) {
326 memset(memory
, 0, size
);
328 if (__CFOASafe
&& category
) {
329 __CFSetLastAllocationEventName(memory
, (char *)category
);
330 } else if (__CFOASafe
) {
331 __CFSetLastAllocationEventName(memory
, (char *)cls
->className
);
333 if (!usesSystemDefaultAllocator
) {
334 // add space to hold allocator ref for non-standard allocators.
335 // (this screws up 8 byte alignment but seems to work)
336 *(CFAllocatorRef
*)((char *)memory
) = (CFAllocatorRef
)CFRetain(realAllocator
);
337 memory
= (CFRuntimeBase
*)((char *)memory
+ sizeof(CFAllocatorRef
));
341 if (!kCFUseCollectableAllocator
|| (1 && 1)) {
345 memory
->_rc
= 0xFFFFFFFFU
;
349 if (!kCFUseCollectableAllocator
|| (1 && 1)) {
356 uint32_t *cfinfop
= (uint32_t *)&(memory
->_cfinfo
);
357 *cfinfop
= (uint32_t)((rc
<< 24) | (customRC
? 0x800000 : 0x0) | ((uint32_t)typeID
<< 8) | (usesSystemDefaultAllocator
? 0x80 : 0x00));
359 if (NULL
!= cls
->init
) {
365 void _CFRuntimeInitStaticInstance(void *ptr
, CFTypeID typeID
) {
366 CFAssert1(typeID
!= _kCFRuntimeNotATypeID
, __kCFLogAssertion
, "%s(): Uninitialized type id", __PRETTY_FUNCTION__
);
367 if (__CFRuntimeClassTableSize
<= typeID
) HALT
;
368 CFRuntimeClass
*cfClass
= __CFRuntimeClassTable
[typeID
];
369 Boolean customRC
= !!(cfClass
->version
& _kCFRuntimeCustomRefCount
);
371 CFLog(kCFLogLevelError
, CFSTR("*** Cannot initialize a static instance to a class (%s) with custom ref counting"), cfClass
->className
);
374 CFRuntimeBase
*memory
= (CFRuntimeBase
*)ptr
;
375 uint32_t *cfinfop
= (uint32_t *)&(memory
->_cfinfo
);
376 *cfinfop
= (uint32_t)(((customRC
? 0xFF : 0) << 24) | (customRC
? 0x800000 : 0x0) | ((uint32_t)typeID
<< 8) | 0x80);
378 memory
->_rc
= customRC
? 0xFFFFFFFFU
: 0x0;
381 if (NULL
!= cfClass
->init
) {
382 (cfClass
->init
)(memory
);
386 void _CFRuntimeSetInstanceTypeID(CFTypeRef cf
, CFTypeID newTypeID
) {
387 if (__CFRuntimeClassTableSize
<= newTypeID
) HALT
;
388 uint32_t *cfinfop
= (uint32_t *)&(((CFRuntimeBase
*)cf
)->_cfinfo
);
389 CFTypeID currTypeID
= (*cfinfop
>> 8) & 0x03FF; // mask up to 0x0FFF
390 CFRuntimeClass
*newcfClass
= __CFRuntimeClassTable
[newTypeID
];
391 Boolean newCustomRC
= (newcfClass
->version
& _kCFRuntimeCustomRefCount
);
392 CFRuntimeClass
*currcfClass
= __CFRuntimeClassTable
[currTypeID
];
393 Boolean currCustomRC
= (currcfClass
->version
& _kCFRuntimeCustomRefCount
);
394 if (currCustomRC
|| (0 != currTypeID
&& newCustomRC
)) {
395 CFLog(kCFLogLevelError
, CFSTR("*** Cannot change the CFTypeID of a %s to a %s due to custom ref counting"), currcfClass
->className
, newcfClass
->className
);
398 // Going from current type ID of 0 to anything is allowed, but if
399 // the object has somehow already been retained and the transition
400 // is to a class doing custom ref counting, the ref count isn't
401 // transferred and there will probably be a crash later when the
402 // object is freed too early.
403 *cfinfop
= (*cfinfop
& 0xFFF000FFU
) | ((uint32_t)newTypeID
<< 8);
406 CF_PRIVATE
void _CFRuntimeSetInstanceTypeIDAndIsa(CFTypeRef cf
, CFTypeID newTypeID
) {
407 _CFRuntimeSetInstanceTypeID(cf
, newTypeID
);
412 __kCFObjectRetainedEvent
= 12,
413 __kCFObjectReleasedEvent
= 13
416 #if DEPLOYMENT_TARGET_MACOSX
417 #define NUM_EXTERN_TABLES 8
418 #define EXTERN_TABLE_IDX(O) (((uintptr_t)(O) >> 8) & 0x7)
419 #elif DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX
420 #define NUM_EXTERN_TABLES 1
421 #define EXTERN_TABLE_IDX(O) 0
426 // we disguise pointers so that programs like 'leaks' forget about these references
427 #define DISGUISE(O) (~(uintptr_t)(O))
431 CFBasicHashRef table
;
432 // uint8_t padding[64 - sizeof(CFBasicHashRef) - sizeof(CFLock_t)];
433 } __NSRetainCounters
[NUM_EXTERN_TABLES
];
435 CF_EXPORT
uintptr_t __CFDoExternRefOperation(uintptr_t op
, id obj
) {
436 if (nil
== obj
) HALT
;
437 uintptr_t idx
= EXTERN_TABLE_IDX(obj
);
438 uintptr_t disguised
= DISGUISE(obj
);
439 CFLock_t
*lock
= &__NSRetainCounters
[idx
].lock
;
440 CFBasicHashRef table
= __NSRetainCounters
[idx
].table
;
443 case 300: // increment
444 case 350: // increment, no event
446 CFBasicHashAddValue(table
, disguised
, disguised
);
448 if (__CFOASafe
&& op
!= 350) __CFRecordAllocationEvent(__kCFObjectRetainedEvent
, obj
, 0, 0, NULL
);
449 return (uintptr_t)obj
;
450 case 400: // decrement
451 if (__CFOASafe
) __CFRecordAllocationEvent(__kCFObjectReleasedEvent
, obj
, 0, 0, NULL
);
452 case 450: // decrement, no event
454 count
= (uintptr_t)CFBasicHashRemoveValue(table
, disguised
);
459 count
= (uintptr_t)CFBasicHashGetCountOfKey(table
, disguised
);
466 CF_EXPORT CFTypeID
CFNumberGetTypeID(void);
468 CF_INLINE CFTypeID
__CFGenericTypeID_inline(const void *cf
) {
469 // yes, 10 bits masked off, though 12 bits are there for the type field; __CFRuntimeClassTableSize is 1024
470 uint32_t *cfinfop
= (uint32_t *)&(((CFRuntimeBase
*)cf
)->_cfinfo
);
471 CFTypeID typeID
= (*cfinfop
>> 8) & 0x03FF; // mask up to 0x0FFF
475 CFTypeID
__CFGenericTypeID(const void *cf
) {
476 return __CFGenericTypeID_inline(cf
);
479 CFTypeID
CFTypeGetTypeID(void) {
480 return __kCFTypeTypeID
;
483 CF_PRIVATE
void __CFGenericValidateType_(CFTypeRef cf
, CFTypeID type
, const char *func
) {
484 if (cf
&& CF_IS_OBJC(type
, cf
)) return;
485 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
); \
486 CFAssert3(__CFGenericTypeID_inline(cf
) == type
, __kCFLogAssertion
, "%s(): pointer %p is not a %s", func
, cf
, __CFRuntimeClassTable
[type
]->className
); \
489 #define __CFGenericAssertIsCF(cf) \
490 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);
493 #define CFTYPE_IS_OBJC(obj) (false)
494 #define CFTYPE_OBJC_FUNCDISPATCH0(rettype, obj, sel) do {} while (0)
495 #define CFTYPE_OBJC_FUNCDISPATCH1(rettype, obj, sel, a1) do {} while (0)
498 CFTypeID
CFGetTypeID(CFTypeRef cf
) {
500 if (NULL
== cf
) { CRSetCrashLogMessage("*** CFGetTypeID() called with NULL ***"); HALT
; }
502 CFTYPE_OBJC_FUNCDISPATCH0(CFTypeID
, cf
, _cfTypeID
);
503 __CFGenericAssertIsCF(cf
);
504 return __CFGenericTypeID_inline(cf
);
507 CFStringRef
CFCopyTypeIDDescription(CFTypeID type
) {
508 CFAssert2((NULL
!= __CFRuntimeClassTable
[type
]) && __kCFNotATypeTypeID
!= type
&& __kCFTypeTypeID
!= type
, __kCFLogAssertion
, "%s(): type %d is not a CF type ID", __PRETTY_FUNCTION__
, type
);
509 return CFStringCreateWithCString(kCFAllocatorSystemDefault
, __CFRuntimeClassTable
[type
]->className
, kCFStringEncodingASCII
);
512 // Bit 31 (highest bit) in second word of cf instance indicates external ref count
514 static CFTypeRef
_CFRetain(CFTypeRef cf
, Boolean tryR
);
516 CFTypeRef
CFRetain(CFTypeRef cf
) {
517 if (NULL
== cf
) { CRSetCrashLogMessage("*** CFRetain() called with NULL ***"); HALT
; }
518 if (cf
) __CFGenericAssertIsCF(cf
);
519 return _CFRetain(cf
, false);
522 CFTypeRef
CFAutorelease(CFTypeRef
__attribute__((cf_consumed
)) cf
) {
523 if (NULL
== cf
) { CRSetCrashLogMessage("*** CFAutorelease() called with NULL ***"); HALT
; }
527 static void _CFRelease(CFTypeRef cf
);
529 void CFRelease(CFTypeRef cf
) {
530 if (NULL
== cf
) { CRSetCrashLogMessage("*** CFRelease() called with NULL ***"); HALT
; }
532 void **addrs
[2] = {&&start
, &&end
};
534 if (addrs
[0] <= __builtin_return_address(0) && __builtin_return_address(0) <= addrs
[1]) {
535 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 if (cf
) __CFGenericAssertIsCF(cf
);
547 CF_PRIVATE
void __CFAllocatorDeallocate(CFTypeRef cf
);
549 CF_PRIVATE
const void *__CFStringCollectionCopy(CFAllocatorRef allocator
, const void *ptr
) {
550 if (NULL
== ptr
) { CRSetCrashLogMessage("*** __CFStringCollectionCopy() called with NULL ***"); HALT
; }
551 CFStringRef theString
= (CFStringRef
)ptr
;
552 CFStringRef result
= CFStringCreateCopy((allocator
), theString
);
553 if (CF_IS_COLLECTABLE_ALLOCATOR(allocator
)) {
554 result
= (CFStringRef
)CFMakeCollectable(result
);
556 return (const void *)result
;
559 extern void CFCollection_non_gc_storage_error(void);
561 CF_PRIVATE
const void *__CFTypeCollectionRetain(CFAllocatorRef allocator
, const void *ptr
) {
562 if (NULL
== ptr
) { CRSetCrashLogMessage("*** __CFTypeCollectionRetain() called with NULL; likely a collection has been corrupted ***"); HALT
; }
563 CFTypeRef cf
= (CFTypeRef
)ptr
;
564 // only collections allocated in the GC zone can opt-out of reference counting.
565 if (CF_IS_COLLECTABLE_ALLOCATOR(allocator
)) {
566 if (CFTYPE_IS_OBJC(cf
)) return cf
; // do nothing for OBJC objects.
567 if (auto_zone_is_valid_pointer(objc_collectableZone(), ptr
)) {
568 CFRuntimeClass
*cfClass
= __CFRuntimeClassTable
[__CFGenericTypeID_inline(cf
)];
569 if (cfClass
->version
& _kCFRuntimeResourcefulObject
) {
570 // GC: If this a CF object in the GC heap that is marked resourceful, then
571 // it must be retained keep it alive in a CF collection.
575 ; // don't retain normal CF objects
578 // support constant CFTypeRef objects.
580 uint32_t lowBits
= ((CFRuntimeBase
*)cf
)->_rc
;
582 uint32_t lowBits
= ((CFRuntimeBase
*)cf
)->_cfinfo
[CF_RC_BITS
];
584 if (lowBits
== 0) return cf
;
585 // complain about non-GC objects in GC containers.
586 CFLog(kCFLogLevelWarning
, CFSTR("storing a non-GC object %p in a GC collection, break on CFCollection_non_gc_storage_error to debug."), cf
);
587 CFCollection_non_gc_storage_error();
588 // XXX should halt, except Patrick is using this somewhere.
596 CF_PRIVATE
void __CFTypeCollectionRelease(CFAllocatorRef allocator
, const void *ptr
) {
597 if (NULL
== ptr
) { CRSetCrashLogMessage("*** __CFTypeCollectionRelease() called with NULL; likely a collection has been corrupted ***"); HALT
; }
598 CFTypeRef cf
= (CFTypeRef
)ptr
;
599 // only collections allocated in the GC zone can opt-out of reference counting.
600 if (CF_IS_COLLECTABLE_ALLOCATOR(allocator
)) {
601 if (CFTYPE_IS_OBJC(cf
)) return; // do nothing for OBJC objects.
602 if (auto_zone_is_valid_pointer(objc_collectableZone(), cf
)) {
603 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
604 // GC: If this a CF object in the GC heap that is marked uncollectable, then
605 // must balance the retain done in __CFTypeCollectionRetain().
606 CFRuntimeClass
*cfClass
= __CFRuntimeClassTable
[__CFGenericTypeID_inline(cf
)];
607 if (cfClass
->version
& _kCFRuntimeResourcefulObject
) {
608 // reclaim is called by _CFRelease(), which must be called to keep the
609 // CF and GC retain counts in sync.
612 // avoid releasing normal CF objects. Like other collections, for example
617 // support constant CFTypeRef objects.
619 uint32_t lowBits
= ((CFRuntimeBase
*)cf
)->_rc
;
621 uint32_t lowBits
= ((CFRuntimeBase
*)cf
)->_cfinfo
[CF_RC_BITS
];
623 if (lowBits
== 0) return;
630 static CFLock_t __CFRuntimeExternRefCountTableLock
= CFLockInit
;
633 static uint64_t __CFGetFullRetainCount(CFTypeRef cf
) {
634 if (NULL
== cf
) { CRSetCrashLogMessage("*** __CFGetFullRetainCount() called with NULL ***"); HALT
; }
636 uint32_t lowBits
= ((CFRuntimeBase
*)cf
)->_rc
;
638 return (uint64_t)0x0fffffffffffffffULL
;
642 uint32_t lowBits
= ((CFRuntimeBase
*)cf
)->_cfinfo
[CF_RC_BITS
];
644 return (uint64_t)0x0fffffffffffffffULL
;
646 uint64_t highBits
= 0;
647 if ((lowBits
& 0x80) != 0) {
648 highBits
= __CFDoExternRefOperation(500, (id
)cf
);
650 uint64_t compositeRC
= (lowBits
& 0x7f) + (highBits
<< 6);
655 CFIndex
CFGetRetainCount(CFTypeRef cf
) {
656 if (NULL
== cf
) { CRSetCrashLogMessage("*** CFGetRetainCount() called with NULL ***"); HALT
; }
657 uint32_t cfinfo
= *(uint32_t *)&(((CFRuntimeBase
*)cf
)->_cfinfo
);
658 if (cfinfo
& 0x800000) { // custom ref counting for object
659 CFTypeID typeID
= (cfinfo
>> 8) & 0x03FF; // mask up to 0x0FFF
660 CFRuntimeClass
*cfClass
= __CFRuntimeClassTable
[typeID
];
661 uint32_t (*refcount
)(intptr_t, CFTypeRef
) = cfClass
->refcount
;
662 if (!refcount
|| !(cfClass
->version
& _kCFRuntimeCustomRefCount
) || (((CFRuntimeBase
*)cf
)->_cfinfo
[CF_RC_BITS
] != 0xFF)) {
663 HALT
; // bogus object
666 if (((CFRuntimeBase
*)cf
)->_rc
!= 0xFFFFFFFFU
) {
667 HALT
; // bogus object
670 uint32_t rc
= refcount(0, cf
);
674 return (rc
< LONG_MAX
) ? (CFIndex
)rc
: (CFIndex
)LONG_MAX
;
677 uint64_t rc
= __CFGetFullRetainCount(cf
);
678 return (rc
< (uint64_t)LONG_MAX
) ? (CFIndex
)rc
: (CFIndex
)LONG_MAX
;
681 CFTypeRef
CFMakeCollectable(CFTypeRef cf
) {
682 if (NULL
== cf
) return NULL
;
686 CFTypeRef
CFMakeUncollectable(CFTypeRef cf
) {
687 if (NULL
== cf
) return NULL
;
688 if (CF_IS_COLLECTABLE(cf
)) {
694 Boolean
CFEqual(CFTypeRef cf1
, CFTypeRef cf2
) {
695 if (NULL
== cf1
) { CRSetCrashLogMessage("*** CFEqual() called with NULL first argument ***"); HALT
; }
696 if (NULL
== cf2
) { CRSetCrashLogMessage("*** CFEqual() called with NULL second argument ***"); HALT
; }
697 if (cf1
== cf2
) return true;
698 CFTYPE_OBJC_FUNCDISPATCH1(Boolean
, cf1
, isEqual
:, cf2
);
699 CFTYPE_OBJC_FUNCDISPATCH1(Boolean
, cf2
, isEqual
:, cf1
);
700 __CFGenericAssertIsCF(cf1
);
701 __CFGenericAssertIsCF(cf2
);
702 if (__CFGenericTypeID_inline(cf1
) != __CFGenericTypeID_inline(cf2
)) return false;
703 if (NULL
!= __CFRuntimeClassTable
[__CFGenericTypeID_inline(cf1
)]->equal
) {
704 return __CFRuntimeClassTable
[__CFGenericTypeID_inline(cf1
)]->equal(cf1
, cf2
);
709 CFHashCode
CFHash(CFTypeRef cf
) {
710 if (NULL
== cf
) { CRSetCrashLogMessage("*** CFHash() called with NULL ***"); HALT
; }
711 CFTYPE_OBJC_FUNCDISPATCH0(CFHashCode
, cf
, hash
);
712 __CFGenericAssertIsCF(cf
);
713 CFHashCode (*hash
)(CFTypeRef cf
) = __CFRuntimeClassTable
[__CFGenericTypeID_inline(cf
)]->hash
;
717 if (CF_IS_COLLECTABLE(cf
)) return (CFHashCode
)_object_getExternalHash((id
)cf
);
718 return (CFHashCode
)cf
;
721 // definition: produces a normally non-NULL debugging description of the object
722 CFStringRef
CFCopyDescription(CFTypeRef cf
) {
723 if (NULL
== cf
) return NULL
;
724 // CFTYPE_OBJC_FUNCDISPATCH0(CFStringRef, cf, _copyDescription); // XXX returns 0 refcounted item under GC
725 __CFGenericAssertIsCF(cf
);
726 if (NULL
!= __CFRuntimeClassTable
[__CFGenericTypeID_inline(cf
)]->copyDebugDesc
) {
727 CFStringRef result
= __CFRuntimeClassTable
[__CFGenericTypeID_inline(cf
)]->copyDebugDesc(cf
);
728 if (NULL
!= result
) return result
;
730 return CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("<%s %p [%p]>"), __CFRuntimeClassTable
[__CFGenericTypeID_inline(cf
)]->className
, cf
, CFGetAllocator(cf
));
733 // Definition: if type produces a formatting description, return that string, otherwise NULL
734 CF_PRIVATE CFStringRef
__CFCopyFormattingDescription(CFTypeRef cf
, CFDictionaryRef formatOptions
) {
735 if (NULL
== cf
) return NULL
;
736 __CFGenericAssertIsCF(cf
);
737 if (NULL
!= __CFRuntimeClassTable
[__CFGenericTypeID_inline(cf
)]->copyFormattingDesc
) {
738 return __CFRuntimeClassTable
[__CFGenericTypeID_inline(cf
)]->copyFormattingDesc(cf
, formatOptions
);
743 extern CFAllocatorRef
__CFAllocatorGetAllocator(CFTypeRef
);
745 CFAllocatorRef
CFGetAllocator(CFTypeRef cf
) {
746 if (NULL
== cf
) return kCFAllocatorSystemDefault
;
747 if (__kCFAllocatorTypeID_CONST
== __CFGenericTypeID_inline(cf
)) {
748 return __CFAllocatorGetAllocator(cf
);
750 return __CFGetAllocator(cf
);
754 extern CFTypeID
CFBinaryHeapGetTypeID();
755 extern CFTypeID
CFBitVectorGetTypeID();
756 extern CFTypeID
CFTreeGetTypeID();
757 extern CFTypeID
CFPlugInInstanceGetTypeID();
758 extern CFTypeID
CFStringTokenizerGetTypeID();
759 extern CFTypeID
CFStorageGetTypeID(void);
760 extern void __CFAllocatorInitialize(void);
761 extern void __CFStringInitialize(void);
762 extern void __CFCharacterSetInitialize(void);
763 extern void __CFPFactoryInitialize(void);
764 extern void __CFPlugInInitialize(void);
765 #if DEPLOYMENT_TARGET_LINUX
766 CF_PRIVATE
void __CFTSDLinuxInitialize();
768 #if DEPLOYMENT_TARGET_WINDOWS
770 CF_PRIVATE
void __CFTSDWindowsInitialize(void);
771 CF_PRIVATE
void __CFTSDWindowsCleanup(void);
772 CF_PRIVATE
void __CFFinalizeWindowsThreadData();
774 extern void __CFStreamInitialize(void);
775 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS
776 extern void __CFXPreferencesInitialize(void);
779 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
780 CF_PRIVATE
uint8_t __CF120290
= false;
781 CF_PRIVATE
uint8_t __CF120291
= false;
782 CF_PRIVATE
uint8_t __CF120293
= false;
783 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
784 asm(".desc ___crashreporter_info__, 0x10");
786 static void __01121__(void) {
787 __CF120291
= pthread_is_threaded_np() ? true : false;
790 static void __01123__(void) {
791 // Ideally, child-side atfork handlers should be async-cancel-safe, as fork()
792 // is async-cancel-safe and can be called from signal handlers. See also
793 // http://standards.ieee.org/reading/ieee/interp/1003-1c-95_int/pasc-1003.1c-37.html
794 // This is not a problem for CF.
797 #if DEPLOYMENT_TARGET_MACOSX
799 CRSetCrashLogMessage2("*** multi-threaded process forked ***");
801 CRSetCrashLogMessage2("*** single-threaded process forked ***");
807 #define EXEC_WARNING_STRING_1 "The process has forked and you cannot use this CoreFoundation functionality safely. You MUST exec().\n"
808 #define EXEC_WARNING_STRING_2 "Break on __THE_PROCESS_HAS_FORKED_AND_YOU_CANNOT_USE_THIS_COREFOUNDATION_FUNCTIONALITY___YOU_MUST_EXEC__() to debug.\n"
810 CF_PRIVATE
void __THE_PROCESS_HAS_FORKED_AND_YOU_CANNOT_USE_THIS_COREFOUNDATION_FUNCTIONALITY___YOU_MUST_EXEC__(void) {
811 write(2, EXEC_WARNING_STRING_1
, sizeof(EXEC_WARNING_STRING_1
) - 1);
812 write(2, EXEC_WARNING_STRING_2
, sizeof(EXEC_WARNING_STRING_2
) - 1);
818 CF_EXPORT
const void *__CFArgStuff
;
819 const void *__CFArgStuff
= NULL
;
820 CF_PRIVATE
void *__CFAppleLanguages
= NULL
;
822 // do not cache CFFIXED_USER_HOME or HOME, there are situations where they can change
836 {"DYLD_IMAGE_SUFFIX", NULL
},
837 {"CFProcessPath", NULL
},
838 {"CFNETWORK_LIBRARY_PATH", NULL
},
839 {"CFUUIDVersionNumber", NULL
},
840 {"CFDebugNamedDataSharing", NULL
},
841 {"CFPropertyListAllowImmutableCollections", NULL
},
842 {"CFBundleUseDYLD", NULL
},
843 {"CFBundleDisableStringsSharing", NULL
},
844 {"CFCharacterSetCheckForExpandedSet", NULL
},
845 {"__CF_DEBUG_EXPANDED_SET", NULL
},
846 {"CFStringDisableROM", NULL
},
847 {"CF_CHARSET_PATH", NULL
},
848 {"__CF_USER_TEXT_ENCODING", NULL
},
849 {"CFNumberDisableCache", NULL
},
850 {"__CFPREFERENCES_AVOID_DAEMON", NULL
},
851 {"APPLE_FRAMEWORKS_ROOT", NULL
},
852 {NULL
, NULL
}, // the last one is for optional "COMMAND_MODE" "legacy", do not use this slot, insert before
855 CF_PRIVATE
const char *__CFgetenv(const char *n
) {
856 for (CFIndex idx
= 0; idx
< sizeof(__CFEnv
) / sizeof(__CFEnv
[0]); idx
++) {
857 if (__CFEnv
[idx
].name
&& 0 == strcmp(n
, __CFEnv
[idx
].name
)) return __CFEnv
[idx
].value
;
862 CF_PRIVATE Boolean
__CFProcessIsRestricted() {
866 #if DEPLOYMENT_TARGET_WINDOWS
867 #define kNilPthreadT { nil, nil }
869 #define kNilPthreadT (pthread_t)0
873 #undef kCFUseCollectableAllocator
874 CF_EXPORT
bool kCFUseCollectableAllocator
;
875 bool kCFUseCollectableAllocator
= false;
877 CF_PRIVATE Boolean __CFProphylacticAutofsAccess
= false;
878 CF_PRIVATE Boolean __CFInitializing
= 0;
879 CF_PRIVATE Boolean __CFInitialized
= 0;
881 // move the next 2 lines down into the #if below, and make it static, after Foundation gets off this symbol on other platforms
882 CF_EXPORT pthread_t _CFMainPThread
;
883 pthread_t _CFMainPThread
= kNilPthreadT
;
884 #if DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_IPHONESIMULATOR
886 CF_EXPORT pthread_t
_CF_pthread_main_thread_np(void);
887 pthread_t
_CF_pthread_main_thread_np(void) {
888 return _CFMainPThread
;
890 #define pthread_main_thread_np() _CF_pthread_main_thread_np()
894 #if DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD
895 static void __CFInitialize(void) __attribute__ ((constructor
));
898 #if DEPLOYMENT_TARGET_WINDOWS
901 void __CFInitialize(void) {
903 if (!__CFInitialized
&& !__CFInitializing
) {
904 __CFInitializing
= 1;
906 #if DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_IPHONESIMULATOR
907 if (!pthread_main_np()) HALT
; // CoreFoundation must be initialized on the main thread
909 // move this next line up into the #if above after Foundation gets off this symbol
910 _CFMainPThread
= pthread_self();
912 #if DEPLOYMENT_TARGET_WINDOWS
913 // Must not call any CF functions
914 __CFTSDWindowsInitialize();
915 #elif DEPLOYMENT_TARGET_LINUX
916 __CFTSDLinuxInitialize();
919 __CFProphylacticAutofsAccess
= true;
921 for (CFIndex idx
= 0; idx
< sizeof(__CFEnv
) / sizeof(__CFEnv
[0]); idx
++) {
922 __CFEnv
[idx
].value
= __CFEnv
[idx
].name
? getenv(__CFEnv
[idx
].name
) : NULL
;
925 #if !defined(kCFUseCollectableAllocator)
926 kCFUseCollectableAllocator
= objc_collectingEnabled();
928 if (kCFUseCollectableAllocator
) {
929 #if !defined(__CFObjCIsCollectable)
930 __CFObjCIsCollectable
= (bool (*)(void *))objc_isAuto
;
933 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
935 __CFStringGetUserDefaultEncoding(&s
, &r
); // force the potential setenv to occur early
936 pthread_atfork(__01121__
, NULL
, __01123__
);
940 memset(__CFRuntimeClassTable
, 0, sizeof(__CFRuntimeClassTable
));
941 memset(__CFRuntimeObjCClassTable
, 0, sizeof(__CFRuntimeObjCClassTable
));
944 /* Here so that two runtime classes get indices 0, 1. */
945 __kCFNotATypeTypeID
= _CFRuntimeRegisterClass(&__CFNotATypeClass
);
946 __kCFTypeTypeID
= _CFRuntimeRegisterClass(&__CFTypeClass
);
948 /* Here so that __kCFAllocatorTypeID gets index 2. */
949 __CFAllocatorInitialize();
951 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
954 char **args
= *_NSGetArgv();
956 for (idx
= 1; idx
< cnt
- 1; idx
++) {
957 if (NULL
== args
[idx
]) continue;
958 if (0 == strcmp(args
[idx
], "-AppleLanguages") && args
[idx
+ 1]) {
959 CFIndex length
= strlen(args
[idx
+ 1]);
960 __CFAppleLanguages
= malloc(length
+ 1);
961 memmove(__CFAppleLanguages
, args
[idx
+ 1], length
+ 1);
969 CFBasicHashGetTypeID();
972 for (CFIndex idx
= 0; idx
< NUM_EXTERN_TABLES
; idx
++) {
973 CFBasicHashCallbacks callbacks
= {NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
};
974 __NSRetainCounters
[idx
].table
= CFBasicHashCreate(kCFAllocatorSystemDefault
, kCFBasicHashHasCounts
| kCFBasicHashLinearHashing
| kCFBasicHashAggressiveGrowth
, &callbacks
);
975 CFBasicHashSetCapacity(__NSRetainCounters
[idx
].table
, 40);
976 __NSRetainCounters
[idx
].lock
= CFLockInit
;
979 /*** _CFRuntimeCreateInstance() can finally be called generally after this line. ***/
981 __CFRuntimeClassTableCount
= 7;
982 __CFStringInitialize(); // CFString's TypeID must be 0x7, now and forever
984 __CFRuntimeClassTableCount
= 16;
985 CFNullGetTypeID(); // See above for hard-coding of this position
986 CFSetGetTypeID(); // See above for hard-coding of this position
987 CFDictionaryGetTypeID(); // See above for hard-coding of this position
988 CFArrayGetTypeID(); // See above for hard-coding of this position
989 CFDataGetTypeID(); // See above for hard-coding of this position
990 CFBooleanGetTypeID(); // See above for hard-coding of this position
991 CFNumberGetTypeID(); // See above for hard-coding of this position
993 CFBinaryHeapGetTypeID();
994 CFBitVectorGetTypeID();
995 __CFCharacterSetInitialize();
996 CFStorageGetTypeID();
1001 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS
1002 CFBundleGetTypeID();
1003 __CFPFactoryInitialize();
1005 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
1006 __CFPlugInInitialize();
1007 CFPlugInInstanceGetTypeID();
1010 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI || DEPLOYMENT_TARGET_WINDOWS
1011 CFMessagePortGetTypeID();
1013 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
1014 CFMachPortGetTypeID();
1016 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS
1017 __CFStreamInitialize();
1019 #if DEPLOYMENT_TARGET_WINDOWS
1020 CFWindowsNamedPipeGetTypeID();
1025 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI || DEPLOYMENT_TARGET_WINDOWS
1026 CFRunLoopGetTypeID();
1027 CFRunLoopObserverGetTypeID();
1028 CFRunLoopSourceGetTypeID();
1029 CFRunLoopTimerGetTypeID();
1031 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX
1032 CFTimeZoneGetTypeID();
1033 CFCalendarGetTypeID();
1034 #if DEPLOYMENT_TARGET_LINUX
1035 CFTimeZoneGetTypeID();
1036 CFCalendarGetTypeID();
1041 CFIndex idx
, cnt
= 0;
1043 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
1044 args
= *_NSGetArgv();
1045 cnt
= *_NSGetArgc();
1046 #elif DEPLOYMENT_TARGET_WINDOWS
1047 wchar_t *commandLine
= GetCommandLineW();
1048 // result is actually pointer to wchar_t *, make sure to account for that below
1049 args
= (char **)CommandLineToArgvW(commandLine
, (int *)&cnt
);
1052 CFStringRef
*list
, buffer
[256];
1053 list
= (cnt
<= 256) ? buffer
: (CFStringRef
*)malloc(cnt
* sizeof(CFStringRef
));
1054 for (idx
= 0, count
= 0; idx
< cnt
; idx
++) {
1055 if (NULL
== args
[idx
]) continue;
1056 #if DEPLOYMENT_TARGET_WINDOWS
1057 list
[count
] = CFStringCreateWithCharacters(kCFAllocatorSystemDefault
, (const UniChar
*)args
[idx
], wcslen((wchar_t *)args
[idx
]));
1059 list
[count
] = CFStringCreateWithCString(kCFAllocatorSystemDefault
, args
[idx
], kCFStringEncodingUTF8
);
1060 if (NULL
== list
[count
]) {
1061 list
[count
] = CFStringCreateWithCString(kCFAllocatorSystemDefault
, args
[idx
], kCFStringEncodingISOLatin1
);
1062 // We CANNOT use the string SystemEncoding here;
1063 // Do not argue: it is not initialized yet, but these
1064 // arguments MUST be initialized before it is.
1065 // We should just ignore the argument if the UTF-8
1066 // conversion fails, but out of charity we try once
1067 // more with ISO Latin1, a standard unix encoding.
1070 if (NULL
!= list
[count
]) count
++;
1072 __CFArgStuff
= CFArrayCreate(kCFAllocatorSystemDefault
, (const void **)list
, count
, &kCFTypeArrayCallBacks
);
1073 if (list
!= buffer
) free(list
);
1074 #if DEPLOYMENT_TARGET_WINDOWS
1079 _CFProcessPath(); // cache this early
1084 if (__CFRuntimeClassTableCount
< 256) __CFRuntimeClassTableCount
= 256;
1087 #if defined(DEBUG) || defined(ENABLE_ZOMBIES)
1088 const char *value
= __CFgetenv("NSZombieEnabled");
1089 if (value
&& (*value
== 'Y' || *value
== 'y')) _CFEnableZombies();
1090 value
= __CFgetenv("NSDeallocateZombies");
1091 if (value
&& (*value
== 'Y' || *value
== 'y')) __CFDeallocateZombies
= 0xff;
1094 #if defined(DEBUG) && (DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED)
1095 CFLog(kCFLogLevelWarning
, CFSTR("Assertions enabled"));
1098 __CFProphylacticAutofsAccess
= false;
1099 __CFInitializing
= 0;
1100 __CFInitialized
= 1;
1105 #if DEPLOYMENT_TARGET_WINDOWS
1107 CF_PRIVATE
void __CFStringCleanup(void);
1108 CF_PRIVATE
void __CFSocketCleanup(void);
1109 CF_PRIVATE
void __CFUniCharCleanup(void);
1110 CF_PRIVATE
void __CFStreamCleanup(void);
1112 static CFBundleRef
RegisterCoreFoundationBundle(void) {
1114 // might be nice to get this from the project file at some point
1115 wchar_t *DLLFileName
= (wchar_t *)L
"CoreFoundation_debug.dll";
1117 wchar_t *DLLFileName
= (wchar_t *)L
"CoreFoundation.dll";
1119 wchar_t path
[MAX_PATH
+1];
1120 path
[0] = path
[1] = 0;
1123 HMODULE ourModule
= GetModuleHandleW(DLLFileName
);
1125 CFAssert(ourModule
, __kCFLogAssertion
, "GetModuleHandle failed");
1127 wResult
= GetModuleFileNameW(ourModule
, path
, MAX_PATH
+1);
1128 CFAssert1(wResult
> 0, __kCFLogAssertion
, "GetModuleFileName failed: %d", GetLastError());
1129 CFAssert1(wResult
< MAX_PATH
+1, __kCFLogAssertion
, "GetModuleFileName result truncated: %s", path
);
1131 // strip off last component, the DLL name
1132 for (idx
= wResult
- 1; idx
; idx
--) {
1133 if ('\\' == path
[idx
]) {
1139 CFStringRef fsPath
= CFStringCreateWithCharacters(kCFAllocatorSystemDefault
, (UniChar
*)path
, idx
);
1140 CFURLRef dllURL
= CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault
, fsPath
, kCFURLWindowsPathStyle
, TRUE
);
1141 CFURLRef bundleURL
= CFURLCreateCopyAppendingPathComponent(kCFAllocatorSystemDefault
, dllURL
, CFSTR("CoreFoundation.resources"), TRUE
);
1145 // this registers us so subsequent calls to CFBundleGetBundleWithIdentifier will succeed
1146 CFBundleRef bundle
= CFBundleCreate(kCFAllocatorSystemDefault
, bundleURL
);
1147 CFRelease(bundleURL
);
1153 #define DLL_PROCESS_ATTACH 1
1154 #define DLL_THREAD_ATTACH 2
1155 #define DLL_THREAD_DETACH 3
1156 #define DLL_PROCESS_DETACH 0
1158 int DllMain( HINSTANCE hInstance
, DWORD dwReason
, LPVOID pReserved
) {
1159 static CFBundleRef cfBundle
= NULL
;
1160 if (dwReason
== DLL_PROCESS_ATTACH
) {
1162 cfBundle
= RegisterCoreFoundationBundle();
1163 } else if (dwReason
== DLL_PROCESS_DETACH
&& pReserved
== 0) {
1164 // Only cleanup if we are being unloaded dynamically (pReserved == 0) <rdar://problem/7480873>
1165 __CFStreamCleanup();
1166 __CFSocketCleanup();
1167 __CFUniCharCleanup();
1169 #if DEPLOYMENT_TARGET_WINDOWS
1170 // No CF functions should access TSD after this is called
1171 __CFTSDWindowsCleanup();
1175 if (cfBundle
) CFRelease(cfBundle
);
1176 __CFStringCleanup();
1177 } else if (dwReason
== DLL_THREAD_DETACH
) {
1178 __CFFinalizeWindowsThreadData();
1185 #if __CF_BIG_ENDIAN__
1186 #define RC_INCREMENT (1ULL)
1187 #define RC_MASK (0xFFFFFFFFULL)
1188 #define RC_GET(V) ((V) & RC_MASK)
1189 #define RC_DEALLOCATING_BIT (0x400000ULL << 32)
1190 #define RC_DEALLOCATED_BIT (0x200000ULL << 32)
1192 #define RC_INCREMENT (1ULL << 32)
1193 #define RC_MASK (0xFFFFFFFFULL << 32)
1194 #define RC_GET(V) (((V) & RC_MASK) >> 32)
1195 #define RC_DEALLOCATING_BIT (0x400000ULL)
1196 #define RC_DEALLOCATED_BIT (0x200000ULL)
1199 #if !DEPLOYMENT_TARGET_WINDOWS && __LP64__
1200 static bool (*CAS64
)(int64_t, int64_t, volatile int64_t *) = OSAtomicCompareAndSwap64Barrier
;
1202 static bool (*CAS32
)(int32_t, int32_t, volatile int32_t *) = OSAtomicCompareAndSwap32Barrier
;
1205 // For "tryR==true", a return of NULL means "failed".
1206 static CFTypeRef
_CFRetain(CFTypeRef cf
, Boolean tryR
) {
1207 uint32_t cfinfo
= *(uint32_t *)&(((CFRuntimeBase
*)cf
)->_cfinfo
);
1208 if (cfinfo
& 0x800000) { // custom ref counting for object
1209 if (tryR
) return NULL
;
1210 CFTypeID typeID
= (cfinfo
>> 8) & 0x03FF; // mask up to 0x0FFF
1211 CFRuntimeClass
*cfClass
= __CFRuntimeClassTable
[typeID
];
1212 uint32_t (*refcount
)(intptr_t, CFTypeRef
) = cfClass
->refcount
;
1213 if (!refcount
|| !(cfClass
->version
& _kCFRuntimeCustomRefCount
) || (((CFRuntimeBase
*)cf
)->_cfinfo
[CF_RC_BITS
] != 0xFF)) {
1214 HALT
; // bogus object
1217 if (((CFRuntimeBase
*)cf
)->_rc
!= 0xFFFFFFFFU
) {
1218 HALT
; // bogus object
1225 Boolean didAuto
= false;
1226 if (tryR
&& (cfinfo
& (0x400000 | 0x200000))) return NULL
; // deallocating or deallocated
1228 if (0 == ((CFRuntimeBase
*)cf
)->_rc
&& !CF_IS_COLLECTABLE(cf
)) return cf
; // Constant CFTypeRef
1229 #if !DEPLOYMENT_TARGET_WINDOWS
1232 allBits
= *(uint64_t *)&(((CFRuntimeBase
*)cf
)->_cfinfo
);
1233 if (tryR
&& (allBits
& RC_DEALLOCATING_BIT
)) return NULL
;
1234 } while (!CAS64(allBits
, allBits
+ RC_INCREMENT
, (int64_t *)&((CFRuntimeBase
*)cf
)->_cfinfo
));
1235 // GC: 0 --> 1 transition? then add a GC retain count, to root the object. we'll remove it on the 1 --> 0 transition.
1236 if (RC_GET(allBits
) == 0 && CF_IS_COLLECTABLE(cf
)) {
1237 auto_zone_retain(objc_collectableZone(), (void*)cf
);
1243 lowBits
= ((CFRuntimeBase
*)cf
)->_rc
;
1244 } while (!CAS32(lowBits
, lowBits
+ 1, (int32_t *)&((CFRuntimeBase
*)cf
)->_rc
));
1245 // GC: 0 --> 1 transition? then add a GC retain count, to root the object. we'll remove it on the 1 --> 0 transition.
1246 if (lowBits
== 0 && CF_IS_COLLECTABLE(cf
)) {
1247 auto_zone_retain(objc_collectableZone(), (void*)cf
);
1254 CFIndex rcLowBits
= __CFBitfieldGetValue(cfinfo
, RC_END
, RC_START
);
1255 if (__builtin_expect(0 == rcLowBits
, 0) && !CF_IS_COLLECTABLE(cf
)) return cf
; // Constant CFTypeRef
1256 volatile uint32_t *infoLocation
= (uint32_t *)&(((CFRuntimeBase
*)cf
)->_cfinfo
);
1259 cfinfo
= *infoLocation
;
1260 #if !DEPLOYMENT_TARGET_WINDOWS
1261 // if already deallocating, don't allow new retain
1262 if (tryR
&& (cfinfo
& 0x400000)) return NULL
;
1264 uint32_t prospectiveNewInfo
= cfinfo
; // don't want compiler to generate prospectiveNewInfo = *infoLocation. This is why infoLocation is declared as a pointer to volatile memory.
1265 prospectiveNewInfo
+= (1 << RC_START
);
1266 rcLowBits
= __CFBitfieldGetValue(prospectiveNewInfo
, RC_END
, RC_START
);
1267 if (__builtin_expect((rcLowBits
& 0x7f) == 0, 0)) {
1268 /* Roll over another bit to the external ref count
1269 Real ref count = low 7 bits of info[CF_RC_BITS] + external ref count << 6
1270 Bit 8 of low bits indicates that external ref count is in use.
1271 External ref count is shifted by 6 rather than 7 so that we can set the low
1272 bits to to 1100 0000 rather than 1000 0000.
1273 This prevents needing to access the external ref count for successive retains and releases
1274 when the composite retain count is right around a multiple of 1 << 7.
1276 prospectiveNewInfo
= cfinfo
;
1277 __CFBitfieldSetValue(prospectiveNewInfo
, RC_END
, RC_START
, ((1 << 7) | (1 << 6)));
1278 __CFLock(&__CFRuntimeExternRefCountTableLock
);
1279 success
= CAS32(*(int32_t *)& cfinfo
, *(int32_t *)&prospectiveNewInfo
, (int32_t *)infoLocation
);
1280 if (__builtin_expect(success
, 1)) {
1281 __CFDoExternRefOperation(350, (id
)cf
);
1283 __CFUnlock(&__CFRuntimeExternRefCountTableLock
);
1285 success
= CAS32(*(int32_t *)& cfinfo
, *(int32_t *)&prospectiveNewInfo
, (int32_t *)infoLocation
);
1286 // XXX_PCB: 0 --> 1 transition? then add a GC retain count, to root the object. we'll remove it on the 1 --> 0 transition.
1287 if (success
&& __CFBitfieldGetValue(cfinfo
, RC_END
, RC_START
) == 0 && CF_IS_COLLECTABLE(cf
)) {
1288 auto_zone_retain(objc_collectableZone(), (void*)cf
);
1292 } while (__builtin_expect(!success
, 0));
1294 if (!didAuto
&& __builtin_expect(__CFOASafe
, 0)) {
1295 __CFRecordAllocationEvent(__kCFRetainEvent
, (void *)cf
, 0, CFGetRetainCount(cf
), NULL
);
1300 // Never called under GC, only called via ARR weak subsystem; a return of NULL is failure
1301 CFTypeRef
_CFTryRetain(CFTypeRef cf
) {
1302 if (NULL
== cf
) return NULL
;
1303 #if OBJC_HAVE_TAGGED_POINTERS
1304 if (_objc_isTaggedPointer(cf
)) return cf
; // success
1306 return _CFRetain(cf
, true);
1309 Boolean
_CFIsDeallocating(CFTypeRef cf
) {
1310 if (NULL
== cf
) return false;
1311 #if OBJC_HAVE_TAGGED_POINTERS
1312 if (_objc_isTaggedPointer(cf
)) return false;
1314 uint32_t cfinfo
= *(uint32_t *)&(((CFRuntimeBase
*)cf
)->_cfinfo
);
1315 if (cfinfo
& 0x800000) { // custom ref counting for object
1316 return true; // lie for now; this weak references to these objects cannot be formed
1318 return (cfinfo
& 0x400000) ? true : false;
1321 static void _CFRelease(CFTypeRef cf
) {
1323 uint32_t cfinfo
= *(uint32_t *)&(((CFRuntimeBase
*)cf
)->_cfinfo
);
1324 if (cfinfo
& 0x200000) return; // deallocated, or not a cf object
1325 CFTypeID typeID
= (cfinfo
>> 8) & 0x03FF; // mask up to 0x0FFF
1326 if (cfinfo
& 0x800000) { // custom ref counting for object
1327 CFRuntimeClass
*cfClass
= __CFRuntimeClassTable
[typeID
];
1328 uint32_t (*refcount
)(intptr_t, CFTypeRef
) = cfClass
->refcount
;
1329 if (!refcount
|| !(cfClass
->version
& _kCFRuntimeCustomRefCount
) || (((CFRuntimeBase
*)cf
)->_cfinfo
[CF_RC_BITS
] != 0xFF)) {
1330 HALT
; // bogus object
1333 if (((CFRuntimeBase
*)cf
)->_rc
!= 0xFFFFFFFFU
) {
1334 HALT
; // bogus object
1341 CFIndex start_rc
= __builtin_expect(__CFOASafe
, 0) ? CFGetRetainCount(cf
) : 0;
1342 Boolean isAllocator
= (__kCFAllocatorTypeID_CONST
== typeID
);
1343 Boolean didAuto
= false;
1345 #if !DEPLOYMENT_TARGET_WINDOWS
1350 allBits
= *(uint64_t *)&(((CFRuntimeBase
*)cf
)->_cfinfo
);
1351 lowBits
= RC_GET(allBits
);
1353 if (CF_IS_COLLECTABLE(cf
)) auto_zone_release(objc_collectableZone(), (void*)cf
);
1354 return; // Constant CFTypeRef
1357 CFRuntimeClass
*cfClass
= __CFRuntimeClassTable
[typeID
];
1358 if ((cfClass
->version
& _kCFRuntimeResourcefulObject
) && cfClass
->reclaim
!= NULL
) {
1359 cfClass
->reclaim(cf
);
1361 if (!CF_IS_COLLECTABLE(cf
)) {
1362 uint64_t newAllBits
= allBits
| RC_DEALLOCATING_BIT
;
1363 if (!CAS64(allBits
, newAllBits
, (int64_t *)&((CFRuntimeBase
*)cf
)->_cfinfo
)) {
1366 void (*func
)(CFTypeRef
) = __CFRuntimeClassTable
[typeID
]->finalize
;
1370 // Any further ref-count changes after this point are operating on a finalized object
1371 allBits
= *(uint64_t *)&(((CFRuntimeBase
*)cf
)->_cfinfo
);
1372 lowBits
= RC_GET(allBits
);
1373 if (isAllocator
|| (1 == lowBits
)) {
1374 do { // hammer until it takes; trying to retain the object on another thread at this point? too late!
1375 allBits
= *(uint64_t *)&(((CFRuntimeBase
*)cf
)->_cfinfo
);
1376 } while (!CAS64(allBits
, (allBits
| RC_DEALLOCATED_BIT
) - RC_INCREMENT
, (int64_t *)&((CFRuntimeBase
*)cf
)->_cfinfo
));
1379 Boolean success
= false;
1380 do { // drop the deallocating bit; racey, but this resurrection stuff isn't thread-safe anyway
1381 allBits
= *(uint64_t *)&(((CFRuntimeBase
*)cf
)->_cfinfo
);
1382 uint64_t newAllBits
= allBits
& ~RC_DEALLOCATING_BIT
;
1383 success
= CAS64(allBits
, newAllBits
, (int64_t *)&((CFRuntimeBase
*)cf
)->_cfinfo
);
1385 goto again
; // still need to have the effect of a CFRelease
1388 } while (!CAS64(allBits
, allBits
- RC_INCREMENT
, (int64_t *)&((CFRuntimeBase
*)cf
)->_cfinfo
));
1389 if (lowBits
== 1 && CF_IS_COLLECTABLE(cf
)) {
1390 // GC: release the collector's hold over the object, which will call the finalize function later on.
1391 auto_zone_release(objc_collectableZone(), (void*)cf
);
1397 lowBits
= ((CFRuntimeBase
*)cf
)->_rc
;
1399 if (CF_IS_COLLECTABLE(cf
)) auto_zone_release(objc_collectableZone(), (void*)cf
);
1400 return; // Constant CFTypeRef
1403 // CANNOT WRITE ANY NEW VALUE INTO [CF_RC_BITS] UNTIL AFTER FINALIZATION
1404 CFRuntimeClass
*cfClass
= __CFRuntimeClassTable
[typeID
];
1405 if ((cfClass
->version
& _kCFRuntimeResourcefulObject
) && cfClass
->reclaim
!= NULL
) {
1406 cfClass
->reclaim(cf
);
1408 if (!CF_IS_COLLECTABLE(cf
)) {
1409 void (*func
)(CFTypeRef
) = __CFRuntimeClassTable
[typeID
]->finalize
;
1413 if (isAllocator
|| CAS32(1, 0, (int32_t *)&((CFRuntimeBase
*)cf
)->_rc
)) {
1418 } while (!CAS32(lowBits
, lowBits
- 1, (int32_t *)&((CFRuntimeBase
*)cf
)->_rc
));
1419 if (lowBits
== 1 && CF_IS_COLLECTABLE(cf
)) {
1420 // GC: release the collector's hold over the object, which will call the finalize function later on.
1421 auto_zone_release(objc_collectableZone(), (void*)cf
);
1426 #if !DEPLOYMENT_TARGET_WINDOWS
1428 volatile uint32_t *infoLocation
= (uint32_t *)&(((CFRuntimeBase
*)cf
)->_cfinfo
);
1429 CFIndex rcLowBits
= __CFBitfieldGetValue(cfinfo
, RC_END
, RC_START
);
1430 if (0 == rcLowBits
) {
1431 if (CF_IS_COLLECTABLE(cf
)) auto_zone_release(objc_collectableZone(), (void*)cf
);
1432 return; // Constant CFTypeRef
1435 Boolean whack
= false;
1437 cfinfo
= *infoLocation
;
1438 rcLowBits
= __CFBitfieldGetValue(cfinfo
, RC_END
, RC_START
);
1439 if (1 == rcLowBits
) {
1440 // we think cf should be deallocated
1441 uint32_t prospectiveNewInfo
= cfinfo
| (0x400000);
1442 if (CF_IS_COLLECTABLE(cf
)) {
1443 prospectiveNewInfo
-= (1 << RC_START
);
1445 success
= CAS32(*(int32_t *)& cfinfo
, *(int32_t *)&prospectiveNewInfo
, (int32_t *)infoLocation
);
1446 if (success
) whack
= true;
1449 uint32_t prospectiveNewInfo
= cfinfo
; // don't want compiler to generate prospectiveNewInfo = *infoLocation. This is why infoLocation is declared as a pointer to volatile memory.
1450 if ((1 << 7) == rcLowBits
) {
1451 // Time to remove a bit from the external ref count
1452 __CFLock(&__CFRuntimeExternRefCountTableLock
);
1453 CFIndex rcHighBitsCnt
= __CFDoExternRefOperation(500, (id
)cf
);
1454 if (1 == rcHighBitsCnt
) {
1455 __CFBitfieldSetValue(prospectiveNewInfo
, RC_END
, RC_START
, (1 << 6) - 1);
1457 __CFBitfieldSetValue(prospectiveNewInfo
, RC_END
, RC_START
, ((1 << 6) | (1 << 7)) - 1);
1459 success
= CAS32(*(int32_t *)& cfinfo
, *(int32_t *)&prospectiveNewInfo
, (int32_t *)infoLocation
);
1461 __CFDoExternRefOperation(450, (id
)cf
);
1463 __CFUnlock(&__CFRuntimeExternRefCountTableLock
);
1465 prospectiveNewInfo
-= (1 << RC_START
);
1466 success
= CAS32(*(int32_t *)& cfinfo
, *(int32_t *)&prospectiveNewInfo
, (int32_t *)infoLocation
);
1472 CFRuntimeClass
*cfClass
= __CFRuntimeClassTable
[typeID
];
1473 if ((cfClass
->version
& _kCFRuntimeResourcefulObject
) && cfClass
->reclaim
!= NULL
) {
1474 cfClass
->reclaim(cf
);
1476 if (CF_IS_COLLECTABLE(cf
)) {
1477 // GC: release the collector's hold over the object, which will call the finalize function later on.
1478 auto_zone_release(objc_collectableZone(), (void*)cf
);
1484 void (*func
)(CFTypeRef
) = __CFRuntimeClassTable
[typeID
]->finalize
;
1488 // Any further ref-count changes after this point are operating on a finalized object
1489 rcLowBits
= __CFBitfieldGetValue(*infoLocation
, RC_END
, RC_START
);
1490 if (1 == rcLowBits
) {
1491 do { // hammer until it takes; trying to retain the object on another thread at this point? too late!
1492 cfinfo
= *infoLocation
;
1493 } while (!CAS32(cfinfo
, cfinfo
| 0x200000, (int32_t *)infoLocation
));
1496 do { // drop the deallocating bit; racey, but this resurrection stuff isn't thread-safe anyway
1497 cfinfo
= *infoLocation
;
1498 uint32_t prospectiveNewInfo
= (cfinfo
& ~(0x400000));
1499 success
= CAS32(*(int32_t *)& cfinfo
, *(int32_t *)&prospectiveNewInfo
, (int32_t *)infoLocation
);
1506 volatile uint32_t *infoLocation
= (uint32_t *)&(((CFRuntimeBase
*)cf
)->_cfinfo
);
1507 CFIndex rcLowBits
= __CFBitfieldGetValue(*infoLocation
, RC_END
, RC_START
);
1508 if (0 == rcLowBits
) {
1509 if (CF_IS_COLLECTABLE(cf
)) auto_zone_release(objc_collectableZone(), (void*)cf
);
1510 return; // Constant CFTypeRef
1514 uint32_t initialCheckInfo
= *infoLocation
;
1515 rcLowBits
= __CFBitfieldGetValue(initialCheckInfo
, RC_END
, RC_START
);
1516 if (1 == rcLowBits
) {
1517 // we think cf should be deallocated
1518 // CANNOT WRITE ANY NEW VALUE INTO [CF_RC_BITS] UNTIL AFTER FINALIZATION
1519 CFRuntimeClass
*cfClass
= __CFRuntimeClassTable
[typeID
];
1520 if ((cfClass
->version
& _kCFRuntimeResourcefulObject
) && cfClass
->reclaim
!= NULL
) {
1521 cfClass
->reclaim(cf
);
1523 if (CF_IS_COLLECTABLE(cf
)) {
1524 uint32_t prospectiveNewInfo
= initialCheckInfo
- (1 << RC_START
);
1525 success
= CAS32(*(int32_t *)&initialCheckInfo
, *(int32_t *)&prospectiveNewInfo
, (int32_t *)infoLocation
);
1526 // GC: release the collector's hold over the object, which will call the finalize function later on.
1528 auto_zone_release(objc_collectableZone(), (void*)cf
);
1535 void (*func
)(CFTypeRef
) = __CFRuntimeClassTable
[typeID
]->finalize
;
1539 // We recheck rcLowBits to see if the object has been retained again during
1540 // the finalization process. This allows for the finalizer to resurrect,
1541 // but the main point is to allow finalizers to be able to manage the
1542 // removal of objects from uniquing caches, which may race with other threads
1543 // which are allocating (looking up and finding) objects from those caches,
1544 // which (that thread) would be the thing doing the extra retain in that case.
1545 rcLowBits
= __CFBitfieldGetValue(*infoLocation
, RC_END
, RC_START
);
1546 success
= (1 == rcLowBits
);
1554 uint32_t prospectiveNewInfo
= initialCheckInfo
; // don't want compiler to generate prospectiveNewInfo = *infoLocation. This is why infoLocation is declared as a pointer to volatile memory.
1555 if ((1 << 7) == rcLowBits
) {
1556 // Time to remove a bit from the external ref count
1557 __CFLock(&__CFRuntimeExternRefCountTableLock
);
1558 CFIndex rcHighBitsCnt
= __CFDoExternRefOperation(500, (id
)cf
);
1559 if (1 == rcHighBitsCnt
) {
1560 __CFBitfieldSetValue(prospectiveNewInfo
, RC_END
, RC_START
, (1 << 6) - 1);
1562 __CFBitfieldSetValue(prospectiveNewInfo
, RC_END
, RC_START
, ((1 << 6) | (1 << 7)) - 1);
1564 success
= CAS32(*(int32_t *)&initialCheckInfo
, *(int32_t *)&prospectiveNewInfo
, (int32_t *)infoLocation
);
1566 __CFDoExternRefOperation(450, (id
)cf
);
1568 __CFUnlock(&__CFRuntimeExternRefCountTableLock
);
1570 prospectiveNewInfo
-= (1 << RC_START
);
1571 success
= CAS32(*(int32_t *)&initialCheckInfo
, *(int32_t *)&prospectiveNewInfo
, (int32_t *)infoLocation
);
1577 if (!didAuto
&& __builtin_expect(__CFOASafe
, 0)) {
1578 __CFRecordAllocationEvent(__kCFReleaseEvent
, (void *)cf
, 0, start_rc
- 1, NULL
);
1583 if (!didAuto
&& __builtin_expect(__CFOASafe
, 0)) {
1584 // do not use CFGetRetainCount() because cf has been freed if it was an allocator
1585 __CFRecordAllocationEvent(__kCFReleaseEvent
, (void *)cf
, 0, 0, NULL
);
1587 // cannot zombify allocators, which get deallocated by __CFAllocatorDeallocate (finalize)
1589 __CFAllocatorDeallocate((void *)cf
);
1591 CFAllocatorRef allocator
= kCFAllocatorSystemDefault
;
1592 Boolean usesSystemDefaultAllocator
= true;
1594 if (!__CFBitfieldGetValue(((const CFRuntimeBase
*)cf
)->_cfinfo
[CF_INFO_BITS
], 7, 7)) {
1595 allocator
= CFGetAllocator(cf
);
1596 usesSystemDefaultAllocator
= _CFAllocatorIsSystemDefault(allocator
);
1600 CFAllocatorDeallocate(allocator
, (uint8_t *)cf
- (usesSystemDefaultAllocator
? 0 : sizeof(CFAllocatorRef
)));
1603 if (kCFAllocatorSystemDefault
!= allocator
) {
1604 CFRelease(allocator
);
1609 #undef __kCFAllocatorTypeID_CONST
1610 #undef __CFGenericAssertIsCF