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>
32struct 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.
80template <typename Fn, ptrauth_key Key>
81class 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) const
90 {
91 if (fn == nullptr) {
92 return 0;
93 } else {
94 return (uintptr_t)
95 ptrauth_auth_and_resign(fn, ptrauth_key_function_pointer, 0,
96 Key, &bits);
97 }
98 }
99
100 // Authenticate otherBits at otherStorage.
101 // Re-sign it with our storage address.
102 // DOES NOT actually write to our storage.
103 uintptr_t prepareWrite(const StorageSignedFunctionPointer& other) const
104 {
105 if (other.bits == 0) {
106 return 0;
107 } else {
108 return (uintptr_t)
109 ptrauth_auth_and_resign((void*)other.bits, Key, &other.bits,
110 Key, &bits);
111 }
112 }
113
114 // Authenticate ptr as if it were stored at our storage address.
115 // Re-sign it as a C function pointer.
116 // DOES NOT actually read from our storage.
117 Fn completeReadFn(uintptr_t ptr) const
118 {
119 if (ptr == 0) {
120 return nullptr;
121 } else {
122 return ptrauth_auth_function((Fn)ptr, Key, &bits);
123 }
124 }
125
126 // Authenticate ptr as if it were at our storage address.
127 // Return it as a dereferenceable pointer.
128 // DOES NOT actually read from our storage.
129 void* completeReadRaw(uintptr_t ptr) const
130 {
131 if (ptr == 0) {
132 return nullptr;
133 } else {
134 return ptrauth_auth_data((void*)ptr, Key, &bits);
135 }
136 }
137
138 StorageSignedFunctionPointer() { }
139
140 StorageSignedFunctionPointer(Fn value)
141 : bits(prepareWrite(value)) { }
142
143 StorageSignedFunctionPointer(const StorageSignedFunctionPointer& value)
144 : bits(prepareWrite(value)) { }
145
146 StorageSignedFunctionPointer&
147 operator = (Fn rhs) {
148 bits = prepareWrite(rhs);
149 return *this;
150 }
151
152 StorageSignedFunctionPointer&
153 operator = (const StorageSignedFunctionPointer& rhs) {
154 bits = prepareWrite(rhs);
155 return *this;
156 }
157
158 operator Fn () const {
159 return completeReadFn(bits);
160 }
161
162 explicit operator void* () const {
163 return completeReadRaw(bits);
164 }
165
166 explicit operator bool () const {
167 return completeReadRaw(bits) != nullptr;
168 }
169};
170
171using BlockCopyFunction = StorageSignedFunctionPointer
172 <void(*)(void *, const void *),
173 ptrauth_key_block_function>;
174
175using BlockDisposeFunction = StorageSignedFunctionPointer
176 <void(*)(const void *),
177 ptrauth_key_block_function>;
178
179using BlockInvokeFunction = StorageSignedFunctionPointer
180 <void(*)(void *, ...),
181 ptrauth_key_block_function>;
182
183using BlockByrefKeepFunction = StorageSignedFunctionPointer
184 <void(*)(struct Block_byref *, struct Block_byref *),
185 ptrauth_key_block_function>;
186
187using BlockByrefDestroyFunction = StorageSignedFunctionPointer
188 <void(*)(struct Block_byref *),
189 ptrauth_key_block_function>;
190
191// c++11 and ptrauth_calls
192#elif !__has_feature(ptrauth_calls)
193// not ptrauth_calls
194
195typedef void(*BlockCopyFunction)(void *, const void *);
196typedef void(*BlockDisposeFunction)(const void *);
197typedef void(*BlockInvokeFunction)(void *, ...);
198typedef void(*BlockByrefKeepFunction)(struct Block_byref*, struct Block_byref*);
199typedef void(*BlockByrefDestroyFunction)(struct Block_byref *);
200
201#else
202// ptrauth_calls but not c++11
203
204typedef uintptr_t BlockCopyFunction;
205typedef uintptr_t BlockDisposeFunction;
206typedef uintptr_t BlockInvokeFunction;
207typedef uintptr_t BlockByrefKeepFunction;
208typedef uintptr_t BlockByrefDestroyFunction;
209
210#endif
211
212
213// Values for Block_layout->flags to describe block objects
214enum {
215 BLOCK_DEALLOCATING = (0x0001), // runtime
216 BLOCK_REFCOUNT_MASK = (0xfffe), // runtime
217 BLOCK_NEEDS_FREE = (1 << 24), // runtime
218 BLOCK_HAS_COPY_DISPOSE = (1 << 25), // compiler
219 BLOCK_HAS_CTOR = (1 << 26), // compiler: helpers have C++ code
220 BLOCK_IS_GC = (1 << 27), // runtime
221 BLOCK_IS_GLOBAL = (1 << 28), // compiler
222 BLOCK_USE_STRET = (1 << 29), // compiler: undefined if !BLOCK_HAS_SIGNATURE
223 BLOCK_HAS_SIGNATURE = (1 << 30), // compiler
224 BLOCK_HAS_EXTENDED_LAYOUT=(1 << 31) // compiler
225};
226
227#define BLOCK_DESCRIPTOR_1 1
228struct Block_descriptor_1 {
229 uintptr_t reserved;
230 uintptr_t size;
231};
232
233#define BLOCK_DESCRIPTOR_2 1
234struct Block_descriptor_2 {
235 // requires BLOCK_HAS_COPY_DISPOSE
236 BlockCopyFunction copy;
237 BlockDisposeFunction dispose;
238};
239
240#define BLOCK_DESCRIPTOR_3 1
241struct Block_descriptor_3 {
242 // requires BLOCK_HAS_SIGNATURE
243 const char *signature;
244 const char *layout; // contents depend on BLOCK_HAS_EXTENDED_LAYOUT
245};
246
247struct Block_layout {
248 void *isa;
249 volatile int32_t flags; // contains ref count
250 int32_t reserved;
251 BlockInvokeFunction invoke;
252 struct Block_descriptor_1 *descriptor;
253 // imported variables
254};
255
256
257// Values for Block_byref->flags to describe __block variables
258enum {
259 // Byref refcount must use the same bits as Block_layout's refcount.
260 // BLOCK_DEALLOCATING = (0x0001), // runtime
261 // BLOCK_REFCOUNT_MASK = (0xfffe), // runtime
262
263 BLOCK_BYREF_LAYOUT_MASK = (0xf << 28), // compiler
264 BLOCK_BYREF_LAYOUT_EXTENDED = ( 1 << 28), // compiler
265 BLOCK_BYREF_LAYOUT_NON_OBJECT = ( 2 << 28), // compiler
266 BLOCK_BYREF_LAYOUT_STRONG = ( 3 << 28), // compiler
267 BLOCK_BYREF_LAYOUT_WEAK = ( 4 << 28), // compiler
268 BLOCK_BYREF_LAYOUT_UNRETAINED = ( 5 << 28), // compiler
269
270 BLOCK_BYREF_IS_GC = ( 1 << 27), // runtime
271
272 BLOCK_BYREF_HAS_COPY_DISPOSE = ( 1 << 25), // compiler
273 BLOCK_BYREF_NEEDS_FREE = ( 1 << 24), // runtime
274};
275
276struct Block_byref {
277 void *isa;
278 struct Block_byref *forwarding;
279 volatile int32_t flags; // contains ref count
280 uint32_t size;
281};
282
283struct Block_byref_2 {
284 // requires BLOCK_BYREF_HAS_COPY_DISPOSE
285 BlockByrefKeepFunction byref_keep;
286 BlockByrefDestroyFunction byref_destroy;
287};
288
289struct Block_byref_3 {
290 // requires BLOCK_BYREF_LAYOUT_EXTENDED
291 const char *layout;
292};
293
294
295// Extended layout encoding.
296
297// Values for Block_descriptor_3->layout with BLOCK_HAS_EXTENDED_LAYOUT
298// and for Block_byref_3->layout with BLOCK_BYREF_LAYOUT_EXTENDED
299
300// If the layout field is less than 0x1000, then it is a compact encoding
301// of the form 0xXYZ: X strong pointers, then Y byref pointers,
302// then Z weak pointers.
303
304// If the layout field is 0x1000 or greater, it points to a
305// string of layout bytes. Each byte is of the form 0xPN.
306// Operator P is from the list below. Value N is a parameter for the operator.
307// Byte 0x00 terminates the layout; remaining block data is non-pointer bytes.
308
309enum {
310 BLOCK_LAYOUT_ESCAPE = 0, // N=0 halt, rest is non-pointer. N!=0 reserved.
311 BLOCK_LAYOUT_NON_OBJECT_BYTES = 1, // N bytes non-objects
312 BLOCK_LAYOUT_NON_OBJECT_WORDS = 2, // N words non-objects
313 BLOCK_LAYOUT_STRONG = 3, // N words strong pointers
314 BLOCK_LAYOUT_BYREF = 4, // N words byref pointers
315 BLOCK_LAYOUT_WEAK = 5, // N words weak pointers
316 BLOCK_LAYOUT_UNRETAINED = 6, // N words unretained pointers
317 BLOCK_LAYOUT_UNKNOWN_WORDS_7 = 7, // N words, reserved
318 BLOCK_LAYOUT_UNKNOWN_WORDS_8 = 8, // N words, reserved
319 BLOCK_LAYOUT_UNKNOWN_WORDS_9 = 9, // N words, reserved
320 BLOCK_LAYOUT_UNKNOWN_WORDS_A = 0xA, // N words, reserved
321 BLOCK_LAYOUT_UNUSED_B = 0xB, // unspecified, reserved
322 BLOCK_LAYOUT_UNUSED_C = 0xC, // unspecified, reserved
323 BLOCK_LAYOUT_UNUSED_D = 0xD, // unspecified, reserved
324 BLOCK_LAYOUT_UNUSED_E = 0xE, // unspecified, reserved
325 BLOCK_LAYOUT_UNUSED_F = 0xF, // unspecified, reserved
326};
327
328
329// Runtime support functions used by compiler when generating copy/dispose helpers
330
331// Values for _Block_object_assign() and _Block_object_dispose() parameters
332enum {
333 // see function implementation for a more complete description of these fields and combinations
334 BLOCK_FIELD_IS_OBJECT = 3, // id, NSObject, __attribute__((NSObject)), block, ...
335 BLOCK_FIELD_IS_BLOCK = 7, // a block variable
336 BLOCK_FIELD_IS_BYREF = 8, // the on stack structure holding the __block variable
337 BLOCK_FIELD_IS_WEAK = 16, // declared __weak, only used in byref copy helpers
338 BLOCK_BYREF_CALLER = 128, // called from __block (byref) copy/dispose support routines.
339};
340
341enum {
342 BLOCK_ALL_COPY_DISPOSE_FLAGS =
343 BLOCK_FIELD_IS_OBJECT | BLOCK_FIELD_IS_BLOCK | BLOCK_FIELD_IS_BYREF |
344 BLOCK_FIELD_IS_WEAK | BLOCK_BYREF_CALLER
345};
346
347
348// Function pointer accessors
349
350static inline __typeof__(void (*)(void *, ...))
351_Block_get_invoke_fn(struct Block_layout *block)
352{
353 return (void (*)(void *, ...))_Block_get_function_pointer(block->invoke);
354}
355
356static inline void
357_Block_set_invoke_fn(struct Block_layout *block, void (*fn)(void *, ...))
358{
359 _Block_set_function_pointer(block->invoke, fn);
360}
361
362
363static inline __typeof__(void (*)(void *, const void *))
364_Block_get_copy_fn(struct Block_descriptor_2 *desc)
365{
366 return (void (*)(void *, const void *))_Block_get_function_pointer(desc->copy);
367}
368
369static inline void
370_Block_set_copy_fn(struct Block_descriptor_2 *desc,
371 void (*fn)(void *, const void *))
372{
373 _Block_set_function_pointer(desc->copy, fn);
374}
375
376
377static inline __typeof__(void (*)(const void *))
378_Block_get_dispose_fn(struct Block_descriptor_2 *desc)
379{
380 return (void (*)(const void *))_Block_get_function_pointer(desc->dispose);
381}
382
383static inline void
384_Block_set_dispose_fn(struct Block_descriptor_2 *desc,
385 void (*fn)(const void *))
386{
387 _Block_set_function_pointer(desc->dispose, fn);
388}
389
390
391// Other support functions
392
393
394// runtime entry to get total size of a closure
395BLOCK_EXPORT size_t Block_size(void *aBlock);
396
397// indicates whether block was compiled with compiler that sets the ABI related metadata bits
398BLOCK_EXPORT bool _Block_has_signature(void *aBlock)
399 __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_4_3);
400
401// returns TRUE if return value of block is on the stack, FALSE otherwise
402BLOCK_EXPORT bool _Block_use_stret(void *aBlock)
403 __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_4_3);
404
405// Returns a string describing the block's parameter and return types.
406// The encoding scheme is the same as Objective-C @encode.
407// Returns NULL for blocks compiled with some compilers.
408BLOCK_EXPORT const char * _Block_signature(void *aBlock)
409 __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_4_3);
410
411// Returns a string describing the block's GC layout.
412// This uses the GC skip/scan encoding.
413// May return NULL.
414BLOCK_EXPORT const char * _Block_layout(void *aBlock)
415 __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_4_3);
416
417// Returns a string describing the block's layout.
418// This uses the "extended layout" form described above.
419// May return NULL.
420BLOCK_EXPORT const char * _Block_extended_layout(void *aBlock)
421 __OSX_AVAILABLE_STARTING(__MAC_10_8, __IPHONE_7_0);
422
423// Callable only from the ARR weak subsystem while in exclusion zone
424BLOCK_EXPORT bool _Block_tryRetain(const void *aBlock)
425 __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_4_3);
426
427// Callable only from the ARR weak subsystem while in exclusion zone
428BLOCK_EXPORT bool _Block_isDeallocating(const void *aBlock)
429 __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_4_3);
430
431
432// the raw data space for runtime classes for blocks
433// class+meta used for stack, malloc, and collectable based blocks
434BLOCK_EXPORT void * _NSConcreteMallocBlock[32]
435 __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_3_2);
436BLOCK_EXPORT void * _NSConcreteAutoBlock[32]
437 __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_3_2);
438BLOCK_EXPORT void * _NSConcreteFinalizingBlock[32]
439 __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_3_2);
440BLOCK_EXPORT void * _NSConcreteWeakBlockVariable[32]
441 __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_3_2);
442// declared in Block.h
443// BLOCK_EXPORT void * _NSConcreteGlobalBlock[32];
444// BLOCK_EXPORT void * _NSConcreteStackBlock[32];
445
446
447struct Block_callbacks_RR {
448 size_t size; // size == sizeof(struct Block_callbacks_RR)
449 void (*retain)(const void *);
450 void (*release)(const void *);
451 void (*destructInstance)(const void *);
452};
453typedef struct Block_callbacks_RR Block_callbacks_RR;
454
455BLOCK_EXPORT void _Block_use_RR2(const Block_callbacks_RR *callbacks);
456
457
458#endif
459