1 /*
2 * Block_private.h
3 *
4 * SPI for Blocks
5 *
6 * Copyright (c) 2008-2010 Apple Inc. All rights reserved.
7 *
8 * @APPLE_LLVM_LICENSE_HEADER@
9 *
10 */
11
12 #ifndef _BLOCK_PRIVATE_H_
13 #define _BLOCK_PRIVATE_H_
14
15 #include <Availability.h>
16 #include <AvailabilityMacros.h>
17 #ifndef KERNEL
18 #include <TargetConditionals.h>
19 #endif
20
21 #include <stdbool.h>
22 #include <stdint.h>
23 #ifdef KERNEL
24 #include <sys/systm.h>
25 #else
26 #include <stdio.h>
27 #endif
28
29
30 #ifdef KERNEL
31 #include <libkern/Block.h>
32 struct Block_byref;
33 #else
34 #include <Block.h>
35 #endif
36
37 #if __has_include(<ptrauth.h>)
38 #include <ptrauth.h>
39 #endif
40
41 #if __has_feature(ptrauth_calls) && __cplusplus < 201103L
42
43 // C ptrauth or old C++ ptrauth
44
45 #define _Block_set_function_pointer(field, value) \
46 ((value) \
47 ? ((field) = \
48 (__typeof__(field)) \
49 ptrauth_auth_and_resign((void*)(value), \
50 ptrauth_key_function_pointer, 0, \
51 ptrauth_key_block_function, &(field))) \
52 : ((field) = 0))
53
54 #define _Block_get_function_pointer(field) \
55 ((field) \
56 ? (__typeof__(field)) \
57 ptrauth_auth_function((void*)(field), \
58 ptrauth_key_block_function, &(field)) \
59 : (__typeof__(field))0)
60
61 #else
62
63 // C++11 ptrauth or no ptrauth
64
65 #define _Block_set_function_pointer(field, value) \
66 (field) = (value)
67
68 #define _Block_get_function_pointer(field) \
69 (field)
70
71 #endif
72
73
74 #if __has_feature(ptrauth_calls) && __cplusplus >= 201103L
75
76 // StorageSignedFunctionPointer<Key, Fn> stores a function pointer of type
77 // Fn but signed with the given ptrauth key and with the address of its
78 // storage as extra data.
79 // Function pointers inside block objects are signed this way.
80 template <typename Fn, ptrauth_key Key>
81 class StorageSignedFunctionPointer {
82 uintptr_t bits;
83
84 public:
85
86 // Authenticate function pointer fn as a C function pointer.
87 // Re-sign it with our key and the storage address as extra data.
88 // DOES NOT actually write to our storage.
89 uintptr_t
prepareWrite(Fn fn)90 prepareWrite(Fn fn) const
91 {
92 if (fn == nullptr) {
93 return 0;
94 } else {
95 return (uintptr_t)
96 ptrauth_auth_and_resign(fn, ptrauth_key_function_pointer, ptrauth_function_pointer_type_discriminator(Fn),
97 Key, &bits);
98 }
99 }
100
101 // Authenticate otherBits at otherStorage.
102 // Re-sign it with our storage address.
103 // DOES NOT actually write to our storage.
104 uintptr_t
prepareWrite(const StorageSignedFunctionPointer & other)105 prepareWrite(const StorageSignedFunctionPointer& other) const
106 {
107 if (other.bits == 0) {
108 return 0;
109 } else {
110 return (uintptr_t)
111 ptrauth_auth_and_resign((void*)other.bits, Key, &other.bits,
112 Key, &bits);
113 }
114 }
115
116 // Authenticate ptr as if it were stored at our storage address.
117 // Re-sign it as a C function pointer.
118 // DOES NOT actually read from our storage.
119 Fn
completeReadFn(uintptr_t ptr)120 completeReadFn(uintptr_t ptr) const
121 {
122 if (ptr == 0) {
123 return nullptr;
124 } else {
125 return (Fn)ptrauth_auth_function((void *)ptr, Key, &bits);
126 }
127 }
128
129 // Authenticate ptr as if it were at our storage address.
130 // Return it as a dereferenceable pointer.
131 // DOES NOT actually read from our storage.
132 void*
completeReadRaw(uintptr_t ptr)133 completeReadRaw(uintptr_t ptr) const
134 {
135 if (ptr == 0) {
136 return nullptr;
137 } else {
138 return ptrauth_auth_data((void*)ptr, Key, &bits);
139 }
140 }
141
StorageSignedFunctionPointer()142 StorageSignedFunctionPointer()
143 {
144 }
145
StorageSignedFunctionPointer(Fn value)146 StorageSignedFunctionPointer(Fn value)
147 : bits(prepareWrite(value))
148 {
149 }
150
StorageSignedFunctionPointer(const StorageSignedFunctionPointer & value)151 StorageSignedFunctionPointer(const StorageSignedFunctionPointer& value)
152 : bits(prepareWrite(value))
153 {
154 }
155
156 StorageSignedFunctionPointer&
157 operator =(Fn rhs)
158 {
159 bits = prepareWrite(rhs);
160 return *this;
161 }
162
163 StorageSignedFunctionPointer&
164 operator =(const StorageSignedFunctionPointer& rhs)
165 {
166 bits = prepareWrite(rhs);
167 return *this;
168 }
169
Fn()170 operator Fn() const {
171 return completeReadFn(bits);
172 }
173
174 explicit
175 operator void*() const
176 {
177 return completeReadRaw(bits);
178 }
179
180 explicit
181 operator bool() const
182 {
183 return completeReadRaw(bits) != nullptr;
184 }
185 };
186
187 using BlockCopyFunction = StorageSignedFunctionPointer
188 <void (*)(void *, const void *),
189 ptrauth_key_block_function>;
190
191 using BlockDisposeFunction = StorageSignedFunctionPointer
192 <void (*)(const void *),
193 ptrauth_key_block_function>;
194
195 using BlockInvokeFunction = StorageSignedFunctionPointer
196 <void (*)(void *, ...),
197 ptrauth_key_block_function>;
198
199 using BlockByrefKeepFunction = StorageSignedFunctionPointer
200 <void (*)(struct Block_byref *, struct Block_byref *),
201 ptrauth_key_block_function>;
202
203 using BlockByrefDestroyFunction = StorageSignedFunctionPointer
204 <void (*)(struct Block_byref *),
205 ptrauth_key_block_function>;
206
207 // c++11 and ptrauth_calls
208 #elif !__has_feature(ptrauth_calls)
209 // not ptrauth_calls
210
211 typedef void (*BlockCopyFunction)(void *, const void *);
212 typedef void (*BlockDisposeFunction)(const void *);
213 typedef void (*BlockInvokeFunction)(void *, ...);
214 typedef void (*BlockByrefKeepFunction)(struct Block_byref*, struct Block_byref*);
215 typedef void (*BlockByrefDestroyFunction)(struct Block_byref *);
216
217 #else
218 // ptrauth_calls but not c++11
219
220 typedef uintptr_t BlockCopyFunction;
221 typedef uintptr_t BlockDisposeFunction;
222 typedef uintptr_t BlockInvokeFunction;
223 typedef uintptr_t BlockByrefKeepFunction;
224 typedef uintptr_t BlockByrefDestroyFunction;
225
226 #endif
227
228 #if __has_feature(ptrauth_calls)
229 #define _Block_get_relative_function_pointer(field, type) \
230 ((type)ptrauth_sign_unauthenticated( \
231 (void *)((uintptr_t)(intptr_t)(field) + (uintptr_t)&(field)), \
232 ptrauth_key_function_pointer, 0))
233 #else
234 #define _Block_get_relative_function_pointer(field, type) \
235 ((type)((uintptr_t)(intptr_t)(field) + (uintptr_t)&(field)))
236 #endif
237
238 #define _Block_descriptor_ptrauth_discriminator 0xC0BB
239
240 // Values for Block_layout->flags to describe block objects
241 enum {
242 BLOCK_DEALLOCATING = (0x0001),// runtime
243 BLOCK_REFCOUNT_MASK = (0xfffe),// runtime
244 BLOCK_INLINE_LAYOUT_STRING = (1 << 21), // compiler
245 BLOCK_SMALL_DESCRIPTOR = (1 << 22), // compiler
246 BLOCK_IS_NOESCAPE = (1 << 23), // compiler
247 BLOCK_NEEDS_FREE = (1 << 24),// runtime
248 BLOCK_HAS_COPY_DISPOSE = (1 << 25),// compiler
249 BLOCK_HAS_CTOR = (1 << 26),// compiler: helpers have C++ code
250 BLOCK_IS_GC = (1 << 27),// runtime
251 BLOCK_IS_GLOBAL = (1 << 28),// compiler
252 BLOCK_USE_STRET = (1 << 29),// compiler: undefined if !BLOCK_HAS_SIGNATURE
253 BLOCK_HAS_SIGNATURE = (1 << 30),// compiler
254 BLOCK_HAS_EXTENDED_LAYOUT=(1 << 31) // compiler
255 };
256
257 #define BLOCK_DESCRIPTOR_1 1
258 struct Block_descriptor_1 {
259 uintptr_t reserved;
260 uintptr_t size;
261 };
262
263 #define BLOCK_DESCRIPTOR_2 1
264 struct Block_descriptor_2 {
265 // requires BLOCK_HAS_COPY_DISPOSE
266 BlockCopyFunction copy;
267 BlockDisposeFunction dispose;
268 };
269
270 #define BLOCK_DESCRIPTOR_3 1
271 struct Block_descriptor_3 {
272 // requires BLOCK_HAS_SIGNATURE
273 const char *signature;
274 const char *layout; // contents depend on BLOCK_HAS_EXTENDED_LAYOUT
275 };
276
277 struct Block_descriptor_small {
278 uint32_t size;
279
280 int32_t signature;
281 int32_t layout;
282
283 /* copy & dispose are optional, only access them if
284 * Block_layout->flags & BLOCK_HAS_COPY_DIPOSE */
285 int32_t copy;
286 int32_t dispose;
287 };
288
289
290 struct Block_layout {
291 void *isa;
292 volatile int32_t flags; // contains ref count
293 int32_t reserved;
294 BlockInvokeFunction invoke;
295 struct Block_descriptor_1 *descriptor;
296 // imported variables
297 };
298
299
300 // Values for Block_byref->flags to describe __block variables
301 enum {
302 // Byref refcount must use the same bits as Block_layout's refcount.
303 // BLOCK_DEALLOCATING = (0x0001), // runtime
304 // BLOCK_REFCOUNT_MASK = (0xfffe), // runtime
305
306 BLOCK_BYREF_LAYOUT_MASK = (0xf << 28),// compiler
307 BLOCK_BYREF_LAYOUT_EXTENDED = (1 << 28),// compiler
308 BLOCK_BYREF_LAYOUT_NON_OBJECT = (2 << 28), // compiler
309 BLOCK_BYREF_LAYOUT_STRONG = (3 << 28),// compiler
310 BLOCK_BYREF_LAYOUT_WEAK = (4 << 28),// compiler
311 BLOCK_BYREF_LAYOUT_UNRETAINED = (5 << 28), // compiler
312
313 BLOCK_BYREF_IS_GC = (1 << 27),// runtime
314
315 BLOCK_BYREF_HAS_COPY_DISPOSE = (1 << 25),// compiler
316 BLOCK_BYREF_NEEDS_FREE = (1 << 24),// runtime
317 };
318
319 struct Block_byref {
320 void *isa;
321 struct Block_byref *forwarding;
322 volatile int32_t flags; // contains ref count
323 uint32_t size;
324 };
325
326 struct Block_byref_2 {
327 // requires BLOCK_BYREF_HAS_COPY_DISPOSE
328 BlockByrefKeepFunction byref_keep;
329 BlockByrefDestroyFunction byref_destroy;
330 };
331
332 struct Block_byref_3 {
333 // requires BLOCK_BYREF_LAYOUT_EXTENDED
334 const char *layout;
335 };
336
337
338 // Extended layout encoding.
339
340 // Values for Block_descriptor_3->layout with BLOCK_HAS_EXTENDED_LAYOUT
341 // and for Block_byref_3->layout with BLOCK_BYREF_LAYOUT_EXTENDED
342
343 // If the layout field is less than 0x1000, then it is a compact encoding
344 // of the form 0xXYZ: X strong pointers, then Y byref pointers,
345 // then Z weak pointers.
346
347 // If the layout field is 0x1000 or greater, it points to a
348 // string of layout bytes. Each byte is of the form 0xPN.
349 // Operator P is from the list below. Value N is a parameter for the operator.
350 // Byte 0x00 terminates the layout; remaining block data is non-pointer bytes.
351
352 enum {
353 BLOCK_LAYOUT_ESCAPE = 0, // N=0 halt, rest is non-pointer. N!=0 reserved.
354 BLOCK_LAYOUT_NON_OBJECT_BYTES = 1, // N bytes non-objects
355 BLOCK_LAYOUT_NON_OBJECT_WORDS = 2, // N words non-objects
356 BLOCK_LAYOUT_STRONG = 3,// N words strong pointers
357 BLOCK_LAYOUT_BYREF = 4,// N words byref pointers
358 BLOCK_LAYOUT_WEAK = 5,// N words weak pointers
359 BLOCK_LAYOUT_UNRETAINED = 6,// N words unretained pointers
360 BLOCK_LAYOUT_UNKNOWN_WORDS_7 = 7,// N words, reserved
361 BLOCK_LAYOUT_UNKNOWN_WORDS_8 = 8,// N words, reserved
362 BLOCK_LAYOUT_UNKNOWN_WORDS_9 = 9,// N words, reserved
363 BLOCK_LAYOUT_UNKNOWN_WORDS_A = 0xA,// N words, reserved
364 BLOCK_LAYOUT_UNUSED_B = 0xB,// unspecified, reserved
365 BLOCK_LAYOUT_UNUSED_C = 0xC,// unspecified, reserved
366 BLOCK_LAYOUT_UNUSED_D = 0xD,// unspecified, reserved
367 BLOCK_LAYOUT_UNUSED_E = 0xE,// unspecified, reserved
368 BLOCK_LAYOUT_UNUSED_F = 0xF,// unspecified, reserved
369 };
370
371
372 // Runtime support functions used by compiler when generating copy/dispose helpers
373
374 // Values for _Block_object_assign() and _Block_object_dispose() parameters
375 enum {
376 // see function implementation for a more complete description of these fields and combinations
377 BLOCK_FIELD_IS_OBJECT = 3,// id, NSObject, __attribute__((NSObject)), block, ...
378 BLOCK_FIELD_IS_BLOCK = 7,// a block variable
379 BLOCK_FIELD_IS_BYREF = 8,// the on stack structure holding the __block variable
380 BLOCK_FIELD_IS_WEAK = 16,// declared __weak, only used in byref copy helpers
381 BLOCK_BYREF_CALLER = 128,// called from __block (byref) copy/dispose support routines.
382 };
383
384 enum {
385 BLOCK_ALL_COPY_DISPOSE_FLAGS =
386 BLOCK_FIELD_IS_OBJECT | BLOCK_FIELD_IS_BLOCK | BLOCK_FIELD_IS_BYREF |
387 BLOCK_FIELD_IS_WEAK | BLOCK_BYREF_CALLER
388 };
389
390
391 // Function pointer accessors
392
393 static inline __typeof__(void (*)(void *, ...))
_Block_get_invoke_fn(struct Block_layout * block)394 _Block_get_invoke_fn(struct Block_layout *block)
395 {
396 return (void (*)(void *, ...))_Block_get_function_pointer(block->invoke);
397 }
398
399 static inline void
_Block_set_invoke_fn(struct Block_layout * block,void (* fn)(void *,...))400 _Block_set_invoke_fn(struct Block_layout *block, void (*fn)(void *, ...))
401 {
402 _Block_set_function_pointer(block->invoke, fn);
403 }
404
405 static inline void *
_Block_get_descriptor(struct Block_layout * aBlock)406 _Block_get_descriptor(struct Block_layout *aBlock)
407 {
408 #if __has_feature(ptrauth_signed_block_descriptors)
409 uintptr_t disc = ptrauth_blend_discriminator(
410 &aBlock->descriptor, _Block_descriptor_ptrauth_discriminator);
411 return ptrauth_auth_data(aBlock->descriptor, ptrauth_key_asda, disc);
412 #else
413 return aBlock->descriptor;
414 #endif
415 }
416
417 static inline __typeof__(void (*)(void *, const void *))
_Block_get_copy_fn(struct Block_descriptor_2 * desc)418 _Block_get_copy_fn(struct Block_descriptor_2 *desc)
419 {
420 return (void (*)(void *, const void *))_Block_get_function_pointer(desc->copy);
421 }
422
423 static inline void
_Block_set_copy_fn(struct Block_descriptor_2 * desc,void (* fn)(void *,const void *))424 _Block_set_copy_fn(struct Block_descriptor_2 *desc,
425 void (*fn)(void *, const void *))
426 {
427 _Block_set_function_pointer(desc->copy, fn);
428 }
429
430
431 static inline __typeof__(void (*)(const void *))
_Block_get_dispose_fn(struct Block_descriptor_2 * desc)432 _Block_get_dispose_fn(struct Block_descriptor_2 *desc)
433 {
434 return (void (*)(const void *))_Block_get_function_pointer(desc->dispose);
435 }
436
437 static inline void
_Block_set_dispose_fn(struct Block_descriptor_2 * desc,void (* fn)(const void *))438 _Block_set_dispose_fn(struct Block_descriptor_2 *desc,
439 void (*fn)(const void *))
440 {
441 _Block_set_function_pointer(desc->dispose, fn);
442 }
443
444 #pragma clang diagnostic push
445 #pragma clang diagnostic ignored "-Wcast-align"
446
447 static inline __typeof__(void (*)(void *, const void *))
_Block_get_copy_function(struct Block_layout * aBlock)448 _Block_get_copy_function(struct Block_layout *aBlock)
449 {
450 if (!(aBlock->flags & BLOCK_HAS_COPY_DISPOSE)) {
451 return NULL;
452 }
453
454 void *desc = _Block_get_descriptor(aBlock);
455 if (aBlock->flags & BLOCK_SMALL_DESCRIPTOR) {
456 struct Block_descriptor_small *bds =
457 (struct Block_descriptor_small *)desc;
458 return _Block_get_relative_function_pointer(
459 bds->copy, void (*)(void *, const void *));
460 }
461
462 struct Block_descriptor_2 *bd2 =
463 (struct Block_descriptor_2 *)((unsigned char *)desc +
464 sizeof(struct Block_descriptor_1));
465 return _Block_get_copy_fn(bd2);
466 }
467
468 static inline __typeof__(void (*)(const void *))
_Block_get_dispose_function(struct Block_layout * aBlock)469 _Block_get_dispose_function(struct Block_layout *aBlock)
470 {
471 if (!(aBlock->flags & BLOCK_HAS_COPY_DISPOSE)) {
472 return NULL;
473 }
474
475 void *desc = _Block_get_descriptor(aBlock);
476 if (aBlock->flags & BLOCK_SMALL_DESCRIPTOR) {
477 struct Block_descriptor_small *bds =
478 (struct Block_descriptor_small *)desc;
479 return _Block_get_relative_function_pointer(
480 bds->dispose, void (*)(const void *));
481 }
482
483 struct Block_descriptor_2 *bd2 =
484 (struct Block_descriptor_2 *)((unsigned char *)desc +
485 sizeof(struct Block_descriptor_1));
486 return _Block_get_dispose_fn(bd2);
487 }
488
489 #pragma clang diagnostic pop
490
491 // Other support functions
492
493
494 // runtime entry to get total size of a closure
495 BLOCK_EXPORT size_t Block_size(void *aBlock);
496
497 // indicates whether block was compiled with compiler that sets the ABI related metadata bits
498 BLOCK_EXPORT bool _Block_has_signature(void *aBlock)
499 __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_4_3);
500
501 // returns TRUE if return value of block is on the stack, FALSE otherwise
502 BLOCK_EXPORT bool _Block_use_stret(void *aBlock)
503 __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_4_3);
504
505 // Returns a string describing the block's parameter and return types.
506 // The encoding scheme is the same as Objective-C @encode.
507 // Returns NULL for blocks compiled with some compilers.
508 BLOCK_EXPORT const char * _Block_signature(void *aBlock)
509 __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_4_3);
510
511 // Returns a string describing the block's GC layout.
512 // This uses the GC skip/scan encoding.
513 // May return NULL.
514 BLOCK_EXPORT const char * _Block_layout(void *aBlock)
515 __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_4_3);
516
517 // Returns a string describing the block's layout.
518 // This uses the "extended layout" form described above.
519 // May return NULL.
520 BLOCK_EXPORT const char * _Block_extended_layout(void *aBlock)
521 __OSX_AVAILABLE_STARTING(__MAC_10_8, __IPHONE_7_0);
522
523 // Callable only from the ARR weak subsystem while in exclusion zone
524 BLOCK_EXPORT bool _Block_tryRetain(const void *aBlock)
525 __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_4_3);
526
527 // Callable only from the ARR weak subsystem while in exclusion zone
528 BLOCK_EXPORT bool _Block_isDeallocating(const void *aBlock)
529 __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_4_3);
530
531
532 // the raw data space for runtime classes for blocks
533 // class+meta used for stack, malloc, and collectable based blocks
534 BLOCK_EXPORT void * _NSConcreteMallocBlock[32]
535 __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_3_2);
536 BLOCK_EXPORT void * _NSConcreteAutoBlock[32]
537 __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_3_2);
538 BLOCK_EXPORT void * _NSConcreteFinalizingBlock[32]
539 __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_3_2);
540 BLOCK_EXPORT void * _NSConcreteWeakBlockVariable[32]
541 __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_3_2);
542 // declared in Block.h
543 // BLOCK_EXPORT void * _NSConcreteGlobalBlock[32];
544 // BLOCK_EXPORT void * _NSConcreteStackBlock[32];
545
546
547 #if !KERNEL
548 struct Block_callbacks_RR {
549 size_t size; // size == sizeof(struct Block_callbacks_RR)
550 void (*retain)(const void *);
551 void (*release)(const void *);
552 void (*destructInstance)(const void *);
553 };
554 typedef struct Block_callbacks_RR Block_callbacks_RR;
555
556 BLOCK_EXPORT void _Block_use_RR2(const Block_callbacks_RR *callbacks);
557 #endif // !KERNEL
558
559 #endif
560