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