]> git.saurik.com Git - apple/cf.git/blob - CFRuntime.c
CF-1153.18.tar.gz
[apple/cf.git] / 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 <string.h>
35 #include <stdlib.h>
36 #include <stdio.h>
37 #include <CoreFoundation/CFUUID.h>
38 #include <CoreFoundation/CFCalendar.h>
39 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
40 #include <dlfcn.h>
41 #include <mach-o/dyld.h>
42 #include <mach/mach.h>
43 #include <crt_externs.h>
44 #include <unistd.h>
45 #include <sys/stat.h>
46 #include <CoreFoundation/CFStringDefaultEncoding.h>
47 #endif
48 #if DEPLOYMENT_TARGET_EMBEDDED
49 // This isn't in the embedded runtime.h header
50 OBJC_EXPORT void *objc_destructInstance(id obj);
51 #endif
52
53
54 #if DEPLOYMENT_TARGET_WINDOWS
55 #include <Shellapi.h>
56 #endif
57
58 enum {
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
63 };
64
65 #if DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX
66 #include <malloc.h>
67 #else
68 #include <malloc/malloc.h>
69 #endif
70
71 #define FAKE_INSTRUMENTS 0
72
73 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
74 CF_PRIVATE void __CFOAInitializeNSObject(void); // from NSObject.m
75
76 bool __CFOASafe = false;
77
78 void (*__CFObjectAllocRecordAllocationFunction)(int, void *, int64_t , uint64_t, const char *) = NULL;
79 void (*__CFObjectAllocSetLastAllocEventNameFunction)(void *, const char *) = NULL;
80
81 void __CFOAInitialize(void) {
82 }
83
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);
87 }
88
89 void __CFSetLastAllocationEventName(void *ptr, const char *classname) {
90 if (!__CFOASafe || !__CFObjectAllocSetLastAllocEventNameFunction) return;
91 __CFObjectAllocSetLastAllocEventNameFunction(ptr, classname);
92 }
93
94 #elif FAKE_INSTRUMENTS
95
96 CF_EXPORT bool __CFOASafe = true;
97
98 void __CFOAInitialize(void) { }
99
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";
104 switch (eventnum) {
105 case 21:
106 event = "zombie";
107 break;
108 case 13:
109 case __kCFReleaseEvent:
110 event = "release";
111 break;
112 case 12:
113 case __kCFRetainEvent:
114 event = "retain";
115 break;
116 }
117 fprintf(stdout, "event,%d,%s,%p,%ld,%lu,%s\n", eventnum, event, ptr, (long)size, (unsigned long)data, classname);
118 }
119
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)");
124 }
125
126 #else
127
128 bool __CFOASafe = false;
129
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) { }
133
134 #endif
135
136 extern void __HALT(void);
137
138 static CFTypeID __kCFNotATypeTypeID = _kCFRuntimeNotATypeID;
139
140 #if !defined (__cplusplus)
141 static const CFRuntimeClass __CFNotATypeClass = {
142 0,
143 "Not A Type",
144 (void *)__HALT,
145 (void *)__HALT,
146 (void *)__HALT,
147 (void *)__HALT,
148 (void *)__HALT,
149 (void *)__HALT,
150 (void *)__HALT
151 };
152
153 static CFTypeID __kCFTypeTypeID = _kCFRuntimeNotATypeID;
154
155 static const CFRuntimeClass __CFTypeClass = {
156 0,
157 "CFType",
158 (void *)__HALT,
159 (void *)__HALT,
160 (void *)__HALT,
161 (void *)__HALT,
162 (void *)__HALT,
163 (void *)__HALT,
164 (void *)__HALT
165 };
166 #else
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;};
173
174 static const CFRuntimeClass __CFNotATypeClass = {
175 0,
176 "Not A Type",
177 SIG1,
178 SIG2,
179 SIG1,
180 SIG3,
181 SIG4,
182 SIG5,
183 SIG6
184 };
185
186 static CFTypeID __kCFTypeTypeID = _kCFRuntimeNotATypeID;
187
188 static const CFRuntimeClass __CFTypeClass = {
189 0,
190 "CFType",
191 SIG1,
192 SIG2,
193 SIG1,
194 SIG3,
195 SIG4,
196 SIG5,
197 SIG6
198 };
199 #endif //__cplusplus
200
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;
205
206 CF_PRIVATE uintptr_t __CFRuntimeObjCClassTable[__CFRuntimeClassTableSize] = {0};
207
208 #if !defined(__CFObjCIsCollectable)
209 bool (*__CFObjCIsCollectable)(void *) = NULL;
210 #endif
211
212 #if !__CONSTANT_CFSTRINGS__ || DEPLOYMENT_TARGET_EMBEDDED_MINI
213 // Compiler uses this symbol name; must match compiler built-in decl, so we use 'int'
214 #if __LP64__
215 int __CFConstantStringClassReference[24] = {0};
216 #else
217 int __CFConstantStringClassReference[12] = {0};
218 #endif
219 #endif
220
221 #if __LP64__
222 int __CFConstantStringClassReference[24] = {0};
223 #else
224 int __CFConstantStringClassReference[12] = {0};
225 #endif
226
227 void *__CFConstantStringClassReferencePtr = NULL;
228
229 Boolean _CFIsObjC(CFTypeID typeID, void *obj) {
230 return CF_IS_OBJC(typeID, obj);
231 }
232
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;
238 }
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;
244 }
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;
249 }
250 __CFRuntimeClassTable[__CFRuntimeClassTableCount++] = (CFRuntimeClass *)cls;
251 CFTypeID typeID = __CFRuntimeClassTableCount - 1;
252 __CFUnlock(&__CFBigRuntimeFunnel);
253 return typeID;
254 }
255
256
257 const CFRuntimeClass * _CFRuntimeGetClassWithTypeID(CFTypeID typeID) {
258 return __CFRuntimeClassTable[typeID]; // hopelessly unthreadsafe
259 }
260
261 void _CFRuntimeUnregisterClassWithTypeID(CFTypeID typeID) {
262 __CFLock(&__CFBigRuntimeFunnel);
263 __CFRuntimeClassTable[typeID] = NULL;
264 __CFUnlock(&__CFBigRuntimeFunnel);
265 }
266
267
268 #if defined(DEBUG) || defined(ENABLE_ZOMBIES)
269
270 CF_PRIVATE uint8_t __CFZombieEnabled = 0;
271 CF_PRIVATE uint8_t __CFDeallocateZombies = 0;
272
273 extern void __CFZombifyNSObject(void); // from NSObject.m
274
275 void _CFEnableZombies(void) {
276 }
277
278 #endif /* DEBUG */
279
280 // XXX_PCB: use the class version field as a bitmask, to allow classes to opt-in for GC scanning.
281
282 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
283 CF_INLINE CFOptionFlags CF_GET_COLLECTABLE_MEMORY_TYPE(const CFRuntimeClass *cls)
284 {
285 return ((cls->version & _kCFRuntimeScannedObject) ? __kCFAllocatorGCScannedMemory : 0) | __kCFAllocatorGCObjectMemory;
286 }
287 #else
288 #define CF_GET_COLLECTABLE_MEMORY_TYPE(x) (0)
289 #endif
290
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];
295 if (NULL == cls) {
296 return NULL;
297 }
298 if (cls->version & _kCFRuntimeRequiresAlignment) {
299 allocator = kCFAllocatorSystemDefault;
300 }
301 Boolean customRC = !!(cls->version & _kCFRuntimeCustomRefCount);
302 if (customRC && !cls->refcount) {
303 CFLog(kCFLogLevelWarning, CFSTR("*** _CFRuntimeCreateInstance() found inconsistent class '%s'."), cls->className);
304 return NULL;
305 }
306 CFAllocatorRef realAllocator = (NULL == allocator) ? __CFGetDefaultAllocator() : allocator;
307 if (kCFAllocatorNull == realAllocator) {
308 return NULL;
309 }
310 Boolean usesSystemDefaultAllocator = _CFAllocatorIsSystemDefault(realAllocator);
311 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);
319 } else {
320 memory = (CFRuntimeBase *)CFAllocatorAllocate(allocator, size, CF_GET_COLLECTABLE_MEMORY_TYPE(cls));
321 }
322 if (NULL == memory) {
323 return NULL;
324 }
325 if (!kCFUseCollectableAllocator || !CF_IS_COLLECTABLE_ALLOCATOR(allocator) || !(CF_GET_COLLECTABLE_MEMORY_TYPE(cls) & __kCFAllocatorGCScannedMemory)) {
326 memset(memory, 0, size);
327 }
328 if (__CFOASafe && category) {
329 __CFSetLastAllocationEventName(memory, (char *)category);
330 } else if (__CFOASafe) {
331 __CFSetLastAllocationEventName(memory, (char *)cls->className);
332 }
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));
338 }
339 uint32_t rc = 0;
340 #if __LP64__
341 if (!kCFUseCollectableAllocator || (1 && 1)) {
342 memory->_rc = 1;
343 }
344 if (customRC) {
345 memory->_rc = 0xFFFFFFFFU;
346 rc = 0xFF;
347 }
348 #else
349 if (!kCFUseCollectableAllocator || (1 && 1)) {
350 rc = 1;
351 }
352 if (customRC) {
353 rc = 0xFF;
354 }
355 #endif
356 uint32_t *cfinfop = (uint32_t *)&(memory->_cfinfo);
357 *cfinfop = (uint32_t)((rc << 24) | (customRC ? 0x800000 : 0x0) | ((uint32_t)typeID << 8) | (usesSystemDefaultAllocator ? 0x80 : 0x00));
358 memory->_cfisa = 0;
359 if (NULL != cls->init) {
360 (cls->init)(memory);
361 }
362 return memory;
363 }
364
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);
370 if (customRC) {
371 CFLog(kCFLogLevelError, CFSTR("*** Cannot initialize a static instance to a class (%s) with custom ref counting"), cfClass->className);
372 return;
373 }
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);
377 #if __LP64__
378 memory->_rc = customRC ? 0xFFFFFFFFU : 0x0;
379 #endif
380 memory->_cfisa = 0;
381 if (NULL != cfClass->init) {
382 (cfClass->init)(memory);
383 }
384 }
385
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);
396 return;
397 }
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);
404 }
405
406 CF_PRIVATE void _CFRuntimeSetInstanceTypeIDAndIsa(CFTypeRef cf, CFTypeID newTypeID) {
407 _CFRuntimeSetInstanceTypeID(cf, newTypeID);
408 }
409
410
411 enum {
412 __kCFObjectRetainedEvent = 12,
413 __kCFObjectReleasedEvent = 13
414 };
415
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
422 #else
423 #error
424 #endif
425
426 // we disguise pointers so that programs like 'leaks' forget about these references
427 #define DISGUISE(O) (~(uintptr_t)(O))
428
429 static struct {
430 CFLock_t lock;
431 CFBasicHashRef table;
432 // uint8_t padding[64 - sizeof(CFBasicHashRef) - sizeof(CFLock_t)];
433 } __NSRetainCounters[NUM_EXTERN_TABLES];
434
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;
441 uintptr_t count;
442 switch (op) {
443 case 300: // increment
444 case 350: // increment, no event
445 __CFLock(lock);
446 CFBasicHashAddValue(table, disguised, disguised);
447 __CFUnlock(lock);
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
453 __CFLock(lock);
454 count = (uintptr_t)CFBasicHashRemoveValue(table, disguised);
455 __CFUnlock(lock);
456 return 0 == count;
457 case 500:
458 __CFLock(lock);
459 count = (uintptr_t)CFBasicHashGetCountOfKey(table, disguised);
460 __CFUnlock(lock);
461 return count;
462 }
463 return 0;
464 }
465
466 CF_EXPORT CFTypeID CFNumberGetTypeID(void);
467
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
472 return typeID;
473 }
474
475 CFTypeID __CFGenericTypeID(const void *cf) {
476 return __CFGenericTypeID_inline(cf);
477 }
478
479 CFTypeID CFTypeGetTypeID(void) {
480 return __kCFTypeTypeID;
481 }
482
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); \
487 }
488
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);
491
492
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)
496
497
498 CFTypeID CFGetTypeID(CFTypeRef cf) {
499 #if defined(DEBUG)
500 if (NULL == cf) { CRSetCrashLogMessage("*** CFGetTypeID() called with NULL ***"); HALT; }
501 #endif
502 CFTYPE_OBJC_FUNCDISPATCH0(CFTypeID, cf, _cfTypeID);
503 __CFGenericAssertIsCF(cf);
504 return __CFGenericTypeID_inline(cf);
505 }
506
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);
510 }
511
512 // Bit 31 (highest bit) in second word of cf instance indicates external ref count
513
514 static CFTypeRef _CFRetain(CFTypeRef cf, Boolean tryR);
515
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);
520 }
521
522 CFTypeRef CFAutorelease(CFTypeRef __attribute__((cf_consumed)) cf) {
523 if (NULL == cf) { CRSetCrashLogMessage("*** CFAutorelease() called with NULL ***"); HALT; }
524 return cf;
525 }
526
527 static void _CFRelease(CFTypeRef cf);
528
529 void CFRelease(CFTypeRef cf) {
530 if (NULL == cf) { CRSetCrashLogMessage("*** CFRelease() called with NULL ***"); HALT; }
531 #if 0
532 void **addrs[2] = {&&start, &&end};
533 start:;
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]);
536 HALT;
537 }
538 #endif
539 if (cf) __CFGenericAssertIsCF(cf);
540 _CFRelease(cf);
541 #if 0
542 end:;
543 #endif
544 }
545
546
547 CF_PRIVATE void __CFAllocatorDeallocate(CFTypeRef cf);
548
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);
555 }
556 return (const void *)result;
557 }
558
559 extern void CFCollection_non_gc_storage_error(void);
560
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.
572 CFRetain(cf);
573 }
574 else
575 ; // don't retain normal CF objects
576 return cf;
577 } else {
578 // support constant CFTypeRef objects.
579 #if __LP64__
580 uint32_t lowBits = ((CFRuntimeBase *)cf)->_rc;
581 #else
582 uint32_t lowBits = ((CFRuntimeBase *)cf)->_cfinfo[CF_RC_BITS];
583 #endif
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.
589 // HALT;
590 }
591 }
592 return CFRetain(cf);
593 }
594
595
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.
610 CFRelease(cf);
611 } else {
612 // avoid releasing normal CF objects. Like other collections, for example
613 }
614 return;
615 #endif
616 } else {
617 // support constant CFTypeRef objects.
618 #if __LP64__
619 uint32_t lowBits = ((CFRuntimeBase *)cf)->_rc;
620 #else
621 uint32_t lowBits = ((CFRuntimeBase *)cf)->_cfinfo[CF_RC_BITS];
622 #endif
623 if (lowBits == 0) return;
624 }
625 }
626 CFRelease(cf);
627 }
628
629 #if !__LP64__
630 static CFLock_t __CFRuntimeExternRefCountTableLock = CFLockInit;
631 #endif
632
633 static uint64_t __CFGetFullRetainCount(CFTypeRef cf) {
634 if (NULL == cf) { CRSetCrashLogMessage("*** __CFGetFullRetainCount() called with NULL ***"); HALT; }
635 #if __LP64__
636 uint32_t lowBits = ((CFRuntimeBase *)cf)->_rc;
637 if (0 == lowBits) {
638 return (uint64_t)0x0fffffffffffffffULL;
639 }
640 return lowBits;
641 #else
642 uint32_t lowBits = ((CFRuntimeBase *)cf)->_cfinfo[CF_RC_BITS];
643 if (0 == lowBits) {
644 return (uint64_t)0x0fffffffffffffffULL;
645 }
646 uint64_t highBits = 0;
647 if ((lowBits & 0x80) != 0) {
648 highBits = __CFDoExternRefOperation(500, (id)cf);
649 }
650 uint64_t compositeRC = (lowBits & 0x7f) + (highBits << 6);
651 return compositeRC;
652 #endif
653 }
654
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
664 }
665 #if __LP64__
666 if (((CFRuntimeBase *)cf)->_rc != 0xFFFFFFFFU) {
667 HALT; // bogus object
668 }
669 #endif
670 uint32_t rc = refcount(0, cf);
671 #if __LP64__
672 return (CFIndex)rc;
673 #else
674 return (rc < LONG_MAX) ? (CFIndex)rc : (CFIndex)LONG_MAX;
675 #endif
676 }
677 uint64_t rc = __CFGetFullRetainCount(cf);
678 return (rc < (uint64_t)LONG_MAX) ? (CFIndex)rc : (CFIndex)LONG_MAX;
679 }
680
681 CFTypeRef CFMakeCollectable(CFTypeRef cf) {
682 if (NULL == cf) return NULL;
683 return cf;
684 }
685
686 CFTypeRef CFMakeUncollectable(CFTypeRef cf) {
687 if (NULL == cf) return NULL;
688 if (CF_IS_COLLECTABLE(cf)) {
689 CFRetain(cf);
690 }
691 return cf;
692 }
693
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);
705 }
706 return false;
707 }
708
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;
714 if (NULL != hash) {
715 return hash(cf);
716 }
717 if (CF_IS_COLLECTABLE(cf)) return (CFHashCode)_object_getExternalHash((id)cf);
718 return (CFHashCode)cf;
719 }
720
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;
729 }
730 return CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("<%s %p [%p]>"), __CFRuntimeClassTable[__CFGenericTypeID_inline(cf)]->className, cf, CFGetAllocator(cf));
731 }
732
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);
739 }
740 return NULL;
741 }
742
743 extern CFAllocatorRef __CFAllocatorGetAllocator(CFTypeRef);
744
745 CFAllocatorRef CFGetAllocator(CFTypeRef cf) {
746 if (NULL == cf) return kCFAllocatorSystemDefault;
747 if (__kCFAllocatorTypeID_CONST == __CFGenericTypeID_inline(cf)) {
748 return __CFAllocatorGetAllocator(cf);
749 }
750 return __CFGetAllocator(cf);
751 }
752
753
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();
767 #endif
768 #if DEPLOYMENT_TARGET_WINDOWS
769 // From CFPlatform.c
770 CF_PRIVATE void __CFTSDWindowsInitialize(void);
771 CF_PRIVATE void __CFTSDWindowsCleanup(void);
772 CF_PRIVATE void __CFFinalizeWindowsThreadData();
773 #endif
774 extern void __CFStreamInitialize(void);
775 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS
776 extern void __CFXPreferencesInitialize(void);
777 #endif
778
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");
785
786 static void __01121__(void) {
787 __CF120291 = pthread_is_threaded_np() ? true : false;
788 }
789
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.
795 if (__CF120290) {
796 __CF120293 = true;
797 #if DEPLOYMENT_TARGET_MACOSX
798 if (__CF120291) {
799 CRSetCrashLogMessage2("*** multi-threaded process forked ***");
800 } else {
801 CRSetCrashLogMessage2("*** single-threaded process forked ***");
802 }
803 #endif
804 }
805 }
806
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"
809
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);
813 // HALT;
814 }
815 #endif
816
817
818 CF_EXPORT const void *__CFArgStuff;
819 const void *__CFArgStuff = NULL;
820 CF_PRIVATE void *__CFAppleLanguages = NULL;
821
822 // do not cache CFFIXED_USER_HOME or HOME, there are situations where they can change
823
824 static struct {
825 const char *name;
826 const char *value;
827 } __CFEnv[] = {
828 {"PATH", NULL},
829 {"USER", NULL},
830 {"HOMEPATH", NULL},
831 {"HOMEDRIVE", NULL},
832 {"USERNAME", NULL},
833 {"TZFILE", NULL},
834 {"TZ", NULL},
835 {"NEXT_ROOT", NULL},
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
853 };
854
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;
858 }
859 return getenv(n);
860 }
861
862 CF_PRIVATE Boolean __CFProcessIsRestricted() {
863 return issetugid();
864 }
865
866 #if DEPLOYMENT_TARGET_WINDOWS
867 #define kNilPthreadT { nil, nil }
868 #else
869 #define kNilPthreadT (pthread_t)0
870 #endif
871
872
873 #undef kCFUseCollectableAllocator
874 CF_EXPORT bool kCFUseCollectableAllocator;
875 bool kCFUseCollectableAllocator = false;
876
877 CF_PRIVATE Boolean __CFProphylacticAutofsAccess = false;
878 CF_PRIVATE Boolean __CFInitializing = 0;
879 CF_PRIVATE Boolean __CFInitialized = 0;
880
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
885
886 CF_EXPORT pthread_t _CF_pthread_main_thread_np(void);
887 pthread_t _CF_pthread_main_thread_np(void) {
888 return _CFMainPThread;
889 }
890 #define pthread_main_thread_np() _CF_pthread_main_thread_np()
891
892 #endif
893
894 #if DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD
895 static void __CFInitialize(void) __attribute__ ((constructor));
896 static
897 #endif
898 #if DEPLOYMENT_TARGET_WINDOWS
899 CF_EXPORT
900 #endif
901 void __CFInitialize(void) {
902
903 if (!__CFInitialized && !__CFInitializing) {
904 __CFInitializing = 1;
905
906 #if DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_IPHONESIMULATOR
907 if (!pthread_main_np()) HALT; // CoreFoundation must be initialized on the main thread
908 #endif
909 // move this next line up into the #if above after Foundation gets off this symbol
910 _CFMainPThread = pthread_self();
911
912 #if DEPLOYMENT_TARGET_WINDOWS
913 // Must not call any CF functions
914 __CFTSDWindowsInitialize();
915 #elif DEPLOYMENT_TARGET_LINUX
916 __CFTSDLinuxInitialize();
917 #endif
918
919 __CFProphylacticAutofsAccess = true;
920
921 for (CFIndex idx = 0; idx < sizeof(__CFEnv) / sizeof(__CFEnv[0]); idx++) {
922 __CFEnv[idx].value = __CFEnv[idx].name ? getenv(__CFEnv[idx].name) : NULL;
923 }
924
925 #if !defined(kCFUseCollectableAllocator)
926 kCFUseCollectableAllocator = objc_collectingEnabled();
927 #endif
928 if (kCFUseCollectableAllocator) {
929 #if !defined(__CFObjCIsCollectable)
930 __CFObjCIsCollectable = (bool (*)(void *))objc_isAuto;
931 #endif
932 }
933 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
934 UInt32 s, r;
935 __CFStringGetUserDefaultEncoding(&s, &r); // force the potential setenv to occur early
936 pthread_atfork(__01121__, NULL, __01123__);
937 #endif
938
939
940 memset(__CFRuntimeClassTable, 0, sizeof(__CFRuntimeClassTable));
941 memset(__CFRuntimeObjCClassTable, 0, sizeof(__CFRuntimeObjCClassTable));
942
943
944 /* Here so that two runtime classes get indices 0, 1. */
945 __kCFNotATypeTypeID = _CFRuntimeRegisterClass(&__CFNotATypeClass);
946 __kCFTypeTypeID = _CFRuntimeRegisterClass(&__CFTypeClass);
947
948 /* Here so that __kCFAllocatorTypeID gets index 2. */
949 __CFAllocatorInitialize();
950
951 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
952 {
953 CFIndex idx, cnt;
954 char **args = *_NSGetArgv();
955 cnt = *_NSGetArgc();
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);
962 break;
963 }
964 }
965 }
966 #endif
967
968
969 CFBasicHashGetTypeID();
970 CFBagGetTypeID();
971
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;
977 }
978
979 /*** _CFRuntimeCreateInstance() can finally be called generally after this line. ***/
980
981 __CFRuntimeClassTableCount = 7;
982 __CFStringInitialize(); // CFString's TypeID must be 0x7, now and forever
983
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
992
993 CFBinaryHeapGetTypeID();
994 CFBitVectorGetTypeID();
995 __CFCharacterSetInitialize();
996 CFStorageGetTypeID();
997 CFErrorGetTypeID();
998 CFTreeGetTypeID();
999 CFURLGetTypeID();
1000
1001 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS
1002 CFBundleGetTypeID();
1003 __CFPFactoryInitialize();
1004 #endif
1005 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
1006 __CFPlugInInitialize();
1007 CFPlugInInstanceGetTypeID();
1008 #endif
1009 CFUUIDGetTypeID();
1010 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI || DEPLOYMENT_TARGET_WINDOWS
1011 CFMessagePortGetTypeID();
1012 #endif
1013 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
1014 CFMachPortGetTypeID();
1015 #endif
1016 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS
1017 __CFStreamInitialize();
1018 #endif
1019 #if DEPLOYMENT_TARGET_WINDOWS
1020 CFWindowsNamedPipeGetTypeID();
1021 #endif
1022
1023 CFDateGetTypeID();
1024
1025 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI || DEPLOYMENT_TARGET_WINDOWS
1026 CFRunLoopGetTypeID();
1027 CFRunLoopObserverGetTypeID();
1028 CFRunLoopSourceGetTypeID();
1029 CFRunLoopTimerGetTypeID();
1030 #endif
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();
1037 #endif
1038 #endif
1039
1040 {
1041 CFIndex idx, cnt = 0;
1042 char **args = NULL;
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);
1050 #endif
1051 CFIndex count;
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]));
1058 #else
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.
1068 }
1069 #endif
1070 if (NULL != list[count]) count++;
1071 }
1072 __CFArgStuff = CFArrayCreate(kCFAllocatorSystemDefault, (const void **)list, count, &kCFTypeArrayCallBacks);
1073 if (list != buffer) free(list);
1074 #if DEPLOYMENT_TARGET_WINDOWS
1075 LocalFree(args);
1076 #endif
1077 }
1078
1079 _CFProcessPath(); // cache this early
1080
1081 __CFOAInitialize();
1082
1083
1084 if (__CFRuntimeClassTableCount < 256) __CFRuntimeClassTableCount = 256;
1085
1086
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;
1092 #endif
1093
1094 #if defined(DEBUG) && (DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED)
1095 CFLog(kCFLogLevelWarning, CFSTR("Assertions enabled"));
1096 #endif
1097
1098 __CFProphylacticAutofsAccess = false;
1099 __CFInitializing = 0;
1100 __CFInitialized = 1;
1101 }
1102 }
1103
1104
1105 #if DEPLOYMENT_TARGET_WINDOWS
1106
1107 CF_PRIVATE void __CFStringCleanup(void);
1108 CF_PRIVATE void __CFSocketCleanup(void);
1109 CF_PRIVATE void __CFUniCharCleanup(void);
1110 CF_PRIVATE void __CFStreamCleanup(void);
1111
1112 static CFBundleRef RegisterCoreFoundationBundle(void) {
1113 #ifdef _DEBUG
1114 // might be nice to get this from the project file at some point
1115 wchar_t *DLLFileName = (wchar_t *)L"CoreFoundation_debug.dll";
1116 #else
1117 wchar_t *DLLFileName = (wchar_t *)L"CoreFoundation.dll";
1118 #endif
1119 wchar_t path[MAX_PATH+1];
1120 path[0] = path[1] = 0;
1121 DWORD wResult;
1122 CFIndex idx;
1123 HMODULE ourModule = GetModuleHandleW(DLLFileName);
1124
1125 CFAssert(ourModule, __kCFLogAssertion, "GetModuleHandle failed");
1126
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);
1130
1131 // strip off last component, the DLL name
1132 for (idx = wResult - 1; idx; idx--) {
1133 if ('\\' == path[idx]) {
1134 path[idx] = '\0';
1135 break;
1136 }
1137 }
1138
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);
1142 CFRelease(fsPath);
1143 CFRelease(dllURL);
1144
1145 // this registers us so subsequent calls to CFBundleGetBundleWithIdentifier will succeed
1146 CFBundleRef bundle = CFBundleCreate(kCFAllocatorSystemDefault, bundleURL);
1147 CFRelease(bundleURL);
1148
1149 return bundle;
1150 }
1151
1152
1153 #define DLL_PROCESS_ATTACH 1
1154 #define DLL_THREAD_ATTACH 2
1155 #define DLL_THREAD_DETACH 3
1156 #define DLL_PROCESS_DETACH 0
1157
1158 int DllMain( HINSTANCE hInstance, DWORD dwReason, LPVOID pReserved ) {
1159 static CFBundleRef cfBundle = NULL;
1160 if (dwReason == DLL_PROCESS_ATTACH) {
1161 __CFInitialize();
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();
1168
1169 #if DEPLOYMENT_TARGET_WINDOWS
1170 // No CF functions should access TSD after this is called
1171 __CFTSDWindowsCleanup();
1172 #endif
1173
1174 // do these last
1175 if (cfBundle) CFRelease(cfBundle);
1176 __CFStringCleanup();
1177 } else if (dwReason == DLL_THREAD_DETACH) {
1178 __CFFinalizeWindowsThreadData();
1179 }
1180 return TRUE;
1181 }
1182
1183 #endif
1184
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)
1191 #else
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)
1197 #endif
1198
1199 #if !DEPLOYMENT_TARGET_WINDOWS && __LP64__
1200 static bool (*CAS64)(int64_t, int64_t, volatile int64_t *) = OSAtomicCompareAndSwap64Barrier;
1201 #else
1202 static bool (*CAS32)(int32_t, int32_t, volatile int32_t *) = OSAtomicCompareAndSwap32Barrier;
1203 #endif
1204
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
1215 }
1216 #if __LP64__
1217 if (((CFRuntimeBase *)cf)->_rc != 0xFFFFFFFFU) {
1218 HALT; // bogus object
1219 }
1220 #endif
1221 refcount(+1, cf);
1222 return cf;
1223 }
1224
1225 Boolean didAuto = false;
1226 if (tryR && (cfinfo & (0x400000 | 0x200000))) return NULL; // deallocating or deallocated
1227 #if __LP64__
1228 if (0 == ((CFRuntimeBase *)cf)->_rc && !CF_IS_COLLECTABLE(cf)) return cf; // Constant CFTypeRef
1229 #if !DEPLOYMENT_TARGET_WINDOWS
1230 uint64_t allBits;
1231 do {
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);
1238 didAuto = true;
1239 }
1240 #else
1241 uint32_t lowBits;
1242 do {
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);
1248 didAuto = true;
1249 }
1250 #endif
1251 #else
1252 #define RC_START 24
1253 #define RC_END 31
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);
1257 bool success = 0;
1258 do {
1259 cfinfo = *infoLocation;
1260 #if !DEPLOYMENT_TARGET_WINDOWS
1261 // if already deallocating, don't allow new retain
1262 if (tryR && (cfinfo & 0x400000)) return NULL;
1263 #endif
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.
1275 */
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);
1282 }
1283 __CFUnlock(&__CFRuntimeExternRefCountTableLock);
1284 } else {
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);
1289 didAuto = true;
1290 }
1291 }
1292 } while (__builtin_expect(!success, 0));
1293 #endif
1294 if (!didAuto && __builtin_expect(__CFOASafe, 0)) {
1295 __CFRecordAllocationEvent(__kCFRetainEvent, (void *)cf, 0, CFGetRetainCount(cf), NULL);
1296 }
1297 return cf;
1298 }
1299
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
1305 #endif
1306 return _CFRetain(cf, true);
1307 }
1308
1309 Boolean _CFIsDeallocating(CFTypeRef cf) {
1310 if (NULL == cf) return false;
1311 #if OBJC_HAVE_TAGGED_POINTERS
1312 if (_objc_isTaggedPointer(cf)) return false;
1313 #endif
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
1317 }
1318 return (cfinfo & 0x400000) ? true : false;
1319 }
1320
1321 static void _CFRelease(CFTypeRef cf) {
1322
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
1331 }
1332 #if __LP64__
1333 if (((CFRuntimeBase *)cf)->_rc != 0xFFFFFFFFU) {
1334 HALT; // bogus object
1335 }
1336 #endif
1337 refcount(-1, cf);
1338 return;
1339 }
1340
1341 CFIndex start_rc = __builtin_expect(__CFOASafe, 0) ? CFGetRetainCount(cf) : 0;
1342 Boolean isAllocator = (__kCFAllocatorTypeID_CONST == typeID);
1343 Boolean didAuto = false;
1344 #if __LP64__
1345 #if !DEPLOYMENT_TARGET_WINDOWS
1346 uint32_t lowBits;
1347 uint64_t allBits;
1348 again:;
1349 do {
1350 allBits = *(uint64_t *)&(((CFRuntimeBase *)cf)->_cfinfo);
1351 lowBits = RC_GET(allBits);
1352 if (0 == lowBits) {
1353 if (CF_IS_COLLECTABLE(cf)) auto_zone_release(objc_collectableZone(), (void*)cf);
1354 return; // Constant CFTypeRef
1355 }
1356 if (1 == lowBits) {
1357 CFRuntimeClass *cfClass = __CFRuntimeClassTable[typeID];
1358 if ((cfClass->version & _kCFRuntimeResourcefulObject) && cfClass->reclaim != NULL) {
1359 cfClass->reclaim(cf);
1360 }
1361 if (!CF_IS_COLLECTABLE(cf)) {
1362 uint64_t newAllBits = allBits | RC_DEALLOCATING_BIT;
1363 if (!CAS64(allBits, newAllBits, (int64_t *)&((CFRuntimeBase *)cf)->_cfinfo)) {
1364 goto again;
1365 }
1366 void (*func)(CFTypeRef) = __CFRuntimeClassTable[typeID]->finalize;
1367 if (NULL != func) {
1368 func(cf);
1369 }
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));
1377 goto really_free;
1378 }
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);
1384 } while (!success);
1385 goto again; // still need to have the effect of a CFRelease
1386 }
1387 }
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);
1392 didAuto = true;
1393 }
1394 #else
1395 uint32_t lowBits;
1396 do {
1397 lowBits = ((CFRuntimeBase *)cf)->_rc;
1398 if (0 == lowBits) {
1399 if (CF_IS_COLLECTABLE(cf)) auto_zone_release(objc_collectableZone(), (void*)cf);
1400 return; // Constant CFTypeRef
1401 }
1402 if (1 == lowBits) {
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);
1407 }
1408 if (!CF_IS_COLLECTABLE(cf)) {
1409 void (*func)(CFTypeRef) = __CFRuntimeClassTable[typeID]->finalize;
1410 if (NULL != func) {
1411 func(cf);
1412 }
1413 if (isAllocator || CAS32(1, 0, (int32_t *)&((CFRuntimeBase *)cf)->_rc)) {
1414 goto really_free;
1415 }
1416 }
1417 }
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);
1422 didAuto = true;
1423 }
1424 #endif
1425 #else
1426 #if !DEPLOYMENT_TARGET_WINDOWS
1427 again:;
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
1433 }
1434 bool success = 0;
1435 Boolean whack = false;
1436 do {
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);
1444 }
1445 success = CAS32(*(int32_t *)& cfinfo, *(int32_t *)&prospectiveNewInfo, (int32_t *)infoLocation);
1446 if (success) whack = true;
1447 } else {
1448 // not yet junk
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);
1456 } else {
1457 __CFBitfieldSetValue(prospectiveNewInfo, RC_END, RC_START, ((1 << 6) | (1 << 7)) - 1);
1458 }
1459 success = CAS32(*(int32_t *)& cfinfo, *(int32_t *)&prospectiveNewInfo, (int32_t *)infoLocation);
1460 if (success) {
1461 __CFDoExternRefOperation(450, (id)cf);
1462 }
1463 __CFUnlock(&__CFRuntimeExternRefCountTableLock);
1464 } else {
1465 prospectiveNewInfo -= (1 << RC_START);
1466 success = CAS32(*(int32_t *)& cfinfo, *(int32_t *)&prospectiveNewInfo, (int32_t *)infoLocation);
1467 }
1468 }
1469 } while (!success);
1470
1471 if (whack) {
1472 CFRuntimeClass *cfClass = __CFRuntimeClassTable[typeID];
1473 if ((cfClass->version & _kCFRuntimeResourcefulObject) && cfClass->reclaim != NULL) {
1474 cfClass->reclaim(cf);
1475 }
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);
1479 didAuto = true;
1480 } else {
1481 if (isAllocator) {
1482 goto really_free;
1483 } else {
1484 void (*func)(CFTypeRef) = __CFRuntimeClassTable[typeID]->finalize;
1485 if (NULL != func) {
1486 func(cf);
1487 }
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));
1494 goto really_free;
1495 }
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);
1500 } while (!success);
1501 goto again;
1502 }
1503 }
1504 }
1505 #else
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
1511 }
1512 bool success = 0;
1513 do {
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);
1522 }
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.
1527 if (success) {
1528 auto_zone_release(objc_collectableZone(), (void*)cf);
1529 didAuto = true;
1530 }
1531 } else {
1532 if (isAllocator) {
1533 goto really_free;
1534 } else {
1535 void (*func)(CFTypeRef) = __CFRuntimeClassTable[typeID]->finalize;
1536 if (NULL != func) {
1537 func(cf);
1538 }
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);
1547 if (success) {
1548 goto really_free;
1549 }
1550 }
1551 }
1552 } else {
1553 // not yet junk
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);
1561 } else {
1562 __CFBitfieldSetValue(prospectiveNewInfo, RC_END, RC_START, ((1 << 6) | (1 << 7)) - 1);
1563 }
1564 success = CAS32(*(int32_t *)&initialCheckInfo, *(int32_t *)&prospectiveNewInfo, (int32_t *)infoLocation);
1565 if (success) {
1566 __CFDoExternRefOperation(450, (id)cf);
1567 }
1568 __CFUnlock(&__CFRuntimeExternRefCountTableLock);
1569 } else {
1570 prospectiveNewInfo -= (1 << RC_START);
1571 success = CAS32(*(int32_t *)&initialCheckInfo, *(int32_t *)&prospectiveNewInfo, (int32_t *)infoLocation);
1572 }
1573 }
1574 } while (!success);
1575 #endif
1576 #endif
1577 if (!didAuto && __builtin_expect(__CFOASafe, 0)) {
1578 __CFRecordAllocationEvent(__kCFReleaseEvent, (void *)cf, 0, start_rc - 1, NULL);
1579 }
1580 return;
1581
1582 really_free:;
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);
1586 }
1587 // cannot zombify allocators, which get deallocated by __CFAllocatorDeallocate (finalize)
1588 if (isAllocator) {
1589 __CFAllocatorDeallocate((void *)cf);
1590 } else {
1591 CFAllocatorRef allocator = kCFAllocatorSystemDefault;
1592 Boolean usesSystemDefaultAllocator = true;
1593
1594 if (!__CFBitfieldGetValue(((const CFRuntimeBase *)cf)->_cfinfo[CF_INFO_BITS], 7, 7)) {
1595 allocator = CFGetAllocator(cf);
1596 usesSystemDefaultAllocator = _CFAllocatorIsSystemDefault(allocator);
1597 }
1598
1599 {
1600 CFAllocatorDeallocate(allocator, (uint8_t *)cf - (usesSystemDefaultAllocator ? 0 : sizeof(CFAllocatorRef)));
1601 }
1602
1603 if (kCFAllocatorSystemDefault != allocator) {
1604 CFRelease(allocator);
1605 }
1606 }
1607 }
1608
1609 #undef __kCFAllocatorTypeID_CONST
1610 #undef __CFGenericAssertIsCF
1611
1612