xref: /xnu-8020.101.4/libkern/os/alloc_util.h (revision e7776783b89a353188416a9a346c6cdb4928faad)
1*e7776783SApple OSS Distributions /*
2*e7776783SApple OSS Distributions  * Copyright (c) 2021 Apple Inc. All rights reserved.
3*e7776783SApple OSS Distributions  *
4*e7776783SApple OSS Distributions  * @APPLE_LICENSE_HEADER_START@
5*e7776783SApple OSS Distributions  *
6*e7776783SApple OSS Distributions  * This file contains Original Code and/or Modifications of Original Code
7*e7776783SApple OSS Distributions  * as defined in and that are subject to the Apple Public Source License
8*e7776783SApple OSS Distributions  * Version 2.0 (the 'License'). You may not use this file except in
9*e7776783SApple OSS Distributions  * compliance with the License. Please obtain a copy of the License at
10*e7776783SApple OSS Distributions  * http://www.opensource.apple.com/apsl/ and read it before using this
11*e7776783SApple OSS Distributions  * file.
12*e7776783SApple OSS Distributions  *
13*e7776783SApple OSS Distributions  * The Original Code and all software distributed under the License are
14*e7776783SApple OSS Distributions  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15*e7776783SApple OSS Distributions  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16*e7776783SApple OSS Distributions  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17*e7776783SApple OSS Distributions  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18*e7776783SApple OSS Distributions  * Please see the License for the specific language governing rights and
19*e7776783SApple OSS Distributions  * limitations under the License.
20*e7776783SApple OSS Distributions  *
21*e7776783SApple OSS Distributions  * @APPLE_LICENSE_HEADER_END@
22*e7776783SApple OSS Distributions  */
23*e7776783SApple OSS Distributions 
24*e7776783SApple OSS Distributions #ifndef _OS_ALLOC_UTIL_H
25*e7776783SApple OSS Distributions #define _OS_ALLOC_UTIL_H
26*e7776783SApple OSS Distributions 
27*e7776783SApple OSS Distributions #include <sys/cdefs.h>
28*e7776783SApple OSS Distributions 
29*e7776783SApple OSS Distributions #ifdef __cplusplus
30*e7776783SApple OSS Distributions 
31*e7776783SApple OSS Distributions #if __cplusplus >= 201103L
32*e7776783SApple OSS Distributions 
33*e7776783SApple OSS Distributions extern "C++" {
34*e7776783SApple OSS Distributions #include <os/cpp_util.h>
35*e7776783SApple OSS Distributions 
36*e7776783SApple OSS Distributions namespace os {
37*e7776783SApple OSS Distributions namespace au_detail {
38*e7776783SApple OSS Distributions /*
39*e7776783SApple OSS Distributions  * This is implemented using constexpr member functions to work around
40*e7776783SApple OSS Distributions  * a compiler bug related to template deduction for __ptrauth-qualified
41*e7776783SApple OSS Distributions  * types (rdar://83481514).
42*e7776783SApple OSS Distributions  *
43*e7776783SApple OSS Distributions  * We use the constexpr variable __p as a parameter to the constexpr
44*e7776783SApple OSS Distributions  * member function; because function parameters strip the __ptrauth
45*e7776783SApple OSS Distributions  * attributes, this allows us to infer the non-__ptrauth qualified
46*e7776783SApple OSS Distributions  * type in the member function template.
47*e7776783SApple OSS Distributions  */
48*e7776783SApple OSS Distributions template<class PtrTy, class CheckTy>
49*e7776783SApple OSS Distributions struct is_compatible_ptr {
50*e7776783SApple OSS Distributions 	template<class T>
51*e7776783SApple OSS Distributions 	static constexpr bool
__compute_resultis_compatible_ptr52*e7776783SApple OSS Distributions 	__compute_result(T *p __unused)
53*e7776783SApple OSS Distributions 	{
54*e7776783SApple OSS Distributions 		using _T = os::remove_extent_t<os::remove_const_t<os::remove_volatile_t<T> > >;
55*e7776783SApple OSS Distributions 		using _U = os::remove_extent_t<CheckTy>;
56*e7776783SApple OSS Distributions 		return os::is_same<void, _T>::value || os::is_same<_T, _U>::value;
57*e7776783SApple OSS Distributions 	}
58*e7776783SApple OSS Distributions 
59*e7776783SApple OSS Distributions 	static constexpr os::remove_reference_t<PtrTy> __p = nullptr;
60*e7776783SApple OSS Distributions 	static const bool value = __compute_result(__p);
61*e7776783SApple OSS Distributions };
62*e7776783SApple OSS Distributions } // namespace au_detail
63*e7776783SApple OSS Distributions } // namespace os
64*e7776783SApple OSS Distributions 
65*e7776783SApple OSS Distributions /*
66*e7776783SApple OSS Distributions  * Type checking macro implementation (C++)
67*e7776783SApple OSS Distributions  */
68*e7776783SApple OSS Distributions #define os_is_compatible_ptr_impl(ptr, type) \
69*e7776783SApple OSS Distributions 	os::au_detail::is_compatible_ptr<decltype(ptr), type>::value
70*e7776783SApple OSS Distributions } // "extern C++"
71*e7776783SApple OSS Distributions 
72*e7776783SApple OSS Distributions #else  /* __cplusplus >= 201103L */
73*e7776783SApple OSS Distributions 
74*e7776783SApple OSS Distributions #define os_is_compatible_ptr_impl(ptr, type) 1
75*e7776783SApple OSS Distributions 
76*e7776783SApple OSS Distributions #endif /* __cplusplus >= 201103L */
77*e7776783SApple OSS Distributions 
78*e7776783SApple OSS Distributions #else  /* __cplusplus */
79*e7776783SApple OSS Distributions 
80*e7776783SApple OSS Distributions /*
81*e7776783SApple OSS Distributions  * Type checking macro implementation (C):
82*e7776783SApple OSS Distributions  * wildcard any void pointer type, and check all other types using
83*e7776783SApple OSS Distributions  * __builtin_types_compatible_p.
84*e7776783SApple OSS Distributions  */
85*e7776783SApple OSS Distributions #define os_is_compatible_ptr_impl(ptr, type) _Generic((ptr),              \
86*e7776783SApple OSS Distributions 	void *: 1,                                                         \
87*e7776783SApple OSS Distributions 	const void *: 1,                                                   \
88*e7776783SApple OSS Distributions 	const volatile void *: 1,                                          \
89*e7776783SApple OSS Distributions 	volatile void * const: 1,                                          \
90*e7776783SApple OSS Distributions 	default: (__builtin_types_compatible_p(__typeof__(*(ptr)), type)))
91*e7776783SApple OSS Distributions 
92*e7776783SApple OSS Distributions #endif /* __cplusplus */
93*e7776783SApple OSS Distributions 
94*e7776783SApple OSS Distributions /*!
95*e7776783SApple OSS Distributions  * @macro os_is_compatible_ptr
96*e7776783SApple OSS Distributions  *
97*e7776783SApple OSS Distributions  * @abstract
98*e7776783SApple OSS Distributions  * Check at compile time that a pointer is compatible with a given type.
99*e7776783SApple OSS Distributions  *
100*e7776783SApple OSS Distributions  * @discussion
101*e7776783SApple OSS Distributions  * The goal of this macro is to check that the type pointed to by @c ptr
102*e7776783SApple OSS Distributions  * is compatible with the given type @c type.
103*e7776783SApple OSS Distributions  *
104*e7776783SApple OSS Distributions  * The underlying implementation differs between C and C++. In C, we
105*e7776783SApple OSS Distributions  * rely on the concept of compatible types, and we implement the check
106*e7776783SApple OSS Distributions  * using __builtin_types_compatible_p. In C++, we check type equivalence
107*e7776783SApple OSS Distributions  * using type traits.
108*e7776783SApple OSS Distributions  *
109*e7776783SApple OSS Distributions  * NOTE: This macro is a no-op for C++98 (no type check is performed).
110*e7776783SApple OSS Distributions  *
111*e7776783SApple OSS Distributions  * @param ptr           the pointer whose type needs to be checked.
112*e7776783SApple OSS Distributions  * @param type          the type which the pointer will be checked against.
113*e7776783SApple OSS Distributions  */
114*e7776783SApple OSS Distributions #define os_is_compatible_ptr(ptr, type)  os_is_compatible_ptr_impl(ptr, type)
115*e7776783SApple OSS Distributions 
116*e7776783SApple OSS Distributions /*!
117*e7776783SApple OSS Distributions  * @macro os_is_ptr_like
118*e7776783SApple OSS Distributions  *
119*e7776783SApple OSS Distributions  * @abstract
120*e7776783SApple OSS Distributions  * Tell whether the given expression resembles a pointer.
121*e7776783SApple OSS Distributions  *
122*e7776783SApple OSS Distributions  * @discussion
123*e7776783SApple OSS Distributions  * When pointer bounds are enabled, only types that are actually classified
124*e7776783SApple OSS Distributions  * as pointers will be considered pointer-like. Otherwise, any pointer-sized
125*e7776783SApple OSS Distributions  * type will be considered pointer-like.
126*e7776783SApple OSS Distributions  *
127*e7776783SApple OSS Distributions  * @param P             the expression to be checked
128*e7776783SApple OSS Distributions  */
129*e7776783SApple OSS Distributions #if __has_ptrcheck
130*e7776783SApple OSS Distributions #define os_is_ptr_like(P) (__builtin_classify_type(P) == 5)
131*e7776783SApple OSS Distributions #else  /* __has_ptrcheck */
132*e7776783SApple OSS Distributions #define os_is_ptr_like(P) (sizeof(P) == sizeof(void *))
133*e7776783SApple OSS Distributions #endif /* __has_ptrcheck */
134*e7776783SApple OSS Distributions 
135*e7776783SApple OSS Distributions /*!
136*e7776783SApple OSS Distributions  * @macro os_ptr_load_and_erase
137*e7776783SApple OSS Distributions  *
138*e7776783SApple OSS Distributions  * @abstract
139*e7776783SApple OSS Distributions  * Load the value of @c elem into a temporary, set @c elem to NULL, and
140*e7776783SApple OSS Distributions  * return the value.
141*e7776783SApple OSS Distributions  *
142*e7776783SApple OSS Distributions  * @param elem          the pointer whose value will be taken, and which will
143*e7776783SApple OSS Distributions  *                      be set to NULL.
144*e7776783SApple OSS Distributions  */
145*e7776783SApple OSS Distributions #define os_ptr_load_and_erase(elem) ({                           \
146*e7776783SApple OSS Distributions 	_Static_assert(os_is_ptr_like(elem),                      \
147*e7776783SApple OSS Distributions 	    "elem isn't pointer sized");                          \
148*e7776783SApple OSS Distributions 	__auto_type __eptr = &(elem);                             \
149*e7776783SApple OSS Distributions 	__auto_type __elem = *__eptr;                             \
150*e7776783SApple OSS Distributions 	_Pragma("clang diagnostic push")                          \
151*e7776783SApple OSS Distributions 	_Pragma("clang diagnostic ignored \"-Wold-style-cast\"")  \
152*e7776783SApple OSS Distributions 	*__eptr = (__typeof__(__elem))NULL;                       \
153*e7776783SApple OSS Distributions 	_Pragma("clang diagnostic pop")                           \
154*e7776783SApple OSS Distributions 	__elem;                                                   \
155*e7776783SApple OSS Distributions })
156*e7776783SApple OSS Distributions 
157*e7776783SApple OSS Distributions #endif /* _OS_ALLOC_UTIL_H */
158