xref: /xnu-12377.61.12/EXTERNAL_HEADERS/ptrcheck.h (revision 4d495c6e23c53686cf65f45067f79024cf5dcee8)
1 /*===---- ptrcheck.h - Pointer bounds hints & specifications ----------------===
2  *
3  * Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4  * See https://llvm.org/LICENSE.txt for license information.
5  * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6  *
7  *===-----------------------------------------------------------------------===
8  */
9 
10 #ifndef __PTRCHECK_H
11 #define __PTRCHECK_H
12 
13 /* __has_ptrcheck can be used in preprocessor macros (and other parts of the
14    language expecting constant expressions) to test if bounds attributes
15    exist. */
16 #if defined(__has_feature) && __has_feature(bounds_attributes)
17   #define __has_ptrcheck 1
18 #else
19   #define __has_ptrcheck 0
20 #endif
21 
22 #if __has_ptrcheck
23 
24 /* An attribute that modifies a pointer type such that its ABI is three pointer
25    components: the pointer value itself (the pointer value); one-past-the-end of
26    the object it is derived from (the upper bound); and the base address of the
27    object it is derived from (the lower bound). The pointer value is allowed to
28    lie outside the [lower bound, upper bound) interval, and it supports the
29    entire range of arithmetic operations that are usually applicable to
30    pointers. Bounds are implicitly checked only when the pointer is dereferenced
31    or converted to a different representation. */
32 #define __bidi_indexable __attribute__((__bidi_indexable__))
33 
34 /* An attribute that modifies a pointer type such that its ABI is two pointer
35    components: the pointer value itself (the lower bound); and one-past-the-end
36    of the object it is derived from (the upper bound). Indexable pointers do not
37    support negative arithmetic operations: it is a compile-time error to use a
38    subtraction or add a negative quantity to them, and it is a runtime error if
39    the same happens at runtime while it can't be detected at compile-time. Same
40    as __bidi_indexable pointers, __indexable pointers are bounds-checked when
41    dereferenced or converted to another representation. */
42 #define __indexable __attribute__((__indexable__))
43 
44 /* An attribute that modifies a pointer type such than it has the ABI of a
45    regular C pointer, without allowing pointer arithmetic. Pointer arithmetic is
46    a compile-time error. A __single pointer is expected to be either NULL or
47    point to exactly one valid value. */
48 #define __single __attribute__((__single__))
49 
50 /* An attribute that modifies a pointer type such than it can be used exactly
51    like a regular C pointer, with unchecked arithmetic and dereferencing. An
52    __unsafe_indexable pointer cannot convert implicitly to another type of
53    pointer since that would require information that is not available to the
54    program. You must use __unsafe_forge_bidi_indexable or __unsafe_forge_single
55    to convert __unsafe_indexable pointers to so-called safe pointers. */
56 #define __unsafe_indexable __attribute__((__unsafe_indexable__))
57 
58 /* An attribute that modifies a pointer type such that it has the ABI of a
59    regular C pointer, but it implicitly converts to a __bidi_indexable pointer
60    with bounds that assume there are N valid elements starting at its address.
61    The conversion happens at the same point the object converts to an rvalue, or
62    immediately for values which cannot be lvalues (such as function calls). */
63 
64 /* Assignments to the pointer object must be accompanied with an assignment to
65    N if it is assignable. */
66 
67 /* N must either be an expression that evaluates to a constant, or an integer
68    declaration from the same scope, or (for structure fields) a declaration
69    contained in basic arithmetic. */
70 #define __counted_by(N) __attribute__((__counted_by__(N)))
71 
72 /* Identical to __counted_by(N), aside that the pointer may be null for
73  * non-zero values of N. */
74 #define __counted_by_or_null(N) __attribute__((__counted_by_or_null__(N)))
75 
76 /* Identical to __counted_by(N), aside that N is a byte count instead of an
77    object count. */
78 #define __sized_by(N) __attribute__((__sized_by__(N)))
79 
80 /* Identical to __sized_by(N), aside that the pointer may be null for non-zero
81  * values of N. */
82 #define __sized_by_or_null(N) __attribute__((__sized_by_or_null__(N)))
83 
84 /* An attribute that modifies a pointer type such that it has the ABI of a
85    regular C pointer, but it implicitly converts to a __bidi_indexable pointer
86    with bounds that assume that E is one-past-the-end of the original object.
87    Implicitly, referencing E in the same scope will create a pointer that
88    converts to a __bidi_indexable pointer one-past-the-end of the original
89    object, but with a lower bound set to the value of the pointer that is
90    attributed. */
91 
92 /* Assignments to the pointer object must be accompanied with an assignment to
93    E if it is assignable. */
94 #define __ended_by(E) __attribute__((__ended_by__(E)))
95 
96 /* The __terminated_by(T) attribute can be applied to arrays and pointers. The
97    argument T specifies the terminator and must be an integer constant
98    expression. Even though T has to be an integer constant, __terminated_by(T)
99    can be applied to pointer arrays as well. For convenience, the
100    __null_terminated macro is provided, which is equivalent to
101    __terminated_by(0).
102 
103    The __terminated_by(T) attribute can be applied only to __single pointers. If
104    the pointer attribute is not specified, it is automatically set to __single.
105    A __terminated_by(T) pointer points to the first element of an array that is
106    terminated with T.
107 
108    Arithmetic on __terminated_by(T) pointers is restricted to only incrementing
109    the pointer by one, and must be able to be evaluated at compile-time.
110    Pointer arithmetic generates a runtime check to ensure that the pointer
111    doesn't point pass the terminator.
112 
113    A __terminated_by(T) pointer has the ABI of a regular C pointer.
114 
115    When __terminated_by(T) is applied to an array, the compiler checks if the
116    array is terminated with the given terminator T during the initialization.
117    Moreover, a __terminated_by(T) array decays to a __terminated_by(T) __single
118    pointer, instead of decaying to a __bidi_indexable pointer. */
119 #define __terminated_by(T) __attribute__((__terminated_by__(T)))
120 #define __null_terminated __terminated_by(0)
121 
122 /* Directives that tells the compiler to assume that subsequent pointer types
123    have the ABI specified by the ABI parameter, which may be one of single,
124    indexable, bidi_indexable or unsafe_indexable. */
125 
126 /* In project files, the ABI is assumed to be single by default. In headers
127    included from libraries or the SDK, the ABI is assumed to be unsafe_indexable
128    by default. */
129 #define __ptrcheck_abi_assume_single() \
130   _Pragma("clang abi_ptr_attr set(single)")
131 
132 #define __ptrcheck_abi_assume_indexable() \
133   _Pragma("clang abi_ptr_attr set(indexable)")
134 
135 #define __ptrcheck_abi_assume_bidi_indexable() \
136   _Pragma("clang abi_ptr_attr set(bidi_indexable)")
137 
138 #define __ptrcheck_abi_assume_unsafe_indexable() \
139   _Pragma("clang abi_ptr_attr set(unsafe_indexable)")
140 
141 /* Create a __bidi_indexable pointer of a given pointer type (T), starting at
142    address P, pointing to S bytes of valid memory. T must be a pointer type. */
143 #define __unsafe_forge_bidi_indexable(T, P, S) \
144   ((T __bidi_indexable)__builtin_unsafe_forge_bidi_indexable((P), (S)))
145 
146 /* Create a __single pointer of a given type (T), starting at address P. T must
147    be a pointer type. */
148 #define __unsafe_forge_single(T, P) \
149   ((T __single)__builtin_unsafe_forge_single((P)))
150 
151 /* Create a __terminated_by pointer of a given pointer type (T), starting at
152    address P, terminated by E. T must be a pointer type. */
153 #define __unsafe_forge_terminated_by(T, P, E)                                  \
154   ((T __terminated_by(E))__builtin_unsafe_forge_terminated_by((P), (E)))
155 
156 /* Create a __terminated_by pointer of a given pointer type (T), starting at
157    address P, terminated by 0. T must be a pointer type. */
158 #define __unsafe_forge_null_terminated(T, P) __unsafe_forge_terminated_by(T, P, 0)
159 
160 /* Create a wide pointer with the same lower bound and upper bounds as X, but
161    with a pointer component also equal to the lower bound. */
162 #define __ptr_lower_bound(X) __builtin_get_pointer_lower_bound(X)
163 
164 /* Create a wide pointer with the same lower bound and upper bounds as X, but
165    with a pointer component also equal to the upper bound. */
166 #define __ptr_upper_bound(X) __builtin_get_pointer_upper_bound(X)
167 
168 /* Convert a __terminated_by(T) pointer to an __indexable pointer. These
169    operations will calculate the upper bound by iterating over the memory
170    pointed to by P in order to find the terminator.
171 
172    The __terminated_by_to_indexable(P) does NOT include the terminator within
173    bounds of the __indexable pointer. Consequently, the terminator cannot be
174    erased (or even accessed) through the __indexable pointer. The address one
175    past the end of the array (pointing to the terminator) can be found with
176    __ptr_upper_bound().
177 
178    The __unsafe_terminated_by_to_indexable(P) does include the terminator within
179    the bounds of the __indexable pointer. This makes the operation unsafe, since
180    the terminator can be erased, and thus using P might result in out-of-bounds
181    access. */
182 #define __terminated_by_to_indexable(P) \
183   __builtin_terminated_by_to_indexable(P)
184 #define __unsafe_terminated_by_to_indexable(P) \
185   __builtin_unsafe_terminated_by_to_indexable(P)
186 
187 #define __null_terminated_to_indexable(P)            \
188   ({                                                 \
189     __typeof__(*(P)) *__null_terminated __ptr = (P); \
190     __terminated_by_to_indexable(__ptr);             \
191   })
192 
193 #define __unsafe_null_terminated_to_indexable(P)     \
194   ({                                                 \
195     __typeof__(*(P)) *__null_terminated __ptr = (P); \
196     __unsafe_terminated_by_to_indexable(__ptr);      \
197   })
198 
199 /* __unsafe_terminated_by_from_indexable(T, PTR [, PTR_TO_TERM]) converts an
200    __indexable pointer to a __terminated_by(T) pointer. The operation will
201    check if the given terminator T occurs in the memory pointed to by PTR.
202    If so, the operation evaluates to __terminated_by(T) pointer. Otherwise, it
203    traps.
204 
205    The operation has an optional parameter PTR_TO_TERM, which changes the way
206    how the check for the terminator existence is generated. PTR_TO_TERM must
207    point to the terminator element and be within the bounds of PTR.
208    If PTR_TO_TERM is provided, the runtime will check if it is in fact within
209    the bounds and points to an element that equals to T. If PTR_TO_TERM is not
210    provided, the runtime will iterate over the memory pointed to by PTR to find
211    the terminator.
212 
213    The operation is unsafe, since the terminator can be erased through PTR after
214    the conversion. This can result in out-of-bounds access through the newly
215    created __terminated_by(T) pointer.
216 
217    For convenience, the
218    __unsafe_null_terminated_from_indexable(PTR [, PTR_TO_TERM]) macro is
219    provided, which assumes that the terminator is 0. */
220 #define __unsafe_terminated_by_from_indexable(T, ...) \
221   __builtin_unsafe_terminated_by_from_indexable((T), __VA_ARGS__)
222 #define __unsafe_null_terminated_from_indexable(...) \
223   __builtin_unsafe_terminated_by_from_indexable(0, __VA_ARGS__)
224 
225 /* Instruct the compiler to disregard the bounds of an array used in a function
226    prototype and allow the decayed pointer to use __counted_by. This is a niche
227    capability that is only useful in limited patterns (the way that `mig` uses
228    arrays being one of them). */
229 #define __array_decay_dicards_count_in_parameters \
230   __attribute__((__decay_discards_count_in_parameters__))
231 
232 /* An attribute to indicate a variable to be effectively constant (or data const)
233    that it is allocated in a const section so cannot be modified after an early
234    stage of bootup, for example. Adding this attribute allows a global variable
235    to be used in __counted_by attribute of struct fields, function parameter, or
236    local variable just like actual constants.
237    Note that ensuring the value never changes once it is used is the user's
238    responsibility. One way to achieve this is the xnu model, in which certain
239    variables are placed in a segment that is remapped as read-only after
240    initialization. */
241 #define __unsafe_late_const __attribute__((__unsafe_late_const__))
242 
243 /* An attribute to indicate that a function is unavailable when -fbounds-safety
244    is enabled because it is unsafe. Calls to functions annotated with this
245    attribute are errors when -fbounds-safety is enabled, but are allowed when
246    -fbounds-safety is disabled.
247 
248    Example:
249 
250    void* __ptrcheck_unavailable some_unsafe_api(void*);
251  */
252 #define __ptrcheck_unavailable                                                 \
253   __attribute__((__unavailable__("unavailable with -fbounds-safety.")))
254 
255 /* __ptrcheck_unavailable_r is the same as __ptrcheck_unavailable but it takes
256    as an argument the name of replacement function that is safe for use with
257    -fbounds-safety enabled.
258 
259    Example:
260 
261    void* __counted_by(size) safe_api(void* __counted_by(size), size_t size);
262 
263    void* __ptrcheck_unavailable_r(safe_api) some_unsafe_api(void*);
264  */
265 #define __ptrcheck_unavailable_r(REPLACEMENT)                                  \
266   __attribute__((__unavailable__(                                                  \
267       "unavailable with -fbounds-safety. Use " #REPLACEMENT " instead.")))
268 
269 #else
270 
271 /* We intentionally define to nothing pointer attributes which do not have an
272    impact on the ABI. __indexable and __bidi_indexable are not defined because
273    of the ABI incompatibility that makes the diagnostic preferable. */
274 #define __single
275 #define __unsafe_indexable
276 #define __counted_by(N)
277 #define __counted_by_or_null(N)
278 #define __sized_by(N)
279 #define __sized_by_or_null(N)
280 #define __ended_by(E)
281 
282 /* We intentionally define the terminated_by attributes to nothing. */
283 #define __terminated_by(T)
284 #define __null_terminated
285 
286 /* Similarly, we intentionally define to nothing the
287    __ptrcheck_abi_assume_single and __ptrcheck_abi_assume_unsafe_indexable
288    macros because they do not lead to an ABI incompatibility. However, we do not
289    define the indexable and unsafe_indexable ones because the diagnostic is
290    better than the silent ABI break. */
291 #define __ptrcheck_abi_assume_single()
292 #define __ptrcheck_abi_assume_unsafe_indexable()
293 
294 /* __unsafe_forge intrinsics are defined as regular C casts. */
295 #define __unsafe_forge_bidi_indexable(T, P, S) ((T)(P))
296 #define __unsafe_forge_single(T, P) ((T)(P))
297 #define __unsafe_forge_terminated_by(T, P, E) ((T)(P))
298 #define __unsafe_forge_null_terminated(T, P) ((T)(P))
299 
300 /* The conversion between terminated_by pointers just evaluates to the pointer
301    argument. */
302 #define __terminated_by_to_indexable(P) (P)
303 #define __unsafe_terminated_by_to_indexable(P) (P)
304 #define __null_terminated_to_indexable(P) (P)
305 #define __unsafe_null_terminated_to_indexable(P) (P)
306 #define __unsafe_terminated_by_from_indexable(T, P, ...) (P)
307 #define __unsafe_null_terminated_from_indexable(P, ...) (P)
308 
309 /* decay operates normally; attribute is meaningless without pointer checks. */
310 #define __array_decay_dicards_count_in_parameters
311 
312 /* The APIs marked with these attributes are available outside the context of
313    pointer checks, so do nothing. */
314 #define __ptrcheck_unavailable
315 #define __ptrcheck_unavailable_r(REPLACEMENT)
316 
317 #endif /* __has_ptrcheck */
318 
319 #endif /* __PTRCHECK_H */
320