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