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_SMALL_DESCRIPTOR_SUPPORTED 1
230 #endif
231
232 #if BLOCK_SMALL_DESCRIPTOR_SUPPORTED
233 #if __has_feature(ptrauth_signed_block_descriptors)
234 #define _Block_get_relative_function_pointer(aBlock, field, type) \
235 ({ \
236 __typeof__(type) _fn; \
237 __asm__ ( \
238 "mov x17, %[bds] \n\t" \
239 "movk x17, %[disc], lsl 48 \n\t" \
240 "ldr x16, [%[bds]] \n\t" \
241 "autda x16, x17 \n\t" \
242 "add x16, x16, %[offset] \n\t" \
243 "ldrsw x17, [x16] \n\t" \
244 "add x16, x16, x17 \n\t" \
245 "paciza x16 \n\t" \
246 "mov %[fn], x16 \n\t" \
247 : [fn] "=r" (_fn) \
248 : [disc] "i" (_Block_descriptor_ptrauth_discriminator), \
249 [bds] "r" (&(aBlock)->descriptor), \
250 [offset] "i" (offsetof(struct Block_descriptor_small, field)) \
251 : "x16", "x17" \
252 ); \
253 _fn; \
254 })
255 #else /* __has_feature(ptrauth_calls) */
256 #define _Block_get_relative_function_pointer(aBlock, field, type) \
257 ({ \
258 struct Block_descriptor_small *_bds = (struct Block_descriptor_small *) \
259 (aBlock)->descriptor; \
260 (type)((uintptr_t)&_bds->field + (uintptr_t)(intptr_t)_bds->field); \
261 })
262 #endif /* __has_feature(ptrauth_calls) */
263 #endif /* BLOCK_SMALL_DESCRIPTOR_SUPPORTED */
264
265 #define _Block_descriptor_ptrauth_discriminator 0xC0BB
266
267 // Values for Block_layout->flags to describe block objects
268 enum {
269 BLOCK_DEALLOCATING = (0x0001),// runtime
270 BLOCK_REFCOUNT_MASK = (0xfffe),// runtime
271 BLOCK_INLINE_LAYOUT_STRING = (1 << 21), // compiler
272
273 #if BLOCK_SMALL_DESCRIPTOR_SUPPORTED
274 BLOCK_SMALL_DESCRIPTOR = (1 << 22),// compiler
275 #endif
276
277 BLOCK_IS_NOESCAPE = (1 << 23), // compiler
278 BLOCK_NEEDS_FREE = (1 << 24),// runtime
279 BLOCK_HAS_COPY_DISPOSE = (1 << 25),// compiler
280 BLOCK_HAS_CTOR = (1 << 26),// compiler: helpers have C++ code
281 BLOCK_IS_GC = (1 << 27),// runtime
282 BLOCK_IS_GLOBAL = (1 << 28),// compiler
283 BLOCK_USE_STRET = (1 << 29),// compiler: undefined if !BLOCK_HAS_SIGNATURE
284 BLOCK_HAS_SIGNATURE = (1 << 30),// compiler
285 BLOCK_HAS_EXTENDED_LAYOUT=(1 << 31) // compiler
286 };
287
288 #define BLOCK_DESCRIPTOR_1 1
289 struct Block_descriptor_1 {
290 uintptr_t reserved;
291 uintptr_t size;
292 };
293
294 #define BLOCK_DESCRIPTOR_2 1
295 struct Block_descriptor_2 {
296 // requires BLOCK_HAS_COPY_DISPOSE
297 BlockCopyFunction copy;
298 BlockDisposeFunction dispose;
299 };
300
301 #define BLOCK_DESCRIPTOR_3 1
302 struct Block_descriptor_3 {
303 // requires BLOCK_HAS_SIGNATURE
304 const char *signature;
305 const char *layout; // contents depend on BLOCK_HAS_EXTENDED_LAYOUT
306 };
307
308 struct Block_descriptor_small {
309 uint32_t size;
310
311 int32_t signature;
312 int32_t layout;
313
314 /* copy & dispose are optional, only access them if
315 * Block_layout->flags & BLOCK_HAS_COPY_DIPOSE */
316 int32_t copy;
317 int32_t dispose;
318 };
319
320
321 struct Block_layout {
322 void *isa;
323 volatile int32_t flags; // contains ref count
324 int32_t reserved;
325 BlockInvokeFunction invoke;
326 struct Block_descriptor_1 *descriptor;
327 // imported variables
328 };
329
330
331 // Values for Block_byref->flags to describe __block variables
332 enum {
333 // Byref refcount must use the same bits as Block_layout's refcount.
334 // BLOCK_DEALLOCATING = (0x0001), // runtime
335 // BLOCK_REFCOUNT_MASK = (0xfffe), // runtime
336
337 BLOCK_BYREF_LAYOUT_MASK = (0xf << 28),// compiler
338 BLOCK_BYREF_LAYOUT_EXTENDED = (1 << 28),// compiler
339 BLOCK_BYREF_LAYOUT_NON_OBJECT = (2 << 28), // compiler
340 BLOCK_BYREF_LAYOUT_STRONG = (3 << 28),// compiler
341 BLOCK_BYREF_LAYOUT_WEAK = (4 << 28),// compiler
342 BLOCK_BYREF_LAYOUT_UNRETAINED = (5 << 28), // compiler
343
344 BLOCK_BYREF_IS_GC = (1 << 27),// runtime
345
346 BLOCK_BYREF_HAS_COPY_DISPOSE = (1 << 25),// compiler
347 BLOCK_BYREF_NEEDS_FREE = (1 << 24),// runtime
348 };
349
350 struct Block_byref {
351 void *isa;
352 struct Block_byref *forwarding;
353 volatile int32_t flags; // contains ref count
354 uint32_t size;
355 };
356
357 struct Block_byref_2 {
358 // requires BLOCK_BYREF_HAS_COPY_DISPOSE
359 BlockByrefKeepFunction byref_keep;
360 BlockByrefDestroyFunction byref_destroy;
361 };
362
363 struct Block_byref_3 {
364 // requires BLOCK_BYREF_LAYOUT_EXTENDED
365 const char *layout;
366 };
367
368
369 // Extended layout encoding.
370
371 // Values for Block_descriptor_3->layout with BLOCK_HAS_EXTENDED_LAYOUT
372 // and for Block_byref_3->layout with BLOCK_BYREF_LAYOUT_EXTENDED
373
374 // If the layout field is less than 0x1000, then it is a compact encoding
375 // of the form 0xXYZ: X strong pointers, then Y byref pointers,
376 // then Z weak pointers.
377
378 // If the layout field is 0x1000 or greater, it points to a
379 // string of layout bytes. Each byte is of the form 0xPN.
380 // Operator P is from the list below. Value N is a parameter for the operator.
381 // Byte 0x00 terminates the layout; remaining block data is non-pointer bytes.
382
383 enum {
384 BLOCK_LAYOUT_ESCAPE = 0, // N=0 halt, rest is non-pointer. N!=0 reserved.
385 BLOCK_LAYOUT_NON_OBJECT_BYTES = 1, // N bytes non-objects
386 BLOCK_LAYOUT_NON_OBJECT_WORDS = 2, // N words non-objects
387 BLOCK_LAYOUT_STRONG = 3,// N words strong pointers
388 BLOCK_LAYOUT_BYREF = 4,// N words byref pointers
389 BLOCK_LAYOUT_WEAK = 5,// N words weak pointers
390 BLOCK_LAYOUT_UNRETAINED = 6,// N words unretained pointers
391 BLOCK_LAYOUT_UNKNOWN_WORDS_7 = 7,// N words, reserved
392 BLOCK_LAYOUT_UNKNOWN_WORDS_8 = 8,// N words, reserved
393 BLOCK_LAYOUT_UNKNOWN_WORDS_9 = 9,// N words, reserved
394 BLOCK_LAYOUT_UNKNOWN_WORDS_A = 0xA,// N words, reserved
395 BLOCK_LAYOUT_UNUSED_B = 0xB,// unspecified, reserved
396 BLOCK_LAYOUT_UNUSED_C = 0xC,// unspecified, reserved
397 BLOCK_LAYOUT_UNUSED_D = 0xD,// unspecified, reserved
398 BLOCK_LAYOUT_UNUSED_E = 0xE,// unspecified, reserved
399 BLOCK_LAYOUT_UNUSED_F = 0xF,// unspecified, reserved
400 };
401
402
403 // Runtime support functions used by compiler when generating copy/dispose helpers
404
405 // Values for _Block_object_assign() and _Block_object_dispose() parameters
406 enum {
407 // see function implementation for a more complete description of these fields and combinations
408 BLOCK_FIELD_IS_OBJECT = 3,// id, NSObject, __attribute__((NSObject)), block, ...
409 BLOCK_FIELD_IS_BLOCK = 7,// a block variable
410 BLOCK_FIELD_IS_BYREF = 8,// the on stack structure holding the __block variable
411 BLOCK_FIELD_IS_WEAK = 16,// declared __weak, only used in byref copy helpers
412 BLOCK_BYREF_CALLER = 128,// called from __block (byref) copy/dispose support routines.
413 };
414
415 enum {
416 BLOCK_ALL_COPY_DISPOSE_FLAGS =
417 BLOCK_FIELD_IS_OBJECT | BLOCK_FIELD_IS_BLOCK | BLOCK_FIELD_IS_BYREF |
418 BLOCK_FIELD_IS_WEAK | BLOCK_BYREF_CALLER
419 };
420
421
422 // Function pointer accessors
423
424 static inline __typeof__(void (*)(void *, ...))
_Block_get_invoke_fn(struct Block_layout * block)425 _Block_get_invoke_fn(struct Block_layout *block)
426 {
427 return (void (*)(void *, ...))_Block_get_function_pointer(block->invoke);
428 }
429
430 static inline void
_Block_set_invoke_fn(struct Block_layout * block,void (* fn)(void *,...))431 _Block_set_invoke_fn(struct Block_layout *block, void (*fn)(void *, ...))
432 {
433 _Block_set_function_pointer(block->invoke, fn);
434 }
435
436 static inline void *
_Block_get_descriptor(struct Block_layout * aBlock)437 _Block_get_descriptor(struct Block_layout *aBlock)
438 {
439 #if __has_feature(ptrauth_signed_block_descriptors)
440 uintptr_t disc = ptrauth_blend_discriminator(
441 &aBlock->descriptor, _Block_descriptor_ptrauth_discriminator);
442 return ptrauth_auth_data(aBlock->descriptor, ptrauth_key_asda, disc);
443 #else
444 return aBlock->descriptor;
445 #endif
446 }
447
448 static inline __typeof__(void (*)(void *, const void *))
_Block_get_copy_fn(struct Block_descriptor_2 * desc)449 _Block_get_copy_fn(struct Block_descriptor_2 *desc)
450 {
451 return (void (*)(void *, const void *))_Block_get_function_pointer(desc->copy);
452 }
453
454 static inline void
_Block_set_copy_fn(struct Block_descriptor_2 * desc,void (* fn)(void *,const void *))455 _Block_set_copy_fn(struct Block_descriptor_2 *desc,
456 void (*fn)(void *, const void *))
457 {
458 _Block_set_function_pointer(desc->copy, fn);
459 }
460
461
462 static inline __typeof__(void (*)(const void *))
_Block_get_dispose_fn(struct Block_descriptor_2 * desc)463 _Block_get_dispose_fn(struct Block_descriptor_2 *desc)
464 {
465 return (void (*)(const void *))_Block_get_function_pointer(desc->dispose);
466 }
467
468 static inline void
_Block_set_dispose_fn(struct Block_descriptor_2 * desc,void (* fn)(const void *))469 _Block_set_dispose_fn(struct Block_descriptor_2 *desc,
470 void (*fn)(const void *))
471 {
472 _Block_set_function_pointer(desc->dispose, fn);
473 }
474
475 #pragma clang diagnostic push
476 #pragma clang diagnostic ignored "-Wcast-align"
477
478 static inline __typeof__(void (*)(void *, const void *))
_Block_get_copy_function(struct Block_layout * aBlock)479 _Block_get_copy_function(struct Block_layout *aBlock)
480 {
481 if (!(aBlock->flags & BLOCK_HAS_COPY_DISPOSE)) {
482 return NULL;
483 }
484
485 #if BLOCK_SMALL_DESCRIPTOR_SUPPORTED
486 if (aBlock->flags & BLOCK_SMALL_DESCRIPTOR) {
487 return _Block_get_relative_function_pointer(
488 aBlock, copy, void (*)(void *, const void *));
489 }
490 #endif
491
492 void *desc = _Block_get_descriptor(aBlock);
493 struct Block_descriptor_2 *bd2 =
494 (struct Block_descriptor_2 *)((unsigned char *)desc +
495 sizeof(struct Block_descriptor_1));
496 return _Block_get_copy_fn(bd2);
497 }
498
499 static inline __typeof__(void (*)(const void *))
_Block_get_dispose_function(struct Block_layout * aBlock)500 _Block_get_dispose_function(struct Block_layout *aBlock)
501 {
502 if (!(aBlock->flags & BLOCK_HAS_COPY_DISPOSE)) {
503 return NULL;
504 }
505
506 #if BLOCK_SMALL_DESCRIPTOR_SUPPORTED
507 if (aBlock->flags & BLOCK_SMALL_DESCRIPTOR) {
508 return _Block_get_relative_function_pointer(
509 aBlock, dispose, void (*)(const void *));
510 }
511 #endif
512
513 void *desc = _Block_get_descriptor(aBlock);
514 struct Block_descriptor_2 *bd2 =
515 (struct Block_descriptor_2 *)((unsigned char *)desc +
516 sizeof(struct Block_descriptor_1));
517 return _Block_get_dispose_fn(bd2);
518 }
519
520 #pragma clang diagnostic pop
521
522 // Other support functions
523
524
525 // runtime entry to get total size of a closure
526 BLOCK_EXPORT size_t Block_size(void *aBlock);
527
528 // indicates whether block was compiled with compiler that sets the ABI related metadata bits
529 BLOCK_EXPORT bool _Block_has_signature(void *aBlock)
530 __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_4_3);
531
532 // returns TRUE if return value of block is on the stack, FALSE otherwise
533 BLOCK_EXPORT bool _Block_use_stret(void *aBlock)
534 __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_4_3);
535
536 // Returns a string describing the block's parameter and return types.
537 // The encoding scheme is the same as Objective-C @encode.
538 // Returns NULL for blocks compiled with some compilers.
539 BLOCK_EXPORT const char * _Block_signature(void *aBlock)
540 __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_4_3);
541
542 // Returns a string describing the block's GC layout.
543 // This uses the GC skip/scan encoding.
544 // May return NULL.
545 BLOCK_EXPORT const char * _Block_layout(void *aBlock)
546 __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_4_3);
547
548 // Returns a string describing the block's layout.
549 // This uses the "extended layout" form described above.
550 // May return NULL.
551 BLOCK_EXPORT const char * _Block_extended_layout(void *aBlock)
552 __OSX_AVAILABLE_STARTING(__MAC_10_8, __IPHONE_7_0);
553
554 // Callable only from the ARR weak subsystem while in exclusion zone
555 BLOCK_EXPORT bool _Block_tryRetain(const void *aBlock)
556 __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_4_3);
557
558 // Callable only from the ARR weak subsystem while in exclusion zone
559 BLOCK_EXPORT bool _Block_isDeallocating(const void *aBlock)
560 __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_4_3);
561
562
563 // the raw data space for runtime classes for blocks
564 // class+meta used for stack, malloc, and collectable based blocks
565 BLOCK_EXPORT void * _NSConcreteMallocBlock[32]
566 __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_3_2);
567 BLOCK_EXPORT void * _NSConcreteAutoBlock[32]
568 __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_3_2);
569 BLOCK_EXPORT void * _NSConcreteFinalizingBlock[32]
570 __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_3_2);
571 BLOCK_EXPORT void * _NSConcreteWeakBlockVariable[32]
572 __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_3_2);
573 // declared in Block.h
574 // BLOCK_EXPORT void * _NSConcreteGlobalBlock[32];
575 // BLOCK_EXPORT void * _NSConcreteStackBlock[32];
576
577
578 #if !KERNEL
579 struct Block_callbacks_RR {
580 size_t size; // size == sizeof(struct Block_callbacks_RR)
581 void (*retain)(const void *);
582 void (*release)(const void *);
583 void (*destructInstance)(const void *);
584 };
585 typedef struct Block_callbacks_RR Block_callbacks_RR;
586
587 BLOCK_EXPORT void _Block_use_RR2(const Block_callbacks_RR *callbacks);
588 #endif // !KERNEL
589
590 #endif
591