1*4f1223e8SApple OSS Distributions // 2*4f1223e8SApple OSS Distributions // Copyright (c) 2019 Apple, Inc. All rights reserved. 3*4f1223e8SApple OSS Distributions // 4*4f1223e8SApple OSS Distributions // @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 5*4f1223e8SApple OSS Distributions // 6*4f1223e8SApple OSS Distributions // This file contains Original Code and/or Modifications of Original Code 7*4f1223e8SApple OSS Distributions // as defined in and that are subject to the Apple Public Source License 8*4f1223e8SApple OSS Distributions // Version 2.0 (the 'License'). You may not use this file except in 9*4f1223e8SApple OSS Distributions // compliance with the License. The rights granted to you under the License 10*4f1223e8SApple OSS Distributions // may not be used to create, or enable the creation or redistribution of, 11*4f1223e8SApple OSS Distributions // unlawful or unlicensed copies of an Apple operating system, or to 12*4f1223e8SApple OSS Distributions // circumvent, violate, or enable the circumvention or violation of, any 13*4f1223e8SApple OSS Distributions // terms of an Apple operating system software license agreement. 14*4f1223e8SApple OSS Distributions // 15*4f1223e8SApple OSS Distributions // Please obtain a copy of the License at 16*4f1223e8SApple OSS Distributions // http://www.opensource.apple.com/apsl/ and read it before using this file. 17*4f1223e8SApple OSS Distributions // 18*4f1223e8SApple OSS Distributions // The Original Code and all software distributed under the License are 19*4f1223e8SApple OSS Distributions // distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 20*4f1223e8SApple OSS Distributions // EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21*4f1223e8SApple OSS Distributions // INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 22*4f1223e8SApple OSS Distributions // FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 23*4f1223e8SApple OSS Distributions // Please see the License for the specific language governing rights and 24*4f1223e8SApple OSS Distributions // limitations under the License. 25*4f1223e8SApple OSS Distributions // 26*4f1223e8SApple OSS Distributions // @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27*4f1223e8SApple OSS Distributions // 28*4f1223e8SApple OSS Distributions 29*4f1223e8SApple OSS Distributions #ifndef XNU_LIBKERN_LIBKERN_CXX_BOUNDED_PTR_H 30*4f1223e8SApple OSS Distributions #define XNU_LIBKERN_LIBKERN_CXX_BOUNDED_PTR_H 31*4f1223e8SApple OSS Distributions 32*4f1223e8SApple OSS Distributions #if !TAPI 33*4f1223e8SApple OSS Distributions 34*4f1223e8SApple OSS Distributions #include <stddef.h> 35*4f1223e8SApple OSS Distributions #include <stdint.h> 36*4f1223e8SApple OSS Distributions #include <os/overflow.h> 37*4f1223e8SApple OSS Distributions #include <os/base.h> 38*4f1223e8SApple OSS Distributions 39*4f1223e8SApple OSS Distributions #if !defined(__improbable) 40*4f1223e8SApple OSS Distributions # define __improbable(...) __builtin_expect((__VA_ARGS__), 0) 41*4f1223e8SApple OSS Distributions #endif 42*4f1223e8SApple OSS Distributions 43*4f1223e8SApple OSS Distributions namespace libkern { 44*4f1223e8SApple OSS Distributions namespace detail { 45*4f1223e8SApple OSS Distributions // Reimplementation of things in <type_traits> because we don't seem 46*4f1223e8SApple OSS Distributions // to have the right to rely on the C++ Standard Library (based on 47*4f1223e8SApple OSS Distributions // attempts to compile IOHIDFamily). 48*4f1223e8SApple OSS Distributions // TODO: Do we really need to re-implement this here? 49*4f1223e8SApple OSS Distributions template <typename ...> using void_t = void; 50*4f1223e8SApple OSS Distributions template <typename T> T && declval() noexcept; 51*4f1223e8SApple OSS Distributions using nullptr_t = decltype(nullptr); 52*4f1223e8SApple OSS Distributions template <bool Cond, typename T = void> struct enable_if; 53*4f1223e8SApple OSS Distributions template <typename T> struct enable_if<true, T> { using type = T; }; 54*4f1223e8SApple OSS Distributions template <bool Cond, typename T = void> using enable_if_t = typename enable_if<Cond, T>::type; 55*4f1223e8SApple OSS Distributions template <typename T1, typename T2> 56*4f1223e8SApple OSS Distributions constexpr bool is_convertible_v = __is_convertible_to(T1, T2); 57*4f1223e8SApple OSS Distributions 58*4f1223e8SApple OSS Distributions template <typename T> inline constexpr bool is_void_v = false; 59*4f1223e8SApple OSS Distributions template <> inline constexpr bool is_void_v<void> = true; 60*4f1223e8SApple OSS Distributions template <> inline constexpr bool is_void_v<void const> = true; 61*4f1223e8SApple OSS Distributions 62*4f1223e8SApple OSS Distributions template <typename T, typename U> struct copy_const { using type = U; }; 63*4f1223e8SApple OSS Distributions template <typename T, typename U> struct copy_const<T const, U> { using type = U const; }; 64*4f1223e8SApple OSS Distributions template <typename T, typename U> using copy_const_t = typename copy_const<T, U>::type; 65*4f1223e8SApple OSS Distributions 66*4f1223e8SApple OSS Distributions template <typename T, typename U> struct copy_cv { using type = U; }; 67*4f1223e8SApple OSS Distributions template <typename T, typename U> struct copy_cv<T const, U> { using type = U const; }; 68*4f1223e8SApple OSS Distributions template <typename T, typename U> struct copy_cv<T volatile, U> { using type = U volatile; }; 69*4f1223e8SApple OSS Distributions template <typename T, typename U> struct copy_cv<T const volatile, U> { using type = U const volatile; }; 70*4f1223e8SApple OSS Distributions template <typename T, typename U> using copy_cv_t = typename copy_cv<T, U>::type; 71*4f1223e8SApple OSS Distributions 72*4f1223e8SApple OSS Distributions template <typename T, typename U> 73*4f1223e8SApple OSS Distributions using WhenComparable = void_t< 74*4f1223e8SApple OSS Distributions decltype(declval<T>() == declval<U>()), 75*4f1223e8SApple OSS Distributions decltype(declval<T>() != declval<U>()) 76*4f1223e8SApple OSS Distributions >; 77*4f1223e8SApple OSS Distributions 78*4f1223e8SApple OSS Distributions template <typename T, typename U> 79*4f1223e8SApple OSS Distributions using WhenOrderable = void_t < 80*4f1223e8SApple OSS Distributions decltype(declval<T>() < declval<U>()), 81*4f1223e8SApple OSS Distributions decltype(declval<T>() > declval<U>()), 82*4f1223e8SApple OSS Distributions decltype(declval<T>() >= declval<U>()), 83*4f1223e8SApple OSS Distributions decltype(declval<T>() <= declval<U>()) 84*4f1223e8SApple OSS Distributions >; 85*4f1223e8SApple OSS Distributions 86*4f1223e8SApple OSS Distributions // Pretend that sizeof(void) is 1, otherwise the in-bounds check doesn't 87*4f1223e8SApple OSS Distributions // make sense for `bounded_ptr<void>`. 88*4f1223e8SApple OSS Distributions template <typename T> constexpr size_t sizeof_v = sizeof(T); 89*4f1223e8SApple OSS Distributions template <> inline constexpr size_t sizeof_v<void> = 1; 90*4f1223e8SApple OSS Distributions template <> inline constexpr size_t sizeof_v<void const> = 1; 91*4f1223e8SApple OSS Distributions template <> inline constexpr size_t sizeof_v<void volatile> = 1; 92*4f1223e8SApple OSS Distributions template <> inline constexpr size_t sizeof_v<void const volatile> = 1; 93*4f1223e8SApple OSS Distributions } // end namespace detail 94*4f1223e8SApple OSS Distributions 95*4f1223e8SApple OSS Distributions // Non-owning pointer to an object (or a range of objects) of type `T` 96*4f1223e8SApple OSS Distributions // that validates that the address is within some specified bounds on 97*4f1223e8SApple OSS Distributions // dereference-like operations. 98*4f1223e8SApple OSS Distributions // 99*4f1223e8SApple OSS Distributions // Conceptually, a `bounded_ptr` points within a range of memory `[begin, end)`. 100*4f1223e8SApple OSS Distributions // If accessing any part of the result of dereferencing the pointer would 101*4f1223e8SApple OSS Distributions // lead to an access outside of the `[begin, end)` range, the pointer is 102*4f1223e8SApple OSS Distributions // said to be out-of-bounds. Due to representational constraints, the range 103*4f1223e8SApple OSS Distributions // of in-bounds memory must be no larger than 4GB. 104*4f1223e8SApple OSS Distributions // 105*4f1223e8SApple OSS Distributions // Dereference-like operations (dereference, subscript, pointer member access) 106*4f1223e8SApple OSS Distributions // validate that the pointer is not out-of-bounds. If an out-of-bounds pointer 107*4f1223e8SApple OSS Distributions // is dereferenced, the `TrappingPolicy` is called as 108*4f1223e8SApple OSS Distributions // `TrappingPolicy::trap(some-message)`, and the operation is said to "trap". 109*4f1223e8SApple OSS Distributions // This terminology is used below to describe the behavior of the `TrappingPolicy`. 110*4f1223e8SApple OSS Distributions // 111*4f1223e8SApple OSS Distributions // Pointer arithmetic is allowed (and the bounds are not validated), so it is 112*4f1223e8SApple OSS Distributions // entirely possible to make a `bounded_ptr` point outside of its range. 113*4f1223e8SApple OSS Distributions // However, overflow checking is performed on arithmetic operations, and 114*4f1223e8SApple OSS Distributions // any operation resulting in an overflow will also "trap". 115*4f1223e8SApple OSS Distributions // 116*4f1223e8SApple OSS Distributions // The behavior of the `TrappingPolicy` can be customized as desired, however 117*4f1223e8SApple OSS Distributions // a trap should never return, causing the current `bounded_ptr` operation to 118*4f1223e8SApple OSS Distributions // be aborted. This is important since the trap could signify an integer 119*4f1223e8SApple OSS Distributions // overflow, a null-pointer dereference or something else that would lead to 120*4f1223e8SApple OSS Distributions // undefined behavior (UB) if `TrappingPolicy::trap` were to return. 121*4f1223e8SApple OSS Distributions // 122*4f1223e8SApple OSS Distributions // Creation of `bounded_ptr`s 123*4f1223e8SApple OSS Distributions // ========================== 124*4f1223e8SApple OSS Distributions // `bounded_ptr` provides a single constructor allowing the bounds of the 125*4f1223e8SApple OSS Distributions // pointer to be specified. When integrating `bounded_ptr` into an existing 126*4f1223e8SApple OSS Distributions // code base, it is recommended to use `bounded_ptr` as an iterator obtained 127*4f1223e8SApple OSS Distributions // from other container-like abstractions, instead of manually using the 128*4f1223e8SApple OSS Distributions // constructor that allows specifying a range. Specifying the range manually 129*4f1223e8SApple OSS Distributions // on construction is error-prone, and `bounded_ptr` can't help reduce 130*4f1223e8SApple OSS Distributions // out-of-bounds accesses if the bounds are specified incorrectly. 131*4f1223e8SApple OSS Distributions // 132*4f1223e8SApple OSS Distributions // Furthermore, it is a design choice to not provide a constructor that uses 133*4f1223e8SApple OSS Distributions // relative offsets from the pointer itself to determine the range, because 134*4f1223e8SApple OSS Distributions // such a constructor is deemed more confusing than helpful. For example, is 135*4f1223e8SApple OSS Distributions // the offset a number of bytes or a number of objects? Is the offset inclusive 136*4f1223e8SApple OSS Distributions // or exclusive? Instead, factory functions should be used to create `bounded_ptr`s. 137*4f1223e8SApple OSS Distributions // 138*4f1223e8SApple OSS Distributions // Remark on const-ness 139*4f1223e8SApple OSS Distributions // ==================== 140*4f1223e8SApple OSS Distributions // Like for raw pointers, the const-ness of a `bounded_ptr` has no bearing on 141*4f1223e8SApple OSS Distributions // whether the pointee is const. Hence, it is possible to obtain a non-const 142*4f1223e8SApple OSS Distributions // reference to an object from a const `bounded_ptr`. To encode a 143*4f1223e8SApple OSS Distributions // pointer-to-const, simply create a `bounded_ptr<T const>`. 144*4f1223e8SApple OSS Distributions template <typename T, typename TrappingPolicy> 145*4f1223e8SApple OSS Distributions struct __attribute__((trivial_abi)) bounded_ptr { 146*4f1223e8SApple OSS Distributions private: 147*4f1223e8SApple OSS Distributions using CharType = detail::copy_cv_t<T, char>; 148*4f1223e8SApple OSS Distributions 149*4f1223e8SApple OSS Distributions public: 150*4f1223e8SApple OSS Distributions // Creates a null `bounded_ptr`. 151*4f1223e8SApple OSS Distributions // 152*4f1223e8SApple OSS Distributions // A null `bounded_ptr` does not point to any object and is conceptually 153*4f1223e8SApple OSS Distributions // out of bounds, so dereferencing it will trap. "Observing" operations 154*4f1223e8SApple OSS Distributions // like comparison and check-for-null, along with assignment, are valid 155*4f1223e8SApple OSS Distributions // operations on a null `bounded_ptr`. 156*4f1223e8SApple OSS Distributions OS_ALWAYS_INLINE constexpr 157*4f1223e8SApple OSS Distributions bounded_ptr(detail::nullptr_t) 158*4f1223e8SApple OSS Distributions : base_(nullptr), count_(0), offset_(0) 159*4f1223e8SApple OSS Distributions { 160*4f1223e8SApple OSS Distributions } 161*4f1223e8SApple OSS Distributions 162*4f1223e8SApple OSS Distributions OS_ALWAYS_INLINE constexpr 163*4f1223e8SApple OSS Distributions explicit 164*4f1223e8SApple OSS Distributions bounded_ptr() 165*4f1223e8SApple OSS Distributions : bounded_ptr(nullptr) 166*4f1223e8SApple OSS Distributions { 167*4f1223e8SApple OSS Distributions } 168*4f1223e8SApple OSS Distributions 169*4f1223e8SApple OSS Distributions // Creates a `bounded_ptr` pointing to the given object, and whose bounds 170*4f1223e8SApple OSS Distributions // are described by the provided `[begin, end)` range. 171*4f1223e8SApple OSS Distributions // 172*4f1223e8SApple OSS Distributions // This constructor does not check whether the constructed pointer is 173*4f1223e8SApple OSS Distributions // within its bounds. However, it does check that the provided `[begin, end)` 174*4f1223e8SApple OSS Distributions // range is a valid range (that is, `begin <= end`). 175*4f1223e8SApple OSS Distributions // 176*4f1223e8SApple OSS Distributions // Furthermore, the number of bytes in the range of in-bounds memory must be 177*4f1223e8SApple OSS Distributions // representable by a uint32_t, which means that there can be no more than 178*4f1223e8SApple OSS Distributions // 2^32 bytes (i.e. 4GB) in that range. Otherwise, the constructor will trap. 179*4f1223e8SApple OSS Distributions OS_ALWAYS_INLINE explicit 180*4f1223e8SApple OSS Distributions bounded_ptr(T* pointer, T const* begin, T const* end) 181*4f1223e8SApple OSS Distributions { 182*4f1223e8SApple OSS Distributions base_ = reinterpret_cast<CharType*>(const_cast<T*>(begin)); 183*4f1223e8SApple OSS Distributions 184*4f1223e8SApple OSS Distributions // Store (end - begin) into count_, making sure we don't overflow 185*4f1223e8SApple OSS Distributions if (__improbable(os_sub_overflow(reinterpret_cast<uintptr_t>(end), 186*4f1223e8SApple OSS Distributions reinterpret_cast<uintptr_t>(begin), 187*4f1223e8SApple OSS Distributions &count_))) { 188*4f1223e8SApple OSS Distributions TrappingPolicy::trap("The range of valid memory is too large to be represented " 189*4f1223e8SApple OSS Distributions "by this type, or [begin, end) is not a well-formed range"); 190*4f1223e8SApple OSS Distributions } 191*4f1223e8SApple OSS Distributions 192*4f1223e8SApple OSS Distributions // Store (pointer - begin) into offset_, making sure we don't overflow. 193*4f1223e8SApple OSS Distributions // Note that offset_ can be negative if `pointer` is outside of the 194*4f1223e8SApple OSS Distributions // range delimited by [begin, end), which can be valid if it represents 195*4f1223e8SApple OSS Distributions // e.g. a subrange of an array. 196*4f1223e8SApple OSS Distributions if (__improbable(os_sub_overflow(reinterpret_cast<uintptr_t>(pointer), 197*4f1223e8SApple OSS Distributions reinterpret_cast<uintptr_t>(begin), 198*4f1223e8SApple OSS Distributions &offset_))) { 199*4f1223e8SApple OSS Distributions TrappingPolicy::trap("The offset of the pointer inside its valid memory " 200*4f1223e8SApple OSS Distributions "range can't be represented using int32_t"); 201*4f1223e8SApple OSS Distributions } 202*4f1223e8SApple OSS Distributions } 203*4f1223e8SApple OSS Distributions 204*4f1223e8SApple OSS Distributions // Creates a `bounded_ptr` to a type `T` from a `bounded_ptr` to a type `U`. 205*4f1223e8SApple OSS Distributions // 206*4f1223e8SApple OSS Distributions // This converting constructor is enabled whenever `U*` is implicitly 207*4f1223e8SApple OSS Distributions // convertible to `T*`. This allows the usual implicit conversions 208*4f1223e8SApple OSS Distributions // between base-and-derived types, and also from any type `U*` to a 209*4f1223e8SApple OSS Distributions // `void*`. If other casts (like between unrelated pointer types) are 210*4f1223e8SApple OSS Distributions // desired, `libkern::reinterpret_pointer_cast` can be used instead. 211*4f1223e8SApple OSS Distributions // 212*4f1223e8SApple OSS Distributions // The bounds on the resulting `bounded_ptr` are inherited from the 213*4f1223e8SApple OSS Distributions // original `bounded_ptr`. 214*4f1223e8SApple OSS Distributions template <typename U, typename Policy, typename = detail::enable_if_t<detail::is_convertible_v<U*, T*> > > 215*4f1223e8SApple OSS Distributions OS_ALWAYS_INLINE 216*4f1223e8SApple OSS Distributions bounded_ptr(bounded_ptr<U, Policy> const & other) 217*4f1223e8SApple OSS Distributions : base_(other.base_) 218*4f1223e8SApple OSS Distributions , count_(other.count_) 219*4f1223e8SApple OSS Distributions , offset_(static_cast<int32_t>(reinterpret_cast<CharType*>(static_cast<T*>(other.get_ptr_())) - other.base_)) 220*4f1223e8SApple OSS Distributions { 221*4f1223e8SApple OSS Distributions } 222*4f1223e8SApple OSS Distributions 223*4f1223e8SApple OSS Distributions // Assigns a `bounded_ptr` to a type `U` to a `bounded_ptr` to a type `T`, 224*4f1223e8SApple OSS Distributions // as long as `U*` is convertible to `T*`. 225*4f1223e8SApple OSS Distributions // 226*4f1223e8SApple OSS Distributions // This is a rebinding operation, like assignment between raw pointers, 227*4f1223e8SApple OSS Distributions // and the destination `bounded_ptr` will inherit the bounds of the 228*4f1223e8SApple OSS Distributions // source `bounded_ptr`. 229*4f1223e8SApple OSS Distributions template <typename U, typename Policy, typename = detail::enable_if_t<detail::is_convertible_v<U*, T*> > > 230*4f1223e8SApple OSS Distributions OS_ALWAYS_INLINE bounded_ptr& 231*4f1223e8SApple OSS Distributions operator=(bounded_ptr<U, Policy> const& other) 232*4f1223e8SApple OSS Distributions { 233*4f1223e8SApple OSS Distributions base_ = other.base_; 234*4f1223e8SApple OSS Distributions count_ = other.count_; 235*4f1223e8SApple OSS Distributions offset_ = static_cast<int32_t>(reinterpret_cast<CharType*>(static_cast<T*>(other.get_ptr_())) - other.base_); 236*4f1223e8SApple OSS Distributions return *this; 237*4f1223e8SApple OSS Distributions } 238*4f1223e8SApple OSS Distributions 239*4f1223e8SApple OSS Distributions // Sets a `bounded_ptr` to null. 240*4f1223e8SApple OSS Distributions // 241*4f1223e8SApple OSS Distributions // This is effectively equivalent to assigning a default-constructed 242*4f1223e8SApple OSS Distributions // `bounded_ptr` to the target. As a result, the original bounds of 243*4f1223e8SApple OSS Distributions // the `bounded_ptr` are discarded, and the resulting `bounded_ptr` 244*4f1223e8SApple OSS Distributions // is both out-of-bounds and also has no bounds assigned to it (like 245*4f1223e8SApple OSS Distributions // a default-constructed `bounded_ptr`). 246*4f1223e8SApple OSS Distributions OS_ALWAYS_INLINE bounded_ptr& 247*4f1223e8SApple OSS Distributions operator=(detail::nullptr_t) 248*4f1223e8SApple OSS Distributions { 249*4f1223e8SApple OSS Distributions *this = bounded_ptr(); 250*4f1223e8SApple OSS Distributions return *this; 251*4f1223e8SApple OSS Distributions } 252*4f1223e8SApple OSS Distributions 253*4f1223e8SApple OSS Distributions // Returns a reference to the object pointed-to by the `bounded_ptr`. 254*4f1223e8SApple OSS Distributions // 255*4f1223e8SApple OSS Distributions // Traps if the pointer is pointing outside of its bounds. 256*4f1223e8SApple OSS Distributions // 257*4f1223e8SApple OSS Distributions // Also note that this function will trap when dereferencing a null 258*4f1223e8SApple OSS Distributions // `bounded_ptr`, unless the bounds of the pointer have been set and 259*4f1223e8SApple OSS Distributions // include address 0, in which case there's effectively nothing to 260*4f1223e8SApple OSS Distributions // diagnose. 261*4f1223e8SApple OSS Distributions template <typename T_ = T> // delay instantiation to avoid forming invalid ref for bounded_ptr<void> 262*4f1223e8SApple OSS Distributions OS_ALWAYS_INLINE T_& 263*4f1223e8SApple OSS Distributions operator*() const 264*4f1223e8SApple OSS Distributions { 265*4f1223e8SApple OSS Distributions if (__improbable(!in_bounds_())) { 266*4f1223e8SApple OSS Distributions TrappingPolicy::trap("bounded_ptr<T>::operator*: Dereferencing this pointer " 267*4f1223e8SApple OSS Distributions "would access memory outside of the bounds set originally"); 268*4f1223e8SApple OSS Distributions } 269*4f1223e8SApple OSS Distributions return *get_ptr_(); 270*4f1223e8SApple OSS Distributions } 271*4f1223e8SApple OSS Distributions 272*4f1223e8SApple OSS Distributions OS_ALWAYS_INLINE T* 273*4f1223e8SApple OSS Distributions operator->() const 274*4f1223e8SApple OSS Distributions { 275*4f1223e8SApple OSS Distributions if (__improbable(!in_bounds_())) { 276*4f1223e8SApple OSS Distributions TrappingPolicy::trap("bounded_ptr<T>::operator->: Accessing a member through this pointer " 277*4f1223e8SApple OSS Distributions "would access memory outside of the bounds set originally"); 278*4f1223e8SApple OSS Distributions } 279*4f1223e8SApple OSS Distributions return get_ptr_(); 280*4f1223e8SApple OSS Distributions } 281*4f1223e8SApple OSS Distributions 282*4f1223e8SApple OSS Distributions // Provides access to the n-th element past the given pointer. 283*4f1223e8SApple OSS Distributions // 284*4f1223e8SApple OSS Distributions // The `bounded_ptr` validates whether the provided index is within the 285*4f1223e8SApple OSS Distributions // bounds of the `bounded_ptr`. Like for raw pointers, a negative index 286*4f1223e8SApple OSS Distributions // may be passed, in which case the pointer is accessed at a negative 287*4f1223e8SApple OSS Distributions // offset (which must still be in bounds). 288*4f1223e8SApple OSS Distributions template <typename T_ = T> // delay instantiation to avoid forming invalid ref for bounded_ptr<void> 289*4f1223e8SApple OSS Distributions OS_ALWAYS_INLINE T_& 290*4f1223e8SApple OSS Distributions operator[](ptrdiff_t n) const 291*4f1223e8SApple OSS Distributions { 292*4f1223e8SApple OSS Distributions return *(*this + n); 293*4f1223e8SApple OSS Distributions } 294*4f1223e8SApple OSS Distributions 295*4f1223e8SApple OSS Distributions // Converts a `bounded_ptr` to a raw pointer, after checking it is within 296*4f1223e8SApple OSS Distributions // its bounds. 297*4f1223e8SApple OSS Distributions // 298*4f1223e8SApple OSS Distributions // The primary intended usage of this function is to aid bridging between 299*4f1223e8SApple OSS Distributions // code that uses `bounded_ptr`s and code that does not. 300*4f1223e8SApple OSS Distributions OS_ALWAYS_INLINE T* 301*4f1223e8SApple OSS Distributions discard_bounds() const 302*4f1223e8SApple OSS Distributions { 303*4f1223e8SApple OSS Distributions if (__improbable(!in_bounds_())) { 304*4f1223e8SApple OSS Distributions TrappingPolicy::trap("bounded_ptr<T>::discard_bounds: Discarding the bounds on " 305*4f1223e8SApple OSS Distributions "this pointer would lose the fact that it is outside of the " 306*4f1223e8SApple OSS Distributions "bounds set originally"); 307*4f1223e8SApple OSS Distributions } 308*4f1223e8SApple OSS Distributions return get_ptr_(); 309*4f1223e8SApple OSS Distributions } 310*4f1223e8SApple OSS Distributions 311*4f1223e8SApple OSS Distributions // Converts a `bounded_ptr` to a raw pointer, without checking whether the 312*4f1223e8SApple OSS Distributions // pointer is within its bounds. 313*4f1223e8SApple OSS Distributions // 314*4f1223e8SApple OSS Distributions // Like `discard_bounds()`, the primary intended usage of this function 315*4f1223e8SApple OSS Distributions // is to aid bridging between code that uses `bounded_ptr`s and code that 316*4f1223e8SApple OSS Distributions // does not. However, unlike `discard_bounds()`, this function does not 317*4f1223e8SApple OSS Distributions // validate that the returned pointer is in bounds. This functionality is 318*4f1223e8SApple OSS Distributions // necessary when the pointer represents something that can't be 319*4f1223e8SApple OSS Distributions // dereferenced (hence it's OK for it to be out-of-bounds), but that 320*4f1223e8SApple OSS Distributions // is still useful for other purposes like comparing against other 321*4f1223e8SApple OSS Distributions // pointers. An example of that is the `end` pointer in a half-open 322*4f1223e8SApple OSS Distributions // interval `[begin, end)`, where the `end` pointer is out-of-bounds and 323*4f1223e8SApple OSS Distributions // can't be dereferenced, yet it's still useful to delimit the range. 324*4f1223e8SApple OSS Distributions OS_ALWAYS_INLINE T* 325*4f1223e8SApple OSS Distributions unsafe_discard_bounds() const 326*4f1223e8SApple OSS Distributions { 327*4f1223e8SApple OSS Distributions return get_ptr_(); 328*4f1223e8SApple OSS Distributions } 329*4f1223e8SApple OSS Distributions 330*4f1223e8SApple OSS Distributions // Implicit conversion to bool, returning whether the pointer is null. 331*4f1223e8SApple OSS Distributions // 332*4f1223e8SApple OSS Distributions // This operation does not perform any validation of the bounds. 333*4f1223e8SApple OSS Distributions OS_ALWAYS_INLINE explicit 334*4f1223e8SApple OSS Distributions operator bool() const 335*4f1223e8SApple OSS Distributions { 336*4f1223e8SApple OSS Distributions return get_ptr_() != nullptr; 337*4f1223e8SApple OSS Distributions } 338*4f1223e8SApple OSS Distributions 339*4f1223e8SApple OSS Distributions // Increment/decrement a `bounded_ptr`. 340*4f1223e8SApple OSS Distributions // 341*4f1223e8SApple OSS Distributions // Like for other arithmetic operations, this does not check whether the 342*4f1223e8SApple OSS Distributions // increment or decrement operation results in an out-of-bounds pointer. 343*4f1223e8SApple OSS Distributions OS_ALWAYS_INLINE bounded_ptr& 344*4f1223e8SApple OSS Distributions operator++() 345*4f1223e8SApple OSS Distributions { 346*4f1223e8SApple OSS Distributions *this += 1; 347*4f1223e8SApple OSS Distributions return *this; 348*4f1223e8SApple OSS Distributions } 349*4f1223e8SApple OSS Distributions OS_ALWAYS_INLINE bounded_ptr 350*4f1223e8SApple OSS Distributions operator++(int) 351*4f1223e8SApple OSS Distributions { 352*4f1223e8SApple OSS Distributions bounded_ptr old = *this; 353*4f1223e8SApple OSS Distributions ++*this; 354*4f1223e8SApple OSS Distributions return old; 355*4f1223e8SApple OSS Distributions } 356*4f1223e8SApple OSS Distributions OS_ALWAYS_INLINE bounded_ptr& 357*4f1223e8SApple OSS Distributions operator--() 358*4f1223e8SApple OSS Distributions { 359*4f1223e8SApple OSS Distributions *this -= 1; 360*4f1223e8SApple OSS Distributions return *this; 361*4f1223e8SApple OSS Distributions } 362*4f1223e8SApple OSS Distributions OS_ALWAYS_INLINE bounded_ptr 363*4f1223e8SApple OSS Distributions operator--(int) 364*4f1223e8SApple OSS Distributions { 365*4f1223e8SApple OSS Distributions bounded_ptr old = *this; 366*4f1223e8SApple OSS Distributions --*this; 367*4f1223e8SApple OSS Distributions return old; 368*4f1223e8SApple OSS Distributions } 369*4f1223e8SApple OSS Distributions 370*4f1223e8SApple OSS Distributions // Increment or decrement a `bounded_ptr` by a given offset. 371*4f1223e8SApple OSS Distributions // 372*4f1223e8SApple OSS Distributions // This is equivalent to adding the given offset to the underlying raw 373*4f1223e8SApple OSS Distributions // pointer. In particular, the bounds of the `bounded_ptr` are left 374*4f1223e8SApple OSS Distributions // untouched by this operation. Furthermore, like for raw pointers, it 375*4f1223e8SApple OSS Distributions // is possible to provide a negative offset, which will have the effect 376*4f1223e8SApple OSS Distributions // of decrementing the `bounded_ptr` instead of incrementing it. 377*4f1223e8SApple OSS Distributions // 378*4f1223e8SApple OSS Distributions // Also note that the offset is NOT a number of bytes -- just like for 379*4f1223e8SApple OSS Distributions // raw pointers, it is a number of "positions" to move the pointer from, 380*4f1223e8SApple OSS Distributions // which essentially means `n * sizeof(T)` bytes. Again, this works exactly 381*4f1223e8SApple OSS Distributions // the same as a raw pointer to an object of type `T`. 382*4f1223e8SApple OSS Distributions // 383*4f1223e8SApple OSS Distributions // Like other arithmetic operations, this does not check whether the 384*4f1223e8SApple OSS Distributions // increment or decrement operation results in an out-of-bounds pointer. 385*4f1223e8SApple OSS Distributions // However, this does check whether the arithmetic operation would result 386*4f1223e8SApple OSS Distributions // in an overflow, in which case the operation will trap. 387*4f1223e8SApple OSS Distributions template <typename T_ = T> 388*4f1223e8SApple OSS Distributions OS_ALWAYS_INLINE bounded_ptr& 389*4f1223e8SApple OSS Distributions operator+=(ptrdiff_t n) 390*4f1223e8SApple OSS Distributions { 391*4f1223e8SApple OSS Distributions static_assert(!detail::is_void_v<T_>, "Arithmetic on bounded_ptr<void> is not allowed."); 392*4f1223e8SApple OSS Distributions 393*4f1223e8SApple OSS Distributions ptrdiff_t bytes; 394*4f1223e8SApple OSS Distributions if (__improbable(os_mul_overflow(n, sizeof(T), &bytes))) { 395*4f1223e8SApple OSS Distributions TrappingPolicy::trap( 396*4f1223e8SApple OSS Distributions "bounded_ptr<T>::operator+=(n): Calculating the number of bytes to " 397*4f1223e8SApple OSS Distributions "add to the offset (n * sizeof(T)) would trigger an overflow"); 398*4f1223e8SApple OSS Distributions } 399*4f1223e8SApple OSS Distributions if (__improbable(os_add_overflow(offset_, bytes, &offset_))) { 400*4f1223e8SApple OSS Distributions TrappingPolicy::trap( 401*4f1223e8SApple OSS Distributions "bounded_ptr<T>::operator+=(n): Adding the specified number of bytes " 402*4f1223e8SApple OSS Distributions "to the offset representing the current position would overflow."); 403*4f1223e8SApple OSS Distributions } 404*4f1223e8SApple OSS Distributions return *this; 405*4f1223e8SApple OSS Distributions } 406*4f1223e8SApple OSS Distributions 407*4f1223e8SApple OSS Distributions template <typename T_ = T> 408*4f1223e8SApple OSS Distributions OS_ALWAYS_INLINE bounded_ptr& 409*4f1223e8SApple OSS Distributions operator-=(ptrdiff_t n) 410*4f1223e8SApple OSS Distributions { 411*4f1223e8SApple OSS Distributions static_assert(!detail::is_void_v<T_>, "Arithmetic on bounded_ptr<void> is not allowed."); 412*4f1223e8SApple OSS Distributions 413*4f1223e8SApple OSS Distributions ptrdiff_t bytes; 414*4f1223e8SApple OSS Distributions if (__improbable(os_mul_overflow(n, sizeof(T), &bytes))) { 415*4f1223e8SApple OSS Distributions TrappingPolicy::trap( 416*4f1223e8SApple OSS Distributions "bounded_ptr<T>::operator-=(n): Calculating the number of bytes to " 417*4f1223e8SApple OSS Distributions "subtract from the offset (n * sizeof(T)) would trigger an overflow"); 418*4f1223e8SApple OSS Distributions } 419*4f1223e8SApple OSS Distributions if (__improbable(os_sub_overflow(offset_, bytes, &offset_))) { 420*4f1223e8SApple OSS Distributions TrappingPolicy::trap( 421*4f1223e8SApple OSS Distributions "bounded_ptr<T>::operator-=(n): Subtracting the specified number of bytes " 422*4f1223e8SApple OSS Distributions "from the offset representing the current position would overflow."); 423*4f1223e8SApple OSS Distributions } 424*4f1223e8SApple OSS Distributions return *this; 425*4f1223e8SApple OSS Distributions } 426*4f1223e8SApple OSS Distributions 427*4f1223e8SApple OSS Distributions friend OS_ALWAYS_INLINE bounded_ptr 428*4f1223e8SApple OSS Distributions operator+(bounded_ptr p, ptrdiff_t n) 429*4f1223e8SApple OSS Distributions { 430*4f1223e8SApple OSS Distributions p += n; 431*4f1223e8SApple OSS Distributions return p; 432*4f1223e8SApple OSS Distributions } 433*4f1223e8SApple OSS Distributions friend OS_ALWAYS_INLINE bounded_ptr 434*4f1223e8SApple OSS Distributions operator+(ptrdiff_t n, bounded_ptr p) 435*4f1223e8SApple OSS Distributions { 436*4f1223e8SApple OSS Distributions p += n; 437*4f1223e8SApple OSS Distributions return p; 438*4f1223e8SApple OSS Distributions } 439*4f1223e8SApple OSS Distributions friend OS_ALWAYS_INLINE bounded_ptr 440*4f1223e8SApple OSS Distributions operator-(bounded_ptr p, ptrdiff_t n) 441*4f1223e8SApple OSS Distributions { 442*4f1223e8SApple OSS Distributions p -= n; 443*4f1223e8SApple OSS Distributions return p; 444*4f1223e8SApple OSS Distributions } 445*4f1223e8SApple OSS Distributions 446*4f1223e8SApple OSS Distributions // Returns the difference between two `bounded_ptr`s. 447*4f1223e8SApple OSS Distributions // 448*4f1223e8SApple OSS Distributions // This is semantically equivalent to subtracting the two underlying 449*4f1223e8SApple OSS Distributions // pointers. The bounds of the pointers are not validated by this 450*4f1223e8SApple OSS Distributions // operation. 451*4f1223e8SApple OSS Distributions friend OS_ALWAYS_INLINE ptrdiff_t 452*4f1223e8SApple OSS Distributions operator-(bounded_ptr const& a, bounded_ptr const& b) 453*4f1223e8SApple OSS Distributions { 454*4f1223e8SApple OSS Distributions return a.get_ptr_() - b.get_ptr_(); 455*4f1223e8SApple OSS Distributions } 456*4f1223e8SApple OSS Distributions 457*4f1223e8SApple OSS Distributions friend OS_ALWAYS_INLINE ptrdiff_t 458*4f1223e8SApple OSS Distributions operator-(bounded_ptr const& a, T const* b) 459*4f1223e8SApple OSS Distributions { 460*4f1223e8SApple OSS Distributions return a.get_ptr_() - b; 461*4f1223e8SApple OSS Distributions } 462*4f1223e8SApple OSS Distributions 463*4f1223e8SApple OSS Distributions friend OS_ALWAYS_INLINE ptrdiff_t 464*4f1223e8SApple OSS Distributions operator-(T const* a, bounded_ptr const& b) 465*4f1223e8SApple OSS Distributions { 466*4f1223e8SApple OSS Distributions return a - b.get_ptr_(); 467*4f1223e8SApple OSS Distributions } 468*4f1223e8SApple OSS Distributions 469*4f1223e8SApple OSS Distributions private: 470*4f1223e8SApple OSS Distributions OS_ALWAYS_INLINE bool 471*4f1223e8SApple OSS Distributions in_bounds_() const 472*4f1223e8SApple OSS Distributions { 473*4f1223e8SApple OSS Distributions static_assert(detail::sizeof_v<T> <= UINT32_MAX - INT32_MAX, 474*4f1223e8SApple OSS Distributions "The type pointed-to by bounded_ptr is too large, which would defeat " 475*4f1223e8SApple OSS Distributions "our optimization to check for inboundedness using arithmetic on unsigned"); 476*4f1223e8SApple OSS Distributions return offset_ >= 0 && static_cast<uint32_t>(offset_) + static_cast<uint32_t>(detail::sizeof_v<T>) <= count_; 477*4f1223e8SApple OSS Distributions } 478*4f1223e8SApple OSS Distributions 479*4f1223e8SApple OSS Distributions OS_ALWAYS_INLINE T* 480*4f1223e8SApple OSS Distributions get_ptr_() const 481*4f1223e8SApple OSS Distributions { 482*4f1223e8SApple OSS Distributions // Compute `base_ + offset_`, catching overflows. 483*4f1223e8SApple OSS Distributions uintptr_t ptr; 484*4f1223e8SApple OSS Distributions if (__improbable(os_add_overflow(reinterpret_cast<uintptr_t>(base_), offset_, &ptr))) { 485*4f1223e8SApple OSS Distributions TrappingPolicy::trap("This bounded_ptr is pointing to memory outside of what can " 486*4f1223e8SApple OSS Distributions "be represented by a native pointer."); 487*4f1223e8SApple OSS Distributions } 488*4f1223e8SApple OSS Distributions return reinterpret_cast<T*>(ptr); 489*4f1223e8SApple OSS Distributions } 490*4f1223e8SApple OSS Distributions 491*4f1223e8SApple OSS Distributions template <typename T_, typename U, typename Policy> 492*4f1223e8SApple OSS Distributions friend bounded_ptr<T_, Policy> reinterpret_pointer_cast(bounded_ptr<U, Policy> const&) noexcept; 493*4f1223e8SApple OSS Distributions 494*4f1223e8SApple OSS Distributions template <typename U, typename P> friend struct bounded_ptr; // for cross-type operations and conversions 495*4f1223e8SApple OSS Distributions 496*4f1223e8SApple OSS Distributions CharType* base_; // pointer to the beginning of the valid address range 497*4f1223e8SApple OSS Distributions uint32_t count_; // number of bytes considered in-bounds (non-negative) 498*4f1223e8SApple OSS Distributions int32_t offset_; // current offset into the range, in bytes 499*4f1223e8SApple OSS Distributions }; 500*4f1223e8SApple OSS Distributions 501*4f1223e8SApple OSS Distributions // Returns whether two `bounded_ptr`s point to the same object. 502*4f1223e8SApple OSS Distributions // 503*4f1223e8SApple OSS Distributions // This comparison is semantically equivalent to comparing the underlying 504*4f1223e8SApple OSS Distributions // raw pointers. In particular, it doesn't validate the bounds of either 505*4f1223e8SApple OSS Distributions // `bounded_ptr`, nor does it compare whether the two `bounded_ptr`s have 506*4f1223e8SApple OSS Distributions // the same bounds. 507*4f1223e8SApple OSS Distributions // 508*4f1223e8SApple OSS Distributions // This comparison is enabled between `bounded_ptr`s whenever the two 509*4f1223e8SApple OSS Distributions // corresponding raw pointer types are comparable. Comparison between a 510*4f1223e8SApple OSS Distributions // raw pointer and a `bounded_ptr` is also allowed, so long as the 511*4f1223e8SApple OSS Distributions // two corresponding raw pointer types are comparable. 512*4f1223e8SApple OSS Distributions template <typename T, typename P1, typename U, typename P2, typename = detail::WhenComparable<T*, U*> > 513*4f1223e8SApple OSS Distributions OS_ALWAYS_INLINE bool 514*4f1223e8SApple OSS Distributions operator==(bounded_ptr<T, P1> const& a, bounded_ptr<U, P2> const& b) 515*4f1223e8SApple OSS Distributions { 516*4f1223e8SApple OSS Distributions return a.unsafe_discard_bounds() == b.unsafe_discard_bounds(); 517*4f1223e8SApple OSS Distributions } 518*4f1223e8SApple OSS Distributions 519*4f1223e8SApple OSS Distributions template <typename T, typename P1, typename U, typename P2, typename = detail::WhenComparable<T*, U*> > 520*4f1223e8SApple OSS Distributions OS_ALWAYS_INLINE bool 521*4f1223e8SApple OSS Distributions operator!=(bounded_ptr<T, P1> const& a, bounded_ptr<U, P2> const& b) 522*4f1223e8SApple OSS Distributions { 523*4f1223e8SApple OSS Distributions return !(a == b); 524*4f1223e8SApple OSS Distributions } 525*4f1223e8SApple OSS Distributions 526*4f1223e8SApple OSS Distributions template <typename T, typename P, typename U, typename = detail::WhenComparable<T*, U*> > 527*4f1223e8SApple OSS Distributions OS_ALWAYS_INLINE bool 528*4f1223e8SApple OSS Distributions operator==(bounded_ptr<T, P> const& a, U* b) 529*4f1223e8SApple OSS Distributions { 530*4f1223e8SApple OSS Distributions return a.unsafe_discard_bounds() == b; 531*4f1223e8SApple OSS Distributions } 532*4f1223e8SApple OSS Distributions 533*4f1223e8SApple OSS Distributions template <typename T, typename P, typename U, typename = detail::WhenComparable<T*, U*> > 534*4f1223e8SApple OSS Distributions OS_ALWAYS_INLINE bool 535*4f1223e8SApple OSS Distributions operator==(U* a, bounded_ptr<T, P> const& b) 536*4f1223e8SApple OSS Distributions { 537*4f1223e8SApple OSS Distributions return a == b.unsafe_discard_bounds(); 538*4f1223e8SApple OSS Distributions } 539*4f1223e8SApple OSS Distributions 540*4f1223e8SApple OSS Distributions template <typename T, typename P, typename U, typename = detail::WhenComparable<T*, U*> > 541*4f1223e8SApple OSS Distributions OS_ALWAYS_INLINE bool 542*4f1223e8SApple OSS Distributions operator!=(bounded_ptr<T, P> const& a, U* b) 543*4f1223e8SApple OSS Distributions { 544*4f1223e8SApple OSS Distributions return !(a == b); 545*4f1223e8SApple OSS Distributions } 546*4f1223e8SApple OSS Distributions 547*4f1223e8SApple OSS Distributions template <typename T, typename P, typename U, typename = detail::WhenComparable<T*, U*> > 548*4f1223e8SApple OSS Distributions OS_ALWAYS_INLINE bool 549*4f1223e8SApple OSS Distributions operator!=(U* a, bounded_ptr<T, P> const& b) 550*4f1223e8SApple OSS Distributions { 551*4f1223e8SApple OSS Distributions return !(a == b); 552*4f1223e8SApple OSS Distributions } 553*4f1223e8SApple OSS Distributions 554*4f1223e8SApple OSS Distributions template <typename T, typename Policy> 555*4f1223e8SApple OSS Distributions OS_ALWAYS_INLINE bool 556*4f1223e8SApple OSS Distributions operator==(detail::nullptr_t, bounded_ptr<T, Policy> const& p) 557*4f1223e8SApple OSS Distributions { 558*4f1223e8SApple OSS Distributions return p.unsafe_discard_bounds() == nullptr; 559*4f1223e8SApple OSS Distributions } 560*4f1223e8SApple OSS Distributions 561*4f1223e8SApple OSS Distributions template <typename T, typename Policy> 562*4f1223e8SApple OSS Distributions OS_ALWAYS_INLINE bool 563*4f1223e8SApple OSS Distributions operator!=(detail::nullptr_t, bounded_ptr<T, Policy> const& p) 564*4f1223e8SApple OSS Distributions { 565*4f1223e8SApple OSS Distributions return p.unsafe_discard_bounds() != nullptr; 566*4f1223e8SApple OSS Distributions } 567*4f1223e8SApple OSS Distributions 568*4f1223e8SApple OSS Distributions template <typename T, typename Policy> 569*4f1223e8SApple OSS Distributions OS_ALWAYS_INLINE bool 570*4f1223e8SApple OSS Distributions operator==(bounded_ptr<T, Policy> const& p, detail::nullptr_t) 571*4f1223e8SApple OSS Distributions { 572*4f1223e8SApple OSS Distributions return p.unsafe_discard_bounds() == nullptr; 573*4f1223e8SApple OSS Distributions } 574*4f1223e8SApple OSS Distributions 575*4f1223e8SApple OSS Distributions template <typename T, typename Policy> 576*4f1223e8SApple OSS Distributions OS_ALWAYS_INLINE bool 577*4f1223e8SApple OSS Distributions operator!=(bounded_ptr<T, Policy> const& p, detail::nullptr_t) 578*4f1223e8SApple OSS Distributions { 579*4f1223e8SApple OSS Distributions return p.unsafe_discard_bounds() != nullptr; 580*4f1223e8SApple OSS Distributions } 581*4f1223e8SApple OSS Distributions 582*4f1223e8SApple OSS Distributions // Returns whether a `bounded_ptr` points to an address that is {less-than, 583*4f1223e8SApple OSS Distributions // less-than-or-equal-to, greater-than, greater-than-or-equal-to} the address 584*4f1223e8SApple OSS Distributions // held in another `bounded_ptr`. 585*4f1223e8SApple OSS Distributions // 586*4f1223e8SApple OSS Distributions // This doesn't validate the bounds of either `bounded_ptr`, nor does it 587*4f1223e8SApple OSS Distributions // compare those bounds to determine the ordering result. This ordering is 588*4f1223e8SApple OSS Distributions // semantically equivalent to ordering the result of calling `get()` on both 589*4f1223e8SApple OSS Distributions // `bounded_ptr`s. 590*4f1223e8SApple OSS Distributions // 591*4f1223e8SApple OSS Distributions // This ordering is enabled between `bounded_ptr`s whenever the two 592*4f1223e8SApple OSS Distributions // corresponding raw pointer types are orderable. Ordering between a 593*4f1223e8SApple OSS Distributions // raw pointer and a `bounded_ptr` is also allowed, so long as the 594*4f1223e8SApple OSS Distributions // two corresponding raw pointer types are orderable. 595*4f1223e8SApple OSS Distributions // 596*4f1223e8SApple OSS Distributions 597*4f1223e8SApple OSS Distributions template <typename T, typename U, typename P1, typename P2, typename = detail::WhenOrderable<T*, U*> > 598*4f1223e8SApple OSS Distributions OS_ALWAYS_INLINE bool 599*4f1223e8SApple OSS Distributions operator<(bounded_ptr<T, P1> const& a, bounded_ptr<U, P2> const& b) 600*4f1223e8SApple OSS Distributions { 601*4f1223e8SApple OSS Distributions return a.unsafe_discard_bounds() < b.unsafe_discard_bounds(); 602*4f1223e8SApple OSS Distributions } 603*4f1223e8SApple OSS Distributions 604*4f1223e8SApple OSS Distributions template <typename T, typename U, typename P1, typename P2, typename = detail::WhenOrderable<T*, U*> > 605*4f1223e8SApple OSS Distributions OS_ALWAYS_INLINE bool 606*4f1223e8SApple OSS Distributions operator<=(bounded_ptr<T, P1> const& a, bounded_ptr<U, P2> const& b) 607*4f1223e8SApple OSS Distributions { 608*4f1223e8SApple OSS Distributions return a.unsafe_discard_bounds() <= b.unsafe_discard_bounds(); 609*4f1223e8SApple OSS Distributions } 610*4f1223e8SApple OSS Distributions 611*4f1223e8SApple OSS Distributions template <typename T, typename U, typename P1, typename P2, typename = detail::WhenOrderable<T*, U*> > 612*4f1223e8SApple OSS Distributions OS_ALWAYS_INLINE bool 613*4f1223e8SApple OSS Distributions operator>(bounded_ptr<T, P1> const& a, bounded_ptr<U, P2> const& b) 614*4f1223e8SApple OSS Distributions { 615*4f1223e8SApple OSS Distributions return a.unsafe_discard_bounds() > b.unsafe_discard_bounds(); 616*4f1223e8SApple OSS Distributions } 617*4f1223e8SApple OSS Distributions 618*4f1223e8SApple OSS Distributions template <typename T, typename U, typename P1, typename P2, typename = detail::WhenOrderable<T*, U*> > 619*4f1223e8SApple OSS Distributions OS_ALWAYS_INLINE bool 620*4f1223e8SApple OSS Distributions operator>=(bounded_ptr<T, P1> const& a, bounded_ptr<U, P2> const& b) 621*4f1223e8SApple OSS Distributions { 622*4f1223e8SApple OSS Distributions return a.unsafe_discard_bounds() >= b.unsafe_discard_bounds(); 623*4f1223e8SApple OSS Distributions } 624*4f1223e8SApple OSS Distributions 625*4f1223e8SApple OSS Distributions template <typename T, typename U, typename P, typename = detail::WhenOrderable<T*, U*> > 626*4f1223e8SApple OSS Distributions OS_ALWAYS_INLINE bool 627*4f1223e8SApple OSS Distributions operator<(T* a, bounded_ptr<U, P> const& b) 628*4f1223e8SApple OSS Distributions { 629*4f1223e8SApple OSS Distributions return a < b.unsafe_discard_bounds(); 630*4f1223e8SApple OSS Distributions } 631*4f1223e8SApple OSS Distributions 632*4f1223e8SApple OSS Distributions template <typename T, typename U, typename P, typename = detail::WhenOrderable<T*, U*> > 633*4f1223e8SApple OSS Distributions OS_ALWAYS_INLINE bool 634*4f1223e8SApple OSS Distributions operator<(bounded_ptr<T, P> const& a, U* b) 635*4f1223e8SApple OSS Distributions { 636*4f1223e8SApple OSS Distributions return a.unsafe_discard_bounds() < b; 637*4f1223e8SApple OSS Distributions } 638*4f1223e8SApple OSS Distributions 639*4f1223e8SApple OSS Distributions template <typename T, typename U, typename P, typename = detail::WhenOrderable<T*, U*> > 640*4f1223e8SApple OSS Distributions OS_ALWAYS_INLINE bool 641*4f1223e8SApple OSS Distributions operator<=(T* a, bounded_ptr<U, P> const& b) 642*4f1223e8SApple OSS Distributions { 643*4f1223e8SApple OSS Distributions return a <= b.unsafe_discard_bounds(); 644*4f1223e8SApple OSS Distributions } 645*4f1223e8SApple OSS Distributions 646*4f1223e8SApple OSS Distributions template <typename T, typename U, typename P, typename = detail::WhenOrderable<T*, U*> > 647*4f1223e8SApple OSS Distributions OS_ALWAYS_INLINE bool 648*4f1223e8SApple OSS Distributions operator<=(bounded_ptr<T, P> const& a, U* b) 649*4f1223e8SApple OSS Distributions { 650*4f1223e8SApple OSS Distributions return a.unsafe_discard_bounds() <= b; 651*4f1223e8SApple OSS Distributions } 652*4f1223e8SApple OSS Distributions 653*4f1223e8SApple OSS Distributions template <typename T, typename U, typename P, typename = detail::WhenOrderable<T*, U*> > 654*4f1223e8SApple OSS Distributions OS_ALWAYS_INLINE bool 655*4f1223e8SApple OSS Distributions operator>(T* a, bounded_ptr<U, P> const& b) 656*4f1223e8SApple OSS Distributions { 657*4f1223e8SApple OSS Distributions return a > b.unsafe_discard_bounds(); 658*4f1223e8SApple OSS Distributions } 659*4f1223e8SApple OSS Distributions 660*4f1223e8SApple OSS Distributions template <typename T, typename U, typename P, typename = detail::WhenOrderable<T*, U*> > 661*4f1223e8SApple OSS Distributions OS_ALWAYS_INLINE bool 662*4f1223e8SApple OSS Distributions operator>(bounded_ptr<T, P> const& a, U* b) 663*4f1223e8SApple OSS Distributions { 664*4f1223e8SApple OSS Distributions return a.unsafe_discard_bounds() > b; 665*4f1223e8SApple OSS Distributions } 666*4f1223e8SApple OSS Distributions 667*4f1223e8SApple OSS Distributions template <typename T, typename U, typename P, typename = detail::WhenOrderable<T*, U*> > 668*4f1223e8SApple OSS Distributions OS_ALWAYS_INLINE bool 669*4f1223e8SApple OSS Distributions operator>=(T* a, bounded_ptr<U, P> const& b) 670*4f1223e8SApple OSS Distributions { 671*4f1223e8SApple OSS Distributions return a >= b.unsafe_discard_bounds(); 672*4f1223e8SApple OSS Distributions } 673*4f1223e8SApple OSS Distributions 674*4f1223e8SApple OSS Distributions template <typename T, typename U, typename P, typename = detail::WhenOrderable<T*, U*> > 675*4f1223e8SApple OSS Distributions OS_ALWAYS_INLINE bool 676*4f1223e8SApple OSS Distributions operator>=(bounded_ptr<T, P> const& a, U* b) 677*4f1223e8SApple OSS Distributions { 678*4f1223e8SApple OSS Distributions return a.unsafe_discard_bounds() >= b; 679*4f1223e8SApple OSS Distributions } 680*4f1223e8SApple OSS Distributions 681*4f1223e8SApple OSS Distributions template <typename T, typename U> 682*4f1223e8SApple OSS Distributions OS_ALWAYS_INLINE T* 683*4f1223e8SApple OSS Distributions reinterpret_pointer_cast(U* p) noexcept 684*4f1223e8SApple OSS Distributions { 685*4f1223e8SApple OSS Distributions return reinterpret_cast<T*>(p); 686*4f1223e8SApple OSS Distributions } 687*4f1223e8SApple OSS Distributions 688*4f1223e8SApple OSS Distributions // Reinterprets a `bounded_ptr` to a type `T` to a `bounded_ptr` to a type `U`. 689*4f1223e8SApple OSS Distributions // 690*4f1223e8SApple OSS Distributions // This is equivalent to `reinterpret_cast`ing the underlying pointer as well 691*4f1223e8SApple OSS Distributions // as the bounds of the original pointer. Like for a raw `reinterpret_cast`, 692*4f1223e8SApple OSS Distributions // no offset adjustment is performed (even if needed, e.g. for derived-to-base 693*4f1223e8SApple OSS Distributions // casts with multiple inheritance). Because this is extremely unsafe, it should 694*4f1223e8SApple OSS Distributions // be used extremely sparingly. 695*4f1223e8SApple OSS Distributions template <typename T, typename U, typename Policy> 696*4f1223e8SApple OSS Distributions OS_ALWAYS_INLINE bounded_ptr<T, Policy> 697*4f1223e8SApple OSS Distributions reinterpret_pointer_cast(bounded_ptr<U, Policy> const& p) noexcept 698*4f1223e8SApple OSS Distributions { 699*4f1223e8SApple OSS Distributions using CharType = detail::copy_cv_t<T, char>; 700*4f1223e8SApple OSS Distributions CharType* new_begin = reinterpret_cast<CharType*>(p.base_); 701*4f1223e8SApple OSS Distributions CharType* new_end = new_begin + p.count_; 702*4f1223e8SApple OSS Distributions return bounded_ptr<T, Policy>(reinterpret_cast<T*>(p.get_ptr_()), 703*4f1223e8SApple OSS Distributions reinterpret_cast<T const*>(new_begin), 704*4f1223e8SApple OSS Distributions reinterpret_cast<T const*>(new_end)); 705*4f1223e8SApple OSS Distributions } 706*4f1223e8SApple OSS Distributions } // end namespace libkern 707*4f1223e8SApple OSS Distributions 708*4f1223e8SApple OSS Distributions #endif /* !TAPI */ 709*4f1223e8SApple OSS Distributions 710*4f1223e8SApple OSS Distributions #endif // !XNU_LIBKERN_LIBKERN_CXX_BOUNDED_PTR_H 711