]>
Commit | Line | Data |
---|---|---|
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 | /* CFBase.c | |
25 | Copyright (c) 1998-2014, Apple Inc. All rights reserved. | |
26 | Responsibility: Christopher Kane | |
27 | */ | |
28 | ||
29 | #include <CoreFoundation/CFBase.h> | |
30 | #include "CFInternal.h" | |
31 | #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI || DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD | |
32 | #include <pthread.h> | |
33 | #endif | |
34 | #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI | |
35 | #include <malloc/malloc.h> | |
36 | #include <mach/mach.h> | |
37 | #include <dlfcn.h> | |
38 | #endif | |
39 | #include <stdlib.h> | |
40 | #include <string.h> | |
41 | ||
42 | // -------- -------- -------- -------- -------- -------- -------- -------- | |
43 | ||
44 | struct __CFAllocator { | |
45 | CFRuntimeBase _base; | |
46 | #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI | |
47 | // CFAllocator structure must match struct _malloc_zone_t! | |
48 | // The first two reserved fields in struct _malloc_zone_t are for us with CFRuntimeBase | |
49 | size_t (*size)(struct _malloc_zone_t *zone, const void *ptr); /* returns the size of a block or 0 if not in this zone; must be fast, especially for negative answers */ | |
50 | void *(*malloc)(struct _malloc_zone_t *zone, size_t size); | |
51 | void *(*calloc)(struct _malloc_zone_t *zone, size_t num_items, size_t size); /* same as malloc, but block returned is set to zero */ | |
52 | void *(*valloc)(struct _malloc_zone_t *zone, size_t size); /* same as malloc, but block returned is set to zero and is guaranteed to be page aligned */ | |
53 | void (*free)(struct _malloc_zone_t *zone, void *ptr); | |
54 | void *(*realloc)(struct _malloc_zone_t *zone, void *ptr, size_t size); | |
55 | void (*destroy)(struct _malloc_zone_t *zone); /* zone is destroyed and all memory reclaimed */ | |
56 | const char *zone_name; | |
57 | ||
58 | /* Optional batch callbacks; these may be NULL */ | |
59 | unsigned (*batch_malloc)(struct _malloc_zone_t *zone, size_t size, void **results, unsigned num_requested); /* given a size, returns pointers capable of holding that size; returns the number of pointers allocated (maybe 0 or less than num_requested) */ | |
60 | void (*batch_free)(struct _malloc_zone_t *zone, void **to_be_freed, unsigned num_to_be_freed); /* frees all the pointers in to_be_freed; note that to_be_freed may be overwritten during the process */ | |
61 | ||
62 | struct malloc_introspection_t *introspect; | |
63 | unsigned version; | |
64 | ||
65 | /* aligned memory allocation. The callback may be NULL. */ | |
66 | void *(*memalign)(struct _malloc_zone_t *zone, size_t alignment, size_t size); | |
67 | ||
68 | /* free a pointer known to be in zone and known to have the given size. The callback may be NULL. */ | |
69 | void (*free_definite_size)(struct _malloc_zone_t *zone, void *ptr, size_t size); | |
70 | #endif | |
71 | CFAllocatorRef _allocator; | |
72 | CFAllocatorContext _context; | |
73 | }; | |
74 | ||
75 | CF_INLINE CFAllocatorRetainCallBack __CFAllocatorGetRetainFunction(const CFAllocatorContext *context) { | |
76 | CFAllocatorRetainCallBack retval = NULL; | |
77 | retval = context->retain; | |
78 | return retval; | |
79 | } | |
80 | ||
81 | CF_INLINE CFAllocatorReleaseCallBack __CFAllocatorGetReleaseFunction(const CFAllocatorContext *context) { | |
82 | CFAllocatorReleaseCallBack retval = NULL; | |
83 | retval = context->release; | |
84 | return retval; | |
85 | } | |
86 | ||
87 | CF_INLINE CFAllocatorCopyDescriptionCallBack __CFAllocatorGetCopyDescriptionFunction(const CFAllocatorContext *context) { | |
88 | CFAllocatorCopyDescriptionCallBack retval = NULL; | |
89 | retval = context->copyDescription; | |
90 | return retval; | |
91 | } | |
92 | ||
93 | CF_INLINE CFAllocatorAllocateCallBack __CFAllocatorGetAllocateFunction(const CFAllocatorContext *context) { | |
94 | CFAllocatorAllocateCallBack retval = NULL; | |
95 | retval = context->allocate; | |
96 | return retval; | |
97 | } | |
98 | ||
99 | CF_INLINE CFAllocatorReallocateCallBack __CFAllocatorGetReallocateFunction(const CFAllocatorContext *context) { | |
100 | CFAllocatorReallocateCallBack retval = NULL; | |
101 | retval = context->reallocate; | |
102 | return retval; | |
103 | } | |
104 | ||
105 | CF_INLINE CFAllocatorDeallocateCallBack __CFAllocatorGetDeallocateFunction(const CFAllocatorContext *context) { | |
106 | CFAllocatorDeallocateCallBack retval = NULL; | |
107 | retval = context->deallocate; | |
108 | return retval; | |
109 | } | |
110 | ||
111 | CF_INLINE CFAllocatorPreferredSizeCallBack __CFAllocatorGetPreferredSizeFunction(const CFAllocatorContext *context) { | |
112 | CFAllocatorPreferredSizeCallBack retval = NULL; | |
113 | retval = context->preferredSize; | |
114 | return retval; | |
115 | } | |
116 | ||
117 | #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI | |
118 | ||
119 | CF_PRIVATE void __CFAllocatorDeallocate(CFTypeRef cf); | |
120 | ||
121 | static kern_return_t __CFAllocatorZoneIntrospectNoOp(void) { | |
122 | return 0; | |
123 | } | |
124 | ||
125 | static boolean_t __CFAllocatorZoneIntrospectTrue(void) { | |
126 | return 1; | |
127 | } | |
128 | ||
129 | static size_t __CFAllocatorCustomSize(malloc_zone_t *zone, const void *ptr) { | |
130 | return 0; | |
131 | ||
132 | // The only way to implement this with a version 0 allocator would be | |
133 | // for CFAllocator to keep track of all blocks allocated itself, which | |
134 | // could be done, but would be bad for performance, so we don't do it. | |
135 | // size_t (*size)(struct _malloc_zone_t *zone, const void *ptr); | |
136 | /* returns the size of a block or 0 if not in this zone; | |
137 | * must be fast, especially for negative answers */ | |
138 | } | |
139 | ||
140 | static void *__CFAllocatorCustomMalloc(malloc_zone_t *zone, size_t size) { | |
141 | CFAllocatorRef allocator = (CFAllocatorRef)zone; | |
142 | return CFAllocatorAllocate(allocator, size, 0); | |
143 | } | |
144 | ||
145 | static void *__CFAllocatorCustomCalloc(malloc_zone_t *zone, size_t num_items, size_t size) { | |
146 | CFAllocatorRef allocator = (CFAllocatorRef)zone; | |
147 | void *newptr = CFAllocatorAllocate(allocator, size, 0); | |
148 | if (newptr) memset(newptr, 0, size); | |
149 | return newptr; | |
150 | } | |
151 | ||
152 | static void *__CFAllocatorCustomValloc(malloc_zone_t *zone, size_t size) { | |
153 | CFAllocatorRef allocator = (CFAllocatorRef)zone; | |
154 | if (size >= ULONG_MAX - 2 * vm_page_size) return NULL; // avoid integer overflow plus don't allow all pages to be allocated either | |
155 | void *newptr = CFAllocatorAllocate(allocator, size + vm_page_size, 0); | |
156 | newptr = (void *)round_page((uintptr_t)newptr); | |
157 | return newptr; | |
158 | } | |
159 | ||
160 | static void __CFAllocatorCustomFree(malloc_zone_t *zone, void *ptr) { | |
161 | CFAllocatorRef allocator = (CFAllocatorRef)zone; | |
162 | CFAllocatorDeallocate(allocator, ptr); | |
163 | } | |
164 | ||
165 | static void *__CFAllocatorCustomRealloc(malloc_zone_t *zone, void *ptr, size_t size) { | |
166 | CFAllocatorRef allocator = (CFAllocatorRef)zone; | |
167 | return CFAllocatorReallocate(allocator, ptr, size, 0); | |
168 | } | |
169 | ||
170 | static void __CFAllocatorCustomDestroy(malloc_zone_t *zone) { | |
171 | CFAllocatorRef allocator = (CFAllocatorRef)zone; | |
172 | // !!! we do it, and caller of malloc_destroy_zone() assumes | |
173 | // COMPLETE responsibility for the result; NO Apple library | |
174 | // code should be modified as a result of discovering that | |
175 | // some activity results in inconveniences to developers | |
176 | // trying to use malloc_destroy_zone() with a CFAllocatorRef; | |
177 | // that's just too bad for them. | |
178 | __CFAllocatorDeallocate(allocator); | |
179 | } | |
180 | ||
181 | static size_t __CFAllocatorCustomGoodSize(malloc_zone_t *zone, size_t size) { | |
182 | CFAllocatorRef allocator = (CFAllocatorRef)zone; | |
183 | return CFAllocatorGetPreferredSizeForSize(allocator, size, 0); | |
184 | } | |
185 | ||
186 | static struct malloc_introspection_t __CFAllocatorZoneIntrospect = { | |
187 | (void *)__CFAllocatorZoneIntrospectNoOp, | |
188 | (void *)__CFAllocatorCustomGoodSize, | |
189 | (void *)__CFAllocatorZoneIntrospectTrue, | |
190 | (void *)__CFAllocatorZoneIntrospectNoOp, | |
191 | (void *)__CFAllocatorZoneIntrospectNoOp, | |
192 | (void *)__CFAllocatorZoneIntrospectNoOp, | |
193 | (void *)__CFAllocatorZoneIntrospectNoOp, | |
194 | (void *)__CFAllocatorZoneIntrospectNoOp | |
195 | }; | |
196 | ||
197 | static size_t __CFAllocatorNullSize(malloc_zone_t *zone, const void *ptr) { | |
198 | return 0; | |
199 | } | |
200 | ||
201 | static void * __CFAllocatorNullMalloc(malloc_zone_t *zone, size_t size) { | |
202 | return NULL; | |
203 | } | |
204 | ||
205 | static void * __CFAllocatorNullCalloc(malloc_zone_t *zone, size_t num_items, size_t size) { | |
206 | return NULL; | |
207 | } | |
208 | ||
209 | static void * __CFAllocatorNullValloc(malloc_zone_t *zone, size_t size) { | |
210 | return NULL; | |
211 | } | |
212 | ||
213 | static void __CFAllocatorNullFree(malloc_zone_t *zone, void *ptr) { | |
214 | } | |
215 | ||
216 | static void * __CFAllocatorNullRealloc(malloc_zone_t *zone, void *ptr, size_t size) { | |
217 | return NULL; | |
218 | } | |
219 | ||
220 | static void __CFAllocatorNullDestroy(malloc_zone_t *zone) { | |
221 | } | |
222 | ||
223 | static size_t __CFAllocatorNullGoodSize(malloc_zone_t *zone, size_t size) { | |
224 | return size; | |
225 | } | |
226 | ||
227 | static struct malloc_introspection_t __CFAllocatorNullZoneIntrospect = { | |
228 | (void *)__CFAllocatorZoneIntrospectNoOp, | |
229 | (void *)__CFAllocatorNullGoodSize, | |
230 | (void *)__CFAllocatorZoneIntrospectTrue, | |
231 | (void *)__CFAllocatorZoneIntrospectNoOp, | |
232 | (void *)__CFAllocatorZoneIntrospectNoOp, | |
233 | (void *)__CFAllocatorZoneIntrospectNoOp, | |
234 | (void *)__CFAllocatorZoneIntrospectNoOp, | |
235 | (void *)__CFAllocatorZoneIntrospectNoOp | |
236 | }; | |
237 | ||
238 | static void *__CFAllocatorSystemAllocate(CFIndex size, CFOptionFlags hint, void *info) { | |
239 | return malloc_zone_malloc(info, size); | |
240 | } | |
241 | ||
242 | static void *__CFAllocatorSystemReallocate(void *ptr, CFIndex newsize, CFOptionFlags hint, void *info) { | |
243 | return malloc_zone_realloc(info, ptr, newsize); | |
244 | } | |
245 | ||
246 | static void __CFAllocatorSystemDeallocate(void *ptr, void *info) { | |
247 | #if defined(DEBUG) | |
248 | size_t size = malloc_size(ptr); | |
249 | if (size) memset(ptr, 0xCC, size); | |
250 | #endif | |
251 | malloc_zone_free(info, ptr); | |
252 | } | |
253 | ||
254 | #else | |
255 | ||
256 | static void *__CFAllocatorSystemAllocate(CFIndex size, CFOptionFlags hint, void *info) { | |
257 | return malloc(size); | |
258 | } | |
259 | ||
260 | static void *__CFAllocatorSystemReallocate(void *ptr, CFIndex newsize, CFOptionFlags hint, void *info) { | |
261 | return realloc(ptr, newsize); | |
262 | } | |
263 | ||
264 | static void __CFAllocatorSystemDeallocate(void *ptr, void *info) { | |
265 | free(ptr); | |
266 | } | |
267 | #endif | |
268 | ||
269 | static void *__CFAllocatorNullAllocate(CFIndex size, CFOptionFlags hint, void *info) { | |
270 | return NULL; | |
271 | } | |
272 | ||
273 | static void *__CFAllocatorNullReallocate(void *ptr, CFIndex newsize, CFOptionFlags hint, void *info) { | |
274 | return NULL; | |
275 | } | |
276 | ||
277 | #if defined (__cplusplus) | |
278 | static void * __CFAllocatorCPPMalloc(CFIndex allocSize, CFOptionFlags hint, void *info) | |
279 | { | |
280 | return malloc(allocSize); | |
281 | } | |
282 | static void * __CFAllocatorCPPReAlloc(void *ptr, CFIndex newsize, CFOptionFlags hint, void *info) | |
283 | { | |
284 | return realloc(ptr, newsize); | |
285 | } | |
286 | static void __CFAllocatorCPPFree(void *ptr, void *info) | |
287 | { | |
288 | free(ptr); | |
289 | } | |
290 | #endif // C++ | |
291 | ||
292 | ||
293 | static struct __CFAllocator __kCFAllocatorMalloc = { | |
294 | INIT_CFRUNTIME_BASE(), | |
295 | #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI | |
296 | __CFAllocatorCustomSize, | |
297 | __CFAllocatorCustomMalloc, | |
298 | __CFAllocatorCustomCalloc, | |
299 | __CFAllocatorCustomValloc, | |
300 | __CFAllocatorCustomFree, | |
301 | __CFAllocatorCustomRealloc, | |
302 | __CFAllocatorNullDestroy, | |
303 | "kCFAllocatorMalloc", | |
304 | NULL, | |
305 | NULL, | |
306 | &__CFAllocatorZoneIntrospect, | |
307 | 6, | |
308 | NULL, | |
309 | NULL, | |
310 | #endif | |
311 | NULL, // _allocator | |
312 | // Using the malloc functions directly is a total cheat, but works (in C) | |
313 | // because the function signatures match in their common prefix of arguments. | |
314 | // This saves us one hop through an adaptor function. | |
315 | #if !defined (__cplusplus) | |
316 | {0, NULL, NULL, NULL, NULL, (void *)malloc, (void *)realloc, (void *)free, NULL} | |
317 | #else | |
318 | {0, NULL, NULL, NULL, NULL, __CFAllocatorCPPMalloc,__CFAllocatorCPPReAlloc, __CFAllocatorCPPFree, NULL} | |
319 | #endif // __cplusplus | |
320 | }; | |
321 | ||
322 | static struct __CFAllocator __kCFAllocatorMallocZone = { | |
323 | INIT_CFRUNTIME_BASE(), | |
324 | #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI | |
325 | __CFAllocatorCustomSize, | |
326 | __CFAllocatorCustomMalloc, | |
327 | __CFAllocatorCustomCalloc, | |
328 | __CFAllocatorCustomValloc, | |
329 | __CFAllocatorCustomFree, | |
330 | __CFAllocatorCustomRealloc, | |
331 | __CFAllocatorNullDestroy, | |
332 | "kCFAllocatorMallocZone", | |
333 | NULL, | |
334 | NULL, | |
335 | &__CFAllocatorZoneIntrospect, | |
336 | 6, | |
337 | NULL, | |
338 | NULL, | |
339 | #endif | |
340 | NULL, // _allocator | |
341 | {0, NULL, NULL, NULL, NULL, __CFAllocatorSystemAllocate, __CFAllocatorSystemReallocate, __CFAllocatorSystemDeallocate, NULL} | |
342 | }; | |
343 | ||
344 | static struct __CFAllocator __kCFAllocatorSystemDefault = { | |
345 | INIT_CFRUNTIME_BASE(), | |
346 | #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI | |
347 | __CFAllocatorCustomSize, | |
348 | __CFAllocatorCustomMalloc, | |
349 | __CFAllocatorCustomCalloc, | |
350 | __CFAllocatorCustomValloc, | |
351 | __CFAllocatorCustomFree, | |
352 | __CFAllocatorCustomRealloc, | |
353 | __CFAllocatorNullDestroy, | |
354 | "kCFAllocatorSystemDefault", | |
355 | NULL, | |
356 | NULL, | |
357 | &__CFAllocatorZoneIntrospect, | |
358 | 6, | |
359 | NULL, | |
360 | NULL, | |
361 | #endif | |
362 | NULL, // _allocator | |
363 | {0, NULL, NULL, NULL, NULL, __CFAllocatorSystemAllocate, __CFAllocatorSystemReallocate, __CFAllocatorSystemDeallocate, NULL} | |
364 | }; | |
365 | ||
366 | static struct __CFAllocator __kCFAllocatorNull = { | |
367 | INIT_CFRUNTIME_BASE(), | |
368 | #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI | |
369 | __CFAllocatorNullSize, | |
370 | __CFAllocatorNullMalloc, | |
371 | __CFAllocatorNullCalloc, | |
372 | __CFAllocatorNullValloc, | |
373 | __CFAllocatorNullFree, | |
374 | __CFAllocatorNullRealloc, | |
375 | __CFAllocatorNullDestroy, | |
376 | "kCFAllocatorNull", | |
377 | NULL, | |
378 | NULL, | |
379 | &__CFAllocatorNullZoneIntrospect, | |
380 | 6, | |
381 | NULL, | |
382 | NULL, | |
383 | #endif | |
384 | NULL, // _allocator | |
385 | {0, NULL, NULL, NULL, NULL, __CFAllocatorNullAllocate, __CFAllocatorNullReallocate, NULL, NULL} | |
386 | }; | |
387 | ||
388 | const CFAllocatorRef kCFAllocatorDefault = NULL; | |
389 | const CFAllocatorRef kCFAllocatorSystemDefault = &__kCFAllocatorSystemDefault; | |
390 | const CFAllocatorRef kCFAllocatorMalloc = &__kCFAllocatorMalloc; | |
391 | const CFAllocatorRef kCFAllocatorMallocZone = &__kCFAllocatorMallocZone; | |
392 | const CFAllocatorRef kCFAllocatorNull = &__kCFAllocatorNull; | |
393 | const CFAllocatorRef kCFAllocatorUseContext = (CFAllocatorRef)0x03ab; | |
394 | #undef kCFAllocatorSystemDefaultGCRefZero | |
395 | #undef kCFAllocatorDefaultGCRefZero | |
396 | const CFAllocatorRef kCFAllocatorSystemDefaultGCRefZero = (CFAllocatorRef)0x03ad; | |
397 | const CFAllocatorRef kCFAllocatorDefaultGCRefZero = (CFAllocatorRef)0x03af; | |
398 | ||
399 | static CFStringRef __CFAllocatorCopyDescription(CFTypeRef cf) { | |
400 | CFAllocatorRef self = (CFAllocatorRef)cf; | |
401 | CFAllocatorRef allocator = (kCFAllocatorUseContext == self->_allocator) ? self : self->_allocator; | |
402 | return CFStringCreateWithFormat(allocator, NULL, CFSTR("<CFAllocator %p [%p]>{info = %p}"), cf, allocator, self->_context.info); | |
403 | // CF: should use copyDescription function here to describe info field | |
404 | // remember to release value returned from copydescr function when this happens | |
405 | } | |
406 | ||
407 | CF_PRIVATE CFAllocatorRef __CFAllocatorGetAllocator(CFTypeRef cf) { | |
408 | CFAllocatorRef allocator = (CFAllocatorRef)cf; | |
409 | return (kCFAllocatorUseContext == allocator->_allocator) ? allocator : allocator->_allocator; | |
410 | } | |
411 | ||
412 | CF_PRIVATE void __CFAllocatorDeallocate(CFTypeRef cf) { | |
413 | CFAllocatorRef self = (CFAllocatorRef)cf; | |
414 | CFAllocatorRef allocator = self->_allocator; | |
415 | CFAllocatorReleaseCallBack releaseFunc = __CFAllocatorGetReleaseFunction(&self->_context); | |
416 | if (kCFAllocatorUseContext == allocator) { | |
417 | /* Rather a chicken and egg problem here, so we do things | |
418 | in the reverse order from what was done at create time. */ | |
419 | CFAllocatorDeallocateCallBack deallocateFunc = __CFAllocatorGetDeallocateFunction(&self->_context); | |
420 | void *info = self->_context.info; | |
421 | if (NULL != deallocateFunc) { | |
422 | INVOKE_CALLBACK2(deallocateFunc, (void *)self, info); | |
423 | } | |
424 | if (NULL != releaseFunc) { | |
425 | INVOKE_CALLBACK1(releaseFunc, info); | |
426 | } | |
427 | } else { | |
428 | if (NULL != releaseFunc) { | |
429 | INVOKE_CALLBACK1(releaseFunc, self->_context.info); | |
430 | } | |
431 | if (!CF_IS_COLLECTABLE_ALLOCATOR(allocator)) CFAllocatorDeallocate(allocator, (void *)self); | |
432 | } | |
433 | } | |
434 | ||
435 | static CFTypeID __kCFAllocatorTypeID = _kCFRuntimeNotATypeID; | |
436 | ||
437 | static const CFRuntimeClass __CFAllocatorClass = { | |
438 | 0, | |
439 | "CFAllocator", | |
440 | NULL, // init | |
441 | NULL, // copy | |
442 | NULL, | |
443 | NULL, // equal | |
444 | NULL, // hash | |
445 | NULL, // | |
446 | __CFAllocatorCopyDescription | |
447 | }; | |
448 | ||
449 | static void _CFAllocatorSetInstanceTypeIDAndIsa(struct __CFAllocator *memory) { | |
450 | _CFRuntimeSetInstanceTypeID(memory, __kCFAllocatorTypeID); | |
451 | memory->_base._cfisa = __CFISAForTypeID(__kCFAllocatorTypeID); | |
452 | } | |
453 | ||
454 | CF_PRIVATE void __CFAllocatorInitialize(void) { | |
455 | static dispatch_once_t initOnce; | |
456 | dispatch_once(&initOnce, ^{ | |
457 | __kCFAllocatorTypeID = _CFRuntimeRegisterClass(&__CFAllocatorClass); // initOnce covered | |
458 | ||
459 | _CFAllocatorSetInstanceTypeIDAndIsa(&__kCFAllocatorSystemDefault); | |
460 | #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI | |
461 | __kCFAllocatorSystemDefault._context.info = (kCFUseCollectableAllocator ? objc_collectableZone() : malloc_default_zone()); | |
462 | #endif | |
463 | __kCFAllocatorSystemDefault._allocator = kCFAllocatorSystemDefault; | |
464 | ||
465 | _CFAllocatorSetInstanceTypeIDAndIsa(&__kCFAllocatorMalloc); | |
466 | __kCFAllocatorMalloc._allocator = kCFAllocatorSystemDefault; | |
467 | ||
468 | #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI | |
469 | _CFAllocatorSetInstanceTypeIDAndIsa(&__kCFAllocatorMallocZone); | |
470 | __kCFAllocatorMallocZone._allocator = kCFAllocatorSystemDefault; | |
471 | __kCFAllocatorMallocZone._context.info = malloc_default_zone(); | |
472 | #endif | |
473 | ||
474 | _CFAllocatorSetInstanceTypeIDAndIsa(&__kCFAllocatorNull); | |
475 | __kCFAllocatorNull._allocator = kCFAllocatorSystemDefault; | |
476 | }); | |
477 | } | |
478 | ||
479 | CFTypeID CFAllocatorGetTypeID(void) { | |
480 | return __kCFAllocatorTypeID; | |
481 | } | |
482 | ||
483 | CFAllocatorRef CFAllocatorGetDefault(void) { | |
484 | return __CFGetDefaultAllocator(); | |
485 | } | |
486 | ||
487 | void CFAllocatorSetDefault(CFAllocatorRef allocator) { | |
488 | CFAllocatorRef current = __CFGetDefaultAllocator(); | |
489 | #if defined(DEBUG) | |
490 | if (NULL != allocator) { | |
491 | __CFGenericValidateType(allocator, __kCFAllocatorTypeID); | |
492 | } | |
493 | #endif | |
494 | #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI | |
495 | if (allocator && allocator->_base._cfisa != __CFISAForTypeID(__kCFAllocatorTypeID)) { // malloc_zone_t * | |
496 | return; // require allocator to this function to be an allocator | |
497 | } | |
498 | #endif | |
499 | if (NULL != allocator && allocator != current) { | |
500 | if (current) CFRelease(current); | |
501 | CFRetain(allocator); | |
502 | // We retain an extra time so that anything set as the default | |
503 | // allocator never goes away. | |
504 | CFRetain(allocator); | |
505 | _CFSetTSD(__CFTSDKeyAllocator, (void *)allocator, NULL); | |
506 | } | |
507 | } | |
508 | ||
509 | static CFAllocatorRef __CFAllocatorCreate(CFAllocatorRef allocator, CFAllocatorContext *context) { | |
510 | struct __CFAllocator *memory = NULL; | |
511 | CFAllocatorRetainCallBack retainFunc; | |
512 | CFAllocatorAllocateCallBack allocateFunc; | |
513 | void *retainedInfo; | |
514 | #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI | |
515 | if (allocator && kCFAllocatorUseContext != allocator && allocator->_base._cfisa != __CFISAForTypeID(__kCFAllocatorTypeID)) { // malloc_zone_t * | |
516 | return NULL; // require allocator to this function to be an allocator | |
517 | } | |
518 | #endif | |
519 | retainFunc = context->retain; | |
520 | FAULT_CALLBACK((void **)&retainFunc); | |
521 | allocateFunc = context->allocate; | |
522 | FAULT_CALLBACK((void **)&allocateFunc); | |
523 | if (NULL != retainFunc) { | |
524 | retainedInfo = (void *)INVOKE_CALLBACK1(retainFunc, context->info); | |
525 | } else { | |
526 | retainedInfo = context->info; | |
527 | } | |
528 | // We don't use _CFRuntimeCreateInstance() | |
529 | if (kCFAllocatorUseContext == allocator) { | |
530 | memory = NULL; | |
531 | if (allocateFunc) { | |
532 | memory = (struct __CFAllocator *)INVOKE_CALLBACK3(allocateFunc, sizeof(struct __CFAllocator), 0, retainedInfo); | |
533 | } | |
534 | if (NULL == memory) { | |
535 | return NULL; | |
536 | } | |
537 | } else { | |
538 | allocator = (NULL == allocator) ? __CFGetDefaultAllocator() : allocator; | |
539 | memory = (struct __CFAllocator *)CFAllocatorAllocate(allocator, sizeof(struct __CFAllocator), __kCFAllocatorGCObjectMemory); | |
540 | if (NULL == memory) { | |
541 | return NULL; | |
542 | } | |
543 | if (__CFOASafe) __CFSetLastAllocationEventName(memory, "CFAllocator"); | |
544 | } | |
545 | memset(memory, 0, sizeof(CFRuntimeBase)); | |
546 | #if __LP64__ | |
547 | memory->_base._rc = 1; | |
548 | #else | |
549 | memory->_base._cfinfo[CF_RC_BITS] = 1; | |
550 | #endif | |
551 | memory->_base._cfinfo[CF_INFO_BITS] = 0; | |
552 | _CFAllocatorSetInstanceTypeIDAndIsa(memory); | |
553 | #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI | |
554 | memory->size = __CFAllocatorCustomSize; | |
555 | memory->malloc = __CFAllocatorCustomMalloc; | |
556 | memory->calloc = __CFAllocatorCustomCalloc; | |
557 | memory->valloc = __CFAllocatorCustomValloc; | |
558 | memory->free = __CFAllocatorCustomFree; | |
559 | memory->realloc = __CFAllocatorCustomRealloc; | |
560 | memory->destroy = __CFAllocatorCustomDestroy; | |
561 | memory->zone_name = "Custom CFAllocator"; | |
562 | memory->batch_malloc = NULL; | |
563 | memory->batch_free = NULL; | |
564 | memory->introspect = &__CFAllocatorZoneIntrospect; | |
565 | memory->version = 6; | |
566 | memory->memalign = NULL; | |
567 | memory->free_definite_size = NULL; | |
568 | #endif | |
569 | memory->_allocator = allocator; | |
570 | memory->_context.version = context->version; | |
571 | memory->_context.info = retainedInfo; | |
572 | memory->_context.retain = retainFunc; | |
573 | memory->_context.release = context->release; | |
574 | FAULT_CALLBACK((void **)&(memory->_context.release)); | |
575 | memory->_context.copyDescription = context->copyDescription; | |
576 | FAULT_CALLBACK((void **)&(memory->_context.copyDescription)); | |
577 | memory->_context.allocate = allocateFunc; | |
578 | memory->_context.reallocate = context->reallocate; | |
579 | FAULT_CALLBACK((void **)&(memory->_context.reallocate)); | |
580 | memory->_context.deallocate = context->deallocate; | |
581 | FAULT_CALLBACK((void **)&(memory->_context.deallocate)); | |
582 | memory->_context.preferredSize = context->preferredSize; | |
583 | FAULT_CALLBACK((void **)&(memory->_context.preferredSize)); | |
584 | ||
585 | return memory; | |
586 | } | |
587 | ||
588 | CFAllocatorRef CFAllocatorCreate(CFAllocatorRef allocator, CFAllocatorContext *context) { | |
589 | return __CFAllocatorCreate(allocator, context); | |
590 | } | |
591 | ||
592 | void *CFAllocatorAllocate(CFAllocatorRef allocator, CFIndex size, CFOptionFlags hint) { | |
593 | CFAllocatorAllocateCallBack allocateFunc; | |
594 | void *newptr = NULL; | |
595 | ||
596 | Boolean initialRefcountOne = true; | |
597 | if (NULL == allocator) { | |
598 | allocator = __CFGetDefaultAllocator(); | |
599 | } | |
600 | ||
601 | #if defined(DEBUG) && (DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI) | |
602 | if (allocator->_base._cfisa == __CFISAForTypeID(__kCFAllocatorTypeID)) { | |
603 | __CFGenericValidateType(allocator, __kCFAllocatorTypeID); | |
604 | } | |
605 | #else | |
606 | __CFGenericValidateType(allocator, __kCFAllocatorTypeID); | |
607 | #endif | |
608 | if (0 == size) return NULL; | |
609 | #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI | |
610 | if (allocator->_base._cfisa != __CFISAForTypeID(__kCFAllocatorTypeID)) { // malloc_zone_t * | |
611 | return malloc_zone_malloc((malloc_zone_t *)allocator, size); | |
612 | } | |
613 | #endif | |
614 | if (CF_IS_COLLECTABLE_ALLOCATOR(allocator)) { | |
615 | newptr = auto_zone_allocate_object((auto_zone_t*)allocator->_context.info, size, CF_GET_GC_MEMORY_TYPE(hint), initialRefcountOne, false); | |
616 | } else { | |
617 | newptr = NULL; | |
618 | allocateFunc = __CFAllocatorGetAllocateFunction(&allocator->_context); | |
619 | if (allocateFunc) { | |
620 | newptr = (void *)INVOKE_CALLBACK3(allocateFunc, size, hint, allocator->_context.info); | |
621 | } | |
622 | } | |
623 | return newptr; | |
624 | } | |
625 | ||
626 | void *CFAllocatorReallocate(CFAllocatorRef allocator, void *ptr, CFIndex newsize, CFOptionFlags hint) { | |
627 | CFAllocatorAllocateCallBack allocateFunc; | |
628 | CFAllocatorReallocateCallBack reallocateFunc; | |
629 | CFAllocatorDeallocateCallBack deallocateFunc; | |
630 | void *newptr; | |
631 | ||
632 | if (0) { | |
633 | allocator = kCFAllocatorSystemDefault; | |
634 | } else if (0) { | |
635 | allocator = kCFUseCollectableAllocator ? kCFAllocatorSystemDefault : __CFGetDefaultAllocator(); | |
636 | } else if (NULL == allocator) { | |
637 | allocator = __CFGetDefaultAllocator(); | |
638 | } | |
639 | ||
640 | #if defined(DEBUG) && (DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI) | |
641 | if (allocator->_base._cfisa == __CFISAForTypeID(__kCFAllocatorTypeID)) { | |
642 | __CFGenericValidateType(allocator, __kCFAllocatorTypeID); | |
643 | } | |
644 | #else | |
645 | __CFGenericValidateType(allocator, __kCFAllocatorTypeID); | |
646 | #endif | |
647 | if (NULL == ptr && 0 < newsize) { | |
648 | #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI | |
649 | if (allocator->_base._cfisa != __CFISAForTypeID(__kCFAllocatorTypeID)) { // malloc_zone_t * | |
650 | return malloc_zone_malloc((malloc_zone_t *)allocator, newsize); | |
651 | } | |
652 | #endif | |
653 | newptr = NULL; | |
654 | allocateFunc = __CFAllocatorGetAllocateFunction(&allocator->_context); | |
655 | if (allocateFunc) { | |
656 | newptr = (void *)INVOKE_CALLBACK3(allocateFunc, newsize, hint, allocator->_context.info); | |
657 | } | |
658 | return newptr; | |
659 | } | |
660 | if (NULL != ptr && 0 == newsize) { | |
661 | #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI | |
662 | if (allocator->_base._cfisa != __CFISAForTypeID(__kCFAllocatorTypeID)) { // malloc_zone_t * | |
663 | #if defined(DEBUG) | |
664 | size_t size = malloc_size(ptr); | |
665 | if (size) memset(ptr, 0xCC, size); | |
666 | #endif | |
667 | malloc_zone_free((malloc_zone_t *)allocator, ptr); | |
668 | return NULL; | |
669 | } | |
670 | #endif | |
671 | deallocateFunc = __CFAllocatorGetDeallocateFunction(&allocator->_context); | |
672 | if (NULL != deallocateFunc) { | |
673 | INVOKE_CALLBACK2(deallocateFunc, ptr, allocator->_context.info); | |
674 | } | |
675 | return NULL; | |
676 | } | |
677 | if (NULL == ptr && 0 == newsize) return NULL; | |
678 | #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI | |
679 | if (allocator->_base._cfisa != __CFISAForTypeID(__kCFAllocatorTypeID)) { // malloc_zone_t * | |
680 | return malloc_zone_realloc((malloc_zone_t *)allocator, ptr, newsize); | |
681 | } | |
682 | #endif | |
683 | reallocateFunc = __CFAllocatorGetReallocateFunction(&allocator->_context); | |
684 | if (NULL == reallocateFunc) return NULL; | |
685 | newptr = (void *)INVOKE_CALLBACK4(reallocateFunc, ptr, newsize, hint, allocator->_context.info); | |
686 | return newptr; | |
687 | } | |
688 | ||
689 | void CFAllocatorDeallocate(CFAllocatorRef allocator, void *ptr) { | |
690 | CFAllocatorDeallocateCallBack deallocateFunc; | |
691 | ||
692 | if (0) { | |
693 | allocator = kCFAllocatorSystemDefault; | |
694 | } else if (0) { | |
695 | allocator = kCFUseCollectableAllocator ? kCFAllocatorSystemDefault : __CFGetDefaultAllocator(); | |
696 | if (CF_IS_COLLECTABLE_ALLOCATOR(allocator)) return; | |
697 | } else if (NULL == allocator) { | |
698 | allocator = __CFGetDefaultAllocator(); | |
699 | } | |
700 | ||
701 | #if defined(DEBUG) && (DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI) | |
702 | if (allocator->_base._cfisa == __CFISAForTypeID(__kCFAllocatorTypeID)) { | |
703 | __CFGenericValidateType(allocator, __kCFAllocatorTypeID); | |
704 | } | |
705 | #else | |
706 | __CFGenericValidateType(allocator, __kCFAllocatorTypeID); | |
707 | #endif | |
708 | #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI | |
709 | if (allocator->_base._cfisa != __CFISAForTypeID(__kCFAllocatorTypeID)) { // malloc_zone_t * | |
710 | #if defined(DEBUG) | |
711 | size_t size = malloc_size(ptr); | |
712 | if (size) memset(ptr, 0xCC, size); | |
713 | #endif | |
714 | return malloc_zone_free((malloc_zone_t *)allocator, ptr); | |
715 | } | |
716 | #endif | |
717 | deallocateFunc = __CFAllocatorGetDeallocateFunction(&allocator->_context); | |
718 | if (NULL != ptr && NULL != deallocateFunc) { | |
719 | INVOKE_CALLBACK2(deallocateFunc, ptr, allocator->_context.info); | |
720 | } | |
721 | } | |
722 | ||
723 | CFIndex CFAllocatorGetPreferredSizeForSize(CFAllocatorRef allocator, CFIndex size, CFOptionFlags hint) { | |
724 | CFAllocatorPreferredSizeCallBack prefFunc; | |
725 | CFIndex newsize = 0; | |
726 | ||
727 | if (0) { | |
728 | allocator = kCFAllocatorSystemDefault; | |
729 | } else if (0) { | |
730 | allocator = kCFUseCollectableAllocator ? kCFAllocatorSystemDefault : __CFGetDefaultAllocator(); | |
731 | } else if (NULL == allocator) { | |
732 | allocator = __CFGetDefaultAllocator(); | |
733 | } | |
734 | ||
735 | #if defined(DEBUG) && (DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI) | |
736 | if (allocator->_base._cfisa == __CFISAForTypeID(__kCFAllocatorTypeID)) { | |
737 | __CFGenericValidateType(allocator, __kCFAllocatorTypeID); | |
738 | } | |
739 | #else | |
740 | __CFGenericValidateType(allocator, __kCFAllocatorTypeID); | |
741 | #endif | |
742 | #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI | |
743 | if (allocator->_base._cfisa != __CFISAForTypeID(__kCFAllocatorTypeID)) { // malloc_zone_t * | |
744 | return malloc_good_size(size); | |
745 | } | |
746 | #endif | |
747 | prefFunc = __CFAllocatorGetPreferredSizeFunction(&allocator->_context); | |
748 | if (0 < size && NULL != prefFunc) { | |
749 | newsize = (CFIndex)(INVOKE_CALLBACK3(prefFunc, size, hint, allocator->_context.info)); | |
750 | } | |
751 | if (newsize < size) newsize = size; | |
752 | return newsize; | |
753 | } | |
754 | ||
755 | void CFAllocatorGetContext(CFAllocatorRef allocator, CFAllocatorContext *context) { | |
756 | if (0) { | |
757 | allocator = kCFAllocatorSystemDefault; | |
758 | } else if (0) { | |
759 | allocator = kCFUseCollectableAllocator ? kCFAllocatorSystemDefault : __CFGetDefaultAllocator(); | |
760 | } else if (NULL == allocator) { | |
761 | allocator = __CFGetDefaultAllocator(); | |
762 | } | |
763 | ||
764 | #if defined(DEBUG) && (DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI) | |
765 | if (allocator->_base._cfisa == __CFISAForTypeID(__kCFAllocatorTypeID)) { | |
766 | __CFGenericValidateType(allocator, __kCFAllocatorTypeID); | |
767 | } | |
768 | #else | |
769 | __CFGenericValidateType(allocator, __kCFAllocatorTypeID); | |
770 | #endif | |
771 | CFAssert1(0 == context->version, __kCFLogAssertion, "%s(): context version not initialized to 0", __PRETTY_FUNCTION__); | |
772 | #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI | |
773 | if (allocator->_base._cfisa != __CFISAForTypeID(__kCFAllocatorTypeID)) { // malloc_zone_t * | |
774 | return; | |
775 | } | |
776 | #endif | |
777 | context->version = 0; | |
778 | context->info = allocator->_context.info; | |
779 | context->retain = __CFAllocatorGetRetainFunction(&allocator->_context); | |
780 | context->release = __CFAllocatorGetReleaseFunction(&allocator->_context); | |
781 | context->copyDescription = __CFAllocatorGetCopyDescriptionFunction(&allocator->_context); | |
782 | context->allocate = __CFAllocatorGetAllocateFunction(&allocator->_context); | |
783 | context->reallocate = __CFAllocatorGetReallocateFunction(&allocator->_context); | |
784 | context->deallocate = __CFAllocatorGetDeallocateFunction(&allocator->_context); | |
785 | context->preferredSize = __CFAllocatorGetPreferredSizeFunction(&allocator->_context); | |
786 | } | |
787 | ||
788 | CF_PRIVATE void *_CFAllocatorAllocateGC(CFAllocatorRef allocator, CFIndex size, CFOptionFlags hint) | |
789 | { | |
790 | if (CF_IS_COLLECTABLE_ALLOCATOR(allocator)) | |
791 | return auto_zone_allocate_object((auto_zone_t*)kCFAllocatorSystemDefault->_context.info, size, CF_GET_GC_MEMORY_TYPE(hint), false, false); | |
792 | else | |
793 | return CFAllocatorAllocate(allocator, size, hint); | |
794 | } | |
795 | ||
796 | CF_PRIVATE void *_CFAllocatorReallocateGC(CFAllocatorRef allocator, void *ptr, CFIndex newsize, CFOptionFlags hint) | |
797 | { | |
798 | if (CF_IS_COLLECTABLE_ALLOCATOR(allocator)) { | |
799 | if (ptr && (newsize == 0)) { | |
800 | return NULL; // equivalent to _CFAllocatorDeallocateGC. | |
801 | } | |
802 | if (ptr == NULL) { | |
803 | return auto_zone_allocate_object((auto_zone_t*)kCFAllocatorSystemDefault->_context.info, newsize, CF_GET_GC_MEMORY_TYPE(hint), false, false); // eq. to _CFAllocator | |
804 | } | |
805 | } | |
806 | // otherwise, auto_realloc() now preserves layout type and refCount. | |
807 | return CFAllocatorReallocate(allocator, ptr, newsize, hint); | |
808 | } | |
809 | ||
810 | CF_PRIVATE void _CFAllocatorDeallocateGC(CFAllocatorRef allocator, void *ptr) | |
811 | { | |
812 | // when running GC, don't deallocate. | |
813 | if (!CF_IS_COLLECTABLE_ALLOCATOR(allocator)) CFAllocatorDeallocate(allocator, ptr); | |
814 | } | |
815 | ||
816 | // -------- -------- -------- -------- -------- -------- -------- -------- | |
817 | ||
818 | ||
819 | CFRange __CFRangeMake(CFIndex loc, CFIndex len) { | |
820 | CFRange range; | |
821 | range.location = loc; | |
822 | range.length = len; | |
823 | return range; | |
824 | } | |
825 | ||
826 | ||
827 | struct __CFNull { | |
828 | CFRuntimeBase _base; | |
829 | }; | |
830 | ||
831 | static struct __CFNull __kCFNull = { | |
832 | INIT_CFRUNTIME_BASE() | |
833 | }; | |
834 | const CFNullRef kCFNull = &__kCFNull; | |
835 | ||
836 | static CFStringRef __CFNullCopyDescription(CFTypeRef cf) { | |
837 | return CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("<CFNull %p [%p]>"), cf, CFGetAllocator(cf)); | |
838 | } | |
839 | ||
840 | static CFStringRef __CFNullCopyFormattingDescription(CFTypeRef cf, CFDictionaryRef formatOptions) { | |
841 | return (CFStringRef)CFRetain(CFSTR("null")); | |
842 | } | |
843 | ||
844 | static void __CFNullDeallocate(CFTypeRef cf) { | |
845 | CFAssert(false, __kCFLogAssertion, "Deallocated CFNull!"); | |
846 | } | |
847 | ||
848 | static CFTypeID __kCFNullTypeID = _kCFRuntimeNotATypeID; | |
849 | ||
850 | static const CFRuntimeClass __CFNullClass = { | |
851 | 0, | |
852 | "CFNull", | |
853 | NULL, // init | |
854 | NULL, // copy | |
855 | __CFNullDeallocate, | |
856 | NULL, | |
857 | NULL, | |
858 | __CFNullCopyFormattingDescription, | |
859 | __CFNullCopyDescription | |
860 | }; | |
861 | ||
862 | CFTypeID CFNullGetTypeID(void) { | |
863 | static dispatch_once_t initOnce; | |
864 | dispatch_once(&initOnce, ^{ | |
865 | __kCFNullTypeID = _CFRuntimeRegisterClass(&__CFNullClass); // initOnce covered | |
866 | _CFRuntimeSetInstanceTypeIDAndIsa(&__kCFNull, __kCFNullTypeID); | |
867 | }); | |
868 | return __kCFNullTypeID; | |
869 | } | |
870 | ||
871 | void CFCollection_non_gc_storage_error(void) { } | |
872 | ||
873 | ||
874 | void _CFRuntimeSetCFMPresent(void *addr) { | |
875 | } | |
876 | ||
877 | ||
878 | // void __HALT(void); | |
879 | ||
880 | /* Keep this assembly at the bottom of the source file! */ | |
881 | ||
882 | ||
883 | extern void __HALT() { | |
884 | #if defined(__ppc__) | |
885 | __asm__("trap"); | |
886 | #elif defined(__i386__) || defined(__x86_64__) | |
887 | #if defined(_MSC_VER) | |
888 | __asm int 3; | |
889 | #else | |
890 | __asm__("int3"); | |
891 | #endif | |
892 | #endif | |
893 | } | |
894 | ||
895 |